@shardworks/spider-apparatus 0.1.226 → 0.1.228

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/README.md CHANGED
@@ -125,7 +125,21 @@ Return the merged effective writ-type → template-name mapping. Config mappings
125
125
 
126
126
  ## Configuration
127
127
 
128
- The Spider reads its config from `guild.json["spider"]`:
128
+ The Spider reads its config from `guild.json["spider"]`. Zero-config works out of the box for mandate dispatch — Spider's apparatus contributes a plugin-default rig template (`default`: draft → implement → review → revise → seal) and a default mapping (`mandate → default`) via its own supportKit. A minimal guild only needs to declare `spider.variables` so the default template can interpolate role / build command / test command:
129
+
130
+ ```json
131
+ {
132
+ "spider": {
133
+ "variables": {
134
+ "role": "artificer",
135
+ "buildCommand": "pnpm -w build",
136
+ "testCommand": "pnpm -w test"
137
+ }
138
+ }
139
+ }
140
+ ```
141
+
142
+ Guilds that need a custom pipeline can override the plugin defaults by declaring their own `rigTemplates` and/or `rigTemplateMappings`:
129
143
 
130
144
  ```json
131
145
  {
@@ -166,14 +180,16 @@ The Spider reads its config from `guild.json["spider"]`:
166
180
  }
167
181
  ```
168
182
 
183
+ A config-level template named `default` overrides the plugin-contributed `spider.default` for the `mandate → default` lookup: the registry resolves the kit mapping against the bare name first, then falls back to `${pluginId}.${templateName}` when the bare name is not claimed.
184
+
169
185
  | Field | Type | Default | Description |
170
186
  |---|---|---|---|
171
187
  | `pollIntervalMs` | `number` | `5000` | Polling interval for the `crawl-continual` tool (ms). |
172
188
  | `buildCommand` | `string` | — | Build command forwarded to quick engines. |
173
189
  | `testCommand` | `string` | — | Test command forwarded to quick engines. |
174
- | `variables` | `Record<string, unknown>` | — | Named values available in rig template givens via `${vars.<path>}`. |
175
- | `rigTemplates` | `Record<string, RigTemplate>` | | Named rig template definitions. |
176
- | `rigTemplateMappings` | `Record<string, string>` | | Writ type → template name. `'default'` is the fallback. |
190
+ | `variables` | `Record<string, unknown>` | — | Named values available in rig template givens via `${vars.<path>}`. The plugin-default template requires `role`, `buildCommand`, and `testCommand`. |
191
+ | `rigTemplates` | `Record<string, RigTemplate>` | plugin default `default` (draft → seal) | Named rig template definitions. Config-level entries override plugin-contributed templates of the same name. |
192
+ | `rigTemplateMappings` | `Record<string, string>` | plugin default `{ mandate: 'default' }` | Writ type → template name. Config-level entries override plugin-contributed mappings for the same writ type. |
177
193
  | `maxConcurrentEngines` | `number` | `3` | Maximum number of engines running concurrently across all rigs. When the limit is reached, runnable engines stay in `pending` and new rigs are not spawned until a slot frees. |
178
194
  | `maxConcurrentEnginesPerRig` | `number` | `1` | Maximum number of engines running concurrently within a single rig. Prevents race conditions with rig-local resources. |
179
195
 
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Spider's plugin-default rig template (`default`).
3
+ *
4
+ * This is the canonical draft → implement → review → revise → seal
5
+ * pipeline that every guild used to declare inline under
6
+ * `spider.rigTemplates.default` in its `guild.json`. It is now
7
+ * contributed as a plugin default so mandate dispatch works out of the
8
+ * box with zero guild configuration — an operator only needs to declare
9
+ * `spider.variables` for the role and build/test commands.
10
+ *
11
+ * Guilds may still override this template by declaring their own
12
+ * `spider.rigTemplates.default` in guild.json; config entries win over
13
+ * plugin-contributed defaults via the RigTemplateRegistry's precedence
14
+ * rules.
15
+ *
16
+ * Per D7 in the plan-and-ship commission, this template has no fallback
17
+ * defaults for `${vars.role}`, `${vars.buildCommand}`, or
18
+ * `${vars.testCommand}` — a missing variable raises at dispatch time so
19
+ * misconfiguration is surfaced loudly rather than masked.
20
+ */
21
+ import type { RigTemplate } from './types.ts';
22
+ export declare const defaultRigTemplate: RigTemplate;
23
+ //# sourceMappingURL=default-template.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"default-template.d.ts","sourceRoot":"","sources":["../src/default-template.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,eAAO,MAAM,kBAAkB,EAAE,WAsChC,CAAC"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Spider's plugin-default rig template (`default`).
3
+ *
4
+ * This is the canonical draft → implement → review → revise → seal
5
+ * pipeline that every guild used to declare inline under
6
+ * `spider.rigTemplates.default` in its `guild.json`. It is now
7
+ * contributed as a plugin default so mandate dispatch works out of the
8
+ * box with zero guild configuration — an operator only needs to declare
9
+ * `spider.variables` for the role and build/test commands.
10
+ *
11
+ * Guilds may still override this template by declaring their own
12
+ * `spider.rigTemplates.default` in guild.json; config entries win over
13
+ * plugin-contributed defaults via the RigTemplateRegistry's precedence
14
+ * rules.
15
+ *
16
+ * Per D7 in the plan-and-ship commission, this template has no fallback
17
+ * defaults for `${vars.role}`, `${vars.buildCommand}`, or
18
+ * `${vars.testCommand}` — a missing variable raises at dispatch time so
19
+ * misconfiguration is surfaced loudly rather than masked.
20
+ */
21
+ export const defaultRigTemplate = {
22
+ engines: [
23
+ {
24
+ id: 'draft',
25
+ designId: 'draft',
26
+ givens: { writ: '${writ}' },
27
+ },
28
+ {
29
+ id: 'implement',
30
+ designId: 'implement',
31
+ upstream: ['draft'],
32
+ givens: { writ: '${writ}', role: '${vars.role}' },
33
+ },
34
+ {
35
+ id: 'review',
36
+ designId: 'review',
37
+ upstream: ['implement'],
38
+ givens: {
39
+ writ: '${writ}',
40
+ role: 'reviewer',
41
+ buildCommand: '${vars.buildCommand}',
42
+ testCommand: '${vars.testCommand}',
43
+ },
44
+ },
45
+ {
46
+ id: 'revise',
47
+ designId: 'revise',
48
+ upstream: ['review'],
49
+ givens: { writ: '${writ}', role: '${vars.role}' },
50
+ },
51
+ {
52
+ id: 'seal',
53
+ designId: 'seal',
54
+ upstream: ['revise'],
55
+ givens: {},
56
+ },
57
+ ],
58
+ resolutionEngine: 'seal',
59
+ };
60
+ //# sourceMappingURL=default-template.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"default-template.js","sourceRoot":"","sources":["../src/default-template.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAIH,MAAM,CAAC,MAAM,kBAAkB,GAAgB;IAC7C,OAAO,EAAE;QACP;YACE,EAAE,EAAE,OAAO;YACX,QAAQ,EAAE,OAAO;YACjB,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;SAC5B;QACD;YACE,EAAE,EAAE,WAAW;YACf,QAAQ,EAAE,WAAW;YACrB,QAAQ,EAAE,CAAC,OAAO,CAAC;YACnB,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,cAAc,EAAE;SAClD;QACD;YACE,EAAE,EAAE,QAAQ;YACZ,QAAQ,EAAE,QAAQ;YAClB,QAAQ,EAAE,CAAC,WAAW,CAAC;YACvB,MAAM,EAAE;gBACN,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,UAAU;gBAChB,YAAY,EAAE,sBAAsB;gBACpC,WAAW,EAAE,qBAAqB;aACnC;SACF;QACD;YACE,EAAE,EAAE,QAAQ;YACZ,QAAQ,EAAE,QAAQ;YAClB,QAAQ,EAAE,CAAC,QAAQ,CAAC;YACpB,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,cAAc,EAAE;SAClD;QACD;YACE,EAAE,EAAE,MAAM;YACV,QAAQ,EAAE,MAAM;YAChB,QAAQ,EAAE,CAAC,QAAQ,CAAC;YACpB,MAAM,EAAE,EAAE;SACX;KACF;IACD,gBAAgB,EAAE,MAAM;CACzB,CAAC"}
@@ -1,11 +1,21 @@
1
1
  /**
2
2
  * Implement engine — quick (Animator-backed).
3
3
  *
4
- * Summons an anima to do the commissioned work. Wraps the writ body with
5
- * task-manifest-aware execution instructions, then calls animator.summon()
6
- * with the draft worktree as the working directory. Returns
7
- * `{ status: 'launched', sessionId }` so the Spider's collect step can poll
8
- * for completion on subsequent walks.
4
+ * Summons an anima to do the commissioned work. Wraps the writ body (or
5
+ * the optional `prompt` override given) with task-manifest-aware execution
6
+ * instructions, then calls animator.summon() with the draft worktree as
7
+ * the working directory. Returns `{ status: 'launched', sessionId }` so the
8
+ * Spider's collect step can poll for completion on subsequent walks.
9
+ *
10
+ * Givens:
11
+ * - writ (required) — the WritDoc for this rig.
12
+ * - role (required) — the anima role to summon.
13
+ * - prompt (optional) — a prompt string that replaces `writ.body` as
14
+ * the body of the execution prompt. The
15
+ * EXECUTION_EPILOGUE is still appended. Used by
16
+ * the combined plan-and-ship rig to hand the
17
+ * planning spec to the implementing anima;
18
+ * absent on the vanilla mandate path.
9
19
  */
10
20
  import type { EngineDesign } from '@shardworks/fabricator-apparatus';
11
21
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"implement.d.ts","sourceRoot":"","sources":["../../src/engines/implement.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;AAKrE;;;;;GAKG;AACH,QAAA,MAAM,kBAAkB,usBASuB,CAAC;AAEhD,QAAA,MAAM,eAAe,EAAE,YAoBtB,CAAC;AAEF,OAAO,EAAE,kBAAkB,EAAE,CAAC;AAC9B,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"implement.d.ts","sourceRoot":"","sources":["../../src/engines/implement.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;AAKrE;;;;;GAKG;AACH,QAAA,MAAM,kBAAkB,usBASuB,CAAC;AAEhD,QAAA,MAAM,eAAe,EAAE,YA4BtB,CAAC;AAEF,OAAO,EAAE,kBAAkB,EAAE,CAAC;AAC9B,eAAe,eAAe,CAAC"}
@@ -1,11 +1,21 @@
1
1
  /**
2
2
  * Implement engine — quick (Animator-backed).
3
3
  *
4
- * Summons an anima to do the commissioned work. Wraps the writ body with
5
- * task-manifest-aware execution instructions, then calls animator.summon()
6
- * with the draft worktree as the working directory. Returns
7
- * `{ status: 'launched', sessionId }` so the Spider's collect step can poll
8
- * for completion on subsequent walks.
4
+ * Summons an anima to do the commissioned work. Wraps the writ body (or
5
+ * the optional `prompt` override given) with task-manifest-aware execution
6
+ * instructions, then calls animator.summon() with the draft worktree as
7
+ * the working directory. Returns `{ status: 'launched', sessionId }` so the
8
+ * Spider's collect step can poll for completion on subsequent walks.
9
+ *
10
+ * Givens:
11
+ * - writ (required) — the WritDoc for this rig.
12
+ * - role (required) — the anima role to summon.
13
+ * - prompt (optional) — a prompt string that replaces `writ.body` as
14
+ * the body of the execution prompt. The
15
+ * EXECUTION_EPILOGUE is still appended. Used by
16
+ * the combined plan-and-ship rig to hand the
17
+ * planning spec to the implementing anima;
18
+ * absent on the vanilla mandate path.
9
19
  */
10
20
  import { guild } from '@shardworks/nexus-core';
11
21
  /**
@@ -30,7 +40,15 @@ const implementEngine = {
30
40
  const animator = guild().apparatus('animator');
31
41
  const writ = givens.writ;
32
42
  const draft = context.upstream['draft'];
33
- const prompt = `${writ.body}\n${EXECUTION_EPILOGUE}`;
43
+ // The `prompt` given, when supplied by the rig template, overrides
44
+ // `writ.body` as the execution body. The EXECUTION_EPILOGUE is appended
45
+ // either way so task-manifest-aware execution instructions travel with
46
+ // both paths. When `prompt` is omitted the engine's behaviour is
47
+ // byte-identical to the pre-refactor version.
48
+ const body = typeof givens.prompt === 'string' && givens.prompt.length > 0
49
+ ? givens.prompt
50
+ : writ.body;
51
+ const prompt = `${body}\n${EXECUTION_EPILOGUE}`;
34
52
  const handle = animator.summon({
35
53
  role: givens.role,
36
54
  prompt,
@@ -1 +1 @@
1
- {"version":3,"file":"implement.js","sourceRoot":"","sources":["../../src/engines/implement.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AAM/C;;;;;GAKG;AACH,MAAM,kBAAkB,GAAG;;;;;;;;;+CASoB,CAAC;AAEhD,MAAM,eAAe,GAAiB;IACpC,EAAE,EAAE,WAAW;IAEf,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO;QACvB,MAAM,QAAQ,GAAG,KAAK,EAAE,CAAC,SAAS,CAAc,UAAU,CAAC,CAAC;QAC5D,MAAM,IAAI,GAAG,MAAM,CAAC,IAAe,CAAC;QACpC,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgB,CAAC;QAEvD,MAAM,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,KAAK,kBAAkB,EAAE,CAAC;QAErD,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC;YAC7B,IAAI,EAAE,MAAM,CAAC,IAAc;YAC3B,MAAM;YACN,GAAG,EAAE,KAAK,CAAC,IAAI;YACf,WAAW,EAAE,EAAE,gBAAgB,EAAE,GAAG,IAAI,CAAC,EAAE,cAAc,EAAE;YAC3D,QAAQ,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE;SAC1D,CAAC,CAAC;QAEH,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC;IAC7D,CAAC;CACF,CAAC;AAEF,OAAO,EAAE,kBAAkB,EAAE,CAAC;AAC9B,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"implement.js","sourceRoot":"","sources":["../../src/engines/implement.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AAM/C;;;;;GAKG;AACH,MAAM,kBAAkB,GAAG;;;;;;;;;+CASoB,CAAC;AAEhD,MAAM,eAAe,GAAiB;IACpC,EAAE,EAAE,WAAW;IAEf,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO;QACvB,MAAM,QAAQ,GAAG,KAAK,EAAE,CAAC,SAAS,CAAc,UAAU,CAAC,CAAC;QAC5D,MAAM,IAAI,GAAG,MAAM,CAAC,IAAe,CAAC;QACpC,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgB,CAAC;QAEvD,mEAAmE;QACnE,wEAAwE;QACxE,uEAAuE;QACvE,iEAAiE;QACjE,8CAA8C;QAC9C,MAAM,IAAI,GAAG,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC;YACxE,CAAC,CAAC,MAAM,CAAC,MAAM;YACf,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QACd,MAAM,MAAM,GAAG,GAAG,IAAI,KAAK,kBAAkB,EAAE,CAAC;QAEhD,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC;YAC7B,IAAI,EAAE,MAAM,CAAC,IAAc;YAC3B,MAAM;YACN,GAAG,EAAE,KAAK,CAAC,IAAI;YACf,WAAW,EAAE,EAAE,gBAAgB,EAAE,GAAG,IAAI,CAAC,EAAE,cAAc,EAAE;YAC3D,QAAQ,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE;SAC1D,CAAC,CAAC;QAEH,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC;IAC7D,CAAC;CACF,CAAC;AAEF,OAAO,EAAE,kBAAkB,EAAE,CAAC;AAC9B,eAAe,eAAe,CAAC"}
@@ -4,11 +4,17 @@
4
4
  * Contributes:
5
5
  * - GET /api/spider/config — aggregated snapshot of Spider config
6
6
  * - GET /api/spider/session-transcript — session transcript and status
7
- * - GET /api/spider/session-stream — SSE stream of real-time session chunks
8
7
  *
9
8
  * Does NOT import from @shardworks/oculus-apparatus to avoid a circular
10
9
  * package dependency. The route shape is compatible with RouteContribution
11
10
  * from the Oculus types.
11
+ *
12
+ * The former /api/spider/session-stream (SSE) route was removed when the
13
+ * Spider UI switched to uniform 2 s polling of /api/spider/session-transcript.
14
+ * The SSE path only worked for in-process (attached) sessions and silently
15
+ * dropped data for detached (cross-process) sessions because the Animator's
16
+ * subscribeToSession cannot bridge processes. Polling the Stacks-backed
17
+ * transcript works uniformly for both attached and detached sessions.
12
18
  */
13
19
  import type { Context } from 'hono';
14
20
  export declare const spiderRoutes: ({
@@ -48,6 +54,15 @@ export declare const spiderRoutes: ({
48
54
  } | {
49
55
  method: string;
50
56
  path: string;
51
- handler: (c: Context) => Promise<Response>;
57
+ handler: (c: Context) => Promise<(Response & import("hono").TypedResponse<{
58
+ error: string;
59
+ }, 400, "json">) | (Response & import("hono").TypedResponse<{
60
+ error: string;
61
+ }, 404, "json">) | (Response & import("hono").TypedResponse<{
62
+ messages: {
63
+ [x: string]: import("hono/utils/types").JSONValue;
64
+ }[];
65
+ sessionStatus: "pending" | "running" | "completed" | "failed" | "cancelled" | "timeout";
66
+ }, import("hono/utils/http-status").ContentfulStatusCode, "json">)>;
52
67
  })[];
53
68
  //# sourceMappingURL=oculus-routes.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"oculus-routes.d.ts","sourceRoot":"","sources":["../src/oculus-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAepC,eAAO,MAAM,YAAY;;;iBAIR,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAiDD,OAAO;IAkF7B,CAAC"}
1
+ {"version":3,"file":"oculus-routes.d.ts","sourceRoot":"","sources":["../src/oculus-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAcpC,eAAO,MAAM,YAAY;;;iBAIR,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAgBD,OAAO;;;;;;;;;;IA8B7B,CAAC"}
@@ -4,13 +4,18 @@
4
4
  * Contributes:
5
5
  * - GET /api/spider/config — aggregated snapshot of Spider config
6
6
  * - GET /api/spider/session-transcript — session transcript and status
7
- * - GET /api/spider/session-stream — SSE stream of real-time session chunks
8
7
  *
9
8
  * Does NOT import from @shardworks/oculus-apparatus to avoid a circular
10
9
  * package dependency. The route shape is compatible with RouteContribution
11
10
  * from the Oculus types.
11
+ *
12
+ * The former /api/spider/session-stream (SSE) route was removed when the
13
+ * Spider UI switched to uniform 2 s polling of /api/spider/session-transcript.
14
+ * The SSE path only worked for in-process (attached) sessions and silently
15
+ * dropped data for detached (cross-process) sessions because the Animator's
16
+ * subscribeToSession cannot bridge processes. Polling the Stacks-backed
17
+ * transcript works uniformly for both attached and detached sessions.
12
18
  */
13
- import { streamSSE } from 'hono/streaming';
14
19
  import { guild } from '@shardworks/nexus-core';
15
20
  export const spiderRoutes = [
16
21
  {
@@ -45,8 +50,8 @@ export const spiderRoutes = [
45
50
  }
46
51
  // Read transcript regardless of status. Detached sessions (babysitter)
47
52
  // write transcript chunks to SQLite incrementally while the session is
48
- // still 'running' or 'pending'; the client polls this endpoint to
49
- // refresh the engine view's session log in flight.
53
+ // still 'running' or 'pending'; the client polls this endpoint every
54
+ // 2 s to refresh the engine view's session log in flight.
50
55
  const transcriptsBook = stacks.readBook('animator', 'transcripts');
51
56
  const transcript = await transcriptsBook.get(sessionId);
52
57
  return c.json({
@@ -55,80 +60,5 @@ export const spiderRoutes = [
55
60
  });
56
61
  },
57
62
  },
58
- {
59
- method: 'GET',
60
- path: '/api/spider/session-stream',
61
- handler: async (c) => {
62
- const sessionId = c.req.query('sessionId');
63
- if (!sessionId) {
64
- return c.json({ error: 'sessionId is required' }, 400);
65
- }
66
- const g = guild();
67
- const stacks = g.apparatus('stacks');
68
- const sessionsBook = stacks.readBook('animator', 'sessions');
69
- const session = await sessionsBook.get(sessionId);
70
- if (!session) {
71
- return c.json({ error: 'Session not found' }, 404);
72
- }
73
- // For already-completed sessions, stream the full transcript and close.
74
- if (session.status !== 'running') {
75
- const transcriptsBook = stacks.readBook('animator', 'transcripts');
76
- const transcript = await transcriptsBook.get(sessionId);
77
- return streamSSE(c, async (stream) => {
78
- await stream.writeSSE({
79
- event: 'transcript',
80
- data: JSON.stringify({ messages: transcript?.messages ?? [] }),
81
- });
82
- await stream.writeSSE({
83
- event: 'done',
84
- data: JSON.stringify({ status: session.status }),
85
- });
86
- });
87
- }
88
- // For running sessions, subscribe to the Animator's in-process broadcaster.
89
- const animator = g.apparatus('animator');
90
- const chunkStream = animator.subscribeToSession(sessionId);
91
- if (!chunkStream) {
92
- // The session is marked running in Stacks but has no in-memory broadcaster
93
- // (e.g. a server restart happened). Return an empty stream so the UI can
94
- // show a meaningful "no data" state and fall back gracefully.
95
- return streamSSE(c, async (stream) => {
96
- await stream.writeSSE({
97
- event: 'done',
98
- data: JSON.stringify({ status: 'running', noStream: true }),
99
- });
100
- });
101
- }
102
- return streamSSE(c, async (stream) => {
103
- try {
104
- for await (const chunk of chunkStream) {
105
- await stream.writeSSE({
106
- event: 'chunk',
107
- data: JSON.stringify(chunk),
108
- });
109
- }
110
- // All chunks consumed — session has ended. Fetch and emit final transcript.
111
- const transcriptsBook = stacks.readBook('animator', 'transcripts');
112
- const transcript = await transcriptsBook.get(sessionId);
113
- await stream.writeSSE({
114
- event: 'transcript',
115
- data: JSON.stringify({ messages: transcript?.messages ?? [] }),
116
- });
117
- const finalSession = await sessionsBook.get(sessionId);
118
- await stream.writeSSE({
119
- event: 'done',
120
- data: JSON.stringify({ status: finalSession?.status ?? 'completed' }),
121
- });
122
- }
123
- catch (err) {
124
- const message = err instanceof Error ? err.message : String(err);
125
- await stream.writeSSE({
126
- event: 'error',
127
- data: JSON.stringify({ error: message }),
128
- });
129
- }
130
- });
131
- },
132
- },
133
63
  ];
134
64
  //# sourceMappingURL=oculus-routes.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"oculus-routes.js","sourceRoot":"","sources":["../src/oculus-routes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"oculus-routes.js","sourceRoot":"","sources":["../src/oculus-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAGH,OAAO,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AAa/C,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B;QACE,MAAM,EAAE,KAAK;QACb,IAAI,EAAE,oBAAoB;QAC1B,OAAO,EAAE,CAAC,CAAU,EAAE,EAAE;YACtB,MAAM,CAAC,GAAG,KAAK,EAAE,CAAC;YAClB,MAAM,UAAU,GAAG,CAAC,CAAC,SAAS,CAAgB,YAAY,CAAC,CAAC;YAC5D,MAAM,MAAM,GAAG,CAAC,CAAC,SAAS,CAAY,QAAQ,CAAC,CAAC;YAEhD,OAAO,CAAC,CAAC,IAAI,CAAC;gBACZ,SAAS,EAAE,MAAM,CAAC,aAAa,EAAE;gBACjC,gBAAgB,EAAE,MAAM,CAAC,oBAAoB,EAAE;gBAC/C,aAAa,EAAE,UAAU,CAAC,iBAAiB,EAAE;gBAC7C,UAAU,EAAE,MAAM,CAAC,cAAc,EAAE;aACpC,CAAC,CAAC;QACL,CAAC;KACF;IACD;QACE,MAAM,EAAE,KAAK;QACb,IAAI,EAAE,gCAAgC;QACtC,OAAO,EAAE,KAAK,EAAE,CAAU,EAAE,EAAE;YAC5B,MAAM,SAAS,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;YAE3C,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,uBAAuB,EAAE,EAAE,GAAG,CAAC,CAAC;YACzD,CAAC;YAED,MAAM,CAAC,GAAG,KAAK,EAAE,CAAC;YAClB,MAAM,MAAM,GAAG,CAAC,CAAC,SAAS,CAAY,QAAQ,CAAC,CAAC;YAEhD,MAAM,YAAY,GAAG,MAAM,CAAC,QAAQ,CAAa,UAAU,EAAE,UAAU,CAAC,CAAC;YACzE,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YAElD,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,EAAE,GAAG,CAAC,CAAC;YACrD,CAAC;YAED,uEAAuE;YACvE,uEAAuE;YACvE,qEAAqE;YACrE,0DAA0D;YAC1D,MAAM,eAAe,GAAG,MAAM,CAAC,QAAQ,CAAkB,UAAU,EAAE,aAAa,CAAC,CAAC;YACpF,MAAM,UAAU,GAAG,MAAM,eAAe,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YAExD,OAAO,CAAC,CAAC,IAAI,CAAC;gBACZ,QAAQ,EAAE,UAAU,EAAE,QAAQ,IAAI,EAAE;gBACpC,aAAa,EAAE,OAAO,CAAC,MAAM;aAC9B,CAAC,CAAC;QACL,CAAC;KACF;CACF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"spider.d.ts","sourceRoot":"","sources":["../src/spider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAwD,MAAM,wBAAwB,CAAC;AAQ3G,OAAO,KAAK,EACV,MAAM,EAUN,WAAW,EAOZ,MAAM,YAAY,CAAC;AAmDpB,uEAAuE;AACvE,MAAM,WAAW,SAAS;IACxB,6EAA6E;IAC7E,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAC3C,oFAAoF;IACpF,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9C;AAyDD;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CAQ1D;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAM5D;AA2/BD,wBAAgB,YAAY,IAAI,MAAM,CAy0CrC"}
1
+ {"version":3,"file":"spider.d.ts","sourceRoot":"","sources":["../src/spider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAwD,MAAM,wBAAwB,CAAC;AAQ3G,OAAO,KAAK,EACV,MAAM,EAUN,WAAW,EAOZ,MAAM,YAAY,CAAC;AAqDpB,uEAAuE;AACvE,MAAM,WAAW,SAAS;IACxB,6EAA6E;IAC7E,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAC3C,oFAAoF;IACpF,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9C;AAyDD;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CAQ1D;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAM5D;AA0hCD,wBAAgB,YAAY,IAAI,MAAM,CAm1CrC"}
package/dist/spider.js CHANGED
@@ -30,6 +30,7 @@ import { animaSessionEngine, draftEngine, implementEngine, implementLoopEngine,
30
30
  import { writPhaseBlockType, scheduledTimeBlockType, bookUpdatedBlockType, patronInputBlockType, } from "./block-types/index.js";
31
31
  import { crawlOneTool, crawlContinualTool, rigShowTool, rigListTool, rigForWritTool, rigResumeTool, inputRequestListTool, inputRequestShowTool, inputRequestAnswerTool, inputRequestCompleteTool, inputRequestRejectTool, inputRequestExportTool, inputRequestImportTool, engineDesignsTool, blockTypesTool, rigCancelTool, } from "./tools/index.js";
32
32
  import { spiderRoutes } from "./oculus-routes.js";
33
+ import { defaultRigTemplate } from "./default-template.js";
33
34
  import { interpolateTemplate, extractExpressions, resolveDotPath, SKIP, } from "./template.js";
34
35
  // ── Helpers ────────────────────────────────────────────────────────────
35
36
  /**
@@ -633,12 +634,33 @@ class RigTemplateRegistry {
633
634
  templates = new Map();
634
635
  /** Config writ-type-to-template-name mappings */
635
636
  configMappings = new Map();
636
- /** Kit-contributed mappings (first-registered wins) */
637
+ /**
638
+ * Kit-contributed mappings (first-registered wins). Each entry records
639
+ * the contributing pluginId so the registry can fall back from an
640
+ * unqualified templateName to the kit's own qualified `${pluginId}.${name}`
641
+ * when no config-level template has claimed the unqualified slot.
642
+ */
637
643
  kitMappings = new Map();
638
644
  /** Config-declared template names (for override checking) */
639
645
  configTemplateNames = new Set();
640
646
  /** designId → pluginId that contributed it */
641
647
  designSourceMap = new Map();
648
+ /**
649
+ * Resolve the actual template name stored in `templates` for a kit
650
+ * mapping entry. Prefer the literal value (so config-level overrides
651
+ * with the same name win); otherwise fall back to the kit's own
652
+ * qualified name. Returns undefined when neither form resolves.
653
+ */
654
+ resolveKitMappedName(entry) {
655
+ if (this.templates.has(entry.templateName))
656
+ return entry.templateName;
657
+ if (!entry.templateName.includes('.')) {
658
+ const qualified = `${entry.pluginId}.${entry.templateName}`;
659
+ if (this.templates.has(qualified))
660
+ return qualified;
661
+ }
662
+ return undefined;
663
+ }
642
664
  /**
643
665
  * Build the designId → pluginId map from all engine KitEntries.
644
666
  * Called once at startup before any kit registration.
@@ -895,7 +917,7 @@ class RigTemplateRegistry {
895
917
  console.warn(`[spider] Kit "${pluginId}" rigTemplateMappings.${writType}: mapping for "${writType}" already registered by another kit — skipped`);
896
918
  continue;
897
919
  }
898
- this.kitMappings.set(writType, templateName);
920
+ this.kitMappings.set(writType, { templateName, pluginId });
899
921
  }
900
922
  }
901
923
  /**
@@ -909,10 +931,12 @@ class RigTemplateRegistry {
909
931
  throw new Error(`[spider] rigTemplateMappings.${writType}: references unknown template "${templateName}"`);
910
932
  }
911
933
  }
912
- // Kit mappings — warn and remove on dangling
913
- for (const [writType, templateName] of [...this.kitMappings]) {
914
- if (!this.templates.has(templateName)) {
915
- console.warn(`[spider] Kit mapping "${writType}" → "${templateName}": template not found — removed`);
934
+ // Kit mappings — warn and remove on dangling. An unqualified templateName
935
+ // is considered resolved if either the bare name or the kit's own
936
+ // `${pluginId}.${templateName}` exists in the template registry.
937
+ for (const [writType, entry] of [...this.kitMappings]) {
938
+ if (this.resolveKitMappedName(entry) === undefined) {
939
+ console.warn(`[spider] Kit mapping "${writType}" → "${entry.templateName}": template not found — removed`);
916
940
  this.kitMappings.delete(writType);
917
941
  }
918
942
  }
@@ -922,9 +946,9 @@ class RigTemplateRegistry {
922
946
  * Since deferred validation already ran, validate immediately.
923
947
  */
924
948
  validateIncrementalMappings() {
925
- for (const [writType, templateName] of [...this.kitMappings]) {
926
- if (!this.templates.has(templateName)) {
927
- console.warn(`[spider] Kit mapping "${writType}" → "${templateName}": template not found — removed`);
949
+ for (const [writType, entry] of [...this.kitMappings]) {
950
+ if (this.resolveKitMappedName(entry) === undefined) {
951
+ console.warn(`[spider] Kit mapping "${writType}" → "${entry.templateName}": template not found — removed`);
928
952
  this.kitMappings.delete(writType);
929
953
  }
930
954
  }
@@ -949,12 +973,18 @@ class RigTemplateRegistry {
949
973
  return t;
950
974
  // Config points to nonexistent template — validated at startup, should not happen at runtime
951
975
  }
952
- // Step 2: Kit mapping for this specific writ type
976
+ // Step 2: Kit mapping for this specific writ type. Unqualified
977
+ // templateName values resolve against the bare name first (so a
978
+ // config-level template of the same name wins), then fall back to the
979
+ // kit's own `${pluginId}.${templateName}` qualified form.
953
980
  const kitMapped = this.kitMappings.get(writType);
954
981
  if (kitMapped !== undefined) {
955
- const t = this.templates.get(kitMapped);
956
- if (t)
957
- return t;
982
+ const resolved = this.resolveKitMappedName(kitMapped);
983
+ if (resolved !== undefined) {
984
+ const t = this.templates.get(resolved);
985
+ if (t)
986
+ return t;
987
+ }
958
988
  }
959
989
  // No explicit mapping — writ type is inert by configuration, skip dispatch.
960
990
  return undefined;
@@ -984,8 +1014,11 @@ class RigTemplateRegistry {
984
1014
  */
985
1015
  listTemplateMappings() {
986
1016
  const result = {};
987
- for (const [writType, templateName] of this.kitMappings) {
988
- result[writType] = templateName;
1017
+ for (const [writType, entry] of this.kitMappings) {
1018
+ // Report the resolved template name so callers can look it up
1019
+ // directly in listTemplates() without re-implementing the
1020
+ // bare-name-to-qualified-name fallback.
1021
+ result[writType] = this.resolveKitMappedName(entry) ?? entry.templateName;
989
1022
  }
990
1023
  for (const [writType, templateName] of this.configMappings) {
991
1024
  result[writType] = templateName;
@@ -1981,6 +2014,16 @@ export function createSpider() {
1981
2014
  'book-updated': bookUpdatedBlockType,
1982
2015
  'patron-input': patronInputBlockType,
1983
2016
  },
2017
+ rigTemplates: {
2018
+ default: defaultRigTemplate,
2019
+ },
2020
+ rigTemplateMappings: {
2021
+ // Unqualified reference — resolved via the registry's
2022
+ // config-overrides-kit fallback. If the guild declares its own
2023
+ // config-level `default` template, that value wins; otherwise the
2024
+ // registry falls back to Spider's own kit-qualified `spider.default`.
2025
+ mandate: 'default',
2026
+ },
1984
2027
  pages: [
1985
2028
  { id: 'spider', title: 'Spider', dir: 'src/static' },
1986
2029
  { id: 'feedback', title: 'Feedback', dir: 'src/static/feedback' },