@tea-agent/loop-agent 0.37.0 → 0.37.1-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +2 -6
- package/CHANGELOG.md +71 -144
- package/README.md +1 -1
- package/bin/loop-agent.js +1 -37
- package/dist/application/task-lifecycle/advance.js +0 -1
- package/dist/application/task-lifecycle/observe.js +0 -15
- package/dist/application/task-lifecycle/plan-transitions.js +0 -15
- package/dist/cli/command-definitions.js +0 -7
- package/dist/cli/program.js +3 -8
- package/dist/commands/init-upgrade.js +19 -351
- package/dist/commands/init.js +67 -14
- package/dist/commands/run-dag-progress.js +0 -14
- package/dist/commands/task-advance.js +3 -33
- package/dist/executors/dag-pi-executor.js +30 -47
- package/dist/executors/pi-sdk-executor.js +0 -34
- package/dist/executors/shell-executor.js +95 -6
- package/dist/shared/operator/capabilities.js +13 -200
- package/dist/shared/package-metadata.js +0 -42
- package/dist/task/contract/project.js +0 -4
- package/dist/task/source-prepare/completeness.js +0 -53
- package/dist/task/source-prepare/parse-intent.js +12 -82
- package/dist/task/source-prepare/prepare.js +5 -102
- package/dist/task/source-prepare/semantic-intake.js +23 -144
- package/dist/worker/console/chat/artifact-card.js +1 -8
- package/dist/worker/console/chat/chat-event-store.js +0 -152
- package/dist/worker/console/chat/human-gate-card.js +1 -9
- package/dist/worker/console/chat/operation-card.js +2 -71
- package/dist/worker/console/chat/pi-runtime.js +62 -111
- package/dist/worker/console/chat/routes.js +10 -43
- package/dist/worker/console/chat/session-store.js +1 -9
- package/dist/worker/console/chat/shortcuts.js +7 -9
- package/dist/worker/console/chat/turn-process.js +23 -204
- package/dist/worker/console/chat/workspace-landing.js +1 -2
- package/dist/worker/console/operation-runner.js +6 -155
- package/dist/worker/console/operator-actions.js +14 -391
- package/dist/worker/console/operator-user-error.js +0 -4
- package/dist/worker/console/recovery-cta.js +3 -50
- package/dist/worker/console/static/assets/index-HX1pbOyl.css +1 -0
- package/dist/worker/console/static/assets/index-M0BLEBfh.js +56 -0
- package/dist/worker/console/static/index.html +2 -2
- package/dist/worker/console/static-src/app/console-types.js +9 -13
- package/dist/worker/console/static-src/app/useOperatorActions.js +2 -4
- package/dist/worker/console/static-src/app/useRecoveryActions.js +56 -65
- package/dist/worker/console/static-src/app/useRecoveryConsole.js +1 -73
- package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +30 -114
- package/dist/worker/console/static-src/operator-chat/refs.js +0 -3
- package/dist/worker/console/static-src/operator-chat/spatial-overlay.js +1 -2
- package/dist/worker/console/static-src/operator-chat/useChatSessions.js +13 -67
- package/dist/worker/console/static-src/operator-chat/useChatThread.js +6 -12
- package/dist/worker/console/static-src/operator-chat/useComposer.js +8 -45
- package/dist/worker/console/static-src/operator-chat/workspace-layout-mode.js +3 -7
- package/dist/worker/loop-agent/loop-agent-client.js +3 -17
- package/dist/worker/observability/read-model.js +0 -20
- package/dist/worker/observe/spec-evidence.js +8 -3
- package/dist/worker/observe/static/operator-chrome.d.ts +0 -1
- package/dist/worker/observe/static/operator-chrome.js +3 -10
- package/dist/worker/observe/static/views/dag-inspector.js +71 -6
- package/dist/worker/observe/static/views/dag.js +0 -12
- package/dist/worker/preflight.js +1 -2
- package/dist/workflows/dag/backend-test-case-coverage-analysis.js +707 -37
- package/dist/workflows/dag/backend-test-case-manifest.js +4 -0
- package/dist/workflows/dag/backend-test-markdown-workflow.js +109 -7
- package/dist/workflows/dag/backend-test-module-stem.js +5 -0
- package/dist/workflows/dag/backend-test-pytest-collection.js +345 -24
- package/dist/workflows/dag/backend-test-scenario-param.js +890 -164
- package/dist/workflows/dag/backend-test-writer-completeness.js +47 -16
- package/dist/workflows/dag/dynamic-runtime/map.js +24 -8
- package/dist/workflows/dag/dynamic-runtime/shared.js +1 -9
- package/dist/workflows/dag/frontend-implementation-contract.js +39 -233
- package/dist/workflows/dag/frontend-prewrite-gate.js +61 -364
- package/dist/workflows/dag/frontend-repair.js +18 -219
- package/dist/workflows/dag/frontend-verification-trace.js +32 -47
- package/dist/workflows/dag/init-hybrid.js +82 -165
- package/dist/workflows/dag/node-execution.js +0 -89
- package/dist/workflows/dag/recovery-recommendation.js +0 -58
- package/dist/workflows/dag/runner.js +15 -333
- package/dist/workflows/dag/scheduler.js +3 -257
- package/dist/workflows/dag/types.js +9 -130
- package/docs/README.md +3 -3
- package/docs/architecture/evolution.md +67 -102
- package/docs/templates/backend-test-dag.json +50 -32
- package/docs/templates/init-managed-agents.md +2 -5
- package/harness.json +2 -2
- package/package.json +3 -9
- package/skills/loop-agent/SKILL.md +0 -1
- package/skills/loop-agent/references/command-reference.md +0 -4
- package/dist/build-stamp.json +0 -6
- package/dist/commands/dag-request-interrupt.js +0 -20
- package/dist/worker/console/chat/assistant-content.js +0 -121
- package/dist/worker/console/chat/semantic-activity.js +0 -477
- package/dist/worker/console/operation-run-facts.js +0 -190
- package/dist/worker/console/operation-wait.js +0 -355
- package/dist/worker/console/recovery-error-copy.js +0 -198
- package/dist/worker/console/static/assets/abnfDiagram-N423BO3Z-DSvF6RXQ.js +0 -1
- package/dist/worker/console/static/assets/arc-DuI4ogtJ.js +0 -1
- package/dist/worker/console/static/assets/architectureDiagram-T3A2C74G-DdBbgD4y.js +0 -36
- package/dist/worker/console/static/assets/blockDiagram-VBNYF7ZC-xQC2HELm.js +0 -132
- package/dist/worker/console/static/assets/c4Diagram-5PPSVZJV-DPMSgwIZ.js +0 -10
- package/dist/worker/console/static/assets/channel-DLVz9TYW.js +0 -1
- package/dist/worker/console/static/assets/chunk-2GRJ4B5K-WTEKTxin.js +0 -1
- package/dist/worker/console/static/assets/chunk-2Q5K7J3B-B6vZ0Pv_.js +0 -1
- package/dist/worker/console/static/assets/chunk-5RXB4S5H-BrerNAix.js +0 -231
- package/dist/worker/console/static/assets/chunk-5VM5RSS4-D_ch2aaI.js +0 -15
- package/dist/worker/console/static/assets/chunk-6Q2QTUOP-VvfacNrq.js +0 -88
- package/dist/worker/console/static/assets/chunk-GF5L2VYU-B-uGFIg2.js +0 -206
- package/dist/worker/console/static/assets/chunk-JWPE2WC7-BlysCtod.js +0 -1
- package/dist/worker/console/static/assets/chunk-KBJHAD2P-BjAUAfcT.js +0 -1
- package/dist/worker/console/static/assets/chunk-RYQCIY6F-BeZnBmb-.js +0 -1
- package/dist/worker/console/static/assets/chunk-XXDRQBXY-Bbfe3UJG.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-BeAuGcO9.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-BeAuGcO9.js +0 -1
- package/dist/worker/console/static/assets/cose-bilkent-JH36ORCC-BKJQnYVM.js +0 -1
- package/dist/worker/console/static/assets/cynefin-VYW2F7L2-B1wtI3hU.js +0 -166
- package/dist/worker/console/static/assets/cynefinDiagram-MW4NZA55-DCF6DBSu.js +0 -62
- package/dist/worker/console/static/assets/cytoscape.esm-yzknjiTM.js +0 -321
- package/dist/worker/console/static/assets/dagre-VZM6K2ZE-BJyNGRlP.js +0 -4
- package/dist/worker/console/static/assets/defaultLocale-DX6XiGOO.js +0 -1
- package/dist/worker/console/static/assets/diagram-7IWD3JNH-B7j1-VsZ.js +0 -30
- package/dist/worker/console/static/assets/diagram-B4RE2ZJO-BREJ140a.js +0 -3
- package/dist/worker/console/static/assets/diagram-LBJQPF4R-CDPHmHGH.js +0 -24
- package/dist/worker/console/static/assets/diagram-Q27KOJAE-BtZLrez1.js +0 -24
- package/dist/worker/console/static/assets/diagram-UB23O5K3-mzybu8oU.js +0 -41
- package/dist/worker/console/static/assets/ebnfDiagram-BXEA7PRR-Dk3I2uO6.js +0 -1
- package/dist/worker/console/static/assets/erDiagram-JOGREHBK-BT97u_tQ.js +0 -85
- package/dist/worker/console/static/assets/flowDiagram-UKHOOZJN-CMOtYzui.js +0 -156
- package/dist/worker/console/static/assets/ganttDiagram-PKOTCBZU-DiNydkuY.js +0 -292
- package/dist/worker/console/static/assets/gitGraphDiagram-DS77QQ5N-Cwt6fLkl.js +0 -106
- package/dist/worker/console/static/assets/graph-DOmOIIwC.js +0 -1
- package/dist/worker/console/static/assets/index-DQxiso1w.js +0 -325
- package/dist/worker/console/static/assets/index-_j0Hzo69.css +0 -1
- package/dist/worker/console/static/assets/infoDiagram-6WML65LV-AsGIGKKB.js +0 -2
- package/dist/worker/console/static/assets/init-Gi6I4Gst.js +0 -1
- package/dist/worker/console/static/assets/ishikawaDiagram-WSZJBQD7-BL8ITZh3.js +0 -70
- package/dist/worker/console/static/assets/journeyDiagram-NVQOT4AX-VPKAUX8M.js +0 -139
- package/dist/worker/console/static/assets/kanban-definition-27J2QSJJ-BL56hfGp.js +0 -89
- package/dist/worker/console/static/assets/layout-D-LzfAck.js +0 -1
- package/dist/worker/console/static/assets/linear-BmSG3nIZ.js +0 -1
- package/dist/worker/console/static/assets/map-DxJ2ADlA.js +0 -1
- package/dist/worker/console/static/assets/mermaid.core-DWGK9kwP.js +0 -308
- package/dist/worker/console/static/assets/mindmap-definition-FAOFIHXS--vvKLjo0.js +0 -96
- package/dist/worker/console/static/assets/ordinal-Cboi1Yqb.js +0 -1
- package/dist/worker/console/static/assets/pegDiagram-VL7TDLO6-B41mxb2-.js +0 -1
- package/dist/worker/console/static/assets/pieDiagram-7S7Q4E2Y-DTlu77sw.js +0 -39
- package/dist/worker/console/static/assets/quadrantDiagram-CIZ2JOQS-Bk5A7alv.js +0 -7
- package/dist/worker/console/static/assets/railroadDiagram-AXF67PYL-Csf9jzQy.js +0 -1
- package/dist/worker/console/static/assets/requirementDiagram-LRYGKXZP-CeptoSNx.js +0 -84
- package/dist/worker/console/static/assets/sankeyDiagram-W5VNT64P-A-DLCLer.js +0 -40
- package/dist/worker/console/static/assets/sequenceDiagram-SI44F4Z6-22VbPdOI.js +0 -162
- package/dist/worker/console/static/assets/sizeCapture-X5ZJPWSS-DWvAyBC9.js +0 -1
- package/dist/worker/console/static/assets/stateDiagram-OKZ733FA-qICZ75yT.js +0 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-DzKvfHTX.js +0 -1
- package/dist/worker/console/static/assets/swimlanes-SLNWSIFB-xi7lcMyp.js +0 -2
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-Cxqr_qM1.js +0 -8
- package/dist/worker/console/static/assets/timeline-definition-Z64GVDOM-Bu6Nl6O2.js +0 -120
- package/dist/worker/console/static/assets/vennDiagram-T6HMQDX7-BzMz4Bn9.js +0 -34
- package/dist/worker/console/static/assets/wardleyDiagram-T6FBY63Y-CxaJnzc5.js +0 -78
- package/dist/worker/console/static/assets/xychartDiagram-ELKLHX3M-5JK-omQK.js +0 -7
- package/dist/worker/console/static/fonts/katex/KaTeX_AMS-Regular.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Caligraphic-Bold.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Caligraphic-Regular.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Fraktur-Bold.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Fraktur-Regular.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Main-Bold.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Main-BoldItalic.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Main-Italic.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Main-Regular.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Math-BoldItalic.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Math-Italic.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_SansSerif-Bold.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_SansSerif-Italic.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_SansSerif-Regular.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Script-Regular.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Size1-Regular.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Size2-Regular.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Size3-Regular.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Size4-Regular.woff2 +0 -0
- package/dist/worker/console/static/fonts/katex/KaTeX_Typewriter-Regular.woff2 +0 -0
- package/dist/worker/console/static-src/operator-chat/activity-journey.js +0 -125
- package/dist/worker/console/static-src/operator-chat/activity-rail-presentation.js +0 -73
- package/dist/worker/console/static-src/operator-chat/activity-references.js +0 -20
- package/dist/worker/console/static-src/operator-chat/slash-palette-layout.js +0 -24
- package/dist/worker/console/static-src/operator-chat/slash-palette-nav.js +0 -141
- package/dist/worker/console/static-src/operator-chat/useActivityRailTransition.js +0 -59
- package/dist/worker/observability/interrupt-eligibility.js +0 -264
- package/dist/workflows/dag/contract-output-registry.js +0 -14
- package/dist/workflows/dag/contract-validator-registrations.js +0 -8
- package/dist/workflows/dag/frontend-recovery-plan.js +0 -73
- package/dist/workflows/dag/frontend-recovery-root-manifest.js +0 -123
- package/dist/workflows/dag/frontend-recovery-run.js +0 -539
- package/dist/workflows/dag/frontend-writer-recovery.js +0 -106
- package/dist/workflows/dag/frontend-writer-rollback.js +0 -821
- package/dist/workflows/dag/interrupt-request.js +0 -559
|
@@ -13,13 +13,6 @@ const CONTROLLER_PROTOCOL_CAPABILITIES = [
|
|
|
13
13
|
"worker-attempt-revision-v1",
|
|
14
14
|
"recovery-decision-v2",
|
|
15
15
|
];
|
|
16
|
-
function officialModelCallable(coverage, kind) {
|
|
17
|
-
if (coverage === "human-gated-required")
|
|
18
|
-
return "prepare-only";
|
|
19
|
-
if (coverage === "advanced" && kind !== "read")
|
|
20
|
-
return "never";
|
|
21
|
-
return "always";
|
|
22
|
-
}
|
|
23
16
|
const officialAction = (action, cli, kind, coverage) => ({
|
|
24
17
|
action,
|
|
25
18
|
cli,
|
|
@@ -58,7 +51,11 @@ const officialAction = (action, cli, kind, coverage) => ({
|
|
|
58
51
|
]
|
|
59
52
|
: []),
|
|
60
53
|
],
|
|
61
|
-
modelCallable:
|
|
54
|
+
modelCallable: coverage === "human-gated-required"
|
|
55
|
+
? "prepare-only"
|
|
56
|
+
: coverage === "advanced" && kind !== "read"
|
|
57
|
+
? "never"
|
|
58
|
+
: "always",
|
|
62
59
|
humanConfirmation: coverage === "human-gated-required" ? "required" : "none",
|
|
63
60
|
});
|
|
64
61
|
const OFFICIAL_ACTIONS = [
|
|
@@ -145,13 +142,13 @@ const OFFICIAL_ACTIONS = [
|
|
|
145
142
|
["stats", "loop-agent stats", "read", "model-callable"],
|
|
146
143
|
[
|
|
147
144
|
"promoteRun",
|
|
148
|
-
"loop-agent task advance",
|
|
145
|
+
"loop-agent task advance <id> --json",
|
|
149
146
|
"mutation",
|
|
150
147
|
"model-callable",
|
|
151
148
|
],
|
|
152
149
|
[
|
|
153
150
|
"closeoutTask",
|
|
154
|
-
"loop-agent task advance",
|
|
151
|
+
"loop-agent task advance <id> --json",
|
|
155
152
|
"mutation",
|
|
156
153
|
"model-callable",
|
|
157
154
|
],
|
|
@@ -448,49 +445,6 @@ export function buildOperatorCapabilitiesDocument() {
|
|
|
448
445
|
modelCallable: "always",
|
|
449
446
|
humanConfirmation: "none",
|
|
450
447
|
},
|
|
451
|
-
{
|
|
452
|
-
action: "operationWait",
|
|
453
|
-
cli: "console canonical operation wait (read-only event-driven long poll)",
|
|
454
|
-
kind: "read",
|
|
455
|
-
inputSchemaVersion: 1,
|
|
456
|
-
resultSchemaVersion: 1,
|
|
457
|
-
resultPolicy: { readOnly: true, bounded: true, redacted: true },
|
|
458
|
-
envelopeSchemaVersion: 1,
|
|
459
|
-
requiredErrorCodes: [
|
|
460
|
-
"NOT_FOUND",
|
|
461
|
-
"INVALID_INPUT",
|
|
462
|
-
"EVENT_CURSOR_EXPIRED",
|
|
463
|
-
],
|
|
464
|
-
description: "Read-only event-driven wait on the canonical operation event ring. Default wakeOn=meaningful: heartbeats never settle the wait and are never returned as event payload (nextSeq still covers them); state/result/stdout/stderr/reconcile/error settle immediately; terminal or needs-reconcile flushes immediately. Every subsequent wait MUST pass afterSeq equal to the previous response nextSeq; omitting or reusing an older cursor replays already-consumed startup events. The response includes recommendedNextCall with the safe cursor. wakeOn=all (diagnostic compatibility) resolves on the first new event including heartbeats. maxWaitMs elapsing returns timedOut:true (a success summary, not a command failure).",
|
|
465
|
-
inputParams: [
|
|
466
|
-
{
|
|
467
|
-
name: "operationId",
|
|
468
|
-
type: "string",
|
|
469
|
-
required: true,
|
|
470
|
-
description: "canonical operation id",
|
|
471
|
-
},
|
|
472
|
-
{
|
|
473
|
-
name: "afterSeq",
|
|
474
|
-
type: "number",
|
|
475
|
-
required: false,
|
|
476
|
-
description: "event cursor; first wait may use 0, every later wait MUST use the previous response nextSeq (>= 0)",
|
|
477
|
-
},
|
|
478
|
-
{
|
|
479
|
-
name: "maxWaitMs",
|
|
480
|
-
type: "number",
|
|
481
|
-
required: false,
|
|
482
|
-
description: "bounded wait budget; clamped server-side (default 180000, floor 60000)",
|
|
483
|
-
},
|
|
484
|
-
{
|
|
485
|
-
name: "wakeOn",
|
|
486
|
-
type: "string",
|
|
487
|
-
required: false,
|
|
488
|
-
description: "wake policy: meaningful (default; heartbeats are cursor-only liveness) | all (first event settles, diagnostics)",
|
|
489
|
-
},
|
|
490
|
-
],
|
|
491
|
-
modelCallable: "always",
|
|
492
|
-
humanConfirmation: "none",
|
|
493
|
-
},
|
|
494
448
|
{
|
|
495
449
|
action: "contractShow",
|
|
496
450
|
cli: "loop-agent task status <taskId> --json",
|
|
@@ -942,74 +896,6 @@ export function buildOperatorCapabilitiesDocument() {
|
|
|
942
896
|
modelCallable: "always",
|
|
943
897
|
humanConfirmation: "none",
|
|
944
898
|
},
|
|
945
|
-
{
|
|
946
|
-
action: "taskAdvance",
|
|
947
|
-
cli: "loop-agent task advance <taskId> [title] --task-kind <kind> --allowed-path <glob> --forbidden-path <glob> --verify <label:command> --json",
|
|
948
|
-
kind: "long-running",
|
|
949
|
-
inputSchemaVersion: 1,
|
|
950
|
-
resultSchemaVersion: 1,
|
|
951
|
-
envelopeSchemaVersion: 1,
|
|
952
|
-
requiredErrorCodes: [
|
|
953
|
-
...COMMON_MUTATION_ERRORS,
|
|
954
|
-
"INVALID_INPUT",
|
|
955
|
-
],
|
|
956
|
-
description: "Canonical typed task advance mutation. Use after task creation/PRD import to apply explicit taskKind and engineering boundaries, generate + strict-validate the DAG, and stop at the writeSet gate. Never pass placeholder ids such as <id>. A successful child process may still return a blocked business outcome; inspect lifecycleState, blockers, gate, and next.",
|
|
957
|
-
inputParams: [
|
|
958
|
-
{
|
|
959
|
-
name: "taskId",
|
|
960
|
-
type: "string",
|
|
961
|
-
required: true,
|
|
962
|
-
description: "canonical YYYY-MM-DD-<slug> task id; placeholders are rejected",
|
|
963
|
-
},
|
|
964
|
-
{
|
|
965
|
-
name: "title",
|
|
966
|
-
type: "string",
|
|
967
|
-
required: false,
|
|
968
|
-
description: "optional task title for create/first advance",
|
|
969
|
-
},
|
|
970
|
-
{
|
|
971
|
-
name: "taskKind",
|
|
972
|
-
type: "string",
|
|
973
|
-
required: false,
|
|
974
|
-
description: "business DAG template; ordinary fixes/docs use standard",
|
|
975
|
-
},
|
|
976
|
-
{
|
|
977
|
-
name: "featureId",
|
|
978
|
-
type: "string",
|
|
979
|
-
required: false,
|
|
980
|
-
description: "required only by feature-scoped task kinds such as knowledge-sync",
|
|
981
|
-
},
|
|
982
|
-
{
|
|
983
|
-
name: "profile",
|
|
984
|
-
type: "string",
|
|
985
|
-
required: false,
|
|
986
|
-
description: "governance profile auto|minimal|standard|reviewed|supervised",
|
|
987
|
-
},
|
|
988
|
-
{
|
|
989
|
-
name: "allowedPaths",
|
|
990
|
-
type: "array",
|
|
991
|
-
itemsType: "string",
|
|
992
|
-
required: false,
|
|
993
|
-
description: "explicit writer boundary globs",
|
|
994
|
-
},
|
|
995
|
-
{
|
|
996
|
-
name: "forbiddenPaths",
|
|
997
|
-
type: "array",
|
|
998
|
-
itemsType: "string",
|
|
999
|
-
required: false,
|
|
1000
|
-
description: "explicit forbidden path globs",
|
|
1001
|
-
},
|
|
1002
|
-
{
|
|
1003
|
-
name: "verifyCommands",
|
|
1004
|
-
type: "array",
|
|
1005
|
-
itemsType: "string",
|
|
1006
|
-
required: false,
|
|
1007
|
-
description: "verification entries as label:command strings",
|
|
1008
|
-
},
|
|
1009
|
-
],
|
|
1010
|
-
modelCallable: "always",
|
|
1011
|
-
humanConfirmation: "none",
|
|
1012
|
-
},
|
|
1013
899
|
{
|
|
1014
900
|
action: "dagRunTask",
|
|
1015
901
|
cli: "loop-agent task advance <taskId> --profile auto --dag-output <path> --json",
|
|
@@ -1079,7 +965,7 @@ export function buildOperatorCapabilitiesDocument() {
|
|
|
1079
965
|
"CONTROLLER_MISMATCH",
|
|
1080
966
|
"INVALID_INPUT",
|
|
1081
967
|
],
|
|
1082
|
-
description: "Consume a single-use execution receipt and execute the reviewed DAG (prefer task advance --approve-gate when gate token present). accepted/queued/running/operationId are NOT completion — supervise via operationGet/status/dagReport/dagDoctor
|
|
968
|
+
description: "Consume a single-use execution receipt and execute the reviewed DAG (prefer task advance --approve-gate when gate token present). accepted/queued/running/operationId are NOT completion — supervise via operationGet/status/dagReport/dagDoctor.",
|
|
1083
969
|
inputParams: [
|
|
1084
970
|
{
|
|
1085
971
|
name: "executionId",
|
|
@@ -1102,7 +988,7 @@ export function buildOperatorCapabilitiesDocument() {
|
|
|
1102
988
|
resultSchemaVersion: 1,
|
|
1103
989
|
envelopeSchemaVersion: 1,
|
|
1104
990
|
requiredErrorCodes: ["INVALID_INPUT", "NOT_FOUND"],
|
|
1105
|
-
description: "Read-only R1 subgraph plan (no mutation). Call before dagRerun. Prefer primaryFailure.nodeId from dagReport. If eligible=false (writer/decision/fingerprint
|
|
991
|
+
description: "Read-only R1 subgraph plan (no mutation). Call before dagRerun. Prefer primaryFailure.nodeId from dagReport. If eligible=false (writer/decision/fingerprint), do not force execute — fall back to standaloneTaskRerun or same-task advance. Returns planHash required by execute.",
|
|
1106
992
|
inputParams: [
|
|
1107
993
|
{
|
|
1108
994
|
name: "runId",
|
|
@@ -1165,73 +1051,6 @@ export function buildOperatorCapabilitiesDocument() {
|
|
|
1165
1051
|
modelCallable: "always",
|
|
1166
1052
|
humanConfirmation: "none",
|
|
1167
1053
|
},
|
|
1168
|
-
{
|
|
1169
|
-
action: "dagInterruptEligibility",
|
|
1170
|
-
cli: "console dag-interrupt-eligibility",
|
|
1171
|
-
kind: "read",
|
|
1172
|
-
inputSchemaVersion: 1,
|
|
1173
|
-
resultSchemaVersion: 1,
|
|
1174
|
-
envelopeSchemaVersion: 1,
|
|
1175
|
-
requiredErrorCodes: ["INVALID_INPUT", "NOT_FOUND"],
|
|
1176
|
-
description: "Read-only eligibility for cooperative live-DAG interrupt. v1 only Console-owned active running operations. Worker-managed / unknown owner / orphaned / terminal runs return eligible=false with stable reasonCodes. Does not create a Human Gate receipt or mutate the run.",
|
|
1177
|
-
inputParams: [
|
|
1178
|
-
{
|
|
1179
|
-
name: "runId",
|
|
1180
|
-
type: "string",
|
|
1181
|
-
required: true,
|
|
1182
|
-
description: "active dag run id to inspect for interrupt eligibility",
|
|
1183
|
-
},
|
|
1184
|
-
],
|
|
1185
|
-
modelCallable: "always",
|
|
1186
|
-
humanConfirmation: "none",
|
|
1187
|
-
},
|
|
1188
|
-
{
|
|
1189
|
-
action: "dagRequestInterrupt",
|
|
1190
|
-
cli: "loop-agent dag request-interrupt --run-id <id> --request-id <id> --target-operation-id <id> --reason-code <code> --reason <detail> --json",
|
|
1191
|
-
kind: "mutation",
|
|
1192
|
-
inputSchemaVersion: 1,
|
|
1193
|
-
resultSchemaVersion: 1,
|
|
1194
|
-
envelopeSchemaVersion: 1,
|
|
1195
|
-
requiredErrorCodes: [
|
|
1196
|
-
...COMMON_MUTATION_ERRORS,
|
|
1197
|
-
"HUMAN_CONFIRMATION_REQUIRED",
|
|
1198
|
-
"RUN_NOT_ACTIVE",
|
|
1199
|
-
"RUN_NOT_CONSOLE_OWNED",
|
|
1200
|
-
"RUNNER_IDENTITY_MISMATCH",
|
|
1201
|
-
"INTERRUPT_ALREADY_PENDING",
|
|
1202
|
-
"RUN_ALREADY_TERMINAL",
|
|
1203
|
-
"INTERRUPT_NEEDS_RECONCILE",
|
|
1204
|
-
],
|
|
1205
|
-
description: "Request cooperative abort of a Console-owned running DAG. Success means interrupt.json is requested, not that the run has already stopped. Browser Human Gate only; model must not call this action.",
|
|
1206
|
-
inputParams: [
|
|
1207
|
-
{
|
|
1208
|
-
name: "runId",
|
|
1209
|
-
type: "string",
|
|
1210
|
-
required: true,
|
|
1211
|
-
description: "active dag run id",
|
|
1212
|
-
},
|
|
1213
|
-
{
|
|
1214
|
-
name: "reasonCode",
|
|
1215
|
-
type: "string",
|
|
1216
|
-
required: true,
|
|
1217
|
-
description: "requirements-changed | suspected-runaway | resource-protection | operator-request | other",
|
|
1218
|
-
},
|
|
1219
|
-
{
|
|
1220
|
-
name: "reasonDetail",
|
|
1221
|
-
type: "string",
|
|
1222
|
-
required: true,
|
|
1223
|
-
description: "10–500 character operator reason; do not auto-fill placeholders",
|
|
1224
|
-
},
|
|
1225
|
-
{
|
|
1226
|
-
name: "confirmationId",
|
|
1227
|
-
type: "string",
|
|
1228
|
-
required: true,
|
|
1229
|
-
description: "human confirmation receipt id from prepareMutationGate",
|
|
1230
|
-
},
|
|
1231
|
-
],
|
|
1232
|
-
modelCallable: "prepare-only",
|
|
1233
|
-
humanConfirmation: "required",
|
|
1234
|
-
},
|
|
1235
1054
|
{
|
|
1236
1055
|
action: "prepareMutationGate",
|
|
1237
1056
|
cli: "console prepare-mutation-gate",
|
|
@@ -1240,13 +1059,13 @@ export function buildOperatorCapabilitiesDocument() {
|
|
|
1240
1059
|
resultSchemaVersion: 1,
|
|
1241
1060
|
envelopeSchemaVersion: 1,
|
|
1242
1061
|
requiredErrorCodes: ["INVALID_INPUT", "NOT_FOUND"],
|
|
1243
|
-
description: "Prepare a one-shot Human Gate receipt for
|
|
1062
|
+
description: "Prepare a one-shot Human Gate receipt for Night Scheduler mutations. Model may prepare; only the browser mutation gate may consume.",
|
|
1244
1063
|
inputParams: [
|
|
1245
1064
|
{
|
|
1246
1065
|
name: "action",
|
|
1247
1066
|
type: "string",
|
|
1248
1067
|
required: true,
|
|
1249
|
-
description: "target action:
|
|
1068
|
+
description: "target action: workerAdmissionPrepare | workerSchedulerAdd | workerSchedulerCancel | workerSchedulerHarvest | workerSchedulerDiscard",
|
|
1250
1069
|
},
|
|
1251
1070
|
{
|
|
1252
1071
|
name: "actionParams",
|
|
@@ -1498,7 +1317,7 @@ export function buildOperatorCapabilitiesDocument() {
|
|
|
1498
1317
|
"INVALID_INPUT",
|
|
1499
1318
|
"HUMAN_CONFIRMATION_REQUIRED",
|
|
1500
1319
|
],
|
|
1501
|
-
description: "Full standalone task regenerate → validate → execute with parent lineage. Only when node rerun plan is ineligible or primaryRecovery recommends rerun-task; the server checks read-only run facts before accepting.
|
|
1320
|
+
description: "Full standalone task regenerate → validate → execute with parent lineage. Only when node rerun plan is ineligible or primaryRecovery recommends rerun-task; the server checks read-only run facts before accepting.",
|
|
1502
1321
|
inputParams: [
|
|
1503
1322
|
{
|
|
1504
1323
|
name: "runId",
|
|
@@ -1619,7 +1438,7 @@ export const OPERATOR_COMMAND_COVERAGE = Object.freeze([
|
|
|
1619
1438
|
{
|
|
1620
1439
|
command: "loop-agent task advance",
|
|
1621
1440
|
coverage: "model-callable",
|
|
1622
|
-
action: "
|
|
1441
|
+
action: "newTask",
|
|
1623
1442
|
source: "loop-agent",
|
|
1624
1443
|
},
|
|
1625
1444
|
{
|
|
@@ -2059,12 +1878,6 @@ export const OPERATOR_COMMAND_COVERAGE = Object.freeze([
|
|
|
2059
1878
|
action: "dagReconcileRun",
|
|
2060
1879
|
source: "loop-agent",
|
|
2061
1880
|
},
|
|
2062
|
-
{
|
|
2063
|
-
command: "loop-agent dag request-interrupt",
|
|
2064
|
-
coverage: "human-gated-required",
|
|
2065
|
-
action: "dagRequestInterrupt",
|
|
2066
|
-
source: "loop-agent",
|
|
2067
|
-
},
|
|
2068
1881
|
{
|
|
2069
1882
|
command: "loop-agent dag rerun",
|
|
2070
1883
|
coverage: "model-callable",
|
|
@@ -45,48 +45,6 @@ export function readPackageName(packageDir) {
|
|
|
45
45
|
}
|
|
46
46
|
return undefined;
|
|
47
47
|
}
|
|
48
|
-
/**
|
|
49
|
-
* Read the build stamp (git SHA + build time) written by the build pipeline
|
|
50
|
-
* into `<packageDir>/dist/build-stamp.json`. `undefined` when absent (e.g.
|
|
51
|
-
* running from source via tsx, or a hand-assembled package), which callers
|
|
52
|
-
* treat as "no stamp available".
|
|
53
|
-
*/
|
|
54
|
-
export function readBuildStamp(packageDir) {
|
|
55
|
-
try {
|
|
56
|
-
const raw = readFileSync(path.join(packageDir, "dist", "build-stamp.json"), "utf-8");
|
|
57
|
-
const parsed = JSON.parse(raw);
|
|
58
|
-
if (parsed.schemaVersion !== 1 ||
|
|
59
|
-
typeof parsed.version !== "string" ||
|
|
60
|
-
typeof parsed.builtAt !== "string")
|
|
61
|
-
return undefined;
|
|
62
|
-
return parsed;
|
|
63
|
-
}
|
|
64
|
-
catch {
|
|
65
|
-
return undefined;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Human-readable CLI version label: plain version, enriched with the build
|
|
70
|
-
* stamp (short git SHA + build date) when available so a stale dist/ that was
|
|
71
|
-
* built from an old commit is immediately recognizable in `--version`.
|
|
72
|
-
*/
|
|
73
|
-
export function readCliVersionLabel(packageDir) {
|
|
74
|
-
const version = readPackageVersion(packageDir) ?? "0.0.0";
|
|
75
|
-
const stamp = readBuildStamp(packageDir);
|
|
76
|
-
if (!stamp?.gitSha)
|
|
77
|
-
return version;
|
|
78
|
-
return `${version} (build ${stamp.gitSha.slice(0, 8)} ${stamp.builtAt.slice(0, 10)})`;
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Strip the build-stamp suffix from a CLI `--version` label, returning the bare
|
|
82
|
-
* SemVer. Controller-identity/preflight comparisons must use this rather than
|
|
83
|
-
* the raw label so a build-stamped `0.35.0 (build 7f8c5b5b …)` still matches
|
|
84
|
-
* `packageVersion === "0.35.0"`.
|
|
85
|
-
*/
|
|
86
|
-
export function normalizeCliVersionLabel(label) {
|
|
87
|
-
const match = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?/.exec(label.trim());
|
|
88
|
-
return match ? match[0] : label.trim();
|
|
89
|
-
}
|
|
90
48
|
/**
|
|
91
49
|
* Compute the SHA-256 hash of a file on disk.
|
|
92
50
|
*
|
|
@@ -46,10 +46,6 @@ export function projectRequirementMarkdown(draft) {
|
|
|
46
46
|
lines.push(`- ${item}`);
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
|
-
// References / Source Resolutions remain projected into 需求.md (durable
|
|
50
|
-
// provenance for human readers); the managed read-back validator accepts
|
|
51
|
-
// the projector's own canonical forms instead of rejecting them
|
|
52
|
-
// (2026-08-16 L1: writer/reader round-trip invariant).
|
|
53
49
|
if (draft.sourceResolutions && draft.sourceResolutions.length > 0) {
|
|
54
50
|
lines.push("", "## Source Resolutions", "");
|
|
55
51
|
for (const res of draft.sourceResolutions) {
|
|
@@ -2,13 +2,6 @@ const FRESH_SOURCE_MISSING_CODES = new Set([
|
|
|
2
2
|
"MISSING_REQUIREMENT",
|
|
3
3
|
"MISSING_CONSTRAINTS",
|
|
4
4
|
]);
|
|
5
|
-
function hasKnowledgeSyncFeatureSurface(featureId, allowedPaths) {
|
|
6
|
-
const featureRoot = `features/${featureId}/`;
|
|
7
|
-
return allowedPaths.some((pathGlob) => {
|
|
8
|
-
const normalized = pathGlob.replaceAll("\\", "/").replace(/^\.\//, "");
|
|
9
|
-
return normalized === `features/${featureId}` || normalized.startsWith(featureRoot);
|
|
10
|
-
});
|
|
11
|
-
}
|
|
12
5
|
export function isFreshLegacyUnversioned(state, sourceFilesPresent) {
|
|
13
6
|
if (state.effectiveStatus !== "legacy-unversioned")
|
|
14
7
|
return false;
|
|
@@ -68,15 +61,6 @@ export function listPrepareGaps(input) {
|
|
|
68
61
|
level: "blocking",
|
|
69
62
|
field: "objective",
|
|
70
63
|
message: "requirement.objective is required",
|
|
71
|
-
details: { headingAliases: ["目标", "objective", "业务目标", "需求概述"] },
|
|
72
|
-
selfHealing: {
|
|
73
|
-
action: "reimport-prd",
|
|
74
|
-
steps: [
|
|
75
|
-
"检查 PRD 是否含「## 目标」或「## Objective」章节;中文括号后缀(如「目标(概述)」)已被识别",
|
|
76
|
-
"若确实缺失:补全 PRD 后重新 importPrd(同 taskId),advance 会自动重投影",
|
|
77
|
-
"不要手改 source/需求.md(会触发 DIRTY_SOURCE);不要在 PRD 目录生成 sidecar draft JSON",
|
|
78
|
-
],
|
|
79
|
-
},
|
|
80
64
|
});
|
|
81
65
|
}
|
|
82
66
|
if (draft.requirement.acceptanceCriteria.length === 0) {
|
|
@@ -85,25 +69,6 @@ export function listPrepareGaps(input) {
|
|
|
85
69
|
level: "blocking",
|
|
86
70
|
field: "acceptanceCriteria",
|
|
87
71
|
message: "at least one acceptance criterion is required",
|
|
88
|
-
details: {
|
|
89
|
-
recognizedHeadings: [
|
|
90
|
-
"验收标准",
|
|
91
|
-
"acceptance criteria",
|
|
92
|
-
"完成标准",
|
|
93
|
-
"完成定义",
|
|
94
|
-
"验收",
|
|
95
|
-
"dod",
|
|
96
|
-
],
|
|
97
|
-
note: "标题含括号/破折号后缀会被自动归一;AC 需为列表项(- / 1.)或 AC-NNN 标题/行内格式",
|
|
98
|
-
},
|
|
99
|
-
selfHealing: {
|
|
100
|
-
action: "reimport-prd",
|
|
101
|
-
steps: [
|
|
102
|
-
"检查 PRD 验收章节标题(如「完成标准(验收)」已可识别)与列表格式:需为「- 项目」或「AC-001: 文本」",
|
|
103
|
-
"格式修正后重新 importPrd(同 taskId);advance 内置 semantic intake 兜底,文档语义完整时会自动结构化",
|
|
104
|
-
"若 advance 已返回 SEMANTIC_INTAKE_FAILED:补全 PRD 后重试,不要手改 source/ 需求.md",
|
|
105
|
-
],
|
|
106
|
-
},
|
|
107
72
|
});
|
|
108
73
|
}
|
|
109
74
|
if (input.acceptanceConflicts && input.acceptanceConflicts.length > 0) {
|
|
@@ -140,16 +105,6 @@ export function listPrepareGaps(input) {
|
|
|
140
105
|
message: "featureId is required when taskKind is knowledge-sync",
|
|
141
106
|
});
|
|
142
107
|
}
|
|
143
|
-
if (draft.taskKind === "knowledge-sync" &&
|
|
144
|
-
draft.featureId &&
|
|
145
|
-
!hasKnowledgeSyncFeatureSurface(draft.featureId, draft.constraints.allowedPaths)) {
|
|
146
|
-
gaps.push({
|
|
147
|
-
code: "KNOWLEDGE_SYNC_PATH_MISMATCH",
|
|
148
|
-
level: "blocking",
|
|
149
|
-
field: "allowedPaths",
|
|
150
|
-
message: `knowledge-sync for ${draft.featureId} requires an allowed path under features/${draft.featureId}/; ordinary docs-only work should use taskKind standard`,
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
108
|
if (draft.requirement.scope.length === 0) {
|
|
154
109
|
gaps.push({
|
|
155
110
|
code: "EMPTY_SCOPE",
|
|
@@ -216,14 +171,6 @@ export function listPrepareGaps(input) {
|
|
|
216
171
|
code: "DIRTY_SOURCE",
|
|
217
172
|
level: "blocking",
|
|
218
173
|
message: "existing non-empty or externally-modified source refuses --apply; use show/diff/adopt/recover or --force-overwrite-source",
|
|
219
|
-
selfHealing: {
|
|
220
|
-
action: "adopt-contract",
|
|
221
|
-
steps: [
|
|
222
|
-
"task status --json 读取 contract.observedCanonicalHash 与当前 revision",
|
|
223
|
-
"若变更确属预期:task contract adopt --task <id> --expected-revision <n> --expected-observed-hash <hash> --request-id <id> --request-payload-sha256 <sha>",
|
|
224
|
-
"若变更不是预期的:改 PRD 后重新 importPrd 走完整重投影;禁止手改 lifecycle.json / .transactions/ 绕过",
|
|
225
|
-
],
|
|
226
|
-
},
|
|
227
174
|
});
|
|
228
175
|
risks.push({
|
|
229
176
|
code: "DIRTY_SOURCE",
|
|
@@ -15,21 +15,7 @@ const HEADING_ALIASES = {
|
|
|
15
15
|
"已确认需求",
|
|
16
16
|
]),
|
|
17
17
|
nonGoals: new Set(["非目标", "out of scope", "non-goals", "non goals"]),
|
|
18
|
-
acceptance: new Set([
|
|
19
|
-
"验收标准",
|
|
20
|
-
"acceptance criteria",
|
|
21
|
-
"acceptance",
|
|
22
|
-
// Common zh-CN product-writing variants seen in real PRDs; without
|
|
23
|
-
// these a PRD re-import flips to deterministic parse and loses all AC
|
|
24
|
-
// (EMPTY_ACCEPTANCE deadlock on the pendingPrdRefresh path).
|
|
25
|
-
"完成定义",
|
|
26
|
-
"完成标准",
|
|
27
|
-
"验收",
|
|
28
|
-
"验收条件",
|
|
29
|
-
"验收准则",
|
|
30
|
-
"dod",
|
|
31
|
-
"definition of done",
|
|
32
|
-
]),
|
|
18
|
+
acceptance: new Set(["验收标准", "acceptance criteria", "acceptance"]),
|
|
33
19
|
constraints: new Set(["约束", "constraints", "不变式", "invariants"]),
|
|
34
20
|
openQuestions: new Set(["待决问题", "open questions", "open-questions"]),
|
|
35
21
|
assumptions: new Set(["假设", "assumptions"]),
|
|
@@ -44,6 +30,15 @@ function stripFencedAndComments(text) {
|
|
|
44
30
|
.replace(/~~~[\s\S]*?~~~/g, "\n")
|
|
45
31
|
.replace(/<!--[\s\S]*?-->/g, "\n");
|
|
46
32
|
}
|
|
33
|
+
function normalizeHeadingText(raw) {
|
|
34
|
+
return raw
|
|
35
|
+
.trim()
|
|
36
|
+
// Strip leading section numbers: "2. 业务目标" / "3.1 已确认范围" / "3.2、非目标"
|
|
37
|
+
.replace(/^(?:\d+(?:\.\d+)*[..、]?\s*)+/u, "")
|
|
38
|
+
.toLowerCase()
|
|
39
|
+
.replace(/[::]\s*$/u, "")
|
|
40
|
+
.replace(/\s+/g, " ");
|
|
41
|
+
}
|
|
47
42
|
function normalizeAcceptanceId(raw) {
|
|
48
43
|
return raw
|
|
49
44
|
.trim()
|
|
@@ -60,67 +55,12 @@ function parseEmbeddedAcHeading(headingText) {
|
|
|
60
55
|
const text = match[2]?.trim() || id;
|
|
61
56
|
return { id, text };
|
|
62
57
|
}
|
|
63
|
-
function normalizeHeadingText(raw) {
|
|
64
|
-
return raw
|
|
65
|
-
.trim()
|
|
66
|
-
// Strip leading section numbers: "2. 业务目标" / "3.1 已确认范围" / "3.2、非目标"
|
|
67
|
-
.replace(/^(?:\d+(?:\.\d+)*[..、]?\s*)+/u, "")
|
|
68
|
-
.toLowerCase()
|
|
69
|
-
.replace(/[::]\s*$/u, "")
|
|
70
|
-
.replace(/\s+/g, " ");
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* Strip decorative suffixes that real PRD writers attach to section
|
|
74
|
-
* headings: "完成标准(验收)" → "完成标准", "Acceptance Criteria (DoD):" →
|
|
75
|
-
* "acceptance criteria", "验收标准 — 交付门槛" → "验收标准". Handles zh/en
|
|
76
|
-
* parens, dashes, colons and trailing separators before the suffix.
|
|
77
|
-
*/
|
|
78
|
-
function stripHeadingDecorations(normalized) {
|
|
79
|
-
return normalized
|
|
80
|
-
.replace(/[((][^(())]*[))]\s*$/u, "")
|
|
81
|
-
.replace(/\s*[—–\-|]\s*[^—–\-|]+$/u, "")
|
|
82
|
-
.replace(/[::]\s*$/u, "")
|
|
83
|
-
.trim();
|
|
84
|
-
}
|
|
85
|
-
const HEADING_PREFIX_HINTS = [
|
|
86
|
-
{ key: "objective", hint: "目标" },
|
|
87
|
-
{ key: "objective", hint: "objective" },
|
|
88
|
-
{ key: "scope", hint: "范围" },
|
|
89
|
-
{ key: "scope", hint: "scope" },
|
|
90
|
-
{ key: "nonGoals", hint: "非目标" },
|
|
91
|
-
{ key: "nonGoals", hint: "out of scope" },
|
|
92
|
-
{ key: "acceptance", hint: "验收" },
|
|
93
|
-
{ key: "acceptance", hint: "acceptance" },
|
|
94
|
-
{ key: "acceptance", hint: "完成标准" },
|
|
95
|
-
{ key: "acceptance", hint: "完成定义" },
|
|
96
|
-
{ key: "acceptance", hint: "dod" },
|
|
97
|
-
{ key: "constraints", hint: "约束" },
|
|
98
|
-
{ key: "constraints", hint: "constraints" },
|
|
99
|
-
{ key: "openQuestions", hint: "待决问题" },
|
|
100
|
-
{ key: "openQuestions", hint: "open questions" },
|
|
101
|
-
{ key: "assumptions", hint: "假设" },
|
|
102
|
-
{ key: "assumptions", hint: "assumptions" },
|
|
103
|
-
];
|
|
104
58
|
function classifyHeading(text) {
|
|
105
59
|
const normalized = normalizeHeadingText(text);
|
|
106
60
|
for (const [key, aliases] of Object.entries(HEADING_ALIASES)) {
|
|
107
61
|
if (aliases.has(normalized))
|
|
108
62
|
return key;
|
|
109
63
|
}
|
|
110
|
-
// Decoration-stripped exact match: "完成标准(验收)" → "完成标准".
|
|
111
|
-
const stripped = stripHeadingDecorations(normalized);
|
|
112
|
-
if (stripped && stripped !== normalized) {
|
|
113
|
-
for (const [key, aliases] of Object.entries(HEADING_ALIASES)) {
|
|
114
|
-
if (aliases.has(stripped))
|
|
115
|
-
return key;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
// Prefix-contains fallback: "验收标准与测试" starts with "验收"; keep the
|
|
119
|
-
// hint list narrow (whole-word/leading-substring) to avoid false hits.
|
|
120
|
-
for (const { key, hint } of HEADING_PREFIX_HINTS) {
|
|
121
|
-
if (stripped === hint || stripped.startsWith(hint))
|
|
122
|
-
return key;
|
|
123
|
-
}
|
|
124
64
|
return "other";
|
|
125
65
|
}
|
|
126
66
|
function isAtxHeading(line) {
|
|
@@ -454,20 +394,10 @@ export function fillMissingRequirementFacts(base, supplemental) {
|
|
|
454
394
|
export function parseVerifyFlag(raw) {
|
|
455
395
|
const idx = raw.indexOf(":");
|
|
456
396
|
if (idx <= 0 || idx === raw.length - 1) {
|
|
457
|
-
|
|
458
|
-
// models were guessing flag names (--verify-label) and separator
|
|
459
|
-
// shapes; the example makes the contract self-evident.
|
|
460
|
-
const hint = !raw.includes(":")
|
|
461
|
-
? `no label separator found; write it as <label>:<command>, e.g. --verify "typecheck:npm run typecheck"`
|
|
462
|
-
: `empty ${idx === 0 ? "label" : "command"}; write it as <label>:<command>, e.g. --verify "typecheck:npm run typecheck"`;
|
|
463
|
-
throw new Error(`invalid --verify value "${raw}"; expected <label>:<command> — ${hint}`);
|
|
464
|
-
}
|
|
465
|
-
const label = raw.slice(0, idx).trim();
|
|
466
|
-
if (!/^[a-z0-9][a-z0-9-]*$/i.test(label)) {
|
|
467
|
-
throw new Error(`invalid --verify label "${label}"; use short kebab-case letters/digits/hyphens (e.g. typecheck, unit-tests, build) — value was "${raw}"`);
|
|
397
|
+
throw new Error(`invalid --verify value "${raw}"; expected <label>:<command>`);
|
|
468
398
|
}
|
|
469
399
|
return {
|
|
470
|
-
label,
|
|
400
|
+
label: raw.slice(0, idx).trim(),
|
|
471
401
|
command: raw.slice(idx + 1).trim(),
|
|
472
402
|
};
|
|
473
403
|
}
|