Commit Graph

27 Commits

Author SHA1 Message Date
gsxdsm
ba1e82381e fix(FN-7952): cut runtime services over to PostgreSQL (#2109)
## Summary

Engine and dashboard traffic now stays on the authoritative PostgreSQL
layer across execution, recovery, project discovery, planning sessions,
analytics, and shutdown. The dashboard no longer presents a migration
notice for a cutover that is already mandatory.

## Design decisions

- Runtime composition requires an async data layer instead of
constructing a hidden SQLite fallback.
- Engine workflow, mission, claim, and self-healing reads await their
PostgreSQL-backed store contracts.
- Project-scoped dashboard stores retain and close their backend owner
exactly once.
- The dashboard test quarantine entry remains paired with its Vitest
exclusion, preserving the repository’s deletion-ratchet policy.

## Validation

- Core, Engine, Dashboard, CLI, and Desktop typechecks pass on the
stacked branch.
- `pnpm test:gate` passes all 478 gate tests.
- This PR changes 62 files.

## Stack

- Depends on #2108.
- CLI/desktop/ops, plugins, and docs/release follow in later PRs.

Related: #2105


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Project discovery now recognizes projects using the
`.fusion/project.json` marker.
* Knowledge indexing and search are more reliable across project-scoped
storage.
* **Bug Fixes**
* Improved session, audit timeline, approval, monitoring, and analytics
data consistency.
* Prevented stale planning-session updates and project-store shutdown
races.
* Ensured chat usage and CLI session status are saved before continuing.
* **UI Changes**
* Removed the storage migration notice banner now that the PostgreSQL
transition is complete.
* **Reliability**
* Improved shutdown handling, workflow execution, and worktree behavior.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-14 22:16:16 -07:00
gsxdsm
2e4fcfcaea fix(FN-7952): establish PostgreSQL core authority (#2108)
## Summary

Fusion’s core runtime now treats PostgreSQL as the authoritative
metadata store without leaving current CLI, dashboard, desktop, or
engine composition roots uncompilable between stack layers. This is the
99-file foundation for the larger cutover: subsequent PRs migrate the
remaining consumers, plugins, and operator surfaces.

## Design decisions

- Runtime store construction fails closed when an asynchronous
PostgreSQL layer is unavailable; SQLite remains readable only at
explicit migration and identity-recovery boundaries.
- Project ownership is enforced across active, archived, workflow,
mission, analytics, and plugin-schema data.
- The small set of cross-package files in this layer are
compatibility-critical call sites required for a green intermediate
commit, not the complete consumer migration.
- Schema migration 0008 remains assigned to session-advisor state from
current `main`; mission lineage idempotency advances to 0009 so neither
invariant can be skipped.

## Validation

- All affected package typechecks pass: Core, Engine, Dashboard, CLI,
and Desktop.
- `pnpm test:gate` passes: 478 tests across the engine gate, PostgreSQL
core gate, and CLI workflow shape.
- The PR changes exactly 99 files.

## Stack

This is the base PR. Engine/dashboard, CLI/desktop/ops, plugins, and
docs/release follow as stacked PRs, each below 100 changed files.

Related: #2105


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* PostgreSQL is now the standard runtime backend, with embedded
PostgreSQL enabled by default.
* Added project-scoped storage for tasks, archives, chat sessions,
missions, knowledge pages, and operational data.
* Improved archived-task search, filtering, pagination, and restoration.
* Added safer plugin schema initialization with validation and project
isolation.
* Added PostgreSQL-backed workflow, mission, validator, and dashboard
capabilities.

* **Bug Fixes**
  * Improved startup timeout cancellation and resource cleanup.
* Prevented cross-project data access and phantom reservation cleanup
errors.
* Ensured archived tasks remain read-only and asynchronous writes
complete reliably.
  * Retired SQLite opt-out settings with clear startup errors.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-14 22:13:30 -07:00
gsxdsm
c15c78feeb feat: migrate storage from SQLite to PostgreSQL (#1793)
# Migrate storage from SQLite to PostgreSQL — full dashboard cutover

Migrates Fusion's storage layer to the embedded PostgreSQL
`AsyncDataLayer` (the default backend) and **completes the
satellite-store + feature cutover** so every dashboard and Command
Center surface works in PG mode.

## Status — every surface works in embedded-PG mode

Verified live against a running embedded-Postgres dashboard (all
**200**, zero 5xx) and gate-tested (**23 files / 99 tests** on embedded
PG, plus engine-core 294 and ci-shape 63 in the blocking merge gate;
core/engine/cli/dashboard typecheck clean).

| Area | Surfaces | State |
|---|---|---|
| Satellite stores | workflows, todos, insights, research, missions,
goals, mailbox | ✅ |
| Views | artifacts, documents, evals | ✅ |
| Command Center | activity, productivity, team, tokens, tools,
**workflows**, **github**, **signals**, **plugin-activations**, **live**
(all 10) | ✅ |
| Run execution | insight generation, research run execution | ✅
(store-path; AI step needs a provider) |
| Live updates | SSE push for mission/research/insight events | ✅ |
| Workflow editing | create / update / delete / select (+ id counter) |
✅ |
| Engine | mission autopilot, incident-signal ingestion, regression
storm-guard, agent wake-on-message | ✅ |
| Core | tasks, agents, secrets, automations, memory, chat, usage, PRs,
git | ✅ |

## Approach

Each satellite store gets an `Async<Store>` wrapper exposing the sync
store's method names over the existing `async-*-store.ts` helpers;
`get<Store>Store()` returns a `Sync | Async` union; consumers `await`
(harmless on sync), and engine/CLI paths that can't convert use
`instanceof Sync` graceful fallback. Analytics aggregators branch on
`"ping" in dbOrLayer` to run schema-qualified raw SQL over `project.*`
(snake_case) in PG. Executors/orchestrators/autopilot are
await-converted to drive the union store; the async store wrappers
extend `EventEmitter` so SSE live-push fires in both backends.

Not-yet-ported capabilities degrade gracefully (never 500) and are
individually called out in commits.

## Sync with main

The branch is kept continuously merged with `main` (currently through
FN-7845, 2026-07-12); the earlier "final rebase deferred" note no longer
applies. Use **Create a merge commit** (or squash) to land it — GitHub's
rebase-merge cannot replay a merge-maintained branch.

## Residual Review Findings

Multi-agent code review of the PostgreSQL satellite-store ports (U1–U5)
applied 3 safe fixes (see `fix(review): apply autofix feedback`). The
following are **real but gated** — recorded here as follow-up work
rather than auto-applied. All are SQLite→PostgreSQL
**concurrency/atomicity regressions**: the sync stores were immune only
by SQLite's single-writer, single-threaded-handler execution; the async
ports open multi-await read-modify-write windows. **Reachability is low
today** because the execution engines that generate concurrent same-run
mutations (insight run executor, research orchestrator/dispatcher) are
`instanceof`-gated to sync mode in PG. No process-crash class survived
(all engine fallbacks correctly guard the sync store).

- **[P1] Research `appendResearchEvent` dual-write is non-atomic**
(`packages/core/src/async-research-store.ts`, corroborated: adversarial
+ reliability). The `research_run_events` insert (own transaction) and
the `run.events` jsonb update are separate writes — a crash between
them, or two concurrent appends, splits the table count from the jsonb
array. **Fix:** perform the seq-insert and the jsonb update in one
`layer.transactionImmediate`.
- **[P1] Research run terminal-reversion via stale full-row persist**
(`async-research-store.ts` `persistResearchRun`/`updateResearchStatus`).
Concurrent `PATCH /runs/:id/status` + `POST /runs/:id/events` can revert
a terminal run to `running` by overwriting the whole row, bypassing the
transition guard. **Fix:** scoped column `UPDATE`s with a `WHERE status
…` guard, or optimistic version column.
- **[P2] `updateResearchRun`/`updateInsightRun` read-then-write TOCTOU**
— concurrent PATCHes last-writer-wins on the lifecycle merge. **Fix:**
`SELECT … FOR UPDATE` / enclosing transaction.
- **[P2] `upsertRun`/`createRunOrThrowConflict` check-then-create race**
(`async-insight-store.ts`) — two callers can each create an "active"
run. **Fix:** partial unique index on `(projectId, trigger) WHERE status
IN ('pending','running')`.
- **[P3] `createResearchRetryRun` return-value divergence** — sync
returns the pre-update `queued` snapshot; async returns the reloaded
`retry_waiting` run (persisted state is identical). Pick one side for
cross-backend parity.
- **[P2/perf] Mission `getMissionWithHierarchy`/`getMissionHealth` N+1
fan-out** — O(milestones×slices) sequential round-trips hold one pool
slot per request; can starve the pool for large hierarchies. **Fix:**
batched/joined reads.
- **Testing gaps:** no PG-mode concurrency tests (interleaved
status/event mutations), no sync↔async parity assertion for the
lifecycle-error codes, and no mission status/health rollup parity test
vs the sync `MissionStore`.

~~Out of scope (deferred): AI run *execution* (insight/research) +
mission autopilot + live SSE mission events remain sync-gated/degraded
in PG mode.~~ **Since ported** — insight/research run execution, mission
autopilot, and SSE live push all run on the async layer now, which also
makes the concurrency findings above genuinely reachable; they remain
open follow-ups.







---

## Update — 2026-07-12: production-readiness hardening & live acceptance

Everything below landed on this branch since the description above was
written:

**Production blockers from review — fixed**
- `recoverStaleTransitionPending` ported to the async layer (backend
moves write + clear the crash-safe marker; startup/maintenance sweeps no
longer throw).
- Lost-update class fixed: `atomicWriteTaskJson`/`WithAudit` write
changed columns only (full-row upserts silently resurrected stale fields
across concurrent store instances — the "task stuck unplanned forever"
bug).
- First-boot **auto-migration**: booting the PG backend over a project
with a legacy `fusion.db` migrates it automatically (loud failure,
SQLite kept as backup), and the dashboard shows a one-time **"your data
was migrated" banner** with the backup paths and a Need-help Discord
link.
- `pg_dump`/`pg_restore` discovered from common install locations for
embedded-mode backups.
- The PG suite is part of the blocking merge gate (`test:pg-gate`).

**Multi-project isolation (PR #2007, merged into this branch)**
- `project_id` partition key on tasks / archived tasks / config,
`taskProjectScope` threaded through every scan/claim/count, per-project
config rows, layer bound to the project at startup.
- Review P1 follow-up: the shared cold-storage `archive.archived_tasks`
table is also partitioned and all archived-board reads/counts/searches
are scoped.
- Schema drift self-heal generalized to schema-qualified columns so
existing databases upgrade in place.

**Other changes**
- Node settings sync **removed** in PG mode (409
`settings-sync-disabled-postgres`) — nodes share state by connecting to
the same database; auth sync kept (per-machine file).
- Perf (review findings): `listTasks` pushes column filter + ORDER BY +
LIMIT/OFFSET into SQL; `getConversation` capped to the most recent 200
messages.
- Fixed a false "operator action required" pause-abort log fired on
every successfully auto-merged task.

**Live acceptance — PASSED (2026-07-12)**
A sandboxed instance (isolated HOME, embedded PG, real Opus executor)
ran a task through the complete cycle: create → triage (AI spec) →
execute → in-review → AI squash-merge landed on the project's `main` →
done. A write+read sweep of every data surface (settings, comments,
documents, attachments + artifact bridge + artifact edit, chat with real
generation, goals, missions, agent mail, secrets, workflows, memory, CC
analytics) was green on embedded PG.

**Known remaining work**
- The per-project `config` PK re-key has no upgrade path for
pre-isolation embedded-PG databases (needs a real `DROP
CONSTRAINT`/re-key migration; fresh databases are fine).
- `pg_dump`/`pg_restore` binaries are not yet bundled in release
artifacts (PATH/common-location discovery only).
- The satellite-store concurrency findings listed above.

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Phil Larson <hello@phillarson.xyz>
Co-authored-by: fusion-merge <fusion-merge@local>
2026-07-13 19:07:58 -07:00
gsxdsm
427ce04a6f FN-7374: stop advertising Claude Sonnet 5 statically
Stop Fusion from statically offering Claude Sonnet 5 when account availability is unknown.

- Remove the supplemental direct Anthropic Claude Sonnet 5 model registration and static pricing row.
- Keep Claude CLI supplemental metadata from force-adding Sonnet 5 while preserving other extra Claude models.
- Update model registry, pricing, adapter, and provider tests to expect unavailable or upstream-only Sonnet 5 handling.
- Add a patch changeset for the operator-facing fix.

Files changed:
 .changeset/fn-7374-anthropic-sonnet-5-404.md       |  7 ++++++
 packages/core/src/__tests__/model-pricing.test.ts  | 20 +++++++---------
 packages/core/src/anthropic-models.ts              | 24 +++----------------
 packages/core/src/model-pricing.ts                 | 11 ++-------
 .../dashboard/src/__tests__/routes-auth.test.ts    | 13 ++++++----
 .../src/__tests__/pi-create-fn-agent.test.ts       | 28 ++++++----------------
 .../src/cli-agent/adapters/__tests__/pi.test.ts    |  6 ++---
 packages/pi-claude-cli/index.ts                    | 13 ++--------
 .../src/__tests__/process-manager.test.ts          |  4 ++--
 .../pi-claude-cli/src/__tests__/provider.test.ts   | 12 ++--------
 10 files changed, 44 insertions(+), 94 deletions(-)

Fusion-Task-Id: FN-7374

Fusion-Task-Lineage: 9c498bb4-c4c1-4dd8-ae80-869dfb1d4c2c

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-01 10:23:39 -07:00
gsxdsm
2335a07620 FN-7291: add Claude Sonnet 5 Anthropic support
Adds Claude Sonnet 5 to Anthropic model catalogs, pricing, and pi execution paths.

- Register supplemental direct Anthropic model metadata for Claude Sonnet 5 with deduping.
- Surface the model through dashboard model routes and engine session creation for non-Claude-CLI pi sessions.
- Add Claude CLI provider metadata, pricing coverage, tests, and a published package changeset.

Files changed:
 .changeset/fn-7291-sonnet-5-anthropic.md           |   7 ++
 packages/core/src/__tests__/model-pricing.test.ts  |  28 +++++
 packages/core/src/anthropic-models.ts              | 127 +++++++++++++++++++++
 packages/core/src/index.ts                         |   7 ++
 packages/core/src/model-pricing.ts                 |  13 ++-
 .../dashboard/src/__tests__/routes-auth.test.ts    |  67 +++++++++++
 packages/dashboard/src/routes.ts                   |   6 +-
 .../dashboard/src/routes/register-model-routes.ts  |   5 +-
 .../src/__tests__/pi-create-fn-agent.test.ts       |  67 +++++++++++
 .../src/cli-agent/adapters/__tests__/pi.test.ts    |  16 +++
 packages/engine/src/pi.ts                          |   2 +
 packages/pi-claude-cli/index.ts                    |  13 +++
 .../src/__tests__/process-manager.test.ts          |   4 +-
 .../pi-claude-cli/src/__tests__/provider.test.ts   |  31 ++++-
 14 files changed, 384 insertions(+), 9 deletions(-)

Fusion-Task-Id: FN-7291

Fusion-Task-Lineage: 6494fce8-4101-47f5-9137-306408fd7920

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-06-30 13:20:27 -07:00
gsxdsm
c17d745665 FN-7109: notify operators when CLI agents await input
Notify external providers when terminal-backed CLI agents pause for tool permission or user input.

- Add a dedicated cli-agent-awaiting-input notification event to settings, schema defaults, dashboard options, and provider tests.
- Dispatch CLI-agent waiting-on-input notifications from the in-process runtime with task context and prompt-scoped dedupe keys.
- Document the operator behavior and add a published package changeset for the new notification surface.

Files changed:
 .changeset/fn-7109-cli-agent-notification.md       |   7 ++
 docs/agents.md                                     |   4 +
 docs/settings-reference.md                         |   4 +-
 .../cli-agent-permission-notifications.md          |  13 +++
 .../core/src/__tests__/global-settings.test.ts     |   1 +
 packages/core/src/settings-schema.ts               |   1 +
 packages/core/src/types.ts                         |   6 ++
 .../SettingsModal.remote-notifications.test.tsx    |   1 +
 .../components/__tests__/settings-mobile.test.tsx  |   2 +-
 .../settings/sections/NotificationsSection.tsx     |   3 +
 .../src/__tests__/in-process-runtime.test.ts       |  56 ++++++++++-
 packages/engine/src/__tests__/notifier.test.ts     |   6 +-
 .../engine/src/__tests__/ntfy-provider.test.ts     |   4 +
 .../engine/src/__tests__/webhook-provider.test.ts  |   2 +
 .../engine/src/cli-agent/__tests__/runtime.test.ts |  39 +++++++-
 .../__tests__/notification-service.test.ts         |  56 ++++++++++-
 .../src/notification/notification-service.ts       |   9 +-
 packages/engine/src/notification/ntfy-provider.ts  |   7 ++
 .../engine/src/notification/webhook-provider.ts    |   2 +
 packages/engine/src/notifier.ts                    |   1 +
 packages/engine/src/runtimes/in-process-runtime.ts | 111 +++++++++++++++++++++
 21 files changed, 326 insertions(+), 9 deletions(-)

Fusion-Task-Id: FN-7109

Fusion-Task-Lineage: 636c1875-92a2-46a7-847e-1f4955c0822f

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-06-27 09:28:31 -07:00
gsxdsm
a9815fb1ff FN-6457: add ACP ask runner and bundled Claude bridge setup
Route ACP-backed planning and validation through a read-only ask-once runner with a pinned Claude bridge foundation.

- Add askAcpOnce for single-turn ACP sessions with timeout handling, JSON recovery, clean stop validation, and disposal.
- Refactor validation seams to use ACP runtime prompts and require structured pass verdicts.
- Resolve the Claude ACP bridge from the plugin bundle and add setup checks for identity, environment, probing, and auth readiness.
- Document the ACP Route B plan and update tests for validator, session, runtime, and plugin setup behavior.

Files changed:
 CONCEPTS.md                                        |   6 +
 docs/acp-contract.md                               |  36 ++
 .../2026-06-14-001-feat-claude-acp-runtime-plan.md | 465 +++++++++++++++++++++
 .../engine/src/__tests__/cli-agent-ask.test.ts     | 104 +++++
 .../src/__tests__/cli-agent-validator.test.ts      | 137 +++---
 .../src/__tests__/interactive-ai-session.test.ts   |  96 +++--
 packages/engine/src/agent-runtime.ts               |   6 +-
 packages/engine/src/cli-agent-ask.ts               | 120 ++++++
 packages/engine/src/cli-agent-validator.ts         |  65 ++-
 .../cli-agent/__tests__/one-shot-session.test.ts   |  16 +-
 packages/engine/src/cli-agent/one-shot-session.ts  |  17 +-
 packages/engine/src/index.ts                       |   8 +-
 packages/engine/src/interactive-ai-session.ts      |  33 +-
 plugins/fusion-plugin-acp-runtime/AGENTS.md        |  14 +
 plugins/fusion-plugin-acp-runtime/CHANGELOG.md     |   6 +
 plugins/fusion-plugin-acp-runtime/README.md        |  13 +-
 plugins/fusion-plugin-acp-runtime/package.json     |   3 +-
 .../src/__tests__/index.test.ts                    |  51 ++-
 .../src/__tests__/process-manager.test.ts          |  32 +-
 .../src/__tests__/runtime-adapter.test.ts          |   4 +-
 .../src/__tests__/setup.test.ts                    |  71 ++++
 plugins/fusion-plugin-acp-runtime/src/cli-spawn.ts |  95 ++++-
 plugins/fusion-plugin-acp-runtime/src/index.ts     |  16 +-
 .../src/process-manager.ts                         |  26 +-
 .../src/runtime-adapter.ts                         |  11 +-
 plugins/fusion-plugin-acp-runtime/src/setup.ts     | 104 +++++
 plugins/fusion-plugin-acp-runtime/src/types.ts     |   6 +-
 pnpm-lock.yaml                                     | 139 ++++--
 28 files changed, 1502 insertions(+), 198 deletions(-)

Fusion-Task-Id: FN-6457
Fusion-Task-Lineage: a3364ed7-cb28-4a2b-b898-6ccd0d95fb92
2026-06-15 02:30:41 -07:00
gsxdsm
b9afce306e fix(review): schema-version gate, output-filter escape-bypass, generic double-wrap, follow-up resolution
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 03:41:54 -07:00
gsxdsm
58723312d8 feat: bootstrap cli-agent runtime and wire executor, transport, chat, and recovery seams
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 03:24:41 -07:00
gsxdsm
85f70148a1 feat(dashboard): wire cli-agent chat surface and runner glue; fix stale engine mocks (U12 completion)
Mount CliChatSurface in ChatView for cli-backed chat sessions (sessions carrying
cliExecutorAdapterId): the message-pane + composer region is delegated to the
surface (transcript/raw-terminal toggle for hybrid/native adapters, terminal-only
for the generic adapter), while regular sessions keep the standard composer. The
existing message list and composer JSX are captured once as render thunks and
passed through, so there is no parallel message/composer UI.

Add a narrow telemetry seam: TelemetryHub gains an optional onEvent tap (also
settable post-construction via setEventListener) invoked with each sanitized
event after routing — best-effort, a throwing listener never breaks ingest. This
is the seam the CliChatSessionRunner uses to build the durable transcript from
the same sanitized events the hook route already feeds the hub, without the hub
becoming a general subscriber bus.

Fix the stale @fusion/engine vi.mocks across dashboard tests: object-literal
mocks that fully replace the module now also return listCliAdapterDescriptors
(added by U15's cli-agent-settings route, evaluated at module load). Mocks that
spread importOriginal/importActual already pick it up.

Tests: new ChatView.cli-mount.test.tsx (cli session → CliChatSurface, regular
session → normal composer, generic → terminal-only); telemetry-hub onEvent tap
coverage. chat-attachment-routes, chat-cli-sessions, cli-agent-hooks-route,
ChatView.cli-toggle all green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 03:02:27 -07:00
gsxdsm
7815055388 Merge U15: cli-agent adapter settings, autonomy approval gate, node editor config 2026-06-05 00:32:12 -07:00
gsxdsm
243113a3cf feat: cli-agent adapter settings, autonomy approval gate, and node editor config (U15)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 00:30:27 -07:00
gsxdsm
8fb7de1f7d Merge U8: cli-agent resume coordinator and self-healing integration 2026-06-05 00:17:14 -07:00
gsxdsm
10acf17c6e feat(engine): cli-agent resume coordinator and self-healing integration (U8)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 00:16:14 -07:00
gsxdsm
8bac390e1b feat(engine): cli-agent one-shot sessions for validator, planning, and CE (U9)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 00:15:57 -07:00
gsxdsm
7e94d62f6f Merge U7: cli-agent executor seam, task session lifecycle, hard-cancel integration 2026-06-05 00:02:41 -07:00
gsxdsm
c1c99a9de0 feat(engine): wire cli-agent executor seam and task session lifecycle (U7)
Add `cli-agent` as a task-execute executor kind. A workflow node with
`config.executor === "cli-agent"` drives an engine-owned CLI coding agent
through the execute step via the new cli-agent/task-session.ts orchestration:
spawn in the worktree, issue the hook token + write hook scripts, inject the
prompt after readiness, subscribe to the state machine, and resolve on a
positive completion signal (R20 gating). Config is snapshotted at launch; the
PTY is reaped (completed) at the in-review handoff.

Executor seam: runGraphCustomNode gains a cli-agent branch delegating to
runCliAgentNode; the hard-cancel/abort path (awaitAbortInFlightTaskWork +
abortAllInFlight) claims and SIGKILLs the CLI session as a first-class surface,
marking it killed (never resume-eligible). Re-entry kills any prior live
session and launches fresh; follow-up resumes the recorded native session id
when supported. A PTY-pool ceiling surfaces as a typed task value, not a stall.

Node-config typing extended minimally (WorkflowNodeExecutorKind /
WorkflowNodeExecutorConfig in @fusion/core).

Tests: cli-agent/__tests__/task-session.test.ts (12) and
__tests__/cli-agent-executor.test.ts (9) cover AE1/AE5, hard cancel, re-entry,
follow-up, config snapshot, ceiling, and the generic-tier confirm-advance path,
using scripted adapters + a mock PTY seam. Engine typecheck clean; full
src/cli-agent suite + new tests green (144 passing).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 00:01:12 -07:00
gsxdsm
fbc7c96221 Merge U5: Codex, Droid, and Pi cli-agent adapters (binaries probed; exec -r footgun guarded) 2026-06-05 00:00:49 -07:00
gsxdsm
07dcb1695e feat(engine): add Codex, Droid, and Pi cli-agent adapters (U5)
Codex (hybrid tier): native done via session-scoped notify config,
heuristic PTY waiting detection, codex resume <thread-id>, probed rollout
JSONL tailer. Droid (native tier): Claude-style hooks with a Notification
permission-vs-idle classifier, --resume / exec -s resume (never -r in exec
mode). Pi (native tier): session-JSONL telemetry + transcript tailing,
pi --session resume. Adds the session-jsonl transcript source.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 00:00:05 -07:00
gsxdsm
a08e144530 Merge U17: cli-agent hook ingestion route, per-session tokens, and hook scripts 2026-06-04 23:40:19 -07:00
gsxdsm
d8248b4c4f feat(dashboard): add cli-agent hook ingestion route and session hook scripts (U17)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 23:39:07 -07:00
gsxdsm
3eca224e83 Merge U6: generic heuristic-tier adapter with idle state surfacing 2026-06-04 23:36:21 -07:00
gsxdsm
f3b700aa5d feat(engine): add generic heuristic-tier cli-agent adapter (U6)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 23:34:33 -07:00
gsxdsm
ec4377e10a feat(engine): add Claude Code native-tier cli-agent adapter (U4)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 23:32:58 -07:00
gsxdsm
773ba76209 test(engine): self-skip real-PTY e2e when PTY I/O unavailable in environment 2026-06-04 23:24:54 -07:00
gsxdsm
ed4c7ba006 feat(engine): add cli-agent telemetry hub and session state machine (U3)
Pure engine code (no HTTP) for the CLI agent executor:

- state-machine.ts: authoritative per-session state machine implementing the
  HTD diagram (starting→ready→busy⇄waitingOnInput→done; done→busy follow-up;
  dead-classification choice → killed/userExited/authFailed/resuming; resume cap
  of 2 with backoff → needsAttention). Positive completion is distinct from idle
  (idle never produces done); inactivity stall backstop re-armed by output/
  telemetry events (no fixed turn timeout); termination classification helper for
  all five paths; per-turn latches reset between turns. Persists every transition
  via CliSessionStore (the transient `resuming` machine state maps onto the U1
  `dead` store enum) and exposes a throttled `onStateChange` subscription for the
  later SSE bridge — no dashboard imports.

- telemetry-hub.ts: in-process ingestion contract (ingest(sessionId, event)) for
  the U17 route and log-tailing adapters. Mints high-entropy per-session hook
  tokens (issueToken/validateToken/invalidate); rebuilds the registry only from
  live sessions in CliSessionStore so stale tokens for non-live sessions never
  validate; a token validates only for its own session. Bounds everything
  ingested: per-event size caps, per-turn count caps (lifecycle events exempt),
  ANSI/control stripping before pattern matching, and secret redaction that
  survives chunk boundaries via a held-back carry window (redactSecrets from
  @fusion/core).

Tests: 35 new (state-machine.test.ts, telemetry-hub.test.ts) covering AE1/AE2,
stall backstop, all termination paths, resume caps, token registry, two-turn
latch reset, oversized capping, ANSI stripping, and cross-chunk redaction.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 23:18:48 -07:00
gsxdsm
4fc1a9dd46 feat(engine): add CliAgentAdapter interface and CliSessionManager (U2)
Engine-owned PTY lifecycle for CLI agent sessions:
- adapter.ts: CliAgentAdapter interface (launch/env-allowlist builders,
  capability flags, readiness detection, injection formatter, resume builder,
  telemetry wiring) + CliAdapterRegistry with typed unknown/duplicate errors.
- session-manager.ts: CliSessionManager owning node-pty processes via the U16
  shared loader. Byte-bounded scrollback ring (default ~512KB), single
  serialized write queue shared by injections + user input (FIFO, deferral in
  quiet windows), latest-active-client resize, scoped-SIGKILL process registry
  on process exit (never port 4040), explicit async attach interface
  (scrollback + AsyncIterable<Uint8Array> + write/resize/detach),
  requestPause/requestResume watermark hooks, separate concurrency pool with
  typed CliConcurrencyLimitError at the ceiling.
- Security: bracketed paste only when ?2004h observed; unconditional control-char
  neutralization on the raw path; user keystrokes bypass neutralization.
- Persists lifecycle into the U1 CliSessionStore (create on spawn, update
  state/termination).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 23:04:13 -07:00