wicked-crew 0.16.11 → 0.16.13
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 +28 -8
- package/dist/api/artifact-outline.d.ts +64 -0
- package/dist/api/artifact-outline.d.ts.map +1 -0
- package/dist/api/artifact-outline.js +254 -0
- package/dist/api/artifact-outline.js.map +1 -0
- package/dist/api/beneath.d.ts +76 -0
- package/dist/api/beneath.d.ts.map +1 -0
- package/dist/api/beneath.js +214 -0
- package/dist/api/beneath.js.map +1 -0
- package/dist/api/capture.d.ts +2 -2
- package/dist/api/chat-citations.d.ts +25 -1
- package/dist/api/chat-citations.d.ts.map +1 -1
- package/dist/api/chat-citations.js +186 -61
- package/dist/api/chat-citations.js.map +1 -1
- package/dist/api/chat-context.d.ts +236 -0
- package/dist/api/chat-context.d.ts.map +1 -0
- package/dist/api/chat-context.js +808 -0
- package/dist/api/chat-context.js.map +1 -0
- package/dist/api/chat-history.d.ts +20 -0
- package/dist/api/chat-history.d.ts.map +1 -1
- package/dist/api/chat-history.js +46 -1
- package/dist/api/chat-history.js.map +1 -1
- package/dist/api/chat-proposals.d.ts +534 -0
- package/dist/api/chat-proposals.d.ts.map +1 -0
- package/dist/api/chat-proposals.js +1562 -0
- package/dist/api/chat-proposals.js.map +1 -0
- package/dist/api/chat-scope.d.ts +41 -0
- package/dist/api/chat-scope.d.ts.map +1 -1
- package/dist/api/chat-scope.js +87 -15
- package/dist/api/chat-scope.js.map +1 -1
- package/dist/api/chat-transcripts.d.ts +27 -2
- package/dist/api/chat-transcripts.d.ts.map +1 -1
- package/dist/api/chat-transcripts.js +105 -4
- package/dist/api/chat-transcripts.js.map +1 -1
- package/dist/api/diagnostics.d.ts +15 -0
- package/dist/api/diagnostics.d.ts.map +1 -1
- package/dist/api/diagnostics.js +56 -0
- package/dist/api/diagnostics.js.map +1 -1
- package/dist/api/elicitation-cache.d.ts +13 -0
- package/dist/api/elicitation-cache.d.ts.map +1 -1
- package/dist/api/elicitation-cache.js +12 -0
- package/dist/api/elicitation-cache.js.map +1 -1
- package/dist/api/eval-sample.d.ts +12 -12
- package/dist/api/frame-guard.d.ts +62 -0
- package/dist/api/frame-guard.d.ts.map +1 -0
- package/dist/api/frame-guard.js +97 -0
- package/dist/api/frame-guard.js.map +1 -0
- package/dist/api/governance-steering.d.ts +4 -4
- package/dist/api/multiscope.d.ts +3 -0
- package/dist/api/multiscope.d.ts.map +1 -1
- package/dist/api/multiscope.js +13 -0
- package/dist/api/multiscope.js.map +1 -1
- package/dist/api/needs.d.ts +6 -0
- package/dist/api/needs.d.ts.map +1 -1
- package/dist/api/needs.js +31 -4
- package/dist/api/needs.js.map +1 -1
- package/dist/api/product.d.ts.map +1 -1
- package/dist/api/product.js +13 -2
- package/dist/api/product.js.map +1 -1
- package/dist/api/project-aggregates.d.ts +6 -6
- package/dist/api/project-aggregates.d.ts.map +1 -1
- package/dist/api/project-aggregates.js +16 -24
- package/dist/api/project-aggregates.js.map +1 -1
- package/dist/api/requirements.d.ts +261 -6
- package/dist/api/requirements.d.ts.map +1 -1
- package/dist/api/requirements.js +344 -64
- package/dist/api/requirements.js.map +1 -1
- package/dist/api/routes.d.ts +156 -4
- package/dist/api/routes.d.ts.map +1 -1
- package/dist/api/routes.js +851 -78
- package/dist/api/routes.js.map +1 -1
- package/dist/api/run-brief.d.ts +78 -0
- package/dist/api/run-brief.d.ts.map +1 -0
- package/dist/api/run-brief.js +318 -0
- package/dist/api/run-brief.js.map +1 -0
- package/dist/api/run-files.d.ts.map +1 -1
- package/dist/api/run-files.js +5 -1
- package/dist/api/run-files.js.map +1 -1
- package/dist/api/run-timing-index.d.ts +27 -0
- package/dist/api/run-timing-index.d.ts.map +1 -1
- package/dist/api/run-timing-index.js +65 -0
- package/dist/api/run-timing-index.js.map +1 -1
- package/dist/api/seat-images.d.ts +102 -0
- package/dist/api/seat-images.d.ts.map +1 -0
- package/dist/api/seat-images.js +333 -0
- package/dist/api/seat-images.js.map +1 -0
- package/dist/api/server.d.ts +3 -0
- package/dist/api/server.d.ts.map +1 -1
- package/dist/api/server.js +265 -2
- package/dist/api/server.js.map +1 -1
- package/dist/api/steering-landing.d.ts +48 -1
- package/dist/api/steering-landing.d.ts.map +1 -1
- package/dist/api/steering-landing.js +116 -42
- package/dist/api/steering-landing.js.map +1 -1
- package/dist/api/system-snapshot.d.ts +51 -2
- package/dist/api/system-snapshot.d.ts.map +1 -1
- package/dist/api/system-snapshot.js +151 -15
- package/dist/api/system-snapshot.js.map +1 -1
- package/dist/api/testing.d.ts +4 -4
- package/dist/api/testing.js +2 -2
- package/dist/api/testing.js.map +1 -1
- package/dist/apps/spec.d.ts +3009 -0
- package/dist/apps/spec.d.ts.map +1 -0
- package/dist/apps/spec.js +870 -0
- package/dist/apps/spec.js.map +1 -0
- package/dist/campaigns/routes.js +1 -1
- package/dist/campaigns/routes.js.map +1 -1
- package/dist/cli/index.js +3 -3
- package/dist/cli/index.js.map +1 -1
- package/dist/core/adapter.d.ts +12 -0
- package/dist/core/adapter.d.ts.map +1 -1
- package/dist/core/adapter.js +36 -1
- package/dist/core/adapter.js.map +1 -1
- package/dist/core/deliver-text.d.ts.map +1 -1
- package/dist/core/deliver-text.js +22 -10
- package/dist/core/deliver-text.js.map +1 -1
- package/dist/core/estate-mcp-client.d.ts +7 -1
- package/dist/core/estate-mcp-client.d.ts.map +1 -1
- package/dist/core/estate-mcp-client.js +10 -2
- package/dist/core/estate-mcp-client.js.map +1 -1
- package/dist/core/exec.d.ts +12 -0
- package/dist/core/exec.d.ts.map +1 -1
- package/dist/core/exec.js +23 -0
- package/dist/core/exec.js.map +1 -1
- package/dist/core/reassign-refusal.d.ts.map +1 -1
- package/dist/core/reassign-refusal.js +23 -3
- package/dist/core/reassign-refusal.js.map +1 -1
- package/dist/core/repoPaths.d.ts +32 -7
- package/dist/core/repoPaths.d.ts.map +1 -1
- package/dist/core/repoPaths.js +56 -9
- package/dist/core/repoPaths.js.map +1 -1
- package/dist/core/requirements-graph-setting.d.ts +32 -0
- package/dist/core/requirements-graph-setting.d.ts.map +1 -0
- package/dist/core/requirements-graph-setting.js +84 -0
- package/dist/core/requirements-graph-setting.js.map +1 -0
- package/dist/core/run-boot-resume.d.ts +4 -1
- package/dist/core/run-boot-resume.d.ts.map +1 -1
- package/dist/core/run-boot-resume.js +6 -1
- package/dist/core/run-boot-resume.js.map +1 -1
- package/dist/core/run-identity.d.ts.map +1 -1
- package/dist/core/run-identity.js +6 -0
- package/dist/core/run-identity.js.map +1 -1
- package/dist/core/types.d.ts +14 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/decisions/chat-recorder.d.ts +14 -3
- package/dist/decisions/chat-recorder.d.ts.map +1 -1
- package/dist/decisions/chat-recorder.js +54 -9
- package/dist/decisions/chat-recorder.js.map +1 -1
- package/dist/editors/csp.d.ts +24 -4
- package/dist/editors/csp.d.ts.map +1 -1
- package/dist/editors/csp.js +35 -8
- package/dist/editors/csp.js.map +1 -1
- package/dist/editors/registry.d.ts +46 -21
- package/dist/editors/registry.d.ts.map +1 -1
- package/dist/editors/registry.js +13 -2
- package/dist/editors/registry.js.map +1 -1
- package/dist/editors/routes.d.ts +4 -1
- package/dist/editors/routes.d.ts.map +1 -1
- package/dist/editors/routes.js +30 -3
- package/dist/editors/routes.js.map +1 -1
- package/dist/editors/visuals.d.ts +51 -0
- package/dist/editors/visuals.d.ts.map +1 -0
- package/dist/editors/visuals.js +164 -0
- package/dist/editors/visuals.js.map +1 -0
- package/dist/editors/webrtc-guard.d.ts +94 -0
- package/dist/editors/webrtc-guard.d.ts.map +1 -0
- package/dist/editors/webrtc-guard.js +506 -0
- package/dist/editors/webrtc-guard.js.map +1 -0
- package/dist/inspect/reading.d.ts +110 -0
- package/dist/inspect/reading.d.ts.map +1 -0
- package/dist/inspect/reading.js +325 -0
- package/dist/inspect/reading.js.map +1 -0
- package/dist/inspect/routes.d.ts +14 -0
- package/dist/inspect/routes.d.ts.map +1 -0
- package/dist/inspect/routes.js +44 -0
- package/dist/inspect/routes.js.map +1 -0
- package/dist/inspect/service.d.ts +161 -0
- package/dist/inspect/service.d.ts.map +1 -0
- package/dist/inspect/service.js +466 -0
- package/dist/inspect/service.js.map +1 -0
- package/dist/interactive/bridge-pool.d.ts +11 -2
- package/dist/interactive/bridge-pool.d.ts.map +1 -1
- package/dist/interactive/bridge-pool.js +10 -1
- package/dist/interactive/bridge-pool.js.map +1 -1
- package/dist/interactive/doc-binding.d.ts +156 -0
- package/dist/interactive/doc-binding.d.ts.map +1 -0
- package/dist/interactive/doc-binding.js +277 -0
- package/dist/interactive/doc-binding.js.map +1 -0
- package/dist/interactive/doc-delete-routes.d.ts +3 -0
- package/dist/interactive/doc-delete-routes.d.ts.map +1 -1
- package/dist/interactive/doc-delete-routes.js +4 -0
- package/dist/interactive/doc-delete-routes.js.map +1 -1
- package/dist/interactive/draft-events.d.ts +89 -3
- package/dist/interactive/draft-events.d.ts.map +1 -1
- package/dist/interactive/draft-events.js +441 -30
- package/dist/interactive/draft-events.js.map +1 -1
- package/dist/interactive/draft-skill.d.ts +7 -0
- package/dist/interactive/draft-skill.d.ts.map +1 -1
- package/dist/interactive/draft-skill.js +10 -3
- package/dist/interactive/draft-skill.js.map +1 -1
- package/dist/interactive/edit-events.d.ts +2 -0
- package/dist/interactive/edit-events.d.ts.map +1 -1
- package/dist/interactive/edit-events.js +11 -0
- package/dist/interactive/edit-events.js.map +1 -1
- package/dist/interactive/proposal-create.d.ts +143 -0
- package/dist/interactive/proposal-create.d.ts.map +1 -0
- package/dist/interactive/proposal-create.js +318 -0
- package/dist/interactive/proposal-create.js.map +1 -0
- package/dist/interactive/proxy-routes.d.ts +60 -3
- package/dist/interactive/proxy-routes.d.ts.map +1 -1
- package/dist/interactive/proxy-routes.js +217 -3
- package/dist/interactive/proxy-routes.js.map +1 -1
- package/dist/interactive/source-packet.d.ts +126 -0
- package/dist/interactive/source-packet.d.ts.map +1 -0
- package/dist/interactive/source-packet.js +482 -0
- package/dist/interactive/source-packet.js.map +1 -0
- package/dist/learnings/estate.d.ts +16 -0
- package/dist/learnings/estate.d.ts.map +1 -0
- package/dist/learnings/estate.js +68 -0
- package/dist/learnings/estate.js.map +1 -0
- package/dist/learnings/extract.d.ts +56 -0
- package/dist/learnings/extract.d.ts.map +1 -0
- package/dist/learnings/extract.js +252 -0
- package/dist/learnings/extract.js.map +1 -0
- package/dist/learnings/recall.d.ts +43 -0
- package/dist/learnings/recall.d.ts.map +1 -0
- package/dist/learnings/recall.js +104 -0
- package/dist/learnings/recall.js.map +1 -0
- package/dist/learnings/service.d.ts +183 -0
- package/dist/learnings/service.d.ts.map +1 -0
- package/dist/learnings/service.js +571 -0
- package/dist/learnings/service.js.map +1 -0
- package/dist/mcp/ask-server.d.ts.map +1 -1
- package/dist/mcp/ask-server.js +37 -4
- package/dist/mcp/ask-server.js.map +1 -1
- package/dist/mcp/broker.d.ts +12 -1
- package/dist/mcp/broker.d.ts.map +1 -1
- package/dist/mcp/broker.js +24 -5
- package/dist/mcp/broker.js.map +1 -1
- package/dist/mcp/invoke.d.ts +26 -2
- package/dist/mcp/invoke.d.ts.map +1 -1
- package/dist/mcp/invoke.js +51 -5
- package/dist/mcp/invoke.js.map +1 -1
- package/dist/persona/routes.d.ts +92 -0
- package/dist/persona/routes.d.ts.map +1 -0
- package/dist/persona/routes.js +69 -0
- package/dist/persona/routes.js.map +1 -0
- package/dist/persona/store.d.ts +104 -0
- package/dist/persona/store.d.ts.map +1 -0
- package/dist/persona/store.js +176 -0
- package/dist/persona/store.js.map +1 -0
- package/dist/persona/voice.d.ts +4 -0
- package/dist/persona/voice.d.ts.map +1 -0
- package/dist/persona/voice.js +58 -0
- package/dist/persona/voice.js.map +1 -0
- package/dist/projects/routes.d.ts +2 -2
- package/dist/setup/known.d.ts +56 -0
- package/dist/setup/known.d.ts.map +1 -0
- package/dist/setup/known.js +159 -0
- package/dist/setup/known.js.map +1 -0
- package/dist/setup/routes.d.ts +13 -0
- package/dist/setup/routes.d.ts.map +1 -0
- package/dist/setup/routes.js +20 -0
- package/dist/setup/routes.js.map +1 -0
- package/dist/standing-orders/history.d.ts +2 -0
- package/dist/standing-orders/history.d.ts.map +1 -1
- package/dist/standing-orders/history.js +1 -0
- package/dist/standing-orders/history.js.map +1 -1
- package/dist/studio/assets/WickedSans-Regular-fb698rcD.woff2 +0 -0
- package/dist/studio/assets/WickedSans-SemiBold-CD53n1AC.woff2 +0 -0
- package/dist/studio/assets/WickedScript-Regular-CY5juO6I.woff2 +0 -0
- package/dist/studio/assets/WickedSerif-Regular-mdPEjaVZ.woff2 +0 -0
- package/dist/studio/assets/index-BUZ_-Syk.css +32 -0
- package/dist/studio/assets/index-u4O_7N-b.js +986 -0
- package/dist/studio/editors/wicked-deck/editor.json +6 -1
- package/dist/studio/editors/wicked-deck/icon.svg +1 -0
- package/dist/studio/editors/wicked-deck/index.html +1 -1
- package/dist/studio/editors/wicked-doc/editor.json +6 -1
- package/dist/studio/editors/wicked-doc/icon.svg +1 -0
- package/dist/studio/editors/wicked-doc/index.html +1 -1
- package/dist/studio/editors/wicked-insights/editor.json +6 -1
- package/dist/studio/editors/wicked-insights/icon.svg +1 -0
- package/dist/studio/editors/wicked-insights/index.html +1 -1
- package/dist/studio/editors/wicked-page/editor.json +6 -1
- package/dist/studio/editors/wicked-page/icon.svg +1 -0
- package/dist/studio/editors/wicked-page/index.html +1 -1
- package/dist/studio/editors/wicked-video/editor.json +6 -1
- package/dist/studio/editors/wicked-video/icon.svg +1 -0
- package/dist/studio/editors/wicked-video/index.html +1 -1
- package/dist/studio/index.html +2 -2
- package/dist/studio/testid-inventory.json +5155 -2707
- package/dist/voice/dashboard.d.ts +376 -0
- package/dist/voice/dashboard.d.ts.map +1 -0
- package/dist/voice/dashboard.js +92 -0
- package/dist/voice/dashboard.js.map +1 -0
- package/dist/voice/inject-input.d.ts +51 -0
- package/dist/voice/inject-input.d.ts.map +1 -0
- package/dist/voice/inject-input.js +126 -0
- package/dist/voice/inject-input.js.map +1 -0
- package/dist/voice/routes.d.ts +41 -0
- package/dist/voice/routes.d.ts.map +1 -0
- package/dist/voice/routes.js +116 -0
- package/dist/voice/routes.js.map +1 -0
- package/dist/voice/service.d.ts +177 -0
- package/dist/voice/service.d.ts.map +1 -0
- package/dist/voice/service.js +400 -0
- package/dist/voice/service.js.map +1 -0
- package/dist/workflow-catalog/build.d.ts +35 -0
- package/dist/workflow-catalog/build.d.ts.map +1 -0
- package/dist/workflow-catalog/build.js +229 -0
- package/dist/workflow-catalog/build.js.map +1 -0
- package/dist/workflow-catalog/catalog-data.d.ts +36 -0
- package/dist/workflow-catalog/catalog-data.d.ts.map +1 -0
- package/dist/workflow-catalog/catalog-data.js +430 -0
- package/dist/workflow-catalog/catalog-data.js.map +1 -0
- package/dist/working-doc/event-lines.d.ts +76 -0
- package/dist/working-doc/event-lines.d.ts.map +1 -0
- package/dist/working-doc/event-lines.js +247 -0
- package/dist/working-doc/event-lines.js.map +1 -0
- package/dist/working-doc/routes.d.ts +1 -1
- package/dist/working-doc/routes.d.ts.map +1 -1
- package/dist/working-doc/routes.js +2 -1
- package/dist/working-doc/routes.js.map +1 -1
- package/dist/working-doc/sections.d.ts +3 -1
- package/dist/working-doc/sections.d.ts.map +1 -1
- package/dist/working-doc/sections.js +4 -2
- package/dist/working-doc/sections.js.map +1 -1
- package/dist/working-doc/service.d.ts +66 -1
- package/dist/working-doc/service.d.ts.map +1 -1
- package/dist/working-doc/service.js +298 -22
- package/dist/working-doc/service.js.map +1 -1
- package/dist/working-doc/store.d.ts +8 -2
- package/dist/working-doc/store.d.ts.map +1 -1
- package/dist/working-doc/store.js.map +1 -1
- package/endpoint-manifest.json +205 -2
- package/package.json +5 -4
- package/workflows/distill-learnings.json +27 -0
- package/workflows/inspect-unit.json +27 -0
- package/dist/studio/assets/index-B-f_VEL2.css +0 -32
- package/dist/studio/assets/index-DhkxIK-0.js +0 -845
package/dist/api/server.d.ts
CHANGED
|
@@ -13,6 +13,9 @@ import { type VenvProvisioner } from '../skills/venv.js';
|
|
|
13
13
|
*/
|
|
14
14
|
export declare function defaultStudioRoot(): string;
|
|
15
15
|
export interface CreateServerOptions {
|
|
16
|
+
/** DES-CHAT-ARTIFACTS-001 §13 A2: run the chat-artifacts TEST configuration (every operation resolves; Go records a
|
|
17
|
+
* stub dispatch and starts nothing). Absent: `WICKED_CHAT_ARTIFACTS_STUB=1` decides. */
|
|
18
|
+
chatArtifactsStub?: boolean;
|
|
16
19
|
/** Override the studio asset root (tests point this at a temp fixture dir). */
|
|
17
20
|
studioRoot?: string;
|
|
18
21
|
/**
|
package/dist/api/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/api/server.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/api/server.ts"],"names":[],"mappings":"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"}
|
package/dist/api/server.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import Fastify from 'fastify';
|
|
2
2
|
import fastifyWebsocket from '@fastify/websocket';
|
|
3
3
|
import fastifyStatic from '@fastify/static';
|
|
4
|
+
import { randomUUID } from 'node:crypto';
|
|
4
5
|
import { existsSync } from 'node:fs';
|
|
5
6
|
import { join, resolve as resolvePath } from 'node:path';
|
|
6
7
|
import { fileURLToPath } from 'node:url';
|
|
@@ -14,6 +15,7 @@ import { ElicitationCache } from './elicitation-cache.js';
|
|
|
14
15
|
import { AskServer } from '../mcp/ask-server.js';
|
|
15
16
|
import { registerAuthHooks, resolveAuth } from './auth.js';
|
|
16
17
|
import { corsAllowed, refuseRequest } from './origin-guard.js';
|
|
18
|
+
import { guardUpgrades, registerFrameGuard } from './frame-guard.js';
|
|
17
19
|
import { AuditLog } from './audit.js';
|
|
18
20
|
import { defaultEvalStoreRoot, EvalRunStore } from './eval-store.js';
|
|
19
21
|
import { DefaultEvalStore } from '../evals/store.js';
|
|
@@ -21,7 +23,17 @@ import { RetryIndex } from './retry-index.js';
|
|
|
21
23
|
import { GroupIndex } from './group-index.js';
|
|
22
24
|
import { RunTimingIndex, recordRunLaunched } from './run-timing-index.js';
|
|
23
25
|
import { OnboardingCaptureChain } from './onboarding-capture.js';
|
|
26
|
+
import { INSPECT_WORKFLOW, InspectService, defaultInspectionsDir, loadInspectWorkflow } from '../inspect/service.js';
|
|
27
|
+
import { registerInspectRoutes } from '../inspect/routes.js';
|
|
28
|
+
import { DISTILL_WORKFLOW, RunLearningsService, defaultLearningsDir, loadDistillWorkflow, runLearningsMode } from '../learnings/service.js';
|
|
29
|
+
import { memoryContents, proposalRows, submitLearning } from '../learnings/estate.js';
|
|
30
|
+
import { recallLearnings } from '../learnings/recall.js';
|
|
24
31
|
import { registerLearnRoutes } from '../learn/routes.js';
|
|
32
|
+
import { registerPersonaRoutes } from '../persona/routes.js';
|
|
33
|
+
import { PersonaStore } from '../persona/store.js';
|
|
34
|
+
import { registerSetupRoutes } from '../setup/routes.js';
|
|
35
|
+
import { voiceBlock } from '../persona/voice.js';
|
|
36
|
+
import { VoiceInjectInputs } from '../voice/inject-input.js';
|
|
25
37
|
import { registerInsightsRoutes } from '../insights/routes.js';
|
|
26
38
|
import { ReviewService } from '../insights/review-service.js';
|
|
27
39
|
import { InsightsStore } from '../insights/store.js';
|
|
@@ -56,6 +68,7 @@ import { TestSetIndex, registerTestSetForRun } from '../qe/test-sets.js';
|
|
|
56
68
|
import { DocGroundingStore } from '../interactive/doc-grounding.js';
|
|
57
69
|
import { ProjectSettingsStore } from '../projects/settings.js';
|
|
58
70
|
import { crewStateHome } from '../projects/state-home.js';
|
|
71
|
+
import { coreUnitId } from './evidence.js';
|
|
59
72
|
import { homedir } from 'node:os';
|
|
60
73
|
import { discoverMcpServers } from '../mcp/discovery.js';
|
|
61
74
|
import { probeMcpServer } from '../mcp/probe.js';
|
|
@@ -102,6 +115,8 @@ import { registerGateHistoryRoute, runBand, runPreset, runProject } from '../sta
|
|
|
102
115
|
import { WorkingDocService } from '../working-doc/service.js';
|
|
103
116
|
import { WorkingDocStore } from '../working-doc/store.js';
|
|
104
117
|
import { isWorkingDoc as isWorkingDocAt } from '../interactive/chat-events.js';
|
|
118
|
+
import { DocBindingStore } from '../interactive/doc-binding.js';
|
|
119
|
+
import { docVersionsOf, reconcileBoundAttempts, recoveredLaunchDetail } from '../interactive/proposal-create.js';
|
|
105
120
|
import { bridgeBackend } from '../working-doc/bridge-backend.js';
|
|
106
121
|
import { registerWorkingDocRoutes } from '../working-doc/routes.js';
|
|
107
122
|
import { projectDocsRoot as workingDocRoot } from '../interactive/project-root.js';
|
|
@@ -111,6 +126,7 @@ import { busRows, openPlanGateRisk } from '../team/routes.js';
|
|
|
111
126
|
import { isSteeringAuthorRun } from './steering-landing.js';
|
|
112
127
|
import { applyWorkerConfigRoot } from './seat-signin.js';
|
|
113
128
|
import { applyCouncilSettings } from '../core/council-settings.js';
|
|
129
|
+
import { applyRequirementsGraphSettings } from '../core/requirements-graph-setting.js';
|
|
114
130
|
import { builtinPresetSkillRefs, coreSkillRefs, registeredSkillRefs } from '../skills/core-closure.js';
|
|
115
131
|
import { assertSkillsRootFenced } from '../skills/root-fence.js';
|
|
116
132
|
import { SkillsRuntime, isPublishingPlaceholder } from '../skills/runtime.js';
|
|
@@ -180,6 +196,9 @@ export async function createServer(adapter, options) {
|
|
|
180
196
|
level: process.env['LOG_LEVEL'] ?? 'info',
|
|
181
197
|
stream: teeStreamWithErrorRing(errorRing),
|
|
182
198
|
},
|
|
199
|
+
// DES-CHAT-ARTIFACTS-001 A2: a proposal id is `<chat id>:<turn uuid>` and a chat id may be 128 characters, so a
|
|
200
|
+
// path parameter may be up to 165 (Fastify's default limit is 100). Generous, still bounded.
|
|
201
|
+
maxParamLength: 256,
|
|
183
202
|
});
|
|
184
203
|
// TH-11: accumulate the route table as it registers — the endpoint manifest's one source of
|
|
185
204
|
// truth. Installed FIRST because fastify only fires onRoute for routes added after the hook
|
|
@@ -195,6 +214,8 @@ export async function createServer(adapter, options) {
|
|
|
195
214
|
let watchRegistry = null;
|
|
196
215
|
// DC-S4b: the studio chat recorder, handed back by `registerRoutes` below (it needs the service built there).
|
|
197
216
|
let chatDecisionRecorder = null;
|
|
217
|
+
// DES-CHAT-ARTIFACTS-001 §4.2 (A2): the proposal resolver (built with the routes), fed from the reply fold below.
|
|
218
|
+
let chatProposals = null;
|
|
198
219
|
// `GET /search`'s index, handed back by `registerRoutes` below; the frame fan-in feeds it late-bound.
|
|
199
220
|
let searchService = null;
|
|
200
221
|
// DC-S7: considered · set aside · cited — the rule reads behind the citation verifier, the unit hook
|
|
@@ -267,6 +288,8 @@ export async function createServer(adapter, options) {
|
|
|
267
288
|
applyWorkerConfigRoot(bootSettings.worker_config_root);
|
|
268
289
|
// Council size + spawn stagger (wicked-core#888): the same boot + on-change env seam.
|
|
269
290
|
applyCouncilSettings(bootSettings);
|
|
291
|
+
// Requirements-graph minimum coverage (operator ruling 2026-10-31): the same boot + on-change seam.
|
|
292
|
+
applyRequirementsGraphSettings(bootSettings);
|
|
270
293
|
// The skills seam (skills keystone): boot-time only — there is NO skills setting to re-apply on
|
|
271
294
|
// PUT /settings (codex round 5: `skills_root` and its env override are retired). The store hangs
|
|
272
295
|
// off `<state home>/skills` (never a `~/.wicked-crew` literal, crew#353), and the boot ASSERTS the
|
|
@@ -452,6 +475,8 @@ export async function createServer(adapter, options) {
|
|
|
452
475
|
// status write and the synchronous record below) stays undated.
|
|
453
476
|
const endedEntries = await audit.readAll({ action: 'run.ended' });
|
|
454
477
|
runTimingIndex.hydrateFromEndedEntries(endedEntries);
|
|
478
|
+
// DES-CHAT-ARTIFACTS-001 §6.2 (A3): proposal-bound attempts that ended without landing.
|
|
479
|
+
runTimingIndex.hydrateLandingFailed(await audit.readAll({ action: 'run.landing_failed' }));
|
|
455
480
|
// crew#619: rebuild the chat↔run retention maps for runs that were still live when the
|
|
456
481
|
// daemon was last stopped. The `run.launched` entries that carry `chatId` and are NOT in
|
|
457
482
|
// `run.ended` represent runs whose transcripts must still be on disk.
|
|
@@ -662,6 +687,58 @@ export async function createServer(adapter, options) {
|
|
|
662
687
|
// `crew-grounding.json` sidecar beside the doc's `versions.json` under the project's docs root
|
|
663
688
|
// (doc-grounding.ts says why not the state home: core's fence refuses unregistered entries).
|
|
664
689
|
const docGrounding = new DocGroundingStore();
|
|
690
|
+
// DES-CHAT-ARTIFACTS-001 §5.2 (A3): the durable binding of every chat-made document, under the registered `chats`
|
|
691
|
+
// state-home entry (core's fence refuses a new top-level entry, and no worker reads the state home).
|
|
692
|
+
const docBindings = new DocBindingStore(join(crewStateDir, 'chats', 'doc-bindings'));
|
|
693
|
+
/**
|
|
694
|
+
* A3 (§6.2): a proposal-bound attempt's outcome was recorded. A failure is said on the run (`run.landing_failed`, the
|
|
695
|
+
* DTO's `landing_failed` and a `landingFailed` frame), releases the chat and the document (their busy checks read the
|
|
696
|
+
* recorded outcome), and appends the retry proposal: Try again fills the same document.
|
|
697
|
+
*/
|
|
698
|
+
const onBoundOutcome = (ref, runId, outcome) => {
|
|
699
|
+
const hit = docBindings.attemptOf(runId);
|
|
700
|
+
if (outcome.kind === 'landed') {
|
|
701
|
+
audit.record('chat.proposal.landed', DAEMON_ACTOR, { runId, detail: { artifactRef: ref, version: outcome.version } });
|
|
702
|
+
return;
|
|
703
|
+
}
|
|
704
|
+
// Idempotent halves (a boot republishes a failure a crash cut short): the run's record once, the retry card once.
|
|
705
|
+
if (runTimingIndex.landingFailedOf(runId) === undefined) {
|
|
706
|
+
const ts = audit.record('run.landing_failed', DAEMON_ACTOR, { runId, detail: { artifactRef: ref, reason: outcome.reason } });
|
|
707
|
+
runTimingIndex.setLandingFailed(runId, outcome.reason, ts > 0 ? ts : Date.now());
|
|
708
|
+
}
|
|
709
|
+
broadcast({ type: 'landingFailed', session: runId, artifact_ref: ref, reason: outcome.reason });
|
|
710
|
+
if (hit === null || chatProposals === null)
|
|
711
|
+
return;
|
|
712
|
+
const chatNow = chatHistory.idOfInstance(hit.binding.chatId, hit.binding.chatInstance);
|
|
713
|
+
if (chatNow === null) {
|
|
714
|
+
app.log.warn(`[proposals] run ${runId} failed, and the chat it was made from is gone — no retry card`);
|
|
715
|
+
docBindings.markPublished(ref, runId);
|
|
716
|
+
return;
|
|
717
|
+
}
|
|
718
|
+
void chatProposals
|
|
719
|
+
.appendRetry(chatNow, hit.attempt.pid, runId, ref, outcome.reason, hit.binding.chatInstance)
|
|
720
|
+
.then((pid) => {
|
|
721
|
+
if (pid !== null)
|
|
722
|
+
docBindings.setRetry(ref, runId, pid);
|
|
723
|
+
docBindings.markPublished(ref, runId);
|
|
724
|
+
})
|
|
725
|
+
.catch((err) => app.log.warn(`[proposals] no retry card for run ${runId} (published again at the next start): ${err instanceof Error ? err.message : String(err)}`));
|
|
726
|
+
};
|
|
727
|
+
/**
|
|
728
|
+
* A3: a bound document's `doc.created` (normal or late) never launches anything: only a person's Go (or Go again)
|
|
729
|
+
* starts a run, under the proposal's and the chat's locks and busy checks. The trigger only settles an `accepting`
|
|
730
|
+
* proposal whose run Go already started (a lost response), as the boot reconcile does.
|
|
731
|
+
*/
|
|
732
|
+
const onBoundDocCreated = async (ref) => {
|
|
733
|
+
const b = docBindings.get(ref);
|
|
734
|
+
if (b === null || chatProposals === null)
|
|
735
|
+
return;
|
|
736
|
+
const chatNow = chatHistory.idOfInstance(b.chatId, b.chatInstance);
|
|
737
|
+
if (chatNow === null)
|
|
738
|
+
return;
|
|
739
|
+
for (const a of b.attempts.filter((x) => x.outcome === undefined))
|
|
740
|
+
await chatProposals.settleAccepting(chatNow, a.pid);
|
|
741
|
+
};
|
|
665
742
|
/** The three seams' ledgers, read AT USE TIME (a seam that armed after this closure was built is
|
|
666
743
|
* still preferred over its file) — shared by the doc-delete sweep and the doc↔run index. */
|
|
667
744
|
const docLedgerSources = () => [
|
|
@@ -877,6 +954,12 @@ export async function createServer(adapter, options) {
|
|
|
877
954
|
// tick that indexes merged knowledge and launches at most one due `learn` refresh at a time.
|
|
878
955
|
const learnSchedules = new LearnScheduleStore();
|
|
879
956
|
registerLearnRoutes(app, { store: learnSchedules, adapter, audit });
|
|
957
|
+
// program DES-LEARN §3.3: the orchestrator's personality — the person's and per-project overrides, one
|
|
958
|
+
// `daemon-persona.json`; its voice block rides every chat's scope statement (personaVoice below).
|
|
959
|
+
const personas = new PersonaStore({ log: (m) => app.log.warn(m) });
|
|
960
|
+
registerPersonaRoutes(app, { store: personas, adapter, audit });
|
|
961
|
+
// DES-LEARN §4: the first run's facts (git identity, languages, nearby checkouts), read-only.
|
|
962
|
+
registerSetupRoutes(app, { adapter });
|
|
880
963
|
const learnScheduler = new LearnScheduler({
|
|
881
964
|
store: learnSchedules,
|
|
882
965
|
adapter,
|
|
@@ -925,6 +1008,105 @@ export async function createServer(adapter, options) {
|
|
|
925
1008
|
app.log.warn(`[review] could not register the '${REVIEW_WORKFLOW}' workflow — the run review is off: ${err instanceof Error ? err.message : String(err)}`);
|
|
926
1009
|
}
|
|
927
1010
|
}
|
|
1011
|
+
// Run learnings (src/learnings): every run proposes what it learned to the approve queue — template
|
|
1012
|
+
// learnings at its checkpoints, the rest distilled at its end by one cheap seat that did not build it.
|
|
1013
|
+
const LEARNINGS_ACTOR = { id: 'run-learnings', kind: 'system', trust: 'operator' };
|
|
1014
|
+
const runLearnings = new RunLearningsService({
|
|
1015
|
+
adapter: {
|
|
1016
|
+
sessionsDetail: () => adapter.sessionsDetail(),
|
|
1017
|
+
runEvents: (id) => adapter.runEvents(id),
|
|
1018
|
+
seatsForWorkflow: (id) => adapter.seatsForWorkflow(id),
|
|
1019
|
+
launchRun: (input) => adapter.launchRun(input),
|
|
1020
|
+
// A distil run that stops at a gate is crew's to end, never the operator's: on the record as run-learnings.
|
|
1021
|
+
cancelRun: async (runId) => {
|
|
1022
|
+
const status = await adapter.cancelRun(runId);
|
|
1023
|
+
audit.record('run.cancelled', LEARNINGS_ACTOR, { runId, detail: { status, reason: 'a learnings distil stopped at a gate; crew files from its report' } });
|
|
1024
|
+
return status;
|
|
1025
|
+
},
|
|
1026
|
+
},
|
|
1027
|
+
submit: submitLearning,
|
|
1028
|
+
listProposals: async () => proposalRows(await callEstateTool('proposal.list', {})),
|
|
1029
|
+
listMemoryContents: async () => memoryContents(await callEstateTool('memory.list', {})),
|
|
1030
|
+
launched: (distillRunId, sourceRunId, projectId) => {
|
|
1031
|
+
try {
|
|
1032
|
+
recordRunLaunched(audit, runTimingIndex, LEARNINGS_ACTOR, distillRunId, {
|
|
1033
|
+
workflow: DISTILL_WORKFLOW,
|
|
1034
|
+
chainedFrom: sourceRunId,
|
|
1035
|
+
deliver: 'none',
|
|
1036
|
+
...(projectId !== null ? { projectId } : {}),
|
|
1037
|
+
});
|
|
1038
|
+
if (projectId !== null) {
|
|
1039
|
+
membershipIndex.set(distillRunId, projectId);
|
|
1040
|
+
projectBus?.emit(MEMBERSHIP_ATTACHED, { project_id: projectId, member: { kind: 'crew.run', ref: distillRunId }, actor: 'run-learnings' }, membershipAttachedKey(projectId, 'crew.run', distillRunId, Date.now()));
|
|
1041
|
+
}
|
|
1042
|
+
broadcast({
|
|
1043
|
+
type: 'runChained',
|
|
1044
|
+
session: distillRunId,
|
|
1045
|
+
from: sourceRunId,
|
|
1046
|
+
workflow: DISTILL_WORKFLOW,
|
|
1047
|
+
...(projectId !== null ? { project_id: projectId } : {}),
|
|
1048
|
+
});
|
|
1049
|
+
}
|
|
1050
|
+
catch (err) {
|
|
1051
|
+
app.log.warn(`[learnings] ${distillRunId} launched, but its bookkeeping failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1052
|
+
}
|
|
1053
|
+
},
|
|
1054
|
+
learningsDir: defaultLearningsDir(),
|
|
1055
|
+
mode: runLearningsMode(),
|
|
1056
|
+
log: (m) => app.log.info(m),
|
|
1057
|
+
newRunId: () => randomUUID(),
|
|
1058
|
+
});
|
|
1059
|
+
if (typeof adapter.registerWorkflow === 'function') {
|
|
1060
|
+
try {
|
|
1061
|
+
await adapter.registerWorkflow(loadDistillWorkflow());
|
|
1062
|
+
}
|
|
1063
|
+
catch (err) {
|
|
1064
|
+
app.log.warn(`[learnings] could not register the '${DISTILL_WORKFLOW}' workflow — run learnings are filed undistilled: ${err instanceof Error ? err.message : String(err)}`);
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
// A run whose end was interrupted by a restart (its handoff written, its distil run finished while the daemon was
|
|
1068
|
+
// down, a submit that failed) is finished now, off the boot path.
|
|
1069
|
+
void runLearnings.recover();
|
|
1070
|
+
// The in-flight check (src/inspect): a person asks "is this going well?" about a working step; one seat that is not
|
|
1071
|
+
// the step's own reads its record, read-only, bounded, and says so. It never touches the run it looks at.
|
|
1072
|
+
const INSPECT_ACTOR = { id: 'unit-inspect', kind: 'system', trust: 'operator' };
|
|
1073
|
+
const unitInspect = new InspectService({
|
|
1074
|
+
adapter: {
|
|
1075
|
+
sessionsDetail: () => adapter.sessionsDetail(),
|
|
1076
|
+
runEvents: (id) => adapter.runEvents(id),
|
|
1077
|
+
seatsForWorkflow: (id) => adapter.seatsForWorkflow(id),
|
|
1078
|
+
launchRun: (input) => adapter.launchRun(input),
|
|
1079
|
+
cancelRun: (id) => adapter.cancelRun(id),
|
|
1080
|
+
},
|
|
1081
|
+
replyOf: async (checkRunId) => {
|
|
1082
|
+
const view = (await adapter.sessionsDetail()).find((v) => v.session.id === checkRunId);
|
|
1083
|
+
const unit = view?.units.find((u) => u.ord === 1) ?? view?.units[0];
|
|
1084
|
+
return view !== undefined && unit !== undefined ? adapter.workOutput(coreUnitId(checkRunId, unit)) : null;
|
|
1085
|
+
},
|
|
1086
|
+
dir: defaultInspectionsDir(),
|
|
1087
|
+
broadcast: (frame) => broadcast(frame),
|
|
1088
|
+
launched: (checkRunId, sourceRunId) => {
|
|
1089
|
+
try {
|
|
1090
|
+
recordRunLaunched(audit, runTimingIndex, INSPECT_ACTOR, checkRunId, { workflow: INSPECT_WORKFLOW, chainedFrom: sourceRunId, deliver: 'none' });
|
|
1091
|
+
}
|
|
1092
|
+
catch (err) {
|
|
1093
|
+
app.log.warn(`[inspect] ${checkRunId} launched, but its bookkeeping failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1094
|
+
}
|
|
1095
|
+
},
|
|
1096
|
+
log: (m) => app.log.info(m),
|
|
1097
|
+
newId: () => randomUUID(),
|
|
1098
|
+
});
|
|
1099
|
+
if (typeof adapter.registerWorkflow === 'function') {
|
|
1100
|
+
try {
|
|
1101
|
+
await adapter.registerWorkflow(loadInspectWorkflow());
|
|
1102
|
+
}
|
|
1103
|
+
catch (err) {
|
|
1104
|
+
app.log.warn(`[inspect] could not register the '${INSPECT_WORKFLOW}' workflow — checks answer with crew's own reading: ${err instanceof Error ? err.message : String(err)}`);
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
// A check a restart interrupted is stopped and answered now, so it never runs on unwatched past its bound.
|
|
1108
|
+
void unitInspect.recover();
|
|
1109
|
+
registerInspectRoutes(app, { service: unitInspect, audit });
|
|
928
1110
|
// DES-DEFAULT-EVALS-001 §7: the default evals as a workflow (`workflows/run-evals.json`). Every launch is prepared
|
|
929
1111
|
// by the daemon, which runs the evals in-process (`runEvalsPrepare`, bound once the routes are registered below);
|
|
930
1112
|
// the Tool step only reads the report copy back.
|
|
@@ -1082,6 +1264,10 @@ export async function createServer(adapter, options) {
|
|
|
1082
1264
|
// F-046: the create-time grounding sidecar is read under the SAME per-project docs root the
|
|
1083
1265
|
// proxy recorded it in.
|
|
1084
1266
|
groundingStore: docGrounding,
|
|
1267
|
+
// DES-CHAT-ARTIFACTS-001 §5.2 (A3): chat-made documents.
|
|
1268
|
+
bindings: docBindings,
|
|
1269
|
+
onBoundDocCreated: (ref) => onBoundDocCreated(ref),
|
|
1270
|
+
onBoundOutcome,
|
|
1085
1271
|
resolveDocsRoot: o.resolveDocsRoot ?? interactiveDocsRoot,
|
|
1086
1272
|
log: (m) => app.log.warn(m),
|
|
1087
1273
|
logError: (m) => app.log.error(m),
|
|
@@ -1101,6 +1287,11 @@ export async function createServer(adapter, options) {
|
|
|
1101
1287
|
const o = options.interactiveEditEvents;
|
|
1102
1288
|
editSub = await startInteractiveEditSubscriber(adapter, {
|
|
1103
1289
|
...busOf(o.dbPath),
|
|
1290
|
+
// A3: a document a chat proposal is still drafting or landing takes no structural edit.
|
|
1291
|
+
isDocBusy: (documentId, projectId) => {
|
|
1292
|
+
const b = docBindings.get(`${projectId ?? '_unfiled'}/${documentId}`);
|
|
1293
|
+
return b !== null && b.attempts.some((a) => a.outcome === undefined && (a.launchingAt !== undefined || a.launchedAt !== undefined || a.emittedAt !== undefined));
|
|
1294
|
+
},
|
|
1104
1295
|
...(o.pollIntervalMs !== undefined ? { pollIntervalMs: o.pollIntervalMs } : {}),
|
|
1105
1296
|
...(o.heartbeatMs !== undefined ? { heartbeatMs: o.heartbeatMs } : {}),
|
|
1106
1297
|
...(o.ledgerPath !== undefined ? { ledgerPath: o.ledgerPath } : {}),
|
|
@@ -1362,6 +1553,8 @@ export async function createServer(adapter, options) {
|
|
|
1362
1553
|
// CoreEvent stream below; `POST /chats/:id/messages` refuses a send to a busy seat and the
|
|
1363
1554
|
// chat frames leave here stamped with the `turn_id` they answer.
|
|
1364
1555
|
const chatTurns = new ChatTurnIndex();
|
|
1556
|
+
/** DES-VOICE: the notes said by voice (the inject route remembers, the event path and the events read stamp). */
|
|
1557
|
+
const voiceInputs = new VoiceInjectInputs();
|
|
1365
1558
|
// ASK-C2 (DES-ASK-TEAM-CHAT-001 §5.2): the ask relay — the answer unit's deltas as chatDelta, the
|
|
1366
1559
|
// step.completed row's output as the chatReply, both fed back through the fold below so the turn
|
|
1367
1560
|
// index stamps them and the transcript/recorder/citations/ws consumers are unchanged.
|
|
@@ -1515,7 +1708,8 @@ export async function createServer(adapter, options) {
|
|
|
1515
1708
|
const stamped = chatTurns.decorate(event);
|
|
1516
1709
|
// crew#618 Acceptance 1: rewrite the chatReply frame ONCE — before both observe (persist) and
|
|
1517
1710
|
// broadcast (/ws → studio render/promote). `observe`'s own rewrite pass is then a no-op.
|
|
1518
|
-
|
|
1711
|
+
// DES-VOICE: a note said by voice says so on its queued/injected frames ("You (by voice)").
|
|
1712
|
+
const rewritten = voiceInputs.stamp(chatTranscripts.rewriteEvent(stamped));
|
|
1519
1713
|
chatTranscripts.observe(rewritten);
|
|
1520
1714
|
// DC-S4b: the seat's `wicked-decisions` block was cut out of the reply above; the recorder takes
|
|
1521
1715
|
// it (once) and, when every seat of the turn has answered, records the operator's words — off
|
|
@@ -1526,6 +1720,17 @@ export async function createServer(adapter, options) {
|
|
|
1526
1720
|
const cliKey = typeof f['cliKey'] === 'string' ? f['cliKey'] : undefined;
|
|
1527
1721
|
if (chat !== undefined && cliKey !== undefined) {
|
|
1528
1722
|
const block = rewritten.type === 'chatReply' ? chatTranscripts.takeDecisionsBlock(chat, cliKey) : null;
|
|
1723
|
+
// A2: the reply's `wicked-make` blocks (cut above, never shown) become a proposal card, resolved off this path.
|
|
1724
|
+
const makeBlocks = rewritten.type === 'chatReply' ? chatTranscripts.takeMakeBlocks(chat, cliKey) : [];
|
|
1725
|
+
if (makeBlocks.length > 0) {
|
|
1726
|
+
chatProposals?.onReply({
|
|
1727
|
+
chat,
|
|
1728
|
+
cliKey,
|
|
1729
|
+
...(typeof f['turn_id'] === 'string' ? { turnId: f['turn_id'] } : {}),
|
|
1730
|
+
ok: f['ok'] === true,
|
|
1731
|
+
blocks: makeBlocks,
|
|
1732
|
+
});
|
|
1733
|
+
}
|
|
1529
1734
|
void chatDecisionRecorder?.onReply({
|
|
1530
1735
|
chat,
|
|
1531
1736
|
cliKey,
|
|
@@ -1687,6 +1892,8 @@ export async function createServer(adapter, options) {
|
|
|
1687
1892
|
// off the hot path, logged. Only runs THIS daemon launched are known here, by design.
|
|
1688
1893
|
// crew#552: an onboarding completion queues its capture; a chained capture's end frees the slot.
|
|
1689
1894
|
onboardingCapture.onEvent(event);
|
|
1895
|
+
runLearnings.onEvent(event);
|
|
1896
|
+
unitInspect.onEvent(event);
|
|
1690
1897
|
if (event.type === 'sessionCompleted' && session !== undefined) {
|
|
1691
1898
|
const onboardedRepo = adapter.onboardedRepoOf(session);
|
|
1692
1899
|
if (onboardedRepo !== undefined) {
|
|
@@ -1743,6 +1950,9 @@ export async function createServer(adapter, options) {
|
|
|
1743
1950
|
stallWatchdog.stop();
|
|
1744
1951
|
});
|
|
1745
1952
|
}
|
|
1953
|
+
// Clickjacking guard (frame-guard.ts): who may frame the daemon's pages, on every response. FIRST
|
|
1954
|
+
// onRequest hook, so a preflight 204, a 403 or a 401 answered by a later hook carries it too.
|
|
1955
|
+
const frameDirective = registerFrameGuard(app, { allowedOrigins: auth.allowedOrigins });
|
|
1746
1956
|
app.addHook('onRequest', async (req, reply) => {
|
|
1747
1957
|
const origin = req.headers.origin;
|
|
1748
1958
|
// crew#1048: CORS is reflected only for origins allowed to read (origin-guard.ts); the refusal
|
|
@@ -1780,6 +1990,8 @@ export async function createServer(adapter, options) {
|
|
|
1780
1990
|
}
|
|
1781
1991
|
});
|
|
1782
1992
|
await app.register(fastifyWebsocket);
|
|
1993
|
+
// A successful upgrade's 101 is written by `ws` itself, past both frame-guard hooks.
|
|
1994
|
+
guardUpgrades(app.websocketServer, frameDirective);
|
|
1783
1995
|
// Identity (401) + trust (403) hooks. Ordering is load-bearing twice over:
|
|
1784
1996
|
// AFTER the CORS hook, so an OPTIONS preflight (which carries no
|
|
1785
1997
|
// Authorization by design) is answered 204 above and never reaches the token
|
|
@@ -1867,8 +2079,13 @@ export async function createServer(adapter, options) {
|
|
|
1867
2079
|
deliveryFreeze,
|
|
1868
2080
|
// wicked-studio#284: the watchdog's remembered frames ride `GET /runs/:id/events`.
|
|
1869
2081
|
stallFrames: (runId) => stallFrameIndex.framesFor(runId),
|
|
2082
|
+
voiceInputs,
|
|
1870
2083
|
// DES-SYSTEM-VIEW: the watchdog's evidence of life (relay frames, busy children) for `GET /system`.
|
|
1871
2084
|
runEvidence: (runId) => stallWatchdog.evidence(runId),
|
|
2085
|
+
personaVoice: (projectId) => {
|
|
2086
|
+
const p = personas.effective(projectId);
|
|
2087
|
+
return p === null ? null : voiceBlock(p.persona);
|
|
2088
|
+
},
|
|
1872
2089
|
// The SAME standing accessor the seams and the adapter launch with (F-RECON-002/003).
|
|
1873
2090
|
rosterWithStanding,
|
|
1874
2091
|
retryIndex,
|
|
@@ -1908,6 +2125,9 @@ export async function createServer(adapter, options) {
|
|
|
1908
2125
|
// EP-C2: where the checks read finds a document's recorded reviews.
|
|
1909
2126
|
docReviewsDir,
|
|
1910
2127
|
docGrounding,
|
|
2128
|
+
// DES-CHAT-ARTIFACTS-001 §5.2 (A3): chat-made documents; `create` is real only when the draft seam is armed.
|
|
2129
|
+
docBindings,
|
|
2130
|
+
...(draftSub !== null ? { launchBoundDraft: draftSub.launchBound, fenceBoundDraft: draftSub.fenceBound } : {}),
|
|
1911
2131
|
// crew#899: a chat's checkouts are brought to their upstream (when clean) before it reads them.
|
|
1912
2132
|
freshenCheckout: (root) => freshenCheckout(root),
|
|
1913
2133
|
...(skillsRuntime !== undefined ? { skills: skillsRuntime } : {}),
|
|
@@ -1926,11 +2146,17 @@ export async function createServer(adapter, options) {
|
|
|
1926
2146
|
await reviewService.prepareLaunch(input, { trigger: 'manual', scheduleId: null, projectIds: reviewProjects() });
|
|
1927
2147
|
},
|
|
1928
2148
|
reviewLaunchRefused: (runId, reason) => reviewService.launchRefused(runId, reason),
|
|
2149
|
+
runLearnings,
|
|
2150
|
+
...(runLearningsMode() !== 'off'
|
|
2151
|
+
? { recallLearnings: (problem, repo, project) => recallLearnings(callEstateTool, problem, repo, project) }
|
|
2152
|
+
: {}),
|
|
1929
2153
|
// Routes that say something to the thread (a refused chat seat, F-2R2-007) emit through the
|
|
1930
2154
|
// SAME /ws fan-out the engine's frames take.
|
|
1931
2155
|
broadcast: (frame) => broadcast(frame),
|
|
1932
2156
|
// ASK-C1/C2: the ask-path index the routes write and the relay reads.
|
|
1933
2157
|
askPaths,
|
|
2158
|
+
// DES-CHAT-ARTIFACTS-001 §13 A2: the chat-artifacts TEST configuration (a recording stub; nothing launches).
|
|
2159
|
+
chatArtifactsStub: options?.chatArtifactsStub ?? process.env['WICKED_CHAT_ARTIFACTS_STUB'] === '1',
|
|
1934
2160
|
// ASK-C1: DELETE /chats/:id on an ask path closes through the same fold an engine
|
|
1935
2161
|
// `chatClosed` takes (scope slot, decisions, considerations, retention-aware transcript).
|
|
1936
2162
|
closeChat: async (frame, runId, ticket) => {
|
|
@@ -1970,6 +2196,7 @@ export async function createServer(adapter, options) {
|
|
|
1970
2196
|
// DC-S4a §6: records whose landing a restart interrupted are re-driven, idempotently (the review
|
|
1971
2197
|
// proposal is keyed by the decision id). Off the boot path; a failure is a logged outcome.
|
|
1972
2198
|
chatDecisionRecorder = registered.chatRecorder;
|
|
2199
|
+
chatProposals = registered.chatProposals;
|
|
1973
2200
|
considerations = registered.considerations;
|
|
1974
2201
|
searchService = registered.search;
|
|
1975
2202
|
decorateRun = registered.decorateRun;
|
|
@@ -2052,9 +2279,14 @@ export async function createServer(adapter, options) {
|
|
|
2052
2279
|
},
|
|
2053
2280
|
changed: (runId, head) => broadcast({ type: 'workingDocChanged', session: runId, head }),
|
|
2054
2281
|
audit: (action, actor, runId, detail) => audit.record(action, actor, { runId, detail }),
|
|
2282
|
+
// The run's own log: crew writes the event-derived lines (Decisions, Open questions, Next) whether or not a tab
|
|
2283
|
+
// has the run open.
|
|
2284
|
+
events: async (runId) => (await adapter.runEvents(runId)),
|
|
2055
2285
|
log: (m) => app.log.warn(m),
|
|
2056
2286
|
});
|
|
2057
2287
|
workingDocTap = (e) => workingDocs.onEvent(e);
|
|
2288
|
+
// After a restart no further event may come for a run: bring every held document's lines up to date once.
|
|
2289
|
+
workingDocs.catchUp();
|
|
2058
2290
|
registerWorkingDocRoutes(app, { service: workingDocs, exists: async (id) => (await adapter.sessions()).includes(id) });
|
|
2059
2291
|
registerStandingOrderRoutes(app, {
|
|
2060
2292
|
store: standingOrders,
|
|
@@ -2071,7 +2303,38 @@ export async function createServer(adapter, options) {
|
|
|
2071
2303
|
// crew#830: a run the previous daemon left `executing` with no worker is marked `runOrphaned` by
|
|
2072
2304
|
// the engine at bootstrap (core#124) but never moved — resume every run whose trail ends on that
|
|
2073
2305
|
// frame, once, and audit it as `run.resumed {via: 'boot'}`; a live run (trail continues) is untouched.
|
|
2074
|
-
|
|
2306
|
+
//
|
|
2307
|
+
// DES-CHAT-ARTIFACTS-001 §6.2 (A3): proposal-bound runs are reconciled FIRST and skipped by that sweep. An `accepting`
|
|
2308
|
+
// proposal whose run exists is decided; every attempt without a recorded outcome either landed while the daemon was
|
|
2309
|
+
// down (crew had announced it and the document's head moved past its base) or lost its seam flight in the restart:
|
|
2310
|
+
// its engine run is cancelled to a confirmed terminal state, `landing_failed` says "interrupted by a restart", and
|
|
2311
|
+
// only then are the chat and the document released and Try again offered. Never a redispatch.
|
|
2312
|
+
void reconcileProposalRuns()
|
|
2313
|
+
.catch((err) => app.log.warn(`[proposals] boot reconcile failed: ${err instanceof Error ? err.message : String(err)}`))
|
|
2314
|
+
.finally(() => void resumeOrphanedRuns(adapter, audit, DAEMON_ACTOR, (m) => app.log.warn(m), (runId) => docBindings.isBound(runId)));
|
|
2315
|
+
function reconcileProposalRuns() {
|
|
2316
|
+
return reconcileBoundAttempts({
|
|
2317
|
+
bindings: docBindings,
|
|
2318
|
+
sessions: () => adapter.sessionsDetail(),
|
|
2319
|
+
cancelRun: (runId) => adapter.cancelRun(runId),
|
|
2320
|
+
docVersions: (projectId, doc) => docVersionsOf(interactiveDocsRoot(projectId ?? undefined), doc),
|
|
2321
|
+
chatIdOf: (chatId, instance) => chatHistory.idOfInstance(chatId, instance),
|
|
2322
|
+
settleAccepting: (chatId, pid) => chatProposals?.settleAccepting(chatId, pid) ?? Promise.resolve(false),
|
|
2323
|
+
// A crash between the engine accepting the run and crew recording it: the run's chat, proposal, artifact and
|
|
2324
|
+
// document are recorded from the binding, as the draft seam would have.
|
|
2325
|
+
ensureLaunchRecord: (b, a) => {
|
|
2326
|
+
if (runTimingIndex.proposalOf(a.runId) !== undefined)
|
|
2327
|
+
return;
|
|
2328
|
+
// Filed under the chat as it is kept now; when that chat is gone, under none (never a chat that took its id since).
|
|
2329
|
+
recordRunLaunched(audit, runTimingIndex, DAEMON_ACTOR, a.runId, recoveredLaunchDetail(chatHistory, b, a));
|
|
2330
|
+
},
|
|
2331
|
+
hasLandingFailed: (runId) => runTimingIndex.landingFailedOf(runId) !== undefined,
|
|
2332
|
+
// Every attempt's document link, every boot (the ledger row of a run a crash recovered may not exist).
|
|
2333
|
+
linkDocument: (runId, doc) => docRuns.set(runId, doc),
|
|
2334
|
+
onOutcome: onBoundOutcome,
|
|
2335
|
+
log: (m) => app.log.warn(m),
|
|
2336
|
+
});
|
|
2337
|
+
}
|
|
2075
2338
|
// The UI-emittable direction of the interactive seam. Registered unconditionally (a null relay
|
|
2076
2339
|
// answers 503, not 404) and BEFORE the static/SPA fallback below, like every other API route.
|
|
2077
2340
|
registerInteractiveEventRoutes(app, interactiveRelay);
|