@sapiom/harness 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +162 -0
- package/README.md +36 -0
- package/dist/cli/bin.js +26 -2
- package/dist/cli/bin.js.map +1 -1
- package/dist/cli/consent.d.ts +29 -1
- package/dist/cli/consent.d.ts.map +1 -1
- package/dist/cli/consent.js +33 -11
- package/dist/cli/consent.js.map +1 -1
- package/dist/core/adapters/adapter.d.ts +72 -0
- package/dist/core/adapters/adapter.d.ts.map +1 -0
- package/dist/core/adapters/adapter.js +18 -0
- package/dist/core/adapters/adapter.js.map +1 -0
- package/dist/core/adapters/claude-code-info.d.ts +11 -0
- package/dist/core/adapters/claude-code-info.d.ts.map +1 -0
- package/dist/core/adapters/claude-code-info.js +27 -0
- package/dist/core/adapters/claude-code-info.js.map +1 -0
- package/dist/core/adapters/claude-code.d.ts.map +1 -1
- package/dist/core/adapters/claude-code.js +9 -8
- package/dist/core/adapters/claude-code.js.map +1 -1
- package/dist/core/adapters/codex-info.d.ts +10 -0
- package/dist/core/adapters/codex-info.d.ts.map +1 -0
- package/dist/core/adapters/codex-info.js +32 -0
- package/dist/core/adapters/codex-info.js.map +1 -0
- package/dist/core/adapters/conductor.d.ts +8 -0
- package/dist/core/adapters/conductor.d.ts.map +1 -0
- package/dist/core/adapters/conductor.js +57 -0
- package/dist/core/adapters/conductor.js.map +1 -0
- package/dist/core/adapters/detect.d.ts +15 -0
- package/dist/core/adapters/detect.d.ts.map +1 -0
- package/dist/core/adapters/detect.js +62 -0
- package/dist/core/adapters/detect.js.map +1 -0
- package/dist/core/adapters/opencode.d.ts +8 -0
- package/dist/core/adapters/opencode.d.ts.map +1 -0
- package/dist/core/adapters/opencode.js +35 -0
- package/dist/core/adapters/opencode.js.map +1 -0
- package/dist/core/adapters/pi.d.ts +8 -0
- package/dist/core/adapters/pi.d.ts.map +1 -0
- package/dist/core/adapters/pi.js +24 -0
- package/dist/core/adapters/pi.js.map +1 -0
- package/dist/core/adapters/registry.d.ts +42 -0
- package/dist/core/adapters/registry.d.ts.map +1 -0
- package/dist/core/adapters/registry.js +67 -0
- package/dist/core/adapters/registry.js.map +1 -0
- package/dist/core/canvas-enrich.d.ts +9 -0
- package/dist/core/canvas-enrich.d.ts.map +1 -1
- package/dist/core/canvas-enrich.js +8 -0
- package/dist/core/canvas-enrich.js.map +1 -1
- package/dist/core/collector/analytics-emitter.d.ts +57 -0
- package/dist/core/collector/analytics-emitter.d.ts.map +1 -0
- package/dist/core/collector/analytics-emitter.js +131 -0
- package/dist/core/collector/analytics-emitter.js.map +1 -0
- package/dist/core/collector/identity-migration.d.ts +25 -0
- package/dist/core/collector/identity-migration.d.ts.map +1 -0
- package/dist/core/collector/identity-migration.js +68 -0
- package/dist/core/collector/identity-migration.js.map +1 -0
- package/dist/core/collector/store-retention.d.ts +51 -0
- package/dist/core/collector/store-retention.d.ts.map +1 -0
- package/dist/core/collector/store-retention.js +117 -0
- package/dist/core/collector/store-retention.js.map +1 -0
- package/dist/core/collector/store.d.ts +17 -1
- package/dist/core/collector/store.d.ts.map +1 -1
- package/dist/core/collector/store.js +24 -3
- package/dist/core/collector/store.js.map +1 -1
- package/dist/core/errors.d.ts +71 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +86 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/inject/claude-settings.d.ts +3 -1
- package/dist/core/inject/claude-settings.d.ts.map +1 -1
- package/dist/core/inject/claude-settings.js +3 -1
- package/dist/core/inject/claude-settings.js.map +1 -1
- package/dist/core/inject/skills-plugin.d.ts +44 -0
- package/dist/core/inject/skills-plugin.d.ts.map +1 -0
- package/dist/core/inject/skills-plugin.js +146 -0
- package/dist/core/inject/skills-plugin.js.map +1 -0
- package/dist/core/macro-runner.d.ts.map +1 -1
- package/dist/core/macro-runner.js +20 -1
- package/dist/core/macro-runner.js.map +1 -1
- package/dist/core/macros.d.ts.map +1 -1
- package/dist/core/macros.js +3 -0
- package/dist/core/macros.js.map +1 -1
- package/dist/core/session-manager.d.ts +37 -18
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +85 -34
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/task-manager.d.ts +25 -4
- package/dist/core/task-manager.d.ts.map +1 -1
- package/dist/core/task-manager.js +118 -6
- package/dist/core/task-manager.js.map +1 -1
- package/dist/core/workflow-registry.d.ts +7 -0
- package/dist/core/workflow-registry.d.ts.map +1 -1
- package/dist/core/workflow-registry.js +74 -50
- package/dist/core/workflow-registry.js.map +1 -1
- package/dist/core/workspace-watcher.d.ts +13 -1
- package/dist/core/workspace-watcher.d.ts.map +1 -1
- package/dist/core/workspace-watcher.js +78 -4
- package/dist/core/workspace-watcher.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/server/index.d.ts +16 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +0 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/ingest.d.ts +8 -0
- package/dist/server/ingest.d.ts.map +1 -1
- package/dist/server/ingest.js +4 -0
- package/dist/server/ingest.js.map +1 -1
- package/dist/server/macros.d.ts +5 -2
- package/dist/server/macros.d.ts.map +1 -1
- package/dist/server/macros.js +5 -2
- package/dist/server/macros.js.map +1 -1
- package/dist/server/rest.d.ts +26 -1
- package/dist/server/rest.d.ts.map +1 -1
- package/dist/server/rest.js +139 -6
- package/dist/server/rest.js.map +1 -1
- package/dist/server/skills.d.ts +45 -0
- package/dist/server/skills.d.ts.map +1 -0
- package/dist/server/skills.js +286 -0
- package/dist/server/skills.js.map +1 -0
- package/dist/shared/types.d.ts +75 -2
- package/dist/shared/types.d.ts.map +1 -1
- package/dist/shared/types.js +12 -1
- package/dist/shared/types.js.map +1 -1
- package/dist/web/assets/index-BTm-QNRt.css +32 -0
- package/dist/web/assets/index-CvNiFngP.js +204 -0
- package/dist/web/index.html +2 -2
- package/package.json +20 -8
- package/dist/core/collector/batcher.d.ts +0 -57
- package/dist/core/collector/batcher.d.ts.map +0 -1
- package/dist/core/collector/batcher.js +0 -143
- package/dist/core/collector/batcher.js.map +0 -1
- package/dist/web/assets/index-B9R4TzH7.css +0 -32
- package/dist/web/assets/index-Dh97QAgq.js +0 -192
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# @sapiom/harness
|
|
2
|
+
|
|
3
|
+
## 0.1.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 0cc7cd5: Fix two canvas v0 bugs:
|
|
8
|
+
|
|
9
|
+
**UI (CanvasPane)**: While an enrichment task runs, the activity strip now overlays the iframe instead of replacing it. The deterministic SVG render is visible immediately after binding; the spinner appears on top during the LLM annotation pass and disappears on completion. Failure state (Retry/Dismiss) remains full-screen and is unchanged.
|
|
10
|
+
|
|
11
|
+
**Server (forceRefresh)**: The already-running check for a workflow's enrichment task is now performed before any cache invalidation or re-render. A double-clicked Visualize correctly rejects with a 409 and leaves the enrichment cache and render files exactly as the still-running task will need them.
|
|
12
|
+
|
|
13
|
+
- a318f0b: HarnessAdapter registry with embedded/external modes
|
|
14
|
+
|
|
15
|
+
- Introduces `HarnessAdapterInfo` union type (`EmbeddedHarnessAdapterInfo` | `ExternalHarnessAdapterInfo`) with a `mode` field distinguishing harnesses spawned by the harness server from companion-app harnesses that own their own sessions.
|
|
16
|
+
- Adds a data-driven registry (`createHarnessAdapterRegistry`, `listHarnessAdapters`, `getHarnessAdapter`) backed by five built-in adapters: claude-code, codex (both embedded), pi, opencode (embedded, experimental), and conductor (external).
|
|
17
|
+
- Each adapter entry carries an `installMcpPrompt()` method with per-harness MCP install guidance — the skills-panel Install MCP modal reads these from the registry rather than embedding its own copy.
|
|
18
|
+
- Adds `GET /api/harnesses` endpoint returning all adapters with `id`, `label`, `mode`, `experimental`, and `installed` fields. Embedded entries are session-createable today; external entries expose `mode:"external"` for future UI rendering.
|
|
19
|
+
- Adds `ExternalHarnessError` (code `HARNESS_EXTERNAL`, HTTP 409) thrown from `SessionManager.getAdapter()` (resume path) and `SessionManager.submitInput()` (input path) when a session's harness id resolves to an external-mode adapter. A `sessions.json` entry written by an earlier build, hand-edited, or imported with `harness="conductor"` now surfaces a clear "managed by the Conductor app" 409 instead of a generic adapter-not-found error or a silent 404.
|
|
20
|
+
- Exports `SPAWNABLE_HARNESS_KINDS` as a const tuple from `shared/types.ts` — the single source of truth that both derives the `HarnessKind` type and supplies the values to `z.enum()` in the session-creation schema, preventing drift between the two.
|
|
21
|
+
- Routes the codex-tailer branching in server/index.ts through `adapter.eventSource` instead of a hardcoded `session.harness !== "codex"` check.
|
|
22
|
+
- `UnknownHarnessAdapterError` (code `UNKNOWN_HARNESS_ADAPTER`) is thrown by registry lookups for unknown ids, listing known ids in the message for self-correction.
|
|
23
|
+
- claude-code and codex behavior is byte-identical — no changes to their existing runtime adapter implementations (launch/resume/doctor/listPastSessions).
|
|
24
|
+
|
|
25
|
+
- c8c4746: Remote telemetry now reaches the hosted collector.
|
|
26
|
+
|
|
27
|
+
The bespoke `CollectorBatcher` (which posted to a non-existent `/v1/harness/events` endpoint) has been replaced by `@sapiom/analytics-core`. Events are now delivered to `POST /v1/analytics/collector` — the same endpoint used by all other Sapiom SDK packages.
|
|
28
|
+
|
|
29
|
+
**What changes for users:**
|
|
30
|
+
- Remote telemetry (consent-gated, as before) now actually works. Previously all remote traffic was silently dropped because the target endpoint did not exist.
|
|
31
|
+
- The local `~/.sapiom/harness/events.ndjson` sink continues to be written on every event regardless of consent, unchanged.
|
|
32
|
+
- Consent behavior (stored settings toggle, `--no-telemetry` flag, `SAPIOM_TELEMETRY_DISABLED=1`, `DO_NOT_TRACK=1`) is unchanged.
|
|
33
|
+
- Anonymous identity migrates: on first boot after upgrade, the install's existing `~/.sapiom/harness/machine-id` value is seeded into `~/.sapiom/analytics.json` so the longitudinal join key survives across versions.
|
|
34
|
+
|
|
35
|
+
- 97e8259: Awaitable kill for harness sessions and tasks with liveness-fallback resolution.
|
|
36
|
+
|
|
37
|
+
`SessionManager.kill()` now returns `Promise<boolean>` that resolves once the
|
|
38
|
+
process is **actually gone** — not fire-and-forget. Existing callers that do not
|
|
39
|
+
await the return value keep working unchanged.
|
|
40
|
+
|
|
41
|
+
Resolution is driven by whichever path fires first: node-pty's real `onExit`
|
|
42
|
+
event, or a synthesized exit from `kill()`'s own escalation path. The escalation
|
|
43
|
+
path is genuinely bounded:
|
|
44
|
+
|
|
45
|
+
1. SIGTERM sent immediately.
|
|
46
|
+
2. After `KILL_ESCALATION_MS` (2000 ms): if still alive, send SIGKILL.
|
|
47
|
+
3. After a further `KILL_ESCALATION_CONFIRM_MS` (500 ms): `markExited()` is
|
|
48
|
+
called **unconditionally** — SIGKILL has been sent and the window has
|
|
49
|
+
elapsed, so the session is over regardless of any liveness probe. This
|
|
50
|
+
prevents an EPERM zombie (a process that `isPidAlive` still reports as alive
|
|
51
|
+
after SIGKILL) from leaving the promise pending forever.
|
|
52
|
+
|
|
53
|
+
`SessionManager.killAll()` is now `async` and resolves when all concurrent kills
|
|
54
|
+
have confirmed death via `markExited()` — the single convergence point for real
|
|
55
|
+
and synthesized exits alike.
|
|
56
|
+
|
|
57
|
+
`TaskManager.killAll()` gains the same awaitable treatment with SIGTERM→SIGKILL
|
|
58
|
+
escalation and per-task exit promises wired through the existing `finish()`
|
|
59
|
+
convergence point. After the SIGKILL confirm window, `finish(id, null)` is
|
|
60
|
+
synthesized for any still-registered process — a zombie that never emits an exit
|
|
61
|
+
event is declared dead rather than leaving `killAll()` pending forever.
|
|
62
|
+
`finish()`'s idempotence guard prevents a double-fire if the real exit event
|
|
63
|
+
arrives concurrently.
|
|
64
|
+
|
|
65
|
+
Server shutdown (`close()` in server/index.ts) now awaits both `killAll()` calls
|
|
66
|
+
with a 5-second outer timeout, so the process actually exits cleanly instead of
|
|
67
|
+
leaving orphaned agent children.
|
|
68
|
+
|
|
69
|
+
- 1ff8d3c: Document that the harness is also launchable via `sapiom dev [dir]` from `@sapiom/cli`.
|
|
70
|
+
- 6d7ccd8: Packaging polish: LICENSE file, explicit exports map, and pack-contents audit.
|
|
71
|
+
|
|
72
|
+
Adds a per-package LICENSE file (MIT, matching repo root) so published tarballs include it. Adds an explicit `exports` map with a main entry (`"."`) and `"./package.json"` sub-path — the latter is required by `@sapiom/cli`'s `createRequire().resolve('@sapiom/harness/package.json')` resolution path; without it a conditional-exports package would fire `ERR_PACKAGE_PATH_NOT_EXPORTED` and break `sapiom dev`. Updates `files` to include `LICENSE`, `CHANGELOG.md`, and `README.md` alongside `dist`. Excludes `src/test-setup.ts` from the build tsconfig so `dist/test-setup.*` no longer appears in the published tarball. Stays ESM-only (`"type": "module"`) — the harness is an app-style bin package, not a library; a dual CJS+ESM build would introduce the dual-package hazard for the typed error hierarchy (`instanceof` dispatch) with no user benefit.
|
|
73
|
+
|
|
74
|
+
- e0334ca: Terminal-only center pane for v0
|
|
75
|
+
|
|
76
|
+
The center pane renders the xterm terminal as the sole content when a session
|
|
77
|
+
is live, and the exited-session overlay (resume / close) when the session has
|
|
78
|
+
exited. The first-run welcome panel continues to appear when no session exists
|
|
79
|
+
on a fresh install.
|
|
80
|
+
|
|
81
|
+
- Analytics hook pipeline (SessionStart / UserPromptSubmit / PreToolUse /
|
|
82
|
+
PostToolUse / Stop / SessionEnd → /ingest → normalizer → store + emitter →
|
|
83
|
+
collector) is fully intact and independent of the center-pane shape
|
|
84
|
+
- Skills panel, canvas, consent chip, telemetry, adapter registry, session
|
|
85
|
+
kill/resume, and typed errors are all preserved
|
|
86
|
+
|
|
87
|
+
- 6c64501: Internal robustness fixes (no behavior change for users):
|
|
88
|
+
|
|
89
|
+
- Serialize WorkflowRegistry writes through a promise queue so concurrent prune/scan/connectPath calls can't interleave and drop entries from workflows.json.
|
|
90
|
+
- Thread the resolved workflow path from the macros router into background task requests so TaskManager can dedupe per-workflow across sessions, not just per-session.
|
|
91
|
+
- Make the workspace-watcher polling fallback walk async (fs/promises) to avoid blocking the event loop on wide directories; lengthen the poll interval to 2 s.
|
|
92
|
+
|
|
93
|
+
- 58ec57f: Fix Sapiom skill registration in harness sessions. `@sapiom/agent-core` now
|
|
94
|
+
exposes its `package.json` through the `exports` map so consumers can resolve
|
|
95
|
+
its bundled `skills/` directory; previously `require.resolve` threw
|
|
96
|
+
`ERR_PACKAGE_PATH_NOT_EXPORTED` and the skill silently never loaded. The harness
|
|
97
|
+
skill-plugin resolver also gains a fallback that locates the skills directory by
|
|
98
|
+
resolving the package's main entry when the `package.json` subpath isn't
|
|
99
|
+
exported. Skills register under the `sapiom` plugin namespace, so the
|
|
100
|
+
agent-authoring skill is available as `/sapiom:sapiom-agent-authoring`.
|
|
101
|
+
- 1b355a4: Typed error codes on session and spawn failures; HTTP status mappings unchanged.
|
|
102
|
+
|
|
103
|
+
Adds a `HarnessError` base class and five typed subclasses — `UnknownSessionError`, `SessionNotReadyError`, `SessionNotResumeableError`, `SessionAlreadyLiveError`, `AdapterNotFoundError` — each carrying a stable machine-readable `code` property. Server routes now dispatch on `instanceof` rather than parsing `error.message` text, so future message rewordings cannot silently alter the HTTP status they produce. Wire responses and response body shapes are unchanged.
|
|
104
|
+
|
|
105
|
+
- a686143: Skills panel Use button populates the terminal (no auto-submit); Sapiom skills registered as session slash commands via --plugin-dir.
|
|
106
|
+
|
|
107
|
+
- Re-adds the "Use skill" button to the skill detail view. Clicking it calls
|
|
108
|
+
`injectInput` with `submit:false`, writing the text to Claude's input line
|
|
109
|
+
without sending Enter — the user edits and presses Enter themselves.
|
|
110
|
+
- Package skills populate `/<id> ` (slash command with trailing space for args);
|
|
111
|
+
user skills populate a natural-language invocation `Use the "<name>" skill: <desc>`.
|
|
112
|
+
- Button is disabled with a visible reason when there is no ready session.
|
|
113
|
+
- On success, a toast confirms "Typed into the terminal — edit and press Enter."
|
|
114
|
+
- Adds `generateSkillsPlugin` in `core/inject/skills-plugin.ts`: creates a
|
|
115
|
+
per-session `--plugin-dir` from the Sapiom skills bundled in `@sapiom/agent-core`.
|
|
116
|
+
claude-code auto-discovers `<plugin-dir>/skills/<name>/SKILL.md` and registers
|
|
117
|
+
`/<name>` as a slash command. Gracefully no-ops when agent-core's skills dir is
|
|
118
|
+
absent or unresolvable — the session still launches normally without the flag.
|
|
119
|
+
- `LaunchOpts.pluginDir` added; `ClaudeCodeAdapter.buildConfigArgs` emits
|
|
120
|
+
`--plugin-dir <path>` when set. Codex adapter ignores the field (unchanged).
|
|
121
|
+
|
|
122
|
+
- Updated dependencies [696f111]
|
|
123
|
+
- Updated dependencies [48fb35c]
|
|
124
|
+
- Updated dependencies [95bfcd1]
|
|
125
|
+
- Updated dependencies [bf44229]
|
|
126
|
+
- Updated dependencies [dab6d44]
|
|
127
|
+
- Updated dependencies [ebfa0bc]
|
|
128
|
+
- Updated dependencies [58ec57f]
|
|
129
|
+
- Updated dependencies [5e9659a]
|
|
130
|
+
- @sapiom/agent-core@0.9.2
|
|
131
|
+
- @sapiom/analytics-core@0.2.1
|
|
132
|
+
- @sapiom/mcp@0.11.2
|
|
133
|
+
|
|
134
|
+
## 0.1.1
|
|
135
|
+
|
|
136
|
+
### Patch Changes
|
|
137
|
+
|
|
138
|
+
- Updated dependencies [5f73ae7]
|
|
139
|
+
- Updated dependencies [d661d57]
|
|
140
|
+
- @sapiom/mcp@0.11.0
|
|
141
|
+
- @sapiom/agent-core@0.9.0
|
|
142
|
+
- @sapiom/agent@0.6.2
|
|
143
|
+
|
|
144
|
+
## 0.1.0
|
|
145
|
+
|
|
146
|
+
### Minor Changes
|
|
147
|
+
|
|
148
|
+
- 020139a: Canvas serving, macro engine, and dev-server port detection — the backend half of the canvas/action-rail/preview workstream:
|
|
149
|
+
|
|
150
|
+
- `GET /canvas/:harnessSessionId/*` serves whatever a session's agent wrote to its `.sapiom/canvas/` directory, with a friendly HTML empty-state when nothing's been rendered yet.
|
|
151
|
+
- `GET /api/macros` / `POST /api/macros/:id/run` resolve and execute the action-rail macros (`{{workflow.path}}`-style placeholder substitution, missing-value validation).
|
|
152
|
+
- Per-session canvas file watching (`canvas.reload` on change) and streaming `localhost:<port>` detection (`port.detected`) for the Preview pane's port chip.
|
|
153
|
+
|
|
154
|
+
### Patch Changes
|
|
155
|
+
|
|
156
|
+
- Updated dependencies [020139a]
|
|
157
|
+
- Updated dependencies [020139a]
|
|
158
|
+
- Updated dependencies [c0fef6d]
|
|
159
|
+
- Updated dependencies [3dfbd10]
|
|
160
|
+
- @sapiom/agent@0.6.1
|
|
161
|
+
- @sapiom/agent-core@0.8.0
|
|
162
|
+
- @sapiom/mcp@0.10.0
|
package/README.md
CHANGED
|
@@ -4,6 +4,8 @@ A local web app for building on Sapiom with your own coding agent.
|
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
6
|
npx @sapiom/harness [dir]
|
|
7
|
+
# also available via the Sapiom CLI (npm i -g @sapiom/cli @sapiom/harness):
|
|
8
|
+
sapiom dev [dir]
|
|
7
9
|
```
|
|
8
10
|
|
|
9
11
|
One command: checks your environment, signs you in, and opens a browser app
|
|
@@ -44,3 +46,37 @@ pnpm --filter @sapiom/harness build # server (tsc) + SPA (vite) → dist/
|
|
|
44
46
|
Architecture: a single Node process (Express + ws + node-pty) serves the built
|
|
45
47
|
SPA, a small REST API, terminal WebSocket streams, and the local telemetry
|
|
46
48
|
ingest endpoint. The interface contract lives in `src/shared/types.ts`.
|
|
49
|
+
|
|
50
|
+
## Testing
|
|
51
|
+
|
|
52
|
+
Three tiers — run whatever fits your change:
|
|
53
|
+
|
|
54
|
+
**Unit tier** (vitest, no browser, no agent): covers server logic, adapters,
|
|
55
|
+
analytics, and canvas rendering. Runs in CI on every PR.
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pnpm --filter @sapiom/harness test
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**Playwright mock tier** (chromium, Vite dev server with `VITE_MOCK=1`, no
|
|
62
|
+
harness server or agent process). The full `web/e2e/` suite against the SPA in
|
|
63
|
+
mock mode. Runs in CI on every PR. For a fast watch loop locally, use UI mode:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
# One-time browser install (not included in pnpm install):
|
|
67
|
+
pnpm --filter @sapiom/harness exec playwright install chromium
|
|
68
|
+
|
|
69
|
+
# Watch/UI mode — re-runs affected specs on save:
|
|
70
|
+
pnpm --filter @sapiom/harness exec playwright test \
|
|
71
|
+
--config web/e2e/playwright.config.ts --ui
|
|
72
|
+
|
|
73
|
+
# Or run the full suite once (same command CI uses):
|
|
74
|
+
pnpm --filter @sapiom/harness test:ui
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**E2E live tier** (real agent binaries, real pty, no CI). Requires Claude Code
|
|
78
|
+
or Codex installed and a valid `SAPIOM_API_KEY` in your environment.
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
pnpm --filter @sapiom/harness e2e:live
|
|
82
|
+
```
|
package/dist/cli/bin.js
CHANGED
|
@@ -112,7 +112,8 @@ const main = async () => {
|
|
|
112
112
|
if (identity?.source === "cached") {
|
|
113
113
|
console.log(`\nSigned in as ${identity.organizationName} (cached credential).`);
|
|
114
114
|
}
|
|
115
|
-
const
|
|
115
|
+
const consentResult = await ensureConsent({ noTelemetry: options.noTelemetry });
|
|
116
|
+
const { telemetryOptIn } = consentResult;
|
|
116
117
|
// First run = no recent directories recorded before this boot. Must be read
|
|
117
118
|
// BEFORE recordRecentDir below stamps the launch dir in — after that the
|
|
118
119
|
// signal is gone for good. Drives the SPA's welcome panel (AppState.firstRun)
|
|
@@ -128,6 +129,8 @@ const main = async () => {
|
|
|
128
129
|
port: options.port,
|
|
129
130
|
bootToken,
|
|
130
131
|
telemetryOptIn,
|
|
132
|
+
consentSource: consentResult.source,
|
|
133
|
+
consentEnvReason: consentResult.envReason,
|
|
131
134
|
identity,
|
|
132
135
|
machineId,
|
|
133
136
|
launchDir: options.dir,
|
|
@@ -149,12 +152,33 @@ const main = async () => {
|
|
|
149
152
|
port: server?.port ?? options.port,
|
|
150
153
|
bootToken,
|
|
151
154
|
identity,
|
|
152
|
-
telemetryOptIn,
|
|
155
|
+
telemetryOptIn: consentResult.telemetryOptIn,
|
|
153
156
|
serverStarted: server !== null,
|
|
154
157
|
});
|
|
155
158
|
if (server && !options.noOpen) {
|
|
156
159
|
await open(`http://localhost:${server.port}/?token=${bootToken}`);
|
|
157
160
|
}
|
|
161
|
+
if (server) {
|
|
162
|
+
// Wire SIGINT (Ctrl+C) and SIGTERM so the awaitable close() path actually
|
|
163
|
+
// runs, which kills all live claude/codex ptys before the process exits.
|
|
164
|
+
// Without this, server.close() is never called from the CLI and the pty
|
|
165
|
+
// orphan problem the awaitable-kill feature was built to fix remains inert
|
|
166
|
+
// in the primary usage path.
|
|
167
|
+
// Guard against double-fire: once is enough; a second signal gets default
|
|
168
|
+
// handling (immediate termination) which is the correct behavior anyway.
|
|
169
|
+
let closing = false;
|
|
170
|
+
const handleSignal = (signal) => {
|
|
171
|
+
if (closing)
|
|
172
|
+
return;
|
|
173
|
+
closing = true;
|
|
174
|
+
// server.close() is already race-bounded to 5s internally.
|
|
175
|
+
void server.close().finally(() => {
|
|
176
|
+
process.exit(signal === "SIGINT" ? 130 : 143);
|
|
177
|
+
});
|
|
178
|
+
};
|
|
179
|
+
process.once("SIGINT", () => handleSignal("SIGINT"));
|
|
180
|
+
process.once("SIGTERM", () => handleSignal("SIGTERM"));
|
|
181
|
+
}
|
|
158
182
|
};
|
|
159
183
|
main().catch((err) => {
|
|
160
184
|
console.error(err);
|
package/dist/cli/bin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../../src/cli/bin.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../../src/cli/bin.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/consent.d.ts
CHANGED
|
@@ -2,6 +2,30 @@ export interface EnsureConsentOptions {
|
|
|
2
2
|
/** The `--no-telemetry` flag — forces telemetry off without prompting. */
|
|
3
3
|
noTelemetry: boolean;
|
|
4
4
|
}
|
|
5
|
+
/**
|
|
6
|
+
* How the telemetry consent state was determined for this boot.
|
|
7
|
+
* Exposed to the server so the UI can show a first-run notice when
|
|
8
|
+
* consent was implicitly set by the non-TTY default rather than explicitly
|
|
9
|
+
* answered by the user.
|
|
10
|
+
*/
|
|
11
|
+
export type ConsentSource =
|
|
12
|
+
/** `--no-telemetry` flag or SAPIOM_TELEMETRY_DISABLED/DO_NOT_TRACK env var. */
|
|
13
|
+
"env-forced-off"
|
|
14
|
+
/** Stored consent from a previous first-run prompt — user answered explicitly. */
|
|
15
|
+
| "stored-explicit"
|
|
16
|
+
/** User answered the Y/n prompt just now (interactive TTY). */
|
|
17
|
+
| "prompted"
|
|
18
|
+
/** Non-TTY first run: the silent default was applied and persisted. */
|
|
19
|
+
| "default-silent";
|
|
20
|
+
export interface ConsentResult {
|
|
21
|
+
telemetryOptIn: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Which env var (if any) is forcing telemetry off this run.
|
|
24
|
+
* Only set when source === "env-forced-off".
|
|
25
|
+
*/
|
|
26
|
+
envReason: string | null;
|
|
27
|
+
source: ConsentSource;
|
|
28
|
+
}
|
|
5
29
|
/**
|
|
6
30
|
* Resolves the telemetry opt-in state. Prompts once on first run and persists
|
|
7
31
|
* the answer; subsequent runs reuse the stored value silently. `--no-telemetry`
|
|
@@ -10,6 +34,10 @@ export interface EnsureConsentOptions {
|
|
|
10
34
|
* skipping the prompt entirely — without touching what's actually stored, so
|
|
11
35
|
* a later run without the env var set sees whatever the user answered (or
|
|
12
36
|
* will still be asked, if this env-vetoed run was their first).
|
|
37
|
+
*
|
|
38
|
+
* Returns a ConsentResult that includes the source of the decision — the UI
|
|
39
|
+
* uses this to show a first-run notice when the user never explicitly answered
|
|
40
|
+
* (source === "default-silent"), skipping it when they did.
|
|
13
41
|
*/
|
|
14
|
-
export declare function ensureConsent(options: EnsureConsentOptions): Promise<
|
|
42
|
+
export declare function ensureConsent(options: EnsureConsentOptions): Promise<ConsentResult>;
|
|
15
43
|
//# sourceMappingURL=consent.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"consent.d.ts","sourceRoot":"","sources":["../../src/cli/consent.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"consent.d.ts","sourceRoot":"","sources":["../../src/cli/consent.ts"],"names":[],"mappings":"AAoDA,MAAM,WAAW,oBAAoB;IACnC,0EAA0E;IAC1E,WAAW,EAAE,OAAO,CAAC;CACtB;AAED;;;;;GAKG;AACH,MAAM,MAAM,aAAa;AACvB,+EAA+E;AAC7E,gBAAgB;AAClB,kFAAkF;GAChF,iBAAiB;AACnB,+DAA+D;GAC7D,UAAU;AACZ,uEAAuE;GACrE,gBAAgB,CAAC;AAErB,MAAM,WAAW,aAAa;IAC5B,cAAc,EAAE,OAAO,CAAC;IACxB;;;OAGG;IACH,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,aAAa,CAAC;CACvB;AAuBD;;;;;;;;;;;;GAYG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,aAAa,CAAC,CAwBzF"}
|
package/dist/cli/consent.js
CHANGED
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
import * as readline from "node:readline/promises";
|
|
2
2
|
import { hasStoredSettings, loadSettings, saveSettings } from "./settings.js";
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
// wider release.
|
|
3
|
+
// Early-access phase: default to opted in (matches the on-by-default prompt
|
|
4
|
+
// below and the non-TTY fallback) — intentional for the early-access phase;
|
|
5
|
+
// flip for a wider release.
|
|
6
|
+
//
|
|
7
|
+
// Pre-wider-release checklist: revisit the non-TTY silent opt-in below.
|
|
8
|
+
// The current default (true) is intentional for the early-access phase;
|
|
9
|
+
// for a wider/public release the conservative choice is false (opt-out by
|
|
10
|
+
// default) so users who never see a TTY (CI, Docker, headless environments)
|
|
11
|
+
// are not silently opted in.
|
|
12
|
+
// See also the first-run UI notice wiring in web/src/components/TelemetryNotice.tsx,
|
|
13
|
+
// which surfaces this path to interactive users who did get the default.
|
|
6
14
|
const DEFAULT_TELEMETRY_OPT_IN = true;
|
|
7
15
|
const CONSENT_COPY = `
|
|
8
|
-
Sapiom Harness collects
|
|
16
|
+
Sapiom Harness collects usage analytics locally and, with telemetry on,
|
|
17
|
+
sends them to Sapiom to improve the product:
|
|
9
18
|
- the prompts you send and the tool calls your agent makes
|
|
10
19
|
- session start/stop lifecycle events
|
|
11
20
|
This is always written locally to ~/.sapiom/harness/events.ndjson for your
|
|
@@ -17,7 +26,11 @@ gear, or run with --no-telemetry).
|
|
|
17
26
|
async function promptConsent() {
|
|
18
27
|
console.log(`\n${CONSENT_COPY}\n`);
|
|
19
28
|
if (!process.stdin.isTTY) {
|
|
20
|
-
|
|
29
|
+
// The full consent copy (what's collected, local store, and opt-out path)
|
|
30
|
+
// was already printed above. Make the default explicit so non-TTY users
|
|
31
|
+
// reviewing logs see it clearly.
|
|
32
|
+
console.log(`Non-interactive session — telemetry is defaulting to ${DEFAULT_TELEMETRY_OPT_IN ? "on" : "off"}` +
|
|
33
|
+
` per the notice above. Run with --no-telemetry or set SAPIOM_TELEMETRY_DISABLED=1 to opt out.\n`);
|
|
21
34
|
return DEFAULT_TELEMETRY_OPT_IN;
|
|
22
35
|
}
|
|
23
36
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
@@ -61,21 +74,30 @@ function envDisableReason() {
|
|
|
61
74
|
* skipping the prompt entirely — without touching what's actually stored, so
|
|
62
75
|
* a later run without the env var set sees whatever the user answered (or
|
|
63
76
|
* will still be asked, if this env-vetoed run was their first).
|
|
77
|
+
*
|
|
78
|
+
* Returns a ConsentResult that includes the source of the decision — the UI
|
|
79
|
+
* uses this to show a first-run notice when the user never explicitly answered
|
|
80
|
+
* (source === "default-silent"), skipping it when they did.
|
|
64
81
|
*/
|
|
65
82
|
export async function ensureConsent(options) {
|
|
66
|
-
if (options.noTelemetry)
|
|
67
|
-
return false;
|
|
83
|
+
if (options.noTelemetry) {
|
|
84
|
+
return { telemetryOptIn: false, envReason: null, source: "env-forced-off" };
|
|
85
|
+
}
|
|
68
86
|
const envReason = envDisableReason();
|
|
69
87
|
if (envReason) {
|
|
70
88
|
console.log(`Telemetry disabled via ${envReason} — skipping the consent prompt.\n`);
|
|
71
|
-
return false;
|
|
89
|
+
return { telemetryOptIn: false, envReason, source: "env-forced-off" };
|
|
72
90
|
}
|
|
73
91
|
const isFirstRun = !(await hasStoredSettings());
|
|
74
92
|
const settings = await loadSettings();
|
|
75
|
-
if (!isFirstRun)
|
|
76
|
-
return settings.telemetryOptIn;
|
|
93
|
+
if (!isFirstRun) {
|
|
94
|
+
return { telemetryOptIn: settings.telemetryOptIn, envReason: null, source: "stored-explicit" };
|
|
95
|
+
}
|
|
96
|
+
// First run: prompt the user (TTY) or apply the silent default (non-TTY).
|
|
97
|
+
const isTTY = process.stdin.isTTY;
|
|
77
98
|
const telemetryOptIn = await promptConsent();
|
|
78
99
|
await saveSettings({ ...settings, telemetryOptIn });
|
|
79
|
-
|
|
100
|
+
const source = isTTY ? "prompted" : "default-silent";
|
|
101
|
+
return { telemetryOptIn, envReason: null, source };
|
|
80
102
|
}
|
|
81
103
|
//# sourceMappingURL=consent.js.map
|
package/dist/cli/consent.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"consent.js","sourceRoot":"","sources":["../../src/cli/consent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE9E,4EAA4E;AAC5E,yEAAyE;AACzE,
|
|
1
|
+
{"version":3,"file":"consent.js","sourceRoot":"","sources":["../../src/cli/consent.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HarnessAdapter union type — the shape every adapter (embedded or external)
|
|
3
|
+
* must satisfy.
|
|
4
|
+
*
|
|
5
|
+
* "embedded" adapters are spawned inside a pty session by the harness.
|
|
6
|
+
* "external" adapters run in their own companion app and have no spawn path —
|
|
7
|
+
* the type makes calling spawn/send on them a compile error, not just a
|
|
8
|
+
* convention.
|
|
9
|
+
*
|
|
10
|
+
* Adding an external harness = one descriptor file + one HARNESS_ADAPTER_INFOS
|
|
11
|
+
* line. An embedded harness that can be spawned as a session additionally
|
|
12
|
+
* requires: a runtime adapter (launch/resume/doctor/listPastSessions) in
|
|
13
|
+
* core/adapters/, a new id in SPAWNABLE_HARNESS_KINDS (shared/types.ts —
|
|
14
|
+
* which widens HarnessKind and the z.enum gate automatically), and a real
|
|
15
|
+
* e2e suite confirming the lifecycle works end-to-end.
|
|
16
|
+
*/
|
|
17
|
+
/** Stable identifier for every harness the registry knows about. */
|
|
18
|
+
export type HarnessAdapterId = "claude-code" | "codex" | "pi" | "opencode" | "conductor";
|
|
19
|
+
/** Whether the harness is spawned by the harness (embedded) or managed by its
|
|
20
|
+
* own companion app (external). */
|
|
21
|
+
export type HarnessAdapterMode = "embedded" | "external";
|
|
22
|
+
/** Fields shared by every adapter regardless of mode. */
|
|
23
|
+
export interface HarnessAdapterBase {
|
|
24
|
+
/** Stable identifier used in APIs and the session registry. */
|
|
25
|
+
id: HarnessAdapterId;
|
|
26
|
+
/** Human-readable name for pickers and logs. */
|
|
27
|
+
label: string;
|
|
28
|
+
/** Spawn mode — narrow on this before calling any spawn-path methods. */
|
|
29
|
+
mode: HarnessAdapterMode;
|
|
30
|
+
/**
|
|
31
|
+
* Per-agent prompt text guiding the user through installing and
|
|
32
|
+
* configuring the Sapiom MCP server (`@sapiom/mcp`) for this harness.
|
|
33
|
+
* Consumed by the skills-panel Install MCP modal. Returns the text string
|
|
34
|
+
* directly — callers may render it as preformatted text.
|
|
35
|
+
*/
|
|
36
|
+
installMcpPrompt(): string;
|
|
37
|
+
/**
|
|
38
|
+
* Best-effort detection of whether the harness is installed on this
|
|
39
|
+
* machine. Never throws.
|
|
40
|
+
*/
|
|
41
|
+
detectInstalled(): Promise<boolean>;
|
|
42
|
+
/**
|
|
43
|
+
* Marks adapters whose launch behavior is best-effort and not yet
|
|
44
|
+
* hardened by an end-to-end suite. Absent (or false) for fully
|
|
45
|
+
* supported harnesses.
|
|
46
|
+
*/
|
|
47
|
+
experimental?: boolean;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* An adapter the harness spawns inside a pty session.
|
|
51
|
+
* The existing `HarnessAdapter` interface (shared/types.ts) carries the actual
|
|
52
|
+
* launch/resume/doctor/listPastSessions contract consumed by SessionManager;
|
|
53
|
+
* this is the registry-level description used for enumeration and the
|
|
54
|
+
* harnesses listing endpoint.
|
|
55
|
+
*/
|
|
56
|
+
export interface EmbeddedHarnessAdapterInfo extends HarnessAdapterBase {
|
|
57
|
+
mode: "embedded";
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* An adapter for a harness that runs in its own companion app.
|
|
61
|
+
* There is deliberately no spawn path — `launchCommand` is absent so a
|
|
62
|
+
* spawn attempt is a compile error rather than a runtime surprise.
|
|
63
|
+
*/
|
|
64
|
+
export interface ExternalHarnessAdapterInfo extends HarnessAdapterBase {
|
|
65
|
+
mode: "external";
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Every registry entry satisfies this union. Narrow on `mode` before
|
|
69
|
+
* attempting any spawn-path operation — external adapters have none.
|
|
70
|
+
*/
|
|
71
|
+
export type HarnessAdapterInfo = EmbeddedHarnessAdapterInfo | ExternalHarnessAdapterInfo;
|
|
72
|
+
//# sourceMappingURL=adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../src/core/adapters/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,oEAAoE;AACpE,MAAM,MAAM,gBAAgB,GACxB,aAAa,GACb,OAAO,GACP,IAAI,GACJ,UAAU,GACV,WAAW,CAAC;AAEhB;oCACoC;AACpC,MAAM,MAAM,kBAAkB,GAAG,UAAU,GAAG,UAAU,CAAC;AAEzD,yDAAyD;AACzD,MAAM,WAAW,kBAAkB;IACjC,+DAA+D;IAC/D,EAAE,EAAE,gBAAgB,CAAC;IACrB,gDAAgD;IAChD,KAAK,EAAE,MAAM,CAAC;IACd,yEAAyE;IACzE,IAAI,EAAE,kBAAkB,CAAC;IACzB;;;;;OAKG;IACH,gBAAgB,IAAI,MAAM,CAAC;IAC3B;;;OAGG;IACH,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IACpC;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,0BAA2B,SAAQ,kBAAkB;IACpE,IAAI,EAAE,UAAU,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,WAAW,0BAA2B,SAAQ,kBAAkB;IACpE,IAAI,EAAE,UAAU,CAAC;CAClB;AAED;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG,0BAA0B,GAAG,0BAA0B,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HarnessAdapter union type — the shape every adapter (embedded or external)
|
|
3
|
+
* must satisfy.
|
|
4
|
+
*
|
|
5
|
+
* "embedded" adapters are spawned inside a pty session by the harness.
|
|
6
|
+
* "external" adapters run in their own companion app and have no spawn path —
|
|
7
|
+
* the type makes calling spawn/send on them a compile error, not just a
|
|
8
|
+
* convention.
|
|
9
|
+
*
|
|
10
|
+
* Adding an external harness = one descriptor file + one HARNESS_ADAPTER_INFOS
|
|
11
|
+
* line. An embedded harness that can be spawned as a session additionally
|
|
12
|
+
* requires: a runtime adapter (launch/resume/doctor/listPastSessions) in
|
|
13
|
+
* core/adapters/, a new id in SPAWNABLE_HARNESS_KINDS (shared/types.ts —
|
|
14
|
+
* which widens HarnessKind and the z.enum gate automatically), and a real
|
|
15
|
+
* e2e suite confirming the lifecycle works end-to-end.
|
|
16
|
+
*/
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../../src/core/adapters/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registry descriptor for the Claude Code adapter.
|
|
3
|
+
*
|
|
4
|
+
* The runtime adapter implementation (launch/resume/doctor/listPastSessions)
|
|
5
|
+
* lives in claude-code.ts. This file carries only the registry-level metadata
|
|
6
|
+
* consumed by the harness listing endpoint and the skills panel Install MCP
|
|
7
|
+
* modal: the human label, spawn mode, MCP install guidance, and PATH detection.
|
|
8
|
+
*/
|
|
9
|
+
import type { EmbeddedHarnessAdapterInfo } from "./adapter.js";
|
|
10
|
+
export declare const claudeCodeAdapterInfo: EmbeddedHarnessAdapterInfo;
|
|
11
|
+
//# sourceMappingURL=claude-code-info.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-code-info.d.ts","sourceRoot":"","sources":["../../../src/core/adapters/claude-code-info.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAC;AAkB/D,eAAO,MAAM,qBAAqB,EAAE,0BAUnC,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { isExecutableOnPath } from "./detect.js";
|
|
2
|
+
const INSTALL_MCP_PROMPT = [
|
|
3
|
+
"Set up the Sapiom MCP server for Claude Code.",
|
|
4
|
+
"",
|
|
5
|
+
"1. Register it under the server name `sapiom-dev`:",
|
|
6
|
+
"",
|
|
7
|
+
" claude mcp add sapiom-dev -- npx -y @sapiom/mcp",
|
|
8
|
+
"",
|
|
9
|
+
" The `@sapiom/mcp` npm package ships the `sapiom-mcp` binary, a local",
|
|
10
|
+
" MCP server that speaks stdio — no global install or daemon needed.",
|
|
11
|
+
"2. Verify the registration: `claude mcp list` should show `sapiom-dev`.",
|
|
12
|
+
"3. Restart Claude Code (or start a new session) so the server is loaded.",
|
|
13
|
+
"4. Networked Sapiom tools need an API key: run the `sapiom_authenticate`",
|
|
14
|
+
" tool once and complete the browser login it opens.",
|
|
15
|
+
].join("\n");
|
|
16
|
+
export const claudeCodeAdapterInfo = {
|
|
17
|
+
id: "claude-code",
|
|
18
|
+
label: "Claude Code",
|
|
19
|
+
mode: "embedded",
|
|
20
|
+
installMcpPrompt() {
|
|
21
|
+
return INSTALL_MCP_PROMPT;
|
|
22
|
+
},
|
|
23
|
+
detectInstalled() {
|
|
24
|
+
return isExecutableOnPath("claude");
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=claude-code-info.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-code-info.js","sourceRoot":"","sources":["../../../src/core/adapters/claude-code-info.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEjD,MAAM,kBAAkB,GAAG;IACzB,+CAA+C;IAC/C,EAAE;IACF,oDAAoD;IACpD,EAAE;IACF,oDAAoD;IACpD,EAAE;IACF,yEAAyE;IACzE,uEAAuE;IACvE,yEAAyE;IACzE,0EAA0E;IAC1E,0EAA0E;IAC1E,uDAAuD;CACxD,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEb,MAAM,CAAC,MAAM,qBAAqB,GAA+B;IAC/D,EAAE,EAAE,aAAa;IACjB,KAAK,EAAE,aAAa;IACpB,IAAI,EAAE,UAAU;IAChB,gBAAgB;QACd,OAAO,kBAAkB,CAAC;IAC5B,CAAC;IACD,eAAe;QACb,OAAO,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IACtC,CAAC;CACF,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude-code.d.ts","sourceRoot":"","sources":["../../../src/core/adapters/claude-code.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,OAAO,KAAK,EACV,WAAW,EACX,cAAc,EACd,UAAU,EACV,cAAc,EACd,SAAS,EACV,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"claude-code.d.ts","sourceRoot":"","sources":["../../../src/core/adapters/claude-code.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,OAAO,KAAK,EACV,WAAW,EACX,cAAc,EACd,UAAU,EACV,cAAc,EACd,SAAS,EACV,MAAM,uBAAuB,CAAC;AAiB/B,MAAM,WAAW,wBAAwB;IACvC,wFAAwF;IACxF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AA8FD,qBAAa,iBAAkB,YAAW,cAAc;IACtD,QAAQ,CAAC,EAAE,EAAG,aAAa,CAAU;IACrC,QAAQ,CAAC,WAAW,EAAG,OAAO,CAAU;IACxC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,OAAO,GAAE,wBAA6B;IAK5C,MAAM,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;IAetC,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,SAAS;IAgBnC,MAAM,CAAC,cAAc,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,SAAS;IAa3D;;;;;;;;;;;;;OAaG;IACH,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,SAAS;IAmBjC,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;CA8B/D;AAcD,wBAAgB,uBAAuB,CAAC,OAAO,CAAC,EAAE,wBAAwB,GAAG,cAAc,CAE1F"}
|
|
@@ -10,20 +10,19 @@ import { readFile, readdir, stat, open } from "node:fs/promises";
|
|
|
10
10
|
import { homedir } from "node:os";
|
|
11
11
|
import { basename, join } from "node:path";
|
|
12
12
|
import { promisify } from "node:util";
|
|
13
|
-
const execFileAsync = promisify(execFile);
|
|
14
|
-
/** Bytes read from the tail of a transcript file. Files can be 100MB+; the
|
|
15
|
-
* summary/title we need is always near the end. */
|
|
16
|
-
const TRANSCRIPT_TAIL_BYTES = 65536;
|
|
17
13
|
/**
|
|
18
|
-
* Claude Code
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* (listPastSessions degrades to an empty list, not an error).
|
|
14
|
+
* Maps a project cwd to the directory name Claude Code uses for its transcript
|
|
15
|
+
* store under `~/.claude/projects/`. Claude Code applies this encoding before
|
|
16
|
+
* creating the directory — see its own source for the canonical definition.
|
|
22
17
|
*/
|
|
23
18
|
function encodeProjectPath(cwd) {
|
|
24
19
|
const normalized = cwd.replace(/\\/g, "/");
|
|
25
20
|
return normalized.replace(/:/g, "").replace(/[/.]/g, "-");
|
|
26
21
|
}
|
|
22
|
+
const execFileAsync = promisify(execFile);
|
|
23
|
+
/** Bytes read from the tail of a transcript file. Files can be 100MB+; the
|
|
24
|
+
* summary/title we need is always near the end. */
|
|
25
|
+
const TRANSCRIPT_TAIL_BYTES = 65536;
|
|
27
26
|
function extractTextFromContent(content) {
|
|
28
27
|
if (typeof content === "string")
|
|
29
28
|
return content;
|
|
@@ -105,6 +104,8 @@ function buildConfigArgs(opts) {
|
|
|
105
104
|
args.push("--settings", opts.settingsFile);
|
|
106
105
|
if (opts.mcpConfigFile)
|
|
107
106
|
args.push("--mcp-config", opts.mcpConfigFile);
|
|
107
|
+
if (opts.pluginDir)
|
|
108
|
+
args.push("--plugin-dir", opts.pluginDir);
|
|
108
109
|
return args;
|
|
109
110
|
}
|
|
110
111
|
export class ClaudeCodeAdapter {
|