wicked-crew 0.4.0 → 0.6.0
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/dist/api/api-prefix.d.ts +13 -0
- package/dist/api/api-prefix.d.ts.map +1 -0
- package/dist/api/api-prefix.js +13 -0
- package/dist/api/api-prefix.js.map +1 -0
- package/dist/api/audit.d.ts +57 -0
- package/dist/api/audit.d.ts.map +1 -0
- package/dist/api/audit.js +115 -0
- package/dist/api/audit.js.map +1 -0
- package/dist/api/auth.d.ts +192 -0
- package/dist/api/auth.d.ts.map +1 -0
- package/dist/api/auth.js +515 -0
- package/dist/api/auth.js.map +1 -0
- package/dist/api/evidence.d.ts +11 -0
- package/dist/api/evidence.d.ts.map +1 -1
- package/dist/api/evidence.js +8 -3
- package/dist/api/evidence.js.map +1 -1
- package/dist/api/gate-cache.d.ts +8 -0
- package/dist/api/gate-cache.d.ts.map +1 -1
- package/dist/api/gate-cache.js +10 -0
- package/dist/api/gate-cache.js.map +1 -1
- package/dist/api/open-path.d.ts +18 -0
- package/dist/api/open-path.d.ts.map +1 -0
- package/dist/api/open-path.js +79 -0
- package/dist/api/open-path.js.map +1 -0
- package/dist/api/routes.d.ts +113 -1
- package/dist/api/routes.d.ts.map +1 -1
- package/dist/api/routes.js +516 -27
- package/dist/api/routes.js.map +1 -1
- package/dist/api/seat-health.d.ts +55 -0
- package/dist/api/seat-health.d.ts.map +1 -0
- package/dist/api/seat-health.js +273 -0
- package/dist/api/seat-health.js.map +1 -0
- package/dist/api/seat-signin.d.ts +27 -0
- package/dist/api/seat-signin.d.ts.map +1 -0
- package/dist/api/seat-signin.js +143 -0
- package/dist/api/seat-signin.js.map +1 -0
- package/dist/api/server.d.ts +111 -3
- package/dist/api/server.d.ts.map +1 -1
- package/dist/api/server.js +236 -11
- package/dist/api/server.js.map +1 -1
- package/dist/api/unit-output.d.ts +62 -0
- package/dist/api/unit-output.d.ts.map +1 -0
- package/dist/api/unit-output.js +108 -0
- package/dist/api/unit-output.js.map +1 -0
- package/dist/cli/index.js +97 -3
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/mcp.d.ts +14 -0
- package/dist/cli/mcp.d.ts.map +1 -0
- package/dist/cli/mcp.js +119 -0
- package/dist/cli/mcp.js.map +1 -0
- package/dist/core/adapter.d.ts +106 -1
- package/dist/core/adapter.d.ts.map +1 -1
- package/dist/core/adapter.js +293 -12
- package/dist/core/adapter.js.map +1 -1
- package/dist/core/bridge-path.d.ts +17 -6
- package/dist/core/bridge-path.d.ts.map +1 -1
- package/dist/core/bridge-path.js +17 -6
- package/dist/core/bridge-path.js.map +1 -1
- package/dist/core/types.d.ts +23 -352
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +11 -4
- package/dist/core/types.js.map +1 -1
- package/dist/interactive/bridge-pool.d.ts +71 -0
- package/dist/interactive/bridge-pool.d.ts.map +1 -0
- package/dist/interactive/bridge-pool.js +187 -0
- package/dist/interactive/bridge-pool.js.map +1 -0
- package/dist/interactive/bridge-root.d.ts +36 -0
- package/dist/interactive/bridge-root.d.ts.map +1 -0
- package/dist/interactive/bridge-root.js +48 -0
- package/dist/interactive/bridge-root.js.map +1 -0
- package/dist/interactive/draft-events.d.ts +144 -0
- package/dist/interactive/draft-events.d.ts.map +1 -0
- package/dist/interactive/draft-events.js +490 -0
- package/dist/interactive/draft-events.js.map +1 -0
- package/dist/interactive/edit-events.d.ts +172 -0
- package/dist/interactive/edit-events.d.ts.map +1 -0
- package/dist/interactive/edit-events.js +530 -0
- package/dist/interactive/edit-events.js.map +1 -0
- package/dist/interactive/ledger.d.ts +39 -0
- package/dist/interactive/ledger.d.ts.map +1 -0
- package/dist/interactive/ledger.js +93 -0
- package/dist/interactive/ledger.js.map +1 -0
- package/dist/interactive/proxy-routes.d.ts +39 -0
- package/dist/interactive/proxy-routes.d.ts.map +1 -0
- package/dist/interactive/proxy-routes.js +189 -0
- package/dist/interactive/proxy-routes.js.map +1 -0
- package/dist/interactive/ws-relay.d.ts +85 -0
- package/dist/interactive/ws-relay.d.ts.map +1 -0
- package/dist/interactive/ws-relay.js +191 -0
- package/dist/interactive/ws-relay.js.map +1 -0
- package/dist/projects/activity.d.ts +29 -0
- package/dist/projects/activity.d.ts.map +1 -0
- package/dist/projects/activity.js +172 -0
- package/dist/projects/activity.js.map +1 -0
- package/dist/projects/charter.d.ts +28 -0
- package/dist/projects/charter.d.ts.map +1 -0
- package/dist/projects/charter.js +53 -0
- package/dist/projects/charter.js.map +1 -0
- package/dist/projects/events.d.ts +55 -0
- package/dist/projects/events.d.ts.map +1 -0
- package/dist/projects/events.js +141 -0
- package/dist/projects/events.js.map +1 -0
- package/dist/projects/membership-index.d.ts +25 -0
- package/dist/projects/membership-index.d.ts.map +1 -0
- package/dist/projects/membership-index.js +46 -0
- package/dist/projects/membership-index.js.map +1 -0
- package/dist/projects/routes.d.ts +90 -0
- package/dist/projects/routes.d.ts.map +1 -0
- package/dist/projects/routes.js +388 -0
- package/dist/projects/routes.js.map +1 -0
- package/dist/projects/settings.d.ts +32 -0
- package/dist/projects/settings.d.ts.map +1 -0
- package/dist/projects/settings.js +64 -0
- package/dist/projects/settings.js.map +1 -0
- package/dist/qe/acceptance.d.ts +137 -0
- package/dist/qe/acceptance.d.ts.map +1 -0
- package/dist/qe/acceptance.js +249 -0
- package/dist/qe/acceptance.js.map +1 -0
- package/dist/qe/gate-events.d.ts +111 -0
- package/dist/qe/gate-events.d.ts.map +1 -0
- package/dist/qe/gate-events.js +168 -0
- package/dist/qe/gate-events.js.map +1 -0
- package/dist/qe/ledger.d.ts +100 -0
- package/dist/qe/ledger.d.ts.map +1 -0
- package/dist/qe/ledger.js +154 -0
- package/dist/qe/ledger.js.map +1 -0
- package/dist/studio/assets/index-CCwXa1cn.js +428 -0
- package/dist/studio/assets/index-HWxo0h41.css +32 -0
- package/dist/studio/index.html +2 -2
- package/package.json +10 -4
- package/dist/studio/assets/index-Ci_R6ARr.js +0 -423
- package/dist/studio/assets/index-Dio_c1Q3.css +0 -32
package/dist/core/adapter.d.ts
CHANGED
|
@@ -1,4 +1,16 @@
|
|
|
1
|
-
import type { CoreEvent, LaunchRunInput, RepoEntry, RepoOnboardRef, SessionView, RecordedEvent, GovernancePolicy, ConformanceRule, GovernanceClaim, CoverageReport, WorkflowDef, SystemSettings } from './types.js';
|
|
1
|
+
import type { CoreEvent, LaunchRunInput, RepoEntry, RepoOnboardRef, SessionView, RecordedEvent, GovernancePolicy, ConformanceRule, GovernanceClaim, CoverageReport, GraphKind, WorkflowDef, SystemSettings, Project, ProjectMember, InteractionRequest } from './types.js';
|
|
2
|
+
/** Where the daemon persists system settings. Exported so tests write fixtures to the ONE
|
|
3
|
+
* spelling of this path (the tests/ tree is audited against spelling core paths itself). */
|
|
4
|
+
export declare function settingsFilePath(): string;
|
|
5
|
+
/** Read user-registered workflow overlays from `dir` (the same dir `registerWorkflow` writes to).
|
|
6
|
+
*
|
|
7
|
+
* Skips: files whose id matches a built-in (those are `_writeBuiltinOverlay` artifacts written FOR
|
|
8
|
+
* the Rust actor, not user workflows — including them would duplicate a built-in in `listWorkflows`),
|
|
9
|
+
* non-`.json` files, and any file that does not parse into a `{id, phases[]}` shape (the Rust actor
|
|
10
|
+
* skips an unreadable overlay too, so crew must not surface one it can't). A missing dir yields `[]`.
|
|
11
|
+
*
|
|
12
|
+
* Exported so the FINDING-002 restart-hydration path is unit-testable without spawning a Core. */
|
|
13
|
+
export declare function readOverlayWorkflows(dir: string, builtinIds: ReadonlySet<string>): WorkflowDef[];
|
|
2
14
|
export declare const BUILTIN_WORKFLOWS: WorkflowDef[];
|
|
3
15
|
/**
|
|
4
16
|
* Chat is not available in this deployment at all — a capability gap, never a bad request.
|
|
@@ -15,6 +27,14 @@ export declare const BUILTIN_WORKFLOWS: WorkflowDef[];
|
|
|
15
27
|
export declare class ChatUnsupportedError extends Error {
|
|
16
28
|
constructor(message: string);
|
|
17
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* The project surface (DES-PROJECT-001) is not available in this deployment — the installed
|
|
32
|
+
* wicked-core-ts predates 0.6.0. Typed for the same reason as `ChatUnsupportedError`: the routes
|
|
33
|
+
* answer 501 ("upgrade the engine") on this, never 400 ("fix your request").
|
|
34
|
+
*/
|
|
35
|
+
export declare class ProjectsUnsupportedError extends Error {
|
|
36
|
+
constructor(what: string);
|
|
37
|
+
}
|
|
18
38
|
/**
|
|
19
39
|
* `resolveElicitation` is not available in this deployment — the NAPI binding has not
|
|
20
40
|
* landed in the installed `wicked-core-ts` yet (DES-002 §4 P-1 stub).
|
|
@@ -63,6 +83,15 @@ export interface CoreAdapterOptions {
|
|
|
63
83
|
* endpoint and the WS fan-out funnel through this stable API — so when the
|
|
64
84
|
* in-flight core-ts subscribe/teardown signature lands, only this file changes.
|
|
65
85
|
*/
|
|
86
|
+
/** The ids of a workflow's phases that carry a HUMAN gate (`human_confirm` unconditional, or the
|
|
87
|
+
* conditional `human_confirm_if`) — i.e. the phases that will PAUSE for a person.
|
|
88
|
+
*
|
|
89
|
+
* FINDING-023 (residual): core#208 made a workflow's phase gate deliberately WIN over a run-level
|
|
90
|
+
* `humanConfirm: none` (it pauses, with a self-disclosing note), but there was no way to learn a
|
|
91
|
+
* workflow's gates BEFORE launching it — an operator picking `none` for an unattended run only found
|
|
92
|
+
* out when it paused. Surfacing this on `GET /workflows/:id` is that missing launch-time signal.
|
|
93
|
+
* `'auto'` (the string form) is NOT a human gate. */
|
|
94
|
+
export declare function humanGatePhaseIds(wf: WorkflowDef): string[];
|
|
66
95
|
export declare class CoreAdapter {
|
|
67
96
|
private readonly core;
|
|
68
97
|
private readonly subscription;
|
|
@@ -89,6 +118,13 @@ export declare class CoreAdapter {
|
|
|
89
118
|
confirmGate(runId: string, approve: boolean, amend?: string): Promise<string>;
|
|
90
119
|
/** Cancel a run → the status token. */
|
|
91
120
|
cancelRun(runId: string): Promise<string>;
|
|
121
|
+
/**
|
|
122
|
+
* Archive (or unarchive) a TERMINAL run (crew#265) — write-off, not delete. Resolves `true`
|
|
123
|
+
* when the session existed, `false` for an unknown id (→ 404); REJECTS when the run is
|
|
124
|
+
* non-terminal (the route answers 409). Fail-closed on an old addon: method-presence guard,
|
|
125
|
+
* same doctrine as `injectWorkerMessage`.
|
|
126
|
+
*/
|
|
127
|
+
archiveRun(runId: string, archived: boolean, note?: string): Promise<boolean>;
|
|
92
128
|
/** Inject an operator message into a run's active PTY worker(s). target="all" or a CLI key. */
|
|
93
129
|
injectWorkerMessage(runId: string, message: string, target: string): Promise<string>;
|
|
94
130
|
/**
|
|
@@ -107,6 +143,51 @@ export declare class CoreAdapter {
|
|
|
107
143
|
sessionsDetail(): Promise<SessionView[]>;
|
|
108
144
|
/** A unit's captured transcript (string, or `null`). */
|
|
109
145
|
workOutput(unitId: string): Promise<string | null>;
|
|
146
|
+
/** True when the installed addon carries the project surface (0.6.0+). */
|
|
147
|
+
projectsSupported(): boolean;
|
|
148
|
+
private requireProjects;
|
|
149
|
+
projectCreate(name: string, description?: string): Promise<Project>;
|
|
150
|
+
projectUpdate(id: string, patch: {
|
|
151
|
+
name?: string | undefined;
|
|
152
|
+
description?: string | undefined;
|
|
153
|
+
status?: string | undefined;
|
|
154
|
+
}): Promise<Project>;
|
|
155
|
+
/** Every stored project (all statuses, newest first). The `default` project is NOT here — the
|
|
156
|
+
* route layer synthesizes it (ADR §7: computed, never stored). */
|
|
157
|
+
projectList(): Promise<Project[]>;
|
|
158
|
+
projectGet(id: string): Promise<Project | null>;
|
|
159
|
+
projectMembers(projectId: string): Promise<ProjectMember[]>;
|
|
160
|
+
/** Attach a member. `created:false` = the idempotent duplicate hit (emit no event for it). */
|
|
161
|
+
projectMemberAttach(projectId: string, kind: string, ref: string, meta?: Record<string, unknown>, attachedBy?: string): Promise<{
|
|
162
|
+
member: ProjectMember;
|
|
163
|
+
created: boolean;
|
|
164
|
+
}>;
|
|
165
|
+
/** Detach (tombstone). `false` = no such live member on that project (the route's 404). */
|
|
166
|
+
projectMemberDetach(projectId: string, memberId: string): Promise<boolean>;
|
|
167
|
+
/** The projects holding a live `(kind, ref)` membership — the run→project reverse read. */
|
|
168
|
+
memberProjects(kind: string, ref: string): Promise<string[]>;
|
|
169
|
+
/**
|
|
170
|
+
* Durable interaction requests (ADR §5.3), newest first — or `null` when this addon predates
|
|
171
|
+
* the binding (the `runEvents` convention: a missing capability must stay distinguishable from
|
|
172
|
+
* "no open prompts", or the caches' fallback chain misreports upgrades as empty inboxes).
|
|
173
|
+
*/
|
|
174
|
+
interactionRequests(sessionId?: string, status?: string): Promise<InteractionRequest[] | null>;
|
|
175
|
+
/** Capture a memory at a STRICT `kind:id[/…]` scope (the engine refuses malformed segments). */
|
|
176
|
+
captureMemory(content: string, scope: string): Promise<void>;
|
|
177
|
+
/** Memories within `scope`'s subtree, newest first — the ADR's memory.coverage probe. */
|
|
178
|
+
listMemories(scope: string, limit: number): Promise<{
|
|
179
|
+
content: string;
|
|
180
|
+
score: number;
|
|
181
|
+
tier: string;
|
|
182
|
+
}[]>;
|
|
183
|
+
/** Ingest a document (title + chunks) into the knowledge store. Returns the chunk count. */
|
|
184
|
+
ingestKnowledge(title: string, chunks: string[]): Promise<number>;
|
|
185
|
+
/** Recall up to `k` knowledge chunks relevant to `query`. */
|
|
186
|
+
recallKnowledge(query: string, k: number): Promise<{
|
|
187
|
+
content: string;
|
|
188
|
+
score: number;
|
|
189
|
+
source: string;
|
|
190
|
+
}[]>;
|
|
110
191
|
chatOpen(chatId: string, clis: string[], cwd?: string): Promise<{
|
|
111
192
|
cliKey: string;
|
|
112
193
|
ok: boolean;
|
|
@@ -175,6 +256,19 @@ export declare class CoreAdapter {
|
|
|
175
256
|
listConformanceClaims(): Promise<GovernanceClaim[]>;
|
|
176
257
|
/** Front-half coverage gate report; null when the store has no graph nodes. */
|
|
177
258
|
getCoverageReport(): Promise<CoverageReport | null>;
|
|
259
|
+
/**
|
|
260
|
+
* Coverage for ONE registered repo, computed over that repo's OWN code graph (FINDING-009). Unlike
|
|
261
|
+
* {@link getCoverageReport} — which reads the daemon store and reports a vacuous `coverage: 1.0` that
|
|
262
|
+
* names no repo — this resolves `repoRef` in the registry and recomputes over its `code_graph_db`.
|
|
263
|
+
* The core rejects an unknown repo (never a silent vacuous report), so this throws for a bad ref.
|
|
264
|
+
*/
|
|
265
|
+
getCoverageReportForRepo(repoRef: string): Promise<CoverageReport | null>;
|
|
266
|
+
/**
|
|
267
|
+
* Node-count-by-kind summary of ONE registered repo's code graph, over that repo's OWN store
|
|
268
|
+
* (#122) — what the estate graph actually holds for the repo, so an operator can see it was
|
|
269
|
+
* populated. The core rejects an unknown repo, so this throws for a bad ref.
|
|
270
|
+
*/
|
|
271
|
+
getGraphKindsForRepo(repoRef: string): Promise<GraphKind[]>;
|
|
178
272
|
/** Upsert a governance policy via the single-writer actor. */
|
|
179
273
|
upsertPolicy(policy: GovernancePolicy): Promise<void>;
|
|
180
274
|
/** Upsert a conformance rule via the single-writer actor. */
|
|
@@ -192,6 +286,17 @@ export declare class CoreAdapter {
|
|
|
192
286
|
/** Recall conformance rules matching a facet query (read-only, does not block actor). */
|
|
193
287
|
recallRulesPreview(query: Record<string, string | string[] | undefined>): Promise<ConformanceRule[]>;
|
|
194
288
|
private readonly userWorkflows;
|
|
289
|
+
/** Whether {@link hydrateFromOverlay} has run this process lifetime. */
|
|
290
|
+
private overlayHydrated;
|
|
291
|
+
/** Load user-registered workflows persisted to the overlay dir into `userWorkflows`, ONCE.
|
|
292
|
+
*
|
|
293
|
+
* FINDING-002 residual: `registerWorkflow` writes each def to the overlay dir AND to the in-memory
|
|
294
|
+
* `userWorkflows` Map, but the Map is process-local and empty on every daemon restart, and nothing
|
|
295
|
+
* read the dir back. So after a restart the Rust actor (which DOES load the overlay dir at startup)
|
|
296
|
+
* would launch a user workflow that `listWorkflows()`/`GET /workflows` no longer showed — it
|
|
297
|
+
* vanished from the registry while remaining runnable. Hydrating from the same dir the writer uses
|
|
298
|
+
* makes the two views agree again. */
|
|
299
|
+
private hydrateFromOverlay;
|
|
195
300
|
listWorkflows(): WorkflowDef[];
|
|
196
301
|
getWorkflow(id: string): WorkflowDef | null;
|
|
197
302
|
/** Write a built-in workflow definition to the Rust overlay dir (and hot-register when possible).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../src/core/adapter.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EACV,SAAS,EACT,cAAc,EACd,SAAS,EACT,cAAc,EACd,WAAW,EACX,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,cAAc,EACd,WAAW,EACX,cAAc,
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../src/core/adapter.ts"],"names":[],"mappings":"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"}
|
package/dist/core/adapter.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createRequire } from 'node:module';
|
|
2
2
|
import { mkdir, access, readFile, writeFile, chmod, rm } from 'node:fs/promises';
|
|
3
|
-
import { existsSync, readFileSync, renameSync } from 'node:fs';
|
|
3
|
+
import { existsSync, readdirSync, readFileSync, renameSync } from 'node:fs';
|
|
4
4
|
import { join, dirname, resolve, isAbsolute, relative, sep } from 'node:path';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
6
|
import { homedir } from 'node:os';
|
|
@@ -12,6 +12,23 @@ function wickedDir(...parts) {
|
|
|
12
12
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? '/tmp';
|
|
13
13
|
return join(home, '.wicked', ...parts);
|
|
14
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Parse a JSON string a napi binding returned. The bindings type their return loosely (`unknown`
|
|
17
|
+
* until a `ts_return_type` regen), so guard BOTH a non-string return and invalid JSON with an error
|
|
18
|
+
* that names the method — a bare `JSON.parse` throw is an unactionable "Unexpected token" (crew#227
|
|
19
|
+
* review). At the current engine contract `raw` is always a valid JSON string.
|
|
20
|
+
*/
|
|
21
|
+
function parseEngineJson(raw, method) {
|
|
22
|
+
if (typeof raw !== 'string') {
|
|
23
|
+
throw new Error(`${method}: expected a JSON string from the engine, got ${typeof raw}`);
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
return JSON.parse(raw);
|
|
27
|
+
}
|
|
28
|
+
catch (e) {
|
|
29
|
+
throw new Error(`${method}: engine returned invalid JSON (${e instanceof Error ? e.message : String(e)})`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
15
32
|
/**
|
|
16
33
|
* Workflow overlay directory — mirrors the Rust `workflow_overlay_dir()` logic in
|
|
17
34
|
* `pipeline.rs`. The Rust actor reads drop-in workflow JSONs from this path at startup
|
|
@@ -26,9 +43,45 @@ function workflowOverlayDir() {
|
|
|
26
43
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? '/tmp';
|
|
27
44
|
return join(home, '.config', 'wicked-core', 'workflows');
|
|
28
45
|
}
|
|
29
|
-
|
|
46
|
+
/** Where the daemon persists system settings. Exported so tests write fixtures to the ONE
|
|
47
|
+
* spelling of this path (the tests/ tree is audited against spelling core paths itself). */
|
|
48
|
+
export function settingsFilePath() {
|
|
30
49
|
return join(homedir(), '.config', 'wicked-core', 'settings.json');
|
|
31
50
|
}
|
|
51
|
+
/** Read user-registered workflow overlays from `dir` (the same dir `registerWorkflow` writes to).
|
|
52
|
+
*
|
|
53
|
+
* Skips: files whose id matches a built-in (those are `_writeBuiltinOverlay` artifacts written FOR
|
|
54
|
+
* the Rust actor, not user workflows — including them would duplicate a built-in in `listWorkflows`),
|
|
55
|
+
* non-`.json` files, and any file that does not parse into a `{id, phases[]}` shape (the Rust actor
|
|
56
|
+
* skips an unreadable overlay too, so crew must not surface one it can't). A missing dir yields `[]`.
|
|
57
|
+
*
|
|
58
|
+
* Exported so the FINDING-002 restart-hydration path is unit-testable without spawning a Core. */
|
|
59
|
+
export function readOverlayWorkflows(dir, builtinIds) {
|
|
60
|
+
let files;
|
|
61
|
+
try {
|
|
62
|
+
files = readdirSync(dir);
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return []; // no overlay dir yet → nothing registered
|
|
66
|
+
}
|
|
67
|
+
const out = [];
|
|
68
|
+
for (const file of files) {
|
|
69
|
+
if (!file.endsWith('.json'))
|
|
70
|
+
continue;
|
|
71
|
+
const id = file.slice(0, -'.json'.length);
|
|
72
|
+
if (builtinIds.has(id))
|
|
73
|
+
continue; // a built-in overlay, not a user workflow
|
|
74
|
+
try {
|
|
75
|
+
const def = JSON.parse(readFileSync(join(dir, file), 'utf8'));
|
|
76
|
+
if (def && typeof def.id === 'string' && Array.isArray(def.phases))
|
|
77
|
+
out.push(def);
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
// Unparseable overlay — core would skip it at load, so crew skips it too.
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return out;
|
|
84
|
+
}
|
|
32
85
|
/** Find the wicked-core standalone binary for the gate-hook command.
|
|
33
86
|
* Checks common install locations so the Rust actor can build a correct
|
|
34
87
|
* hook command even when loaded as a napi addon (where current_exe() = node).
|
|
@@ -58,6 +111,31 @@ function locateWickedCoreExe() {
|
|
|
58
111
|
// `subscribe` seam has a blast radius of exactly one file.
|
|
59
112
|
const require = createRequire(import.meta.url);
|
|
60
113
|
const { Core } = require('wicked-core-ts');
|
|
114
|
+
/**
|
|
115
|
+
* Does the installed wicked-core-ts addon understand `LaunchOptions.extraWriteRoots` (≥ 0.6.1)?
|
|
116
|
+
*
|
|
117
|
+
* A napi object silently IGNORES fields the addon doesn't declare, so passing the option to an
|
|
118
|
+
* older addon would launch a run whose boundary never widened — the worker then gets a boundary
|
|
119
|
+
* deny on the very deliverable path the caller declared (the crew#263 failure, resurrected
|
|
120
|
+
* silently). Fail CLOSED on version instead: same doctrine as the `projectId` guard below.
|
|
121
|
+
*/
|
|
122
|
+
function addonSupportsExtraWriteRoots() {
|
|
123
|
+
try {
|
|
124
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
125
|
+
const pkg = require('wicked-core-ts/package.json');
|
|
126
|
+
// Match only the numeric MAJOR.MINOR.PATCH prefix: `split('.').map(Number)` returns NaN on
|
|
127
|
+
// pre-release/build suffixes (`0.6.1-beta.1`), which would fail-closed a capable addon
|
|
128
|
+
// (Copilot). No match ⇒ unparseable ⇒ fail closed.
|
|
129
|
+
const m = /^(\d+)\.(\d+)\.(\d+)/.exec(pkg.version ?? '');
|
|
130
|
+
if (!m)
|
|
131
|
+
return false;
|
|
132
|
+
const [maj, min, pat] = [Number(m[1]), Number(m[2]), Number(m[3])];
|
|
133
|
+
return maj > 0 || min > 6 || (min === 6 && pat >= 1);
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
61
139
|
// ── Built-in workflow definitions (crew#44) ──────────────────────────────────
|
|
62
140
|
// Static mirrors of wicked-core workflow defs: feature, bug, migration, survey-repo,
|
|
63
141
|
// domain-graph-slice, memories, collab, onboarding, chat, and domain-extraction.
|
|
@@ -98,7 +176,7 @@ const CORE_SEEDED_WORKFLOWS = new Set(['feature', 'bug', 'migration', 'onboardin
|
|
|
98
176
|
* moves. This is display only: as of FINDING-049 these defs are never written to core's overlay dir
|
|
99
177
|
* (see CORE_SEEDED_WORKFLOWS), so a stale value here cannot reach the engine.
|
|
100
178
|
*/
|
|
101
|
-
const EVIDENCE_FLOOR_PIN = '
|
|
179
|
+
const EVIDENCE_FLOOR_PIN = 'e2e7af1db9e48454';
|
|
102
180
|
export const BUILTIN_WORKFLOWS = [
|
|
103
181
|
{
|
|
104
182
|
id: 'chat',
|
|
@@ -133,7 +211,7 @@ export const BUILTIN_WORKFLOWS = [
|
|
|
133
211
|
{ id: 'design', kind: 'recon', gate_type: 'strategy', gate: 'auto', executes_code: false, verified_evidence: false, required_deliverables: [], depends_on: ['clarify'], role: 'neutral', skill_ref: null, allowed_skills: [], validator_pin: null },
|
|
134
212
|
{ id: 'build', kind: 'build', gate_type: 'execution', gate: 'auto', executes_code: true, verified_evidence: false, required_deliverables: [], depends_on: ['design'], role: 'creator', skill_ref: null, allowed_skills: [], validator_pin: null },
|
|
135
213
|
{ id: 'adversarial-review', kind: 'review', gate_type: 'execution', gate: { human_confirm: { unconditional: false } }, executes_code: false, verified_evidence: false, required_deliverables: [], depends_on: ['build'], role: 'evaluator', skill_ref: null, allowed_skills: [], validator_pin: EVIDENCE_FLOOR_PIN },
|
|
136
|
-
{ id: 'test', kind: 'test', gate_type: 'execution', gate: { human_confirm_if: 'verdict_not_pass' }, executes_code: false, verified_evidence: true, required_deliverables: [], depends_on: ['build'], role: 'neutral', skill_ref: null, allowed_skills: [], validator_pin:
|
|
214
|
+
{ id: 'test', kind: 'test', gate_type: 'execution', gate: { human_confirm_if: 'verdict_not_pass' }, executes_code: false, verified_evidence: true, required_deliverables: [], depends_on: ['build'], role: 'neutral', skill_ref: null, allowed_skills: [], validator_pin: EVIDENCE_FLOOR_PIN },
|
|
137
215
|
{ id: 'review', kind: 'review', gate_type: 'execution', gate: 'auto', executes_code: false, verified_evidence: false, required_deliverables: [], depends_on: ['test'], role: 'neutral', skill_ref: null, allowed_skills: [], validator_pin: null },
|
|
138
216
|
],
|
|
139
217
|
},
|
|
@@ -157,12 +235,19 @@ export const BUILTIN_WORKFLOWS = [
|
|
|
157
235
|
],
|
|
158
236
|
},
|
|
159
237
|
{
|
|
238
|
+
// MUST stay byte-identical to wicked-core/workflows/survey-repo.json — crew's overlay write is the
|
|
239
|
+
// ONLY def the engine resolves at runtime (core does not seed survey-repo), so a stale mirror here
|
|
240
|
+
// silently runs the OLD def. The pre-fix mirror carried 3 phases with no `instructions` and no
|
|
241
|
+
// `synthesize`, so survey-repo ran 3 near-identical prompts and produced no run-level synthesis —
|
|
242
|
+
// exactly FINDING-011, still live because the fix only landed in the core JSON the runtime ignores.
|
|
243
|
+
// Guarded by builtin-overlay-shadow.test.ts (survey-repo is now in MIRRORED_IDS).
|
|
160
244
|
id: 'survey-repo',
|
|
161
245
|
is_system: true,
|
|
162
246
|
phases: [
|
|
163
|
-
{ id: 'structure', kind: 'recon', gate_type: 'value', gate: 'auto', executes_code: false, verified_evidence: false, required_deliverables: [], depends_on: [], role: 'neutral', skill_ref: null, allowed_skills: [], validator_pin: null },
|
|
164
|
-
{ id: 'stack', kind: 'recon', gate_type: 'value', gate: 'auto', executes_code: false, verified_evidence: false, required_deliverables: [], depends_on: ['structure'], role: 'neutral', skill_ref: null, allowed_skills: [], validator_pin: null },
|
|
165
|
-
{ id: 'conventions', kind: 'recon', gate_type: 'value', gate: 'auto', executes_code: false, verified_evidence: false, required_deliverables: [], depends_on: ['stack'], role: 'neutral', skill_ref: null, allowed_skills: [], validator_pin: null },
|
|
247
|
+
{ id: 'structure', kind: 'recon', instructions: 'Map the repository layout only: top-level directories, entry points, and where source, tests, config, and docs live. Do not analyze languages, dependencies, or conventions — later phases cover those.', gate_type: 'value', gate: 'auto', executes_code: false, verified_evidence: false, required_deliverables: [], depends_on: [], role: 'neutral', skill_ref: null, allowed_skills: [], validator_pin: null },
|
|
248
|
+
{ id: 'stack', kind: 'recon', instructions: 'Identify the technology stack from the manifests (package.json, Cargo.toml, pyproject.toml, ...): languages, frameworks, build tools, key dependencies. Build on the structure summary provided as prior context; do not re-map the layout.', gate_type: 'value', gate: 'auto', executes_code: false, verified_evidence: false, required_deliverables: [], depends_on: ['structure'], role: 'neutral', skill_ref: null, allowed_skills: [], validator_pin: null },
|
|
249
|
+
{ id: 'conventions', kind: 'recon', instructions: 'Identify the working conventions: naming, module boundaries, test placement and style, lint/format configuration, CI expectations. Build on the prior phases\' outputs provided as context; do not re-survey structure or stack.', gate_type: 'value', gate: 'auto', executes_code: false, verified_evidence: false, required_deliverables: [], depends_on: ['stack'], role: 'neutral', skill_ref: null, allowed_skills: [], validator_pin: null },
|
|
250
|
+
{ id: 'synthesize', kind: 'recon', instructions: 'Do not re-survey the repository. Merge the three prior phase outputs provided as context into one coherent survey — structure, then stack, then conventions — resolving overlaps and flagging any contradictions between them.', gate_type: 'value', gate: 'auto', executes_code: false, verified_evidence: false, required_deliverables: [], depends_on: ['structure', 'stack', 'conventions'], role: 'neutral', skill_ref: null, allowed_skills: [], validator_pin: null },
|
|
166
251
|
],
|
|
167
252
|
},
|
|
168
253
|
{
|
|
@@ -211,11 +296,20 @@ export const BUILTIN_WORKFLOWS = [
|
|
|
211
296
|
{
|
|
212
297
|
id: 'domain-extraction',
|
|
213
298
|
phases: [
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
299
|
+
// required_deliverables reconciled with core (wicked-core/workflows/domain-extraction.json):
|
|
300
|
+
// survey/analyze/extract annotate the estate STORE and domain-graph now PERSISTS the graph
|
|
301
|
+
// into the store (not a JSON file), so their evidence is DB state — verified by the coverage
|
|
302
|
+
// gate (reads the store) and domain-graph's fail-closed-on-coverage<1.0 — not a worktree file.
|
|
303
|
+
// Only coverage emits a genuine standalone report the deterministic floor reads. Declaring
|
|
304
|
+
// phantom files failed every phase under core's FINDING-101 deliverable gate.
|
|
305
|
+
{ id: 'survey', kind: 'recon', gate_type: null, gate: 'auto', executes_code: false, verified_evidence: false, required_deliverables: [], depends_on: [], role: 'neutral', skill_ref: 'wicked-garden-domain', allowed_skills: [], validator_pin: null },
|
|
306
|
+
{ id: 'analyze', kind: 'recon', gate_type: null, gate: 'auto', executes_code: false, verified_evidence: false, required_deliverables: [], depends_on: ['survey'], role: 'neutral', skill_ref: 'wicked-garden-domain', allowed_skills: [], validator_pin: null },
|
|
307
|
+
{ id: 'extract', kind: 'recon', gate_type: 'value', gate: 'auto', executes_code: false, verified_evidence: false, required_deliverables: [], depends_on: ['analyze'], role: 'creator', skill_ref: 'wicked-garden-domain-extractor', allowed_skills: [], validator_pin: null },
|
|
308
|
+
{ id: 'coverage', kind: 'test', gate_type: 'execution', gate: { human_confirm_if: 'verdict_not_pass' }, executes_code: false, verified_evidence: true, required_deliverables: ['coverage-report.json'], depends_on: ['extract'], role: 'evaluator', skill_ref: 'wicked-garden-domain-coverage', allowed_skills: [], validator_pin: 'bfe4020a365c598b' },
|
|
309
|
+
// domain-graph is a DETERMINISTIC Tool that runs `wicked-core domain-graph`, which PERSISTS the
|
|
310
|
+
// domain/requirement/rule graph into the repo store (core#237) — not an LLM skill that could hit
|
|
311
|
+
// a non-persisting hermetic fallback. Mirrors wicked-core/workflows/domain-extraction.json.
|
|
312
|
+
{ id: 'domain-graph', executor: { type: 'tool', cmd: ['wicked-core', 'domain-graph', '--db', '{code_graph_db}', '--out', 'requirements_graph.json'] }, kind: 'build', gate_type: 'strategy', gate: { human_confirm: { unconditional: false } }, executes_code: false, verified_evidence: false, required_deliverables: [], depends_on: ['coverage'], role: 'neutral', skill_ref: null, allowed_skills: [], validator_pin: null },
|
|
219
313
|
],
|
|
220
314
|
},
|
|
221
315
|
];
|
|
@@ -237,6 +331,17 @@ export class ChatUnsupportedError extends Error {
|
|
|
237
331
|
this.name = 'ChatUnsupportedError';
|
|
238
332
|
}
|
|
239
333
|
}
|
|
334
|
+
/**
|
|
335
|
+
* The project surface (DES-PROJECT-001) is not available in this deployment — the installed
|
|
336
|
+
* wicked-core-ts predates 0.6.0. Typed for the same reason as `ChatUnsupportedError`: the routes
|
|
337
|
+
* answer 501 ("upgrade the engine") on this, never 400 ("fix your request").
|
|
338
|
+
*/
|
|
339
|
+
export class ProjectsUnsupportedError extends Error {
|
|
340
|
+
constructor(what) {
|
|
341
|
+
super(`${what} is not supported by this wicked-core build (needs wicked-core-ts >= 0.6.0)`);
|
|
342
|
+
this.name = 'ProjectsUnsupportedError';
|
|
343
|
+
}
|
|
344
|
+
}
|
|
240
345
|
/**
|
|
241
346
|
* `resolveElicitation` is not available in this deployment — the NAPI binding has not
|
|
242
347
|
* landed in the installed `wicked-core-ts` yet (DES-002 §4 P-1 stub).
|
|
@@ -316,6 +421,21 @@ function quarantineStaleOnboardingOverlay() {
|
|
|
316
421
|
* endpoint and the WS fan-out funnel through this stable API — so when the
|
|
317
422
|
* in-flight core-ts subscribe/teardown signature lands, only this file changes.
|
|
318
423
|
*/
|
|
424
|
+
/** The ids of a workflow's phases that carry a HUMAN gate (`human_confirm` unconditional, or the
|
|
425
|
+
* conditional `human_confirm_if`) — i.e. the phases that will PAUSE for a person.
|
|
426
|
+
*
|
|
427
|
+
* FINDING-023 (residual): core#208 made a workflow's phase gate deliberately WIN over a run-level
|
|
428
|
+
* `humanConfirm: none` (it pauses, with a self-disclosing note), but there was no way to learn a
|
|
429
|
+
* workflow's gates BEFORE launching it — an operator picking `none` for an unattended run only found
|
|
430
|
+
* out when it paused. Surfacing this on `GET /workflows/:id` is that missing launch-time signal.
|
|
431
|
+
* `'auto'` (the string form) is NOT a human gate. */
|
|
432
|
+
export function humanGatePhaseIds(wf) {
|
|
433
|
+
return wf.phases
|
|
434
|
+
.filter((p) => typeof p.gate === 'object' &&
|
|
435
|
+
p.gate !== null &&
|
|
436
|
+
('human_confirm' in p.gate || 'human_confirm_if' in p.gate))
|
|
437
|
+
.map((p) => p.id);
|
|
438
|
+
}
|
|
319
439
|
export class CoreAdapter {
|
|
320
440
|
core;
|
|
321
441
|
subscription;
|
|
@@ -408,6 +528,23 @@ export class CoreAdapter {
|
|
|
408
528
|
opts.humanConfirm = input.humanConfirm;
|
|
409
529
|
if (input.repoRef !== undefined)
|
|
410
530
|
opts.repoRef = input.repoRef;
|
|
531
|
+
if (input.projectId !== undefined) {
|
|
532
|
+
// Fail CLOSED on an old addon: silently dropping projectId would launch an unfiled run the
|
|
533
|
+
// caller believed was filed — the exact failure §2.2 exists to prevent.
|
|
534
|
+
if (typeof this.core.projectCreate !== 'function') {
|
|
535
|
+
throw new ProjectsUnsupportedError('Filing a run into a project');
|
|
536
|
+
}
|
|
537
|
+
opts.projectId = input.projectId;
|
|
538
|
+
}
|
|
539
|
+
if (input.extraWriteRoots !== undefined && input.extraWriteRoots.length > 0) {
|
|
540
|
+
// Fail CLOSED on an old addon (napi ignores undeclared fields): a silently-dropped
|
|
541
|
+
// widening resurrects the crew#263 boundary deny on the declared deliverable path.
|
|
542
|
+
if (!addonSupportsExtraWriteRoots()) {
|
|
543
|
+
throw new Error('extraWriteRoots needs wicked-core-ts >= 0.6.1; the installed addon would silently ' +
|
|
544
|
+
'ignore it and the run would be denied writing its own deliverable');
|
|
545
|
+
}
|
|
546
|
+
opts.extraWriteRoots = input.extraWriteRoots;
|
|
547
|
+
}
|
|
411
548
|
if (input.workflow !== undefined) {
|
|
412
549
|
opts.workflow = input.workflow;
|
|
413
550
|
// Ensure DROP-IN workflow definitions are present in the Rust overlay dir on first use.
|
|
@@ -442,6 +579,20 @@ export class CoreAdapter {
|
|
|
442
579
|
cancelRun(runId) {
|
|
443
580
|
return this.core.cancelRun(runId);
|
|
444
581
|
}
|
|
582
|
+
/**
|
|
583
|
+
* Archive (or unarchive) a TERMINAL run (crew#265) — write-off, not delete. Resolves `true`
|
|
584
|
+
* when the session existed, `false` for an unknown id (→ 404); REJECTS when the run is
|
|
585
|
+
* non-terminal (the route answers 409). Fail-closed on an old addon: method-presence guard,
|
|
586
|
+
* same doctrine as `injectWorkerMessage`.
|
|
587
|
+
*/
|
|
588
|
+
async archiveRun(runId, archived, note) {
|
|
589
|
+
const archive = this.core.archiveRun;
|
|
590
|
+
if (typeof archive !== 'function') {
|
|
591
|
+
throw new Error('Run archival needs wicked-core-ts >= 0.6.2; this build does not support it');
|
|
592
|
+
}
|
|
593
|
+
// JSON-encoded bool by contract (parse, never truthiness-test — 'false' is truthy).
|
|
594
|
+
return JSON.parse(await archive.call(this.core, runId, archived, note ?? null));
|
|
595
|
+
}
|
|
445
596
|
/** Inject an operator message into a run's active PTY worker(s). target="all" or a CLI key. */
|
|
446
597
|
injectWorkerMessage(runId, message, target) {
|
|
447
598
|
if (typeof this.core.injectWorkerMessage !== 'function') {
|
|
@@ -506,6 +657,87 @@ export class CoreAdapter {
|
|
|
506
657
|
async workOutput(unitId) {
|
|
507
658
|
return JSON.parse(await this.core.workOutput(unitId));
|
|
508
659
|
}
|
|
660
|
+
// ── Projects (DES-PROJECT-001) ──────────────────────────────────────────────
|
|
661
|
+
// 1:1 maps of the 0.6.0 engine surface. Writes ride the single-writer actor;
|
|
662
|
+
// reads are read-only store opens inside the addon. Every method throws
|
|
663
|
+
// ProjectsUnsupportedError on a pre-0.6.0 addon (routes answer 501).
|
|
664
|
+
/** True when the installed addon carries the project surface (0.6.0+). */
|
|
665
|
+
projectsSupported() {
|
|
666
|
+
return typeof this.core.projectCreate === 'function';
|
|
667
|
+
}
|
|
668
|
+
requireProjects(fn, what) {
|
|
669
|
+
if (typeof fn !== 'function')
|
|
670
|
+
throw new ProjectsUnsupportedError(what);
|
|
671
|
+
return fn;
|
|
672
|
+
}
|
|
673
|
+
async projectCreate(name, description) {
|
|
674
|
+
const fn = this.requireProjects(this.core.projectCreate, 'Creating a project');
|
|
675
|
+
return JSON.parse(await fn.call(this.core, name, description ?? null));
|
|
676
|
+
}
|
|
677
|
+
async projectUpdate(id, patch) {
|
|
678
|
+
const fn = this.requireProjects(this.core.projectUpdate, 'Updating a project');
|
|
679
|
+
return JSON.parse(await fn.call(this.core, id, patch.name ?? null, patch.description ?? null, patch.status ?? null));
|
|
680
|
+
}
|
|
681
|
+
/** Every stored project (all statuses, newest first). The `default` project is NOT here — the
|
|
682
|
+
* route layer synthesizes it (ADR §7: computed, never stored). */
|
|
683
|
+
async projectList() {
|
|
684
|
+
const fn = this.requireProjects(this.core.projectList, 'Listing projects');
|
|
685
|
+
return JSON.parse(await fn.call(this.core));
|
|
686
|
+
}
|
|
687
|
+
async projectGet(id) {
|
|
688
|
+
const fn = this.requireProjects(this.core.projectGet, 'Reading a project');
|
|
689
|
+
return JSON.parse(await fn.call(this.core, id));
|
|
690
|
+
}
|
|
691
|
+
async projectMembers(projectId) {
|
|
692
|
+
const fn = this.requireProjects(this.core.projectMembers, 'Listing project members');
|
|
693
|
+
return JSON.parse(await fn.call(this.core, projectId));
|
|
694
|
+
}
|
|
695
|
+
/** Attach a member. `created:false` = the idempotent duplicate hit (emit no event for it). */
|
|
696
|
+
async projectMemberAttach(projectId, kind, ref, meta, attachedBy) {
|
|
697
|
+
const fn = this.requireProjects(this.core.projectMemberAttach, 'Attaching a project member');
|
|
698
|
+
return JSON.parse(await fn.call(this.core, projectId, kind, ref, meta !== undefined ? JSON.stringify(meta) : null, attachedBy ?? null));
|
|
699
|
+
}
|
|
700
|
+
/** Detach (tombstone). `false` = no such live member on that project (the route's 404). */
|
|
701
|
+
async projectMemberDetach(projectId, memberId) {
|
|
702
|
+
const fn = this.requireProjects(this.core.projectMemberDetach, 'Detaching a project member');
|
|
703
|
+
return JSON.parse(await fn.call(this.core, projectId, memberId));
|
|
704
|
+
}
|
|
705
|
+
/** The projects holding a live `(kind, ref)` membership — the run→project reverse read. */
|
|
706
|
+
async memberProjects(kind, ref) {
|
|
707
|
+
const fn = this.requireProjects(this.core.memberProjects, 'Resolving a member’s projects');
|
|
708
|
+
return JSON.parse(await fn.call(this.core, kind, ref));
|
|
709
|
+
}
|
|
710
|
+
/**
|
|
711
|
+
* Durable interaction requests (ADR §5.3), newest first — or `null` when this addon predates
|
|
712
|
+
* the binding (the `runEvents` convention: a missing capability must stay distinguishable from
|
|
713
|
+
* "no open prompts", or the caches' fallback chain misreports upgrades as empty inboxes).
|
|
714
|
+
*/
|
|
715
|
+
async interactionRequests(sessionId, status) {
|
|
716
|
+
if (typeof this.core.interactionRequests !== 'function')
|
|
717
|
+
return null;
|
|
718
|
+
return JSON.parse(await this.core.interactionRequests(sessionId ?? null, status ?? null));
|
|
719
|
+
}
|
|
720
|
+
// ── The foundation record (ADR §3.2): charter writes + record probes ────────
|
|
721
|
+
/** Capture a memory at a STRICT `kind:id[/…]` scope (the engine refuses malformed segments). */
|
|
722
|
+
async captureMemory(content, scope) {
|
|
723
|
+
const fn = this.requireProjects(this.core.captureMemory, 'Capturing a memory');
|
|
724
|
+
await fn.call(this.core, content, scope);
|
|
725
|
+
}
|
|
726
|
+
/** Memories within `scope`'s subtree, newest first — the ADR's memory.coverage probe. */
|
|
727
|
+
async listMemories(scope, limit) {
|
|
728
|
+
const fn = this.requireProjects(this.core.listMemories, 'Listing memories');
|
|
729
|
+
return JSON.parse(await fn.call(this.core, scope, limit));
|
|
730
|
+
}
|
|
731
|
+
/** Ingest a document (title + chunks) into the knowledge store. Returns the chunk count. */
|
|
732
|
+
async ingestKnowledge(title, chunks) {
|
|
733
|
+
const fn = this.requireProjects(this.core.ingestKnowledge, 'Ingesting knowledge');
|
|
734
|
+
return JSON.parse(await fn.call(this.core, title, JSON.stringify(chunks)));
|
|
735
|
+
}
|
|
736
|
+
/** Recall up to `k` knowledge chunks relevant to `query`. */
|
|
737
|
+
async recallKnowledge(query, k) {
|
|
738
|
+
const fn = this.requireProjects(this.core.recallKnowledge, 'Recalling knowledge');
|
|
739
|
+
return JSON.parse(await fn.call(this.core, query, k));
|
|
740
|
+
}
|
|
509
741
|
// ── Chat sessions (core#134 / crew#165) ────────────────────────────────────
|
|
510
742
|
async chatOpen(chatId, clis, cwd) {
|
|
511
743
|
const raw = await this.core.chatOpen(chatId, JSON.stringify(clis), cwd ?? null);
|
|
@@ -743,6 +975,25 @@ export class CoreAdapter {
|
|
|
743
975
|
async getCoverageReport() {
|
|
744
976
|
return JSON.parse(await this.core.getCoverageReport());
|
|
745
977
|
}
|
|
978
|
+
/**
|
|
979
|
+
* Coverage for ONE registered repo, computed over that repo's OWN code graph (FINDING-009). Unlike
|
|
980
|
+
* {@link getCoverageReport} — which reads the daemon store and reports a vacuous `coverage: 1.0` that
|
|
981
|
+
* names no repo — this resolves `repoRef` in the registry and recomputes over its `code_graph_db`.
|
|
982
|
+
* The core rejects an unknown repo (never a silent vacuous report), so this throws for a bad ref.
|
|
983
|
+
*/
|
|
984
|
+
async getCoverageReportForRepo(repoRef) {
|
|
985
|
+
// The napi binding returns a JSON string (`serde_json::to_string`); parse it with a guard that
|
|
986
|
+
// names the method on either a non-string return or invalid JSON (Copilot #227).
|
|
987
|
+
return parseEngineJson(await this.core.getCoverageReportForRepo(repoRef), 'getCoverageReportForRepo');
|
|
988
|
+
}
|
|
989
|
+
/**
|
|
990
|
+
* Node-count-by-kind summary of ONE registered repo's code graph, over that repo's OWN store
|
|
991
|
+
* (#122) — what the estate graph actually holds for the repo, so an operator can see it was
|
|
992
|
+
* populated. The core rejects an unknown repo, so this throws for a bad ref.
|
|
993
|
+
*/
|
|
994
|
+
async getGraphKindsForRepo(repoRef) {
|
|
995
|
+
return parseEngineJson(await this.core.getGraphKindsForRepo(repoRef), 'getGraphKindsForRepo');
|
|
996
|
+
}
|
|
746
997
|
// ── Governance writes (crew#42) ────────────────────────────────────────────
|
|
747
998
|
/** Upsert a governance policy via the single-writer actor. */
|
|
748
999
|
async upsertPolicy(policy) {
|
|
@@ -791,7 +1042,28 @@ export class CoreAdapter {
|
|
|
791
1042
|
// workflows are added to `userWorkflows` and persisted to disk; the Rust actor
|
|
792
1043
|
// picks them up via `register_workflow` NAPI (when available) for immediate use.
|
|
793
1044
|
userWorkflows = new Map();
|
|
1045
|
+
/** Whether {@link hydrateFromOverlay} has run this process lifetime. */
|
|
1046
|
+
overlayHydrated = false;
|
|
1047
|
+
/** Load user-registered workflows persisted to the overlay dir into `userWorkflows`, ONCE.
|
|
1048
|
+
*
|
|
1049
|
+
* FINDING-002 residual: `registerWorkflow` writes each def to the overlay dir AND to the in-memory
|
|
1050
|
+
* `userWorkflows` Map, but the Map is process-local and empty on every daemon restart, and nothing
|
|
1051
|
+
* read the dir back. So after a restart the Rust actor (which DOES load the overlay dir at startup)
|
|
1052
|
+
* would launch a user workflow that `listWorkflows()`/`GET /workflows` no longer showed — it
|
|
1053
|
+
* vanished from the registry while remaining runnable. Hydrating from the same dir the writer uses
|
|
1054
|
+
* makes the two views agree again. */
|
|
1055
|
+
hydrateFromOverlay() {
|
|
1056
|
+
if (this.overlayHydrated)
|
|
1057
|
+
return;
|
|
1058
|
+
this.overlayHydrated = true;
|
|
1059
|
+
const builtinIds = new Set(BUILTIN_WORKFLOWS.map((w) => w.id));
|
|
1060
|
+
for (const def of readOverlayWorkflows(workflowOverlayDir(), builtinIds)) {
|
|
1061
|
+
if (!this.userWorkflows.has(def.id))
|
|
1062
|
+
this.userWorkflows.set(def.id, def);
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
794
1065
|
listWorkflows() {
|
|
1066
|
+
this.hydrateFromOverlay();
|
|
795
1067
|
// Builtins first (stable ordering), but user-registered workflows take precedence when
|
|
796
1068
|
// ids conflict — consistent with getWorkflow() which prefers userWorkflows.get().
|
|
797
1069
|
const seen = new Set();
|
|
@@ -812,6 +1084,7 @@ export class CoreAdapter {
|
|
|
812
1084
|
return result;
|
|
813
1085
|
}
|
|
814
1086
|
getWorkflow(id) {
|
|
1087
|
+
this.hydrateFromOverlay();
|
|
815
1088
|
return this.userWorkflows.get(id) ?? BUILTIN_WORKFLOWS.find((w) => w.id === id) ?? null;
|
|
816
1089
|
}
|
|
817
1090
|
/** Write a built-in workflow definition to the Rust overlay dir (and hot-register when possible).
|
|
@@ -947,6 +1220,14 @@ export class CoreAdapter {
|
|
|
947
1220
|
if (typeof v !== 'number' || !Number.isInteger(v) || v < 1 || v > 10000)
|
|
948
1221
|
delete parsed.graphNodeLimit;
|
|
949
1222
|
}
|
|
1223
|
+
// worker_config_root (seat sign-in): absolute path or "" (= engine default). A hand-edited
|
|
1224
|
+
// relative path is dropped rather than exported as WICKED_WORKER_HOME, where the engine
|
|
1225
|
+
// would resolve it against an arbitrary spawn cwd.
|
|
1226
|
+
if ('worker_config_root' in parsed) {
|
|
1227
|
+
const r = parsed.worker_config_root;
|
|
1228
|
+
if (typeof r !== 'string' || (r !== '' && !isAbsolute(r)))
|
|
1229
|
+
delete parsed.worker_config_root;
|
|
1230
|
+
}
|
|
950
1231
|
return { ...DEFAULT_SETTINGS, ...parsed };
|
|
951
1232
|
}
|
|
952
1233
|
catch {
|