Commit Graph
202 Commits
Author SHA1 Message Date
Tyler 6ffef69705 Merge pull request #6 from Twest2/StepForge pr/02-security-boundary
Template tests / tests (push) Failing after 2m37s
Close the renderer privilege boundary: navigation, IPC, permissions, shell (plan PR 2)
2026-07-03 11:27:28 -07:00
TylerandClaude Fable 5 50e445e7c3 Close the renderer privilege boundary: navigation, IPC, permissions, shell
Template tests / tests (pull_request) Failing after 33s
Phase 1 of the improvement plan (PR 2 of the sequence). A remote page could
previously inherit the privileged preload bridge: the main window had no
navigation guard or popup handler, IPC handlers accepted any sender, every
Electron permission was granted to everyone, and shell:openPath accepted an
arbitrary renderer-supplied target.

- New app/security.js (plain-Node testable) centralizes the policy:
  app-page identity, navigation/popup denial, deny-by-default permissions,
  external-URL validation, IPC sender guard, payload budgets, field
  validators, and a produced-files registry.
- Every window (main, region overlay, capture worker) is sandboxed, denies
  all navigation away from its own page, denies every popup, and refuses
  webview attachment.
- Every IPC channel now rejects events that are not from the main window's
  top frame on index.html, rejects non-plain/oversized argument bags, and
  channels with risky inputs validate ids, enums, names, and sizes
  (path-traversal and prototype-pollution guards included).
- Permissions are deny-by-default; the only grant in the app is display
  capture (+media) for the dedicated capture-worker page. The display-media
  handler also verifies the requesting frame.
- shell:openPath/showItemInFolder are gone. Replacements are intent-specific:
  openProduced (only files the main process produced this session),
  revealLinkedArchive (path read from the store, not the renderer), and
  openExternal (parsed, scheme-checked http(s)/mailto only).
- archive:peek removed: unused, and it let the renderer read arbitrary
  archives by path.
- export:run only accepts output directories that came from a dialog pick or
  remembered settings; anything else re-prompts.
- Renderer: description links never navigate; http(s)/mailto open externally
  via the validated handler.
- 12 new security regression tests: hostile navigation targets, permission
  matrix, sender spoofing (wrong window/subframe/navigated/disposed frames),
  oversized payloads, traversal/pollution attempts, produced-file registry,
  and source-level guards (no blanket grants, no generic shell channels,
  sandbox on every window).

Verified: 215 unit tests pass; startup smoke, unit-workflows, sample
artifacts, and build-release E2E pass; click self-test still reaches
source: stream with markers 3/3 and burst 8/8 under the deny-by-default
policy (arm/debounce remain the known pre-existing failures, untouched
here); UI screenshot confirms the sandboxed renderer boots.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-03 11:25:36 -07:00
Tyler 6a3005f24c Merge pull request #5 from Twest2/StepForge pr/01-toolchain-ci
Template tests / tests (push) Failing after 33s
Pin Node toolchain, remove runtime npm repair, make CI and E2E truthful (plan PR 1)
2026-07-03 11:12:29 -07:00
TylerandClaude Fable 5 0f966a5fd0 Pin the Node toolchain, remove runtime npm repair, make CI and E2E truthful
Template tests / tests (pull_request) Failing after 1m26s
Phase 0 of the improvement plan (ai_prompts/prompt4.md): make the baseline
reproducible and stop the test runner from masking real failures.

- Pin Node >= 22.12 (engines + .nvmrc + engine-strict); every entry point
  fails fast with clear guidance instead of dying late with ERR_REQUIRE_ESM
  inside the packaging dependency graph.
- electron-launcher.js is diagnostics-only: all runtime npm install/rebuild/
  repair paths are removed. npm ci on the pinned toolchain is the only
  supported install path (README + GETTING_STARTED updated).
- Refuse to silently launch unsandboxed on Linux: --no-sandbox now requires
  an explicit STEPFORGE_ALLOW_NO_SANDBOX/ELECTRON_DISABLE_SANDBOX opt-in and
  is otherwise a hard error with actionable fixes; user-namespace sandboxing
  is detected and preferred.
- Click-capture E2E no longer converts startup crashes into "SKIPPED": the
  only allowed skip is the upfront absence of a display server. A missing
  shared library or crash now fails with the startup log. Same guard added
  to the startup smoke check.
- GitHub CI: run on pull_request, pin Node from .nvmrc, drop the macOS matrix
  entry (not a support target), and audit production and full dependency
  trees as separate signals. Gitea CI: pull_request trigger + pinned Node.
- Refresh package-lock on Node 22/npm 10 and remediate the form-data and
  undici advisories (npm audit: 0 vulnerabilities, prod and full tree).
- Stop tracking generated machine-specific build reports
  (build/build_report.md, build/artifacts_manifest.json).

Verified: 203 unit tests pass; repo-structure, startup-smoke, unit-workflows,
sample-artifacts, and build-release checks pass locally with a real Electron
launch. The click self-test now truthfully reports the pre-existing Linux
arm/debounce capture failures (also red on Gitea CI main run 177) instead of
hiding behind SKIPPED; that defect is scheduled for the capture-fix PR.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-03 13:09:51 -07:00
Tyler 534a28ece8 Merge GitHub main and keep Linux WIP
Template tests / tests (push) Failing after 33s
2026-06-29 08:22:40 -05:00
Tyler c2e05c900f Remove linux support
Template tests / tests (push) Successful in 2m0s
2026-06-29 08:11:43 -05:00
Tyler 7c006a7bb7 Fix Windows installer and build versioning 2026-06-26 22:37:13 -05:00
Tyler 999f4a13b8 Minor fixes 2026-06-26 22:21:53 -05:00
Tyler 3356b935fc Minor fixes 2026-06-26 22:10:54 -05:00
Tyler 749f8d2d0d Add back red circle to windows 2026-06-26 21:38:22 -05:00
Tyler dd49e42290 Fix npm test glob on CI 2026-06-26 18:41:12 -05:00
Tyler 266a92fedb Fix windows breakage from linux dev 2026-06-26 18:38:03 -05:00
Tyler 0325b6efbc ubuntu not working. idk I'm just gonna use windows anyway 2026-06-26 18:00:22 -05:00
Tyler 3c5c520799 work on linux release
Linux release not fully working as well as windows, will investigate later
2026-06-26 17:02:35 -05:00
Tyler 962f929de2 fixed recording workflow on ubuntu
ai gen description: Root cause 1 — The mandatory constraint removal (most critical)

In Electron 29+ / Chromium 116+, the old getUserMedia format with a mandatory: {} wrapper was removed. The capture worker was still using it:

video: { mandatory: { chromeMediaSource: 'desktop', ... } }  // broke in Electron 29+
This caused getUserMedia to throw in the worker, which sent a stream-error back to the main process, which fell back to the frame loop. Fix: flat constraint format with no mandatory wrapper.

Root cause 2 — Frame loop spammed getSources() every 200ms

Once the stream backend failed, the fallback frame loop called desktopCapturer.getSources() 5× per second. On Linux via the XDG portal, each getSources() call is a new permission request → dialog every few seconds. Fix: on Linux without click capture, don't fall back to the frame loop at all — just let interval/hotkey captures take individual fresh shots.

Root cause 3 — Interval/hotkey captures bypassed the stream backend

Even when the stream backend is running, sessionCapture('interval') went straight to shoot() → grab() → getSources(). Fix: non-click triggers now pull a buffered frame from the stream backend's ring buffer (sampled every 100ms), completely avoiding getSources().

Root cause 4 — Stream backend never started on Wayland

The earlier fix made recorderWanted = false on Wayland, so the stream backend never even started. Fix: recorderWanted is now true whenever stream capture is enabled (the default), regardless of whether click detection is available.

Safety net — setPermissionCheckHandler

Electron 29+ requires an explicit permission grant for display-capture in renderer windows. Added a handler that grants all permissions (safe for a fully local/offline app like StepForge).

Windows is completely unaffected — the constraint fix is Electron-version level (affects both platforms the same), and all the Linux-specific frame-loop guards only fire when clickCaptureAvailable() returns false, which only happens on Wayland.
2026-06-26 16:11:16 -05:00
Tyler a5a8498e71 Keep recording bar in ubuntu 2026-06-26 15:49:49 -05:00
Tyler 32788fafdc fixed ubuntu (Wayland) recording workflow 2026-06-26 15:48:09 -05:00
TylerandGitHub 412a4f4820 Merge pull request #4 from Twest2/feature/ai-vision-hybrid
Feature/ai vision hybrid
2026-06-26 08:52:52 -05:00
Tyler 3915865029 Keep ai model saved when app closes. 2026-06-26 08:48:38 -05:00
Tyler 79edb6bb56 Change model
Ran into an issue with the previous model for having mllama archetecture so I changed it
2026-06-26 08:36:45 -05:00
Tyler a971ff870f Added feature to where local ai models can see the image in each step. 2026-06-26 08:05:18 -05:00
TylerandGitHub 9bd4a959c4 Semantic capture titles, AI documentation assist, and keyboard tracking (#3)
Template tests / tests (push) Successful in 1m58s
Semantic capture titles, AI documentation assist, and keyboard tracking
2026-06-24 12:11:11 -05:00
TylerandClaude Sonnet 4.6 ebeb6ac578 label Enable AI setting as experimental
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-06-24 12:04:40 -05:00
TylerandClaude Sonnet 4.6 f60cf1a688 label generate-all-steps menu item as experimental
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-06-24 12:02:59 -05:00
TylerandClaude Sonnet 4.6 2d1b474931 fix generate-all-steps: never overwrite existing content, right target per step
The previous version called target:'all' on every step unconditionally,
which caused the AI to rewrite steps that already had good titles and
descriptions — often making them worse or inaccurate.

New behaviour:
- Build a queue of only the steps that are actually missing content
  (placeholder title and/or empty description).
- Determine target per step: 'title', 'description', or 'all' — only
  fill what is blank; leave existing user-written text completely alone.
- If all steps already have titles and descriptions, show a toast and stop.
- Call reload() once at the end instead of patching this.steps mid-loop,
  so the editor and step list both update atomically from the store.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-06-24 11:27:24 -05:00
TylerandClaude Sonnet 4.6 c60b7247af generate all text fields with AI now fills every step, not just current
Previously the menu action only ran AI generation on the selected step.
Now it loops through all steps sequentially, showing progress ("AI:
filling step N of M…"), then reloads the visible step when done.
Partial failures are reported in the final toast.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-06-24 11:22:27 -05:00
TylerandClaude Sonnet 4.6 cf056d2b97 stop AI from generating text/code/table blocks on generate-all
The model was producing Text and Code blocks on every 'generate all
fields' action — uninstructed, generic, and never useful for the user.

Blocks are only appropriate when the user explicitly edits an existing
block (target === 'block'). For title/description/all generation:
- Schema collapses to { "title", "description" } — no blocks key
- targetText no longer mentions blocks
- allowedBlockNote is null (omitted from prompt)
- Rule explicitly says "Do NOT add any blocks array"

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-06-24 11:18:41 -05:00
TylerandClaude Sonnet 4.6 3fa366a0d0 revert UIAutomation background thread — it stalled click detection
TryLoadUia() blocked for several seconds loading reflection assemblies at
ClickProcessorLoop startup, during which no CLICK events were emitted.
Restored MouseHookCallback to emit CTX + CLICK synchronously (fast Win32
only) as before — no startup cost, clicks are never delayed.

The wider OCR crop and smarter search-results title fallback are kept.
UIAutomation element lookup can be revisited with a pre-warmed approach.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-06-24 11:14:49 -05:00
TylerandClaude Sonnet 4.6 d0b1816175 fix step-behind titles: UIAutomation element label from click watcher + smarter search fallback
**Root cause**
When OCR fails, the title fell back to the browser window title.  For a
click on a search-results page, the window title reflects the *previous*
search query ("oracle - Google Search"), producing "Search for Oracle"
even though the user is clicking a link *on* that page.

**Fix 1: UIAutomation element label from the click watcher**
The C# click-watcher hook now enriches each click in a background thread
(ClickProcessorLoop) rather than in the hook callback:
- MouseHookCallback captures window title synchronously (fast Win32),
  then queues a PendingClick and returns immediately.
- ClickProcessorLoop calls AutomationElement.FromPoint() via reflection
  (no compile-time assembly reference → no startup failure if UIA is
  absent).  Wrapped in a 300ms timeout thread so slow UIA calls don't
  delay the click event past the frame buffer window.
- Emits CTX + ELEM (label/role/value) + CLICK as an atomic batch.

Node.js:
- Parses ELEM events, merges element info into _pendingWindowContext.
- clickMeta.windowContext now carries elementLabel/elementRole/elementValue
  in addition to windowTitle/appName.
- buildCaptureTitle priority-5 (element label) now fires from click-watcher
  data, giving "Select Oracle | Cloud Applications…" without OCR.

**Fix 2: Wider OCR crop**
ocrAroundClick now uses a full-display-width × 100px horizontal strip at
the click height.  The previous 420 px crop cropped through long link text
(e.g. "Oracle | Cloud Applications and Cloud Platform"), causing fragments
to be scored lower than the complete text.

**Fix 3: Search-results window title fallback**
extractSearchQuery now only produces "Search for Oracle" when recentTyped
is non-empty (the user was actually typing a query).  For a pure click on
the search-results page (no recent typing), the fallback is "Select a
Oracle result in Chrome" — honest about what we know without implying the
user performed the search in this step.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-06-24 11:05:34 -05:00
TylerandClaude Sonnet 4.6 dfa65c894b ci: only run tests on push to main, not on PR commits
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-06-24 10:53:30 -05:00
TylerandClaude Sonnet 4.6 162ae0ae05 improve AI rewrite UX and title quality
**AI button: dynamic tooltip hints**
- titleAiBtn and descAiBtn now show "Rewrite with AI" when the field
  already has user content, "Generate with AI" when empty.
- updateAiButtonHints() fires on every title/description input event
  and whenever syncStepFields() runs to keep hints current.

**Stronger rewrite prompt**
- When the user has typed a draft title or description, the prompt now
  shows it explicitly: "User's draft title (rewrite this): '...'"
- Rules changed from "improve its wording" to "Your only job is to
  polish its grammar and phrasing. Do NOT replace it with something
  different." — prevents the model from ignoring the user's text and
  generating fresh content from capture context.
- The suggested-title hint is suppressed when a draft title exists so
  the model doesn't silently swap the user's text for the auto-title.

**Title quality: generic window title filter**
- GENERIC_WINDOW_TITLES Set filters "New Tab", "Untitled", "Loading"
  etc. from the window-title path so they no longer produce titles
  like "Open New Tab in Chrome".

**Title quality: app name stripping for non-browser apps**
- stripBrowserNameSuffix now accepts an optional appName; it strips
  the app's display name and process name from the window title suffix
  using the same pattern as browser names.
- "Document1.docx - Word" with appName "winword" → "Document1.docx".
- buildCaptureTitle passes metadata.appName into the strip call.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-06-24 10:42:56 -05:00
TylerandClaude Sonnet 4.6 879434f14f fix: capture window title from click watcher instead of spawning PowerShell
Root cause of all-"Screen capture" titles: collectWindowsWindowContext
called execFileSync('powershell.exe') with a 1200 ms timeout, but
PowerShell cold-start on typical Windows systems takes 1-3 seconds.
Every capture timed out silently, returned empty metadata, and fell
back to "Screen capture".

Fix:
- The click watcher C# process (already running, already compiled)
  now emits a CTX event immediately before each CLICK event using
  GetForegroundWindow → GetWindowText + QueryFullProcessImageName.
  These are synchronous Win32 calls, sub-millisecond, no startup cost.
- CTX payload is base64-encoded to survive the line protocol safely:
    CTX <b64title> <b64app> <unixMs>
- processClickWatcherData parses CTX lines and stores the decoded
  strings in this._lastWindowContext.
- enqueueClickCapture attaches it as clickMeta.windowContext.
- buildCaptureContext uses it directly (Promise.resolve) when present,
  bypassing the PowerShell spawn entirely.

Fallback (manual captures without a session click watcher running):
- collectWindowsWindowContext is now async and uses execFile with a
  4 s timeout instead of execFileSync at 1200 ms, so it no longer
  blocks the event loop and has room to succeed on slower machines.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-06-24 10:16:11 -05:00
TylerandClaude Sonnet 4.6 13b5f67de8 add keyboard tracking and app-qualified smart titles
**Keyboard hook (Windows)**
- Extends the existing C# WH_MOUSE_LL process to also install
  WH_KEYBOARD_LL alongside it (keyboard hook is optional — failure
  does not break mouse capture).
- Emits CHAR <code> <ts> for printable keystrokes, KEY <name> <ts>
  for modifier combos (Ctrl+T) and special keys (Backspace, Enter).

**Text accumulation in capture session**
- CaptureService tracks _keyBuffer (typed chars since last step) and
  _lastShortcut (last modifier combo) using the new onKeyboardEvent()
  method.
- snapshotKeyContext() is called at enqueueClickCapture time so each
  step's clickMeta.keyContext carries { recentTyped, recentShortcut }.
- Buffer resets after each snapshot; stale input (>8s gap) is dropped.

**UIAutomation element value**
- collectWindowsWindowContext now reads ValuePattern.Current.Value
  from the clicked element — giving us what's actually typed in a
  search box or text field without needing the keyboard buffer.

**Smart title generation (core/text-intel.js)**
- Priority chain: keyboard shortcut → element value → typed text
  → OCR → element label → page title → app name.
- SHORTCUT_TITLES maps 50+ common shortcuts (Ctrl+T, Ctrl+S, F5 …)
  to natural language descriptions: "Open new tab", "Save", etc.
- qualifyTitleWithApp() appends "in Chrome / VS Code / Terminal / …"
  to every title when the app is known: "Click Save in VS Code",
  "Search for oracle in Chrome", "Open new tab in Chrome".
- APP_DISPLAY_NAMES covers browsers, editors, terminals, office apps.

Six new unit tests cover shortcuts, typed-text search, element value,
and app-qualified OCR titles. Capture test updated for keyContext.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-06-24 10:04:34 -05:00
TylerandClaude Sonnet 4.6 8d645c0aca fix smart title generation from browser window context
The title engine was falling back to "Screen capture" for all browser
captures because it treated the entire browser window title as noise.

Changes:
- stripBrowserNameSuffix: removes "- Google Chrome" / "| Firefox" etc.
  from the end of window titles, leaving just the page title.
  "oracle - Google Search - Google Chrome" → "oracle - Google Search"
  "Oracle | Cloud Applications - Google Chrome" → page title only

- extractSearchQuery: detects "[query] - Google Search" / Bing / etc.
  patterns after stripping the browser suffix, and formats the result
  as "Search for oracle".

- buildCaptureTitle: uses stripped page title + search detection before
  falling through to the "Screen capture" fallback.

- pickBestOcrPhrase: considers the full OCR line (≤80 chars) as a
  candidate with a +35 completeness bonus before splitting on | or ·.
  This preserves "Oracle | Cloud Applications and Cloud Platform" as a
  single phrase instead of breaking it into fragments.

- candidateWords: filters out standalone punctuation tokens (|, ·, •)
  so they don't inflate word-count penalties for compound brand names.

- verbForElementRole: hyperlinks and links now produce "Select" instead
  of "Click"; search box / search field produces "Search for".

Five new unit tests cover: browser title stripping, search query
extraction, full pipe-separated link text, link and search box verbs.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-06-24 09:44:36 -05:00
TylerandClaude Sonnet 4.6 68ceee83ef fix ai title generation and remove separate rewrite section
- Remove the standalone "AI Rewrite" section from the editor panel.
  The existing title and description AI buttons already flush the step
  first, so they rewrite whatever the user has typed in those fields.

- Never pass a generic fallback title ("Screen capture", "Window
  capture", "Region capture", "Capture") as the AI title candidate or
  as step content. It is now treated as "(not set — generate a
  specific action title)" so the AI always produces something real.

- hasRichCaptureContext now counts any non-trivial app name or window
  title as sufficient context, instead of requiring non-browser noise.

- Prompt rules updated: "NEVER output Screen/Window/Region capture",
  separate paths for improving a user draft vs generating from context,
  and clearer guidance when context is limited (use app/window name).

- isPlaceholderTitle helper guards summarizeStepForAi so a
  default-titled step presents itself as empty to the AI.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-06-24 09:27:23 -05:00
TylerandClaude Sonnet 4.6 d244626583 ai smart auto-documentation and text rewrite
- Store captureMetadata (OCR text, window/app/element info) with each
  step at capture time so AI always has the original rich context.
- Add buildCaptureContext() to TextIntelService; capture.js uses it
  instead of buildCaptureTitle() so both title and metadata come from
  one pass.
- generateStepPatch() prefers stored captureMetadata over re-running
  OCR, giving the AI the best possible context when the user clicks
  an AI button later.
- Add autoDoc setting: when enabled every capture (shoot, region, and
  session hotkey/click) is automatically documented by AI. Manual
  captures await AI before returning; session captures fire-and-forget
  and push a step:updated event so the renderer reloads seamlessly.
- Add ai:rewriteText IPC and rewriteText() method for plain-text
  polishing via a separate callOllamaText() that skips JSON mode.
- Add "AI Rewrite" section in the editor right panel: textarea + AI
  button that rewrites whatever the user types in place.
- Improve buildAiPrompt() rules: action-focused title instructions,
  explicit anti-junk rules (no "Capture the screen / OCR" blocks),
  and a context-quality gate that suppresses blocks when context is
  thin.
- Add autoDoc checkbox to AI settings dialog.
- Renderer handles step:updated to reload the selected step after
  background auto-doc finishes.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-06-24 09:17:31 -05:00
Tyler 375c14b028 prefer OCR for capture titles 2026-06-24 08:55:19 -05:00
Tyler 1a1dbb846b fix settings AI test connection wiring 2026-06-23 18:14:12 -05:00
Tyler 0bd326d8b2 harden Electron startup repair 2026-06-23 18:10:35 -05:00
Tyler bd10f7d147 lazy load ocr dependency 2026-06-23 18:02:24 -05:00
Tyler 33eb0f745e semantic titles ai assist 2026-06-23 17:46:33 -05:00
TylerandGitHub cb5e0c6837 Merge pull request #2 from Twest2/text_locations
Honor text block positions in exports
2026-06-23 16:57:06 -05:00
Tyler ffaa123893 Honor text block positions in exports 2026-06-23 16:44:28 -05:00
Tyler 2b27428849 minor changes
Template tests / tests (push) Successful in 1m44s
2026-06-23 16:26:13 -05:00
Tyler 4cbab15429 Update README.md to point to new getting started documents
Template tests / tests (push) Successful in 1m42s
2026-06-23 12:18:40 -05:00
Tyler 063624ea57 Add and update TODO 2026-06-23 12:16:51 -05:00
Tyler 7fe30cf8ef Windows getting started docs with stepforge example
Template tests / tests (push) Successful in 1m44s
2026-06-23 12:10:42 -05:00
Tyler d607905b58 Disable electron-builder publish for Windows installer
Template tests / tests (push) Successful in 1m42s
2026-06-23 11:15:56 -05:00
Tyler 0f25d327c0 Disable electron-builder publish for Windows installer
Template tests / tests (push) Successful in 1m42s
2026-06-23 11:10:22 -05:00
Tyler 058582d7af Add Windows installer packaging
Template tests / tests (push) Successful in 1m40s
2026-06-23 11:01:43 -05:00