wicked-crew 0.7.1 → 0.7.3

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.
Files changed (56) hide show
  1. package/dist/api/delivery-index.d.ts +61 -0
  2. package/dist/api/delivery-index.d.ts.map +1 -0
  3. package/dist/api/delivery-index.js +87 -0
  4. package/dist/api/delivery-index.js.map +1 -0
  5. package/dist/api/governance-steering.d.ts +139 -0
  6. package/dist/api/governance-steering.d.ts.map +1 -0
  7. package/dist/api/governance-steering.js +302 -0
  8. package/dist/api/governance-steering.js.map +1 -0
  9. package/dist/api/governance-wiki.d.ts +28 -0
  10. package/dist/api/governance-wiki.d.ts.map +1 -0
  11. package/dist/api/governance-wiki.js +97 -0
  12. package/dist/api/governance-wiki.js.map +1 -0
  13. package/dist/api/routes.d.ts +21 -16
  14. package/dist/api/routes.d.ts.map +1 -1
  15. package/dist/api/routes.js +196 -10
  16. package/dist/api/routes.js.map +1 -1
  17. package/dist/api/server.d.ts.map +1 -1
  18. package/dist/api/server.js +56 -1
  19. package/dist/api/server.js.map +1 -1
  20. package/dist/api/testing.d.ts +117 -0
  21. package/dist/api/testing.d.ts.map +1 -0
  22. package/dist/api/testing.js +152 -0
  23. package/dist/api/testing.js.map +1 -0
  24. package/dist/campaign/supervision.d.ts +296 -0
  25. package/dist/campaign/supervision.d.ts.map +1 -0
  26. package/dist/campaign/supervision.js +515 -0
  27. package/dist/campaign/supervision.js.map +1 -0
  28. package/dist/campaigns/plan.d.ts +64 -0
  29. package/dist/campaigns/plan.d.ts.map +1 -0
  30. package/dist/campaigns/plan.js +201 -0
  31. package/dist/campaigns/plan.js.map +1 -0
  32. package/dist/campaigns/routes.d.ts +28 -0
  33. package/dist/campaigns/routes.d.ts.map +1 -0
  34. package/dist/campaigns/routes.js +177 -0
  35. package/dist/campaigns/routes.js.map +1 -0
  36. package/dist/core/adapter.d.ts +160 -1
  37. package/dist/core/adapter.d.ts.map +1 -1
  38. package/dist/core/adapter.js +300 -1
  39. package/dist/core/adapter.js.map +1 -1
  40. package/dist/projects/routes.d.ts +4 -4
  41. package/dist/qe/acceptance.d.ts +20 -1
  42. package/dist/qe/acceptance.d.ts.map +1 -1
  43. package/dist/qe/acceptance.js +32 -0
  44. package/dist/qe/acceptance.js.map +1 -1
  45. package/dist/qe/conformance.d.ts +158 -0
  46. package/dist/qe/conformance.d.ts.map +1 -0
  47. package/dist/qe/conformance.js +244 -0
  48. package/dist/qe/conformance.js.map +1 -0
  49. package/dist/studio/assets/index-BAW9rqNT.css +32 -0
  50. package/dist/studio/assets/index-UahdRwF7.js +532 -0
  51. package/dist/studio/index.html +2 -2
  52. package/dist/studio/testid-inventory.json +4387 -0
  53. package/endpoint-manifest.json +154 -9
  54. package/package.json +3 -3
  55. package/dist/studio/assets/index-D-BFUYnY.js +0 -530
  56. package/dist/studio/assets/index-D6S9zUtO.css +0 -32
@@ -0,0 +1,61 @@
1
+ /**
2
+ * The run→delivered-PR index (CREW-UX-8, crew#321).
3
+ *
4
+ * `LaunchRunBody.deliver?: 'pr'` is input-only; the deliver phase computes the PR URL
5
+ * (`core/deliver.ts` — re-derived from the remote, refused without one) and prints it as the
6
+ * unit's last output line, which is console text, not a wire. This index is the read-side
7
+ * latency layer that lets the run DTOs echo `session.delivery` on BOTH `GET /runs` and
8
+ * `GET /runs/:id` without a `workOutput` read per request — the persisted field that makes a
9
+ * list surface's "4 of 5 siblings delivered" rollup affordable without an N-fetch fan-out
10
+ * (wicked-studio#27).
11
+ *
12
+ * Mirrors `RetryIndex`/`GuidanceIndex`'s posture exactly: the DURABLE record is the audit
13
+ * trail (the engine run record has no such field) — action `run.delivered`, `detail.url` —
14
+ * hydrated once at server start (best-effort: a missing or unreadable trail leaves deliveries
15
+ * blank, the pre-#321 behavior, not an error) and updated at the same post-terminal point
16
+ * that writes the audit entry.
17
+ *
18
+ * KNOWN LIMIT (stated in the contract too): runs that delivered before this landed have no
19
+ * `run.delivered` entry and carry no field. Do NOT backfill by scanning `work_output` at
20
+ * hydrate — that is an unbounded boot cost. Historical runs still resolve their URL through
21
+ * the per-run output endpoint.
22
+ */
23
+ import type { AuditLog } from './audit.js';
24
+ import type { SessionView, WorkUnit } from '../core/types.js';
25
+ /** The wire shape `AgentSession.delivery` carries (api-types 0.11.0). */
26
+ export interface SessionDelivery {
27
+ kind: 'pull_request';
28
+ url: string;
29
+ }
30
+ /**
31
+ * The PR URL in a deliver transcript — crew's own extraction, mirrored
32
+ * (`core/deliver.ts`: `grep -Eo 'https://[^[:space:]]+/pull/[0-9]+' | tail -1`). Requiring
33
+ * the digits keeps `…/pull/new/<branch>` — the create-PR form git prints on every push —
34
+ * from ever matching; the LAST match wins, same as `tail -1`.
35
+ */
36
+ export declare function prUrlFrom(text: string): string | null;
37
+ /**
38
+ * This run's deliver unit, or `null`. The composed id suffix (`<base>:deliver`) is the
39
+ * primary key; the `tool_cmd` probe is the fallback for an operator OVERLAY that carried the
40
+ * deliver phase under its own name — do NOT key on `workflow_id`, which is plain for
41
+ * overlay-carried deliver phases (crew#321).
42
+ */
43
+ export declare function deliverUnitOf(view: SessionView): WorkUnit | null;
44
+ export declare class DeliveryIndex {
45
+ private readonly runToUrl;
46
+ /**
47
+ * Load deliveries from EVERY `run.delivered` entry in the trail — exhaustively, not capped
48
+ * (BRIEF-UX-002 C5, the same defect class as `RetryIndex.hydrate`: a durable record must
49
+ * not vanish because 1000+ newer writes landed on top of it). The trail answers newest
50
+ * first, so the FIRST entry seen per run wins; older entries for the same run are
51
+ * superseded and skipped. Still best-effort, like its siblings; cost is one full-file scan
52
+ * at boot. (Third exhaustive trail scan at boot, after RetryIndex and GuidanceIndex — a
53
+ * FOURTH should trigger consolidating them into one pass, per crew#321.)
54
+ */
55
+ hydrate(audit: AuditLog, log?: (msg: string) => void): Promise<void>;
56
+ /** Record the run's delivered PR URL (idempotent — the newest write wins). */
57
+ set(runId: string, url: string): void;
58
+ /** The delivery for this run, or `undefined` (the DTO spells that as an ABSENT field). */
59
+ deliveryFor(runId: string): SessionDelivery | undefined;
60
+ }
61
+ //# sourceMappingURL=delivery-index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delivery-index.d.ts","sourceRoot":"","sources":["../../src/api/delivery-index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE9D,yEAAyE;AACzE,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGrD;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,WAAW,GAAG,QAAQ,GAAG,IAAI,CAIhE;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA6B;IAEtD;;;;;;;;OAQG;IACG,OAAO,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAsB1E,8EAA8E;IAC9E,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAIrC,0FAA0F;IAC1F,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;CAIxD"}
@@ -0,0 +1,87 @@
1
+ /**
2
+ * The run→delivered-PR index (CREW-UX-8, crew#321).
3
+ *
4
+ * `LaunchRunBody.deliver?: 'pr'` is input-only; the deliver phase computes the PR URL
5
+ * (`core/deliver.ts` — re-derived from the remote, refused without one) and prints it as the
6
+ * unit's last output line, which is console text, not a wire. This index is the read-side
7
+ * latency layer that lets the run DTOs echo `session.delivery` on BOTH `GET /runs` and
8
+ * `GET /runs/:id` without a `workOutput` read per request — the persisted field that makes a
9
+ * list surface's "4 of 5 siblings delivered" rollup affordable without an N-fetch fan-out
10
+ * (wicked-studio#27).
11
+ *
12
+ * Mirrors `RetryIndex`/`GuidanceIndex`'s posture exactly: the DURABLE record is the audit
13
+ * trail (the engine run record has no such field) — action `run.delivered`, `detail.url` —
14
+ * hydrated once at server start (best-effort: a missing or unreadable trail leaves deliveries
15
+ * blank, the pre-#321 behavior, not an error) and updated at the same post-terminal point
16
+ * that writes the audit entry.
17
+ *
18
+ * KNOWN LIMIT (stated in the contract too): runs that delivered before this landed have no
19
+ * `run.delivered` entry and carry no field. Do NOT backfill by scanning `work_output` at
20
+ * hydrate — that is an unbounded boot cost. Historical runs still resolve their URL through
21
+ * the per-run output endpoint.
22
+ */
23
+ /**
24
+ * The PR URL in a deliver transcript — crew's own extraction, mirrored
25
+ * (`core/deliver.ts`: `grep -Eo 'https://[^[:space:]]+/pull/[0-9]+' | tail -1`). Requiring
26
+ * the digits keeps `…/pull/new/<branch>` — the create-PR form git prints on every push —
27
+ * from ever matching; the LAST match wins, same as `tail -1`.
28
+ */
29
+ export function prUrlFrom(text) {
30
+ const matches = text.match(/https:\/\/\S+\/pull\/\d+/g);
31
+ return matches === null ? null : (matches[matches.length - 1] ?? null);
32
+ }
33
+ /**
34
+ * This run's deliver unit, or `null`. The composed id suffix (`<base>:deliver`) is the
35
+ * primary key; the `tool_cmd` probe is the fallback for an operator OVERLAY that carried the
36
+ * deliver phase under its own name — do NOT key on `workflow_id`, which is plain for
37
+ * overlay-carried deliver phases (crew#321).
38
+ */
39
+ export function deliverUnitOf(view) {
40
+ const byId = view.units.find((u) => u.id.endsWith(':deliver'));
41
+ if (byId !== undefined)
42
+ return byId;
43
+ return view.units.find((u) => (u.tool_cmd ?? []).join(' ').includes('gh pr create')) ?? null;
44
+ }
45
+ export class DeliveryIndex {
46
+ runToUrl = new Map();
47
+ /**
48
+ * Load deliveries from EVERY `run.delivered` entry in the trail — exhaustively, not capped
49
+ * (BRIEF-UX-002 C5, the same defect class as `RetryIndex.hydrate`: a durable record must
50
+ * not vanish because 1000+ newer writes landed on top of it). The trail answers newest
51
+ * first, so the FIRST entry seen per run wins; older entries for the same run are
52
+ * superseded and skipped. Still best-effort, like its siblings; cost is one full-file scan
53
+ * at boot. (Third exhaustive trail scan at boot, after RetryIndex and GuidanceIndex — a
54
+ * FOURTH should trigger consolidating them into one pass, per crew#321.)
55
+ */
56
+ async hydrate(audit, log) {
57
+ try {
58
+ const seen = new Set();
59
+ for (const entry of await audit.readAll({ action: 'run.delivered' })) {
60
+ if (typeof entry.runId !== 'string')
61
+ continue;
62
+ if (seen.has(entry.runId))
63
+ continue;
64
+ // Newest entry decides, even when malformed — marking the run seen BEFORE the url
65
+ // check keeps a corrupt newest write from resurrecting an older one (the #312 rule).
66
+ seen.add(entry.runId);
67
+ const url = entry.detail?.['url'];
68
+ if (typeof url !== 'string' || url === '')
69
+ continue;
70
+ this.runToUrl.set(entry.runId, url);
71
+ }
72
+ }
73
+ catch (err) {
74
+ log?.(`[runs] delivery-index hydrate failed (prior runs read as undelivered until restart): ${err instanceof Error ? err.message : String(err)}`);
75
+ }
76
+ }
77
+ /** Record the run's delivered PR URL (idempotent — the newest write wins). */
78
+ set(runId, url) {
79
+ this.runToUrl.set(runId, url);
80
+ }
81
+ /** The delivery for this run, or `undefined` (the DTO spells that as an ABSENT field). */
82
+ deliveryFor(runId) {
83
+ const url = this.runToUrl.get(runId);
84
+ return url === undefined ? undefined : { kind: 'pull_request', url };
85
+ }
86
+ }
87
+ //# sourceMappingURL=delivery-index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delivery-index.js","sourceRoot":"","sources":["../../src/api/delivery-index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAWH;;;;;GAKG;AACH,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC;IACxD,OAAO,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC;AACzE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,IAAiB;IAC7C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC;IAC/D,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACpC,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,IAAI,IAAI,CAAC;AAC/F,CAAC;AAED,MAAM,OAAO,aAAa;IACP,QAAQ,GAAG,IAAI,GAAG,EAAkB,CAAC;IAEtD;;;;;;;;OAQG;IACH,KAAK,CAAC,OAAO,CAAC,KAAe,EAAE,GAA2B;QACxD,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;YAC/B,KAAK,MAAM,KAAK,IAAI,MAAM,KAAK,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC,EAAE,CAAC;gBACrE,IAAI,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ;oBAAE,SAAS;gBAC9C,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC;oBAAE,SAAS;gBACpC,kFAAkF;gBAClF,qFAAqF;gBACrF,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;gBACtB,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,CAAC;gBAClC,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,EAAE;oBAAE,SAAS;gBACpD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;YACtC,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,EAAE,CACH,wFACE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CACjD,EAAE,CACH,CAAC;QACJ,CAAC;IACH,CAAC;IAED,8EAA8E;IAC9E,GAAG,CAAC,KAAa,EAAE,GAAW;QAC5B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAChC,CAAC;IAED,0FAA0F;IAC1F,WAAW,CAAC,KAAa;QACvB,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACrC,OAAO,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,GAAG,EAAE,CAAC;IACvE,CAAC;CACF"}
@@ -0,0 +1,139 @@
1
+ /**
2
+ * The `/api/v1/governance/steering/*` surface (STEERING program) — the management wire behind
3
+ * the studio's top-level Steering nav: batch IMPORT of steering docs/rules, and "add with chat"
4
+ * AUTHORING as a governed run. Per-rule CRUD deliberately lives elsewhere — this module adds no
5
+ * second door: `GET/POST /governance/rules` (now steering-aware: `?type=` facet,
6
+ * `?include_retired=`, steering-field writes) and `DELETE /governance/rules/:id` in
7
+ * `api/routes.ts` ARE the steering-rule CRUD, because a steering rule IS a conformance rule
8
+ * (the wiki/rules model and the old policy model merged into one).
9
+ *
10
+ * Thin by design, like `campaigns/routes.ts`: validation is zod (strict, unknown keys named —
11
+ * the FINDING-031 doctrine); import normalization/validation is the ENGINE's ingest path on the
12
+ * single-writer actor (fail-closed per entry — the daemon never opens the store for writes);
13
+ * authoring is the EXISTING run machinery (`launchRun` + the `steering-author` drop-in workflow
14
+ * + the standard `POST /runs/:id/gate` HITL flow) — no new chat stack. Error posture mirrors the
15
+ * campaign surface: a build whose engine addon predates the steering model answers 501
16
+ * (`SteeringUnsupportedError` — "upgrade the engine"), never 400 ("fix your request").
17
+ *
18
+ * estate's MCP surface stays READ-ONLY on rules; every steering WRITE flows through here (the
19
+ * governed operator path) — the AW-11 "no rules.write on estate" invariant is a design input of
20
+ * this module, not a coincidence.
21
+ */
22
+ import type { FastifyInstance, FastifyRequest } from 'fastify';
23
+ import { z } from 'zod';
24
+ import { type CoreAdapter } from '../core/adapter.js';
25
+ import type { Actor } from '../core/types.js';
26
+ import type { AuditLog } from './audit.js';
27
+ /**
28
+ * The steering-type vocabulary (`wicked-crew-api-types::SteeringType`) — enum-as-string, the
29
+ * engine's serde default is `architecture`. ONE spelling, exported: `api/routes.ts` reads it for
30
+ * the `?type=` browse facet so the two surfaces can never disagree about what a type is.
31
+ */
32
+ export declare const STEERING_TYPE_VALUES: readonly ["architecture", "development", "security", "testing", "operations", "compliance", "design-ux"];
33
+ export declare const STEERING_TYPES: ReadonlySet<string>;
34
+ /** The engine's serde default for a rule row that predates (or omits) `steering_type`. */
35
+ export declare const DEFAULT_STEERING_TYPE = "architecture";
36
+ /** Per-entry ceiling on an import doc / rule payload (UTF-8 bytes) — mirrors the run-files cap. */
37
+ export declare const STEERING_ENTRY_MAX_BYTES: number;
38
+ /** Batch ceiling — an import is a page action, not a bulk-migration channel. */
39
+ export declare const STEERING_IMPORT_MAX_ENTRIES = 200;
40
+ /** Authoring intent is operator prose, not a document store (the guidance-cap doctrine). */
41
+ export declare const STEERING_INSTRUCTIONS_MAX_BYTES: number;
42
+ export declare const SteeringImportSchema: z.ZodObject<{
43
+ type: z.ZodOptional<z.ZodEnum<["architecture", "development", "security", "testing", "operations", "compliance", "design-ux"]>>;
44
+ entries: z.ZodArray<z.ZodDiscriminatedUnion<"kind", [z.ZodObject<{
45
+ kind: z.ZodLiteral<"doc">;
46
+ name: z.ZodOptional<z.ZodString>;
47
+ content: z.ZodString;
48
+ }, "strict", z.ZodTypeAny, {
49
+ kind: "doc";
50
+ content: string;
51
+ name?: string | undefined;
52
+ }, {
53
+ kind: "doc";
54
+ content: string;
55
+ name?: string | undefined;
56
+ }>, z.ZodObject<{
57
+ kind: z.ZodLiteral<"rule">;
58
+ rule: z.ZodType<import("wicked-crew-api-types").ConformanceRule, z.ZodTypeDef, import("wicked-crew-api-types").ConformanceRule>;
59
+ }, "strict", z.ZodTypeAny, {
60
+ kind: "rule";
61
+ rule: import("wicked-crew-api-types").ConformanceRule;
62
+ }, {
63
+ kind: "rule";
64
+ rule: import("wicked-crew-api-types").ConformanceRule;
65
+ }>]>, "many">;
66
+ }, "strict", z.ZodTypeAny, {
67
+ entries: ({
68
+ kind: "doc";
69
+ content: string;
70
+ name?: string | undefined;
71
+ } | {
72
+ kind: "rule";
73
+ rule: import("wicked-crew-api-types").ConformanceRule;
74
+ })[];
75
+ type?: "architecture" | "development" | "security" | "testing" | "operations" | "compliance" | "design-ux" | undefined;
76
+ }, {
77
+ entries: ({
78
+ kind: "doc";
79
+ content: string;
80
+ name?: string | undefined;
81
+ } | {
82
+ kind: "rule";
83
+ rule: import("wicked-crew-api-types").ConformanceRule;
84
+ })[];
85
+ type?: "architecture" | "development" | "security" | "testing" | "operations" | "compliance" | "design-ux" | undefined;
86
+ }>;
87
+ export declare const SteeringAuthorSchema: z.ZodObject<{
88
+ instructions: z.ZodString;
89
+ type: z.ZodOptional<z.ZodEnum<["architecture", "development", "security", "testing", "operations", "compliance", "design-ux"]>>;
90
+ paths: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
91
+ documents: z.ZodOptional<z.ZodArray<z.ZodObject<{
92
+ name: z.ZodString;
93
+ content: z.ZodString;
94
+ }, "strict", z.ZodTypeAny, {
95
+ content: string;
96
+ name: string;
97
+ }, {
98
+ content: string;
99
+ name: string;
100
+ }>, "many">>;
101
+ repoRef: z.ZodOptional<z.ZodString>;
102
+ sessionId: z.ZodOptional<z.ZodString>;
103
+ }, "strict", z.ZodTypeAny, {
104
+ instructions: string;
105
+ type?: "architecture" | "development" | "security" | "testing" | "operations" | "compliance" | "design-ux" | undefined;
106
+ repoRef?: string | undefined;
107
+ paths?: string[] | undefined;
108
+ documents?: {
109
+ content: string;
110
+ name: string;
111
+ }[] | undefined;
112
+ sessionId?: string | undefined;
113
+ }, {
114
+ instructions: string;
115
+ type?: "architecture" | "development" | "security" | "testing" | "operations" | "compliance" | "design-ux" | undefined;
116
+ repoRef?: string | undefined;
117
+ paths?: string[] | undefined;
118
+ documents?: {
119
+ content: string;
120
+ name: string;
121
+ }[] | undefined;
122
+ sessionId?: string | undefined;
123
+ }>;
124
+ /**
125
+ * Where the author route lands inline documents so the run can read them: a per-run inbox on the
126
+ * daemon host — the existing run file mechanism (runs read the daemon's filesystem; the paths
127
+ * ride the problem statement, never the prompt-fattening content itself).
128
+ */
129
+ export declare function steeringInboxDir(runId: string): string;
130
+ export interface SteeringRoutesDeps {
131
+ audit: AuditLog;
132
+ actorOf: (req: FastifyRequest & {
133
+ actor?: Actor;
134
+ }) => Actor;
135
+ /** The default council roster for the authoring run (already parsed). */
136
+ roster: () => unknown[];
137
+ }
138
+ export declare function registerGovernanceSteeringRoutes(app: FastifyInstance, adapter: CoreAdapter, deps: SteeringRoutesDeps): void;
139
+ //# sourceMappingURL=governance-steering.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"governance-steering.d.ts","sourceRoot":"","sources":["../../src/api/governance-steering.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAKH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAA4B,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAChF,OAAO,KAAK,EAAE,KAAK,EAA6C,MAAM,kBAAkB,CAAC;AACzF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAK3C;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,0GAQvB,CAAC;AAEX,eAAO,MAAM,cAAc,EAAE,WAAW,CAAC,MAAM,CAAiC,CAAC;AAEjF,0FAA0F;AAC1F,eAAO,MAAM,qBAAqB,iBAAiB,CAAC;AAEpD,mGAAmG;AACnG,eAAO,MAAM,wBAAwB,QAAa,CAAC;AACnD,gFAAgF;AAChF,eAAO,MAAM,2BAA2B,MAAM,CAAC;AAC/C,4FAA4F;AAC5F,eAAO,MAAM,+BAA+B,QAAY,CAAC;AA0CzD,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAQtB,CAAC;AAEZ,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAYtB,CAAC;AAEZ;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAQtD;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,QAAQ,CAAC;IAChB,OAAO,EAAE,CAAC,GAAG,EAAE,cAAc,GAAG;QAAE,KAAK,CAAC,EAAE,KAAK,CAAA;KAAE,KAAK,KAAK,CAAC;IAC5D,yEAAyE;IACzE,MAAM,EAAE,MAAM,OAAO,EAAE,CAAC;CACzB;AAED,wBAAgB,gCAAgC,CAC9C,GAAG,EAAE,eAAe,EACpB,OAAO,EAAE,WAAW,EACpB,IAAI,EAAE,kBAAkB,GACvB,IAAI,CAkMN"}
@@ -0,0 +1,302 @@
1
+ /**
2
+ * The `/api/v1/governance/steering/*` surface (STEERING program) — the management wire behind
3
+ * the studio's top-level Steering nav: batch IMPORT of steering docs/rules, and "add with chat"
4
+ * AUTHORING as a governed run. Per-rule CRUD deliberately lives elsewhere — this module adds no
5
+ * second door: `GET/POST /governance/rules` (now steering-aware: `?type=` facet,
6
+ * `?include_retired=`, steering-field writes) and `DELETE /governance/rules/:id` in
7
+ * `api/routes.ts` ARE the steering-rule CRUD, because a steering rule IS a conformance rule
8
+ * (the wiki/rules model and the old policy model merged into one).
9
+ *
10
+ * Thin by design, like `campaigns/routes.ts`: validation is zod (strict, unknown keys named —
11
+ * the FINDING-031 doctrine); import normalization/validation is the ENGINE's ingest path on the
12
+ * single-writer actor (fail-closed per entry — the daemon never opens the store for writes);
13
+ * authoring is the EXISTING run machinery (`launchRun` + the `steering-author` drop-in workflow
14
+ * + the standard `POST /runs/:id/gate` HITL flow) — no new chat stack. Error posture mirrors the
15
+ * campaign surface: a build whose engine addon predates the steering model answers 501
16
+ * (`SteeringUnsupportedError` — "upgrade the engine"), never 400 ("fix your request").
17
+ *
18
+ * estate's MCP surface stays READ-ONLY on rules; every steering WRITE flows through here (the
19
+ * governed operator path) — the AW-11 "no rules.write on estate" invariant is a design input of
20
+ * this module, not a coincidence.
21
+ */
22
+ import { randomUUID } from 'node:crypto';
23
+ import { existsSync, promises as fsp } from 'node:fs';
24
+ import { basename, isAbsolute, join } from 'node:path';
25
+ import { z } from 'zod';
26
+ import { SteeringUnsupportedError } from '../core/adapter.js';
27
+ import { API_PREFIX } from './api-prefix.js';
28
+ const V = API_PREFIX;
29
+ /**
30
+ * The steering-type vocabulary (`wicked-crew-api-types::SteeringType`) — enum-as-string, the
31
+ * engine's serde default is `architecture`. ONE spelling, exported: `api/routes.ts` reads it for
32
+ * the `?type=` browse facet so the two surfaces can never disagree about what a type is.
33
+ */
34
+ export const STEERING_TYPE_VALUES = [
35
+ 'architecture',
36
+ 'development',
37
+ 'security',
38
+ 'testing',
39
+ 'operations',
40
+ 'compliance',
41
+ 'design-ux',
42
+ ];
43
+ export const STEERING_TYPES = new Set(STEERING_TYPE_VALUES);
44
+ /** The engine's serde default for a rule row that predates (or omits) `steering_type`. */
45
+ export const DEFAULT_STEERING_TYPE = 'architecture';
46
+ /** Per-entry ceiling on an import doc / rule payload (UTF-8 bytes) — mirrors the run-files cap. */
47
+ export const STEERING_ENTRY_MAX_BYTES = 512 * 1024;
48
+ /** Batch ceiling — an import is a page action, not a bulk-migration channel. */
49
+ export const STEERING_IMPORT_MAX_ENTRIES = 200;
50
+ /** Authoring intent is operator prose, not a document store (the guidance-cap doctrine). */
51
+ export const STEERING_INSTRUCTIONS_MAX_BYTES = 16 * 1024;
52
+ function message(err) {
53
+ return err instanceof Error ? err.message : String(err);
54
+ }
55
+ /** Same unknown-key-naming 400 body builder as api/routes.ts (restated because that module does
56
+ * not export it and importing routes.ts here would be a cycle through registerRoutes). */
57
+ function invalidBody(err, what) {
58
+ const unknown = err.issues.flatMap((i) => (i.code === 'unrecognized_keys' ? i.keys : []));
59
+ const error = unknown.length > 0
60
+ ? `${what}: unknown field${unknown.length > 1 ? 's' : ''} ${unknown
61
+ .map((k) => `\`${k}\``)
62
+ .join(', ')} — this endpoint does not accept ${unknown.length > 1 ? 'them' : 'it'}, and ignoring ${unknown.length > 1 ? 'them' : 'it'} would run a different request than you sent`
63
+ : what;
64
+ return { error, details: err.issues };
65
+ }
66
+ // A doc entry: frontmattered markdown, the SAME format `rules ingest --dir` consumes. The rule
67
+ // entry's payload is validated shape-wise by the ENGINE's normalize/validate path (fail-closed
68
+ // per entry) — the route checks only "is an object", so engine-side validation stays the ONE
69
+ // spelling of what a rule is.
70
+ const ImportDocSchema = z
71
+ .object({
72
+ kind: z.literal('doc'),
73
+ name: z.string().min(1).max(256).optional(),
74
+ content: z.string().min(1),
75
+ })
76
+ .strict();
77
+ const ImportRuleSchema = z
78
+ .object({
79
+ kind: z.literal('rule'),
80
+ rule: z.custom((v) => typeof v === 'object' && v !== null && !Array.isArray(v), { message: '`rule` must be a rule object' }),
81
+ })
82
+ .strict();
83
+ export const SteeringImportSchema = z
84
+ .object({
85
+ type: z.enum(STEERING_TYPE_VALUES).optional(),
86
+ entries: z
87
+ .array(z.discriminatedUnion('kind', [ImportDocSchema, ImportRuleSchema]))
88
+ .min(1)
89
+ .max(STEERING_IMPORT_MAX_ENTRIES),
90
+ })
91
+ .strict();
92
+ export const SteeringAuthorSchema = z
93
+ .object({
94
+ instructions: z.string().min(1),
95
+ type: z.enum(STEERING_TYPE_VALUES).optional(),
96
+ paths: z.array(z.string().min(1)).max(32).optional(),
97
+ documents: z
98
+ .array(z.object({ name: z.string().min(1).max(128), content: z.string().min(1) }).strict())
99
+ .max(32)
100
+ .optional(),
101
+ repoRef: z.string().min(1).optional(),
102
+ sessionId: z.string().min(1).optional(),
103
+ })
104
+ .strict();
105
+ /**
106
+ * Where the author route lands inline documents so the run can read them: a per-run inbox on the
107
+ * daemon host — the existing run file mechanism (runs read the daemon's filesystem; the paths
108
+ * ride the problem statement, never the prompt-fattening content itself).
109
+ */
110
+ export function steeringInboxDir(runId) {
111
+ // Env override first (the workflowOverlayDir pattern) — what keeps tests out of the
112
+ // operator's real ~/.wicked.
113
+ if (process.env.WICKED_STEERING_INBOX_DIR) {
114
+ return join(process.env.WICKED_STEERING_INBOX_DIR, runId);
115
+ }
116
+ const home = process.env.HOME ?? process.env.USERPROFILE ?? '/tmp';
117
+ return join(home, '.wicked', 'steering-inbox', runId);
118
+ }
119
+ export function registerGovernanceSteeringRoutes(app, adapter, deps) {
120
+ const { audit, actorOf } = deps;
121
+ // ── Batch import (the Steering page's Import action) ─────────────────────────
122
+ // JSON body only, deliberately: this daemon speaks no multipart (no parser registered, and the
123
+ // studio client speaks JSON everywhere else), so doc bytes ride `content` inline. `type` is the
124
+ // page's inferred steering type, applied engine-side as the default for entries that omit one.
125
+ // 200 even when entries rejected — fail-closed PER ENTRY, and the per-entry results ARE the
126
+ // answer; only a malformed batch (400), a pre-steering engine (501), or an engine failure (500)
127
+ // refuse the request as a whole.
128
+ app.post(`${V}/governance/steering/import`, {
129
+ config: {
130
+ manifest: {
131
+ requestType: 'SteeringImportBody',
132
+ responseType: 'SteeringImportResponse',
133
+ // 501: the installed engine addon predates the steering model (wicked-core-ts < 0.7.5)
134
+ // — upgrade the engine, the request was already correct.
135
+ statusCodes: [200, 400, 500, 501],
136
+ },
137
+ },
138
+ }, async (req, reply) => {
139
+ const parsed = SteeringImportSchema.safeParse(req.body);
140
+ if (!parsed.success) {
141
+ return reply.code(400).send(invalidBody(parsed.error, 'Invalid steering import body'));
142
+ }
143
+ // Byte caps checked in the route, not zod's char-counting `max`, so the 400 names the
144
+ // actual limit (the guidance-cap doctrine).
145
+ for (const [i, entry] of parsed.data.entries.entries()) {
146
+ const payload = entry.kind === 'doc' ? entry.content : JSON.stringify(entry.rule);
147
+ const bytes = Buffer.byteLength(payload, 'utf8');
148
+ if (bytes > STEERING_ENTRY_MAX_BYTES) {
149
+ return reply.code(400).send({
150
+ error: `entries[${i}] is ${bytes} bytes, over the ${STEERING_ENTRY_MAX_BYTES}-byte per-entry cap`,
151
+ });
152
+ }
153
+ }
154
+ try {
155
+ const results = await adapter.importSteeringRules(parsed.data.entries, parsed.data.type);
156
+ const imported = results.filter((r) => r.status === 'imported').length;
157
+ const rejected = results.length - imported;
158
+ audit.record('governance.steering.imported', actorOf(req), {
159
+ detail: {
160
+ entries: results.length,
161
+ imported,
162
+ rejected,
163
+ ...(parsed.data.type !== undefined ? { type: parsed.data.type } : {}),
164
+ },
165
+ });
166
+ return { results, imported, rejected };
167
+ }
168
+ catch (err) {
169
+ if (err instanceof SteeringUnsupportedError) {
170
+ return reply.code(501).send({ error: message(err) });
171
+ }
172
+ // An engine/store failure is OURS, not the caller's — the batch already parsed, so
173
+ // nothing here maps to 400 (per-ENTRY validation failures come back in `results`).
174
+ return reply.code(500).send({ error: message(err) });
175
+ }
176
+ });
177
+ // ── "Add with chat" (the Steering page's conversational authoring action) ────
178
+ // REUSES crew's run machinery end to end: launches the `steering-author` drop-in workflow
179
+ // (BUILTIN_WORKFLOWS — analyze → propose, with an unconditional human gate on the terminal
180
+ // propose phase: TH-12 propose-as-gate), inline documents land in the per-run steering inbox
181
+ // (the run reads the daemon host's filesystem — the existing run file mechanism), and the
182
+ // operator answers the proposal through the standard POST /runs/:id/gate. Approved rules land
183
+ // via POST /governance/rules with `provenance.source: "chat"` — the run itself writes nothing.
184
+ //
185
+ // Gated on the steering engine too, on purpose: the run only PROPOSES, but proposing rules
186
+ // whose steering fields the CRUD would then refuse (501) is a trap, not a feature.
187
+ app.post(`${V}/governance/steering/author`, {
188
+ config: {
189
+ manifest: {
190
+ requestType: 'SteeringAuthorBody',
191
+ responseType: '{ runId: string }',
192
+ // 409: engine busy / sessionId already exists; 501: pre-steering engine.
193
+ statusCodes: [201, 400, 409, 500, 501],
194
+ },
195
+ },
196
+ }, async (req, reply) => {
197
+ const parsed = SteeringAuthorSchema.safeParse(req.body);
198
+ if (!parsed.success) {
199
+ return reply.code(400).send(invalidBody(parsed.error, 'Invalid steering author body'));
200
+ }
201
+ const b = parsed.data;
202
+ const intentBytes = Buffer.byteLength(b.instructions, 'utf8');
203
+ if (intentBytes > STEERING_INSTRUCTIONS_MAX_BYTES) {
204
+ return reply.code(400).send({
205
+ error: `instructions is ${intentBytes} bytes, over the ${STEERING_INSTRUCTIONS_MAX_BYTES}-byte cap — put long material in \`documents\` or \`paths\`, not the intent`,
206
+ });
207
+ }
208
+ for (const [i, doc] of (b.documents ?? []).entries()) {
209
+ const bytes = Buffer.byteLength(doc.content, 'utf8');
210
+ if (bytes > STEERING_ENTRY_MAX_BYTES) {
211
+ return reply.code(400).send({
212
+ error: `documents[${i}] is ${bytes} bytes, over the ${STEERING_ENTRY_MAX_BYTES}-byte per-document cap`,
213
+ });
214
+ }
215
+ }
216
+ // The run id NAMES the per-run inbox directory below, and `join` honors `../` — a
217
+ // free-form id could land inline documents outside the inbox (or alias another run's).
218
+ // Same doctrine as the document `name` scrub: caller text is never a path — but the id
219
+ // must round-trip exactly (it is the run's identity), so refuse loudly instead of
220
+ // scrubbing silently.
221
+ if (b.sessionId !== undefined && !/^(?!\.+$)[A-Za-z0-9._-]{1,128}$/.test(b.sessionId)) {
222
+ return reply.code(400).send({
223
+ error: 'sessionId must be 1-128 characters of [A-Za-z0-9._-] (and not dots only) — it names ' +
224
+ "the run's steering-inbox directory on the daemon host",
225
+ });
226
+ }
227
+ if (!adapter.steeringSupported()) {
228
+ return reply
229
+ .code(501)
230
+ .send({ error: new SteeringUnsupportedError('Authoring steering rules').message });
231
+ }
232
+ // Paths are read on the DAEMON host — validate loudly here rather than letting the run
233
+ // burn a phase discovering a browser-local path. Absolute only (the extraWriteRoots
234
+ // doctrine), and existing (a named 400 beats a worker's "no such file" mid-run).
235
+ for (const p of b.paths ?? []) {
236
+ if (!isAbsolute(p)) {
237
+ return reply
238
+ .code(400)
239
+ .send({ error: `paths: \`${p}\` must be absolute on the daemon host` });
240
+ }
241
+ if (!existsSync(p)) {
242
+ return reply.code(400).send({
243
+ error: `paths: \`${p}\` does not exist on the daemon host — the authoring run reads the daemon's filesystem, not the browser's`,
244
+ });
245
+ }
246
+ }
247
+ const runId = b.sessionId ?? randomUUID();
248
+ // Inline documents → per-run inbox files; only their PATHS ride the problem statement
249
+ // (content in the prompt would fatten it past what prompt transports tolerate).
250
+ const docPaths = [];
251
+ if (b.documents !== undefined && b.documents.length > 0) {
252
+ const dir = steeringInboxDir(runId);
253
+ await fsp.mkdir(dir, { recursive: true });
254
+ for (const [i, doc] of b.documents.entries()) {
255
+ // basename + charset scrub: the caller's `name` is display text, never a path. The
256
+ // index prefix keeps scrubbed names collision-free and the filename non-empty.
257
+ const safe = `${i}-${basename(doc.name).replace(/[^a-zA-Z0-9._-]/g, '_')}`;
258
+ const target = join(dir, safe);
259
+ await fsp.writeFile(target, doc.content, 'utf8');
260
+ docPaths.push(target);
261
+ }
262
+ }
263
+ const type = b.type ?? DEFAULT_STEERING_TYPE;
264
+ const sources = [...(b.paths ?? []), ...docPaths];
265
+ const problem = [
266
+ `Author steering rules for the '${type}' steering type (use it as the default steering_type for every proposed rule without a better fit).`,
267
+ '',
268
+ 'Operator intent:',
269
+ b.instructions,
270
+ ...(sources.length > 0
271
+ ? ['', 'Analyze these files/directories on this machine:', ...sources.map((s) => `- ${s}`)]
272
+ : []),
273
+ ].join('\n');
274
+ try {
275
+ await adapter.launchRun({
276
+ problem,
277
+ sessionId: runId,
278
+ clisJson: JSON.stringify(deps.roster()),
279
+ workflow: 'steering-author',
280
+ ...(b.repoRef !== undefined ? { repoRef: b.repoRef } : {}),
281
+ });
282
+ // The same trail entry POST /runs writes — this IS a run launch, findable by the same
283
+ // `?action=run.launched` query — plus the steering detail the Steering header renders.
284
+ audit.record('run.launched', actorOf(req), {
285
+ runId,
286
+ detail: {
287
+ workflow: 'steering-author',
288
+ steeringType: type,
289
+ sources: sources.length,
290
+ ...(b.repoRef !== undefined ? { repoRef: b.repoRef } : {}),
291
+ },
292
+ });
293
+ return reply.code(201).send({ runId });
294
+ }
295
+ catch (err) {
296
+ const msg = message(err);
297
+ const busy = /busy|in flight|already/i.test(msg);
298
+ return reply.code(busy ? 409 : 400).send({ error: msg });
299
+ }
300
+ });
301
+ }
302
+ //# sourceMappingURL=governance-steering.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"governance-steering.js","sourceRoot":"","sources":["../../src/api/governance-steering.ts"],"names":[],"mappings":"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"}