@cassiomc1/forgeloop 1.12.0 → 1.14.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/.github/copilot-instructions.md +1 -1
- package/AGENTS.md +1 -1
- package/AGENT_COMPATIBILITY.md +8 -0
- package/CLAUDE.md +1 -1
- package/CONTRIBUTING.md +90 -0
- package/DOCS_INDEX.md +46 -12
- package/ENG/c-development-eng.md +112 -0
- package/ENG/cpp-development-eng.md +109 -0
- package/ENG/dotnet-aspnetcore-development-eng.md +401 -0
- package/ENG/go-development-eng.md +103 -0
- package/ENG/java-development-eng.md +125 -0
- package/ENG/nodejs-backend-development-eng.md +605 -0
- package/ENG/php-development-eng.md +104 -0
- package/ENG/rust-development-eng.md +422 -0
- package/ENG/sec-code-eng.md +7 -7
- package/ENG/sql-development-eng.md +108 -0
- package/ENG/swift-development-eng.md +111 -0
- package/ENG/typescript-development-eng.md +108 -0
- package/EXECUTION_STATE.md +12 -0
- package/GUIDE_ROUTER.md +418 -9
- package/LOOP_ENGINEERING.md +28 -2
- package/ORCHESTRATOR_INTEGRATION.md +9 -5
- package/PROTOCOL_INTEGRATION.md +55 -2
- package/QUALITY_SCORECARD.md +1 -0
- package/README.md +78 -52
- package/TERMINOLOGY.md +2 -0
- package/THIRD_PARTY_NOTICES.md +19 -7
- package/THREAT_MODEL.md +140 -1
- package/completions/_forgeloop +22 -4
- package/completions/forgeloop.bash +40 -4
- package/completions/forgeloop.fish +130 -1
- package/docs/ADVISORY_CONTEXT.md +25 -0
- package/docs/AGENT_BROWSER_ADAPTER.md +81 -0
- package/docs/AGENT_BROWSER_VERIFICATION.md +6 -0
- package/docs/AGENT_PROTOCOL_SUMMARY.md +81 -3
- package/docs/AGENT_SKILL.md +66 -0
- package/docs/ARTIFACT_REFERENCE.md +123 -0
- package/docs/AUDIT_UX.md +46 -0
- package/docs/BROWSER_VERIFICATION.md +136 -0
- package/docs/CLI_REFERENCE.md +392 -10
- package/docs/CODE_ATTESTATION.md +2 -2
- package/docs/DOCUMENTATION_GUIDE.md +34 -12
- package/docs/GETTING_STARTED.md +59 -0
- package/docs/JEV_BENCHMARKS.md +31 -0
- package/docs/MODEL_ROUTING.md +37 -0
- package/docs/OPENSRC_ADAPTER.md +241 -0
- package/docs/PACKAGE_CONTENTS.md +60 -19
- package/docs/PROVIDERS.md +126 -0
- package/docs/PROVIDER_ARCHITECTURE.md +199 -0
- package/docs/RECIPES.md +32 -0
- package/docs/RELEASE_CHECKLIST.md +66 -5
- package/docs/SECURITY_REVIEW.md +71 -0
- package/docs/SEMANTIC_DECISION_PLANE.md +71 -0
- package/docs/TEST_INTELLIGENCE.md +29 -0
- package/docs/TEST_PRUNING.md +14 -0
- package/docs/TROUBLESHOOTING.md +298 -3
- package/docs/UNIVERSAL_INTEGRATION.md +31 -0
- package/docs/assets/diagrams/forgeloop-code-attestation-flow.html +2 -2
- package/docs/assets/diagrams/forgeloop-code-attestation-flow.receipt.json +5 -5
- package/docs/assets/diagrams/forgeloop-code-attestation-flow.svg +1 -1
- package/docs/assets/diagrams/forgeloop-engineering-flow.html +39 -26
- package/docs/assets/diagrams/forgeloop-engineering-flow.receipt.json +6 -6
- package/docs/assets/diagrams/forgeloop-engineering-flow.svg +26 -26
- package/docs/assets/diagrams/forgeloop-verification-trust-flow.html +2 -1
- package/docs/assets/diagrams/forgeloop-verification-trust-flow.receipt.json +5 -5
- package/docs/assets/diagrams/forgeloop-verification-trust-flow.svg +1 -1
- package/docs/diagrams/README.md +13 -9
- package/docs/diagrams/forgeloop-code-attestation-flow.workflow.json +1 -1
- package/docs/diagrams/forgeloop-engineering-flow.workflow.json +24 -19
- package/docs/diagrams/forgeloop-verification-trust-flow.workflow.json +1 -0
- package/docs/diagrams/reviews/forgeloop-code-attestation-flow.review.json +4 -4
- package/docs/diagrams/reviews/forgeloop-engineering-flow.review.json +4 -4
- package/docs/diagrams/reviews/forgeloop-verification-trust-flow.review.json +4 -4
- package/docs/documentation-manifest.json +1397 -0
- package/docs/protocol-requirements.json +101 -0
- package/package.json +46 -4
- package/schemas/config.schema.json +14 -0
- package/schemas/context-plan.schema.json +18 -0
- package/schemas/routing-input.schema.json +1 -1
- package/schemas/semantic-decision.schema.json +46 -0
- package/schemas/test-utility.schema.json +44 -0
- package/scripts/CI_VALIDATORS.md +84 -11
- package/scripts/benchmark-jev.mjs +5 -0
- package/scripts/benchmark-test-intelligence.mjs +4 -0
- package/scripts/generate-agent-protocol-summary.mjs +40 -1
- package/scripts/generate-forgeloop-skill.mjs +133 -0
- package/scripts/jev-smoke.mjs +19 -0
- package/skills/forgeloop/README.md +9 -0
- package/skills/forgeloop/SKILL.md +77 -0
- package/skills/forgeloop/references/lifecycle.md +9 -0
- package/skills/forgeloop/references/recovery.md +7 -0
- package/skills/forgeloop/references/verification.md +7 -0
- package/src/adapters/agent-browser/assertions.js +47 -0
- package/src/adapters/agent-browser/commands.js +54 -0
- package/src/adapters/agent-browser/index.js +3 -0
- package/src/adapters/agent-browser/locator.js +40 -0
- package/src/adapters/agent-browser/process.js +215 -0
- package/src/adapters/agent-browser/provider.js +313 -0
- package/src/adapters/emulated-services/constants.js +24 -0
- package/src/adapters/emulated-services/index.js +7 -0
- package/src/adapters/emulated-services/process.js +162 -0
- package/src/adapters/emulated-services/provider.js +282 -0
- package/src/adapters/opensrc/normalize.js +90 -0
- package/src/adapters/opensrc/process.js +248 -0
- package/src/adapters/opensrc/provider.js +338 -0
- package/src/adapters/opensrc/search.js +264 -0
- package/src/adapters/typesafe/client.js +28 -0
- package/src/adapters/typesafe/engine.js +63 -0
- package/src/adapters/typesafe/normalize.js +41 -0
- package/src/cli.js +108 -0
- package/src/commands/checkpoint-revalidate.js +176 -0
- package/src/commands/context-plan.js +38 -0
- package/src/commands/contract-create.js +264 -0
- package/src/commands/contract-revise.js +236 -0
- package/src/commands/decision-show.js +14 -0
- package/src/commands/decision-status.js +22 -0
- package/src/commands/discover.js +41 -0
- package/src/commands/doctor.js +15 -0
- package/src/commands/gate-record.js +205 -0
- package/src/commands/gate-revalidate.js +137 -0
- package/src/commands/model-route.js +32 -0
- package/src/commands/next.js +19 -7
- package/src/commands/route.js +146 -18
- package/src/commands/semantic-plan.js +17 -0
- package/src/commands/task-abandon.js +224 -0
- package/src/commands/task-create.js +84 -25
- package/src/commands/task-list.js +22 -2
- package/src/commands/task-migrate-contract-bootstrap-repair.js +288 -0
- package/src/commands/task-repair-contract-bootstrap.js +263 -0
- package/src/commands/test-inventory.js +5 -0
- package/src/commands/test-prune-plan.js +5 -0
- package/src/commands/test-prune-probe.js +5 -0
- package/src/commands/test-utility.js +5 -0
- package/src/commands/validate-protocol.js +10 -1
- package/src/config/guides.json +44 -0
- package/src/core/artifact-registry.js +24 -0
- package/src/core/audit-ux.js +514 -0
- package/src/core/browser-verification/constants.js +149 -0
- package/src/core/browser-verification/normalize.js +254 -0
- package/src/core/browser-verification/provider.js +519 -0
- package/src/core/browser-verification/service.js +115 -0
- package/src/core/build-script.js +151 -0
- package/src/core/c-cpp-project.js +143 -0
- package/src/core/checkpoint-revalidation.js +319 -0
- package/src/core/cli-command-definitions.js +249 -1
- package/src/core/command-executors.js +115 -3
- package/src/core/command-input.js +212 -102
- package/src/core/completion-artifacts.js +14 -5
- package/src/core/completion.js +4 -6
- package/src/core/config.js +3 -0
- package/src/core/context-compiler/budget.js +9 -0
- package/src/core/context-compiler/candidates.js +39 -0
- package/src/core/context-compiler/compiler.js +63 -0
- package/src/core/context-compiler/fingerprint.js +11 -0
- package/src/core/context-compiler/policy.js +13 -0
- package/src/core/context-compiler/result.js +23 -0
- package/src/core/contract-bootstrap-recovery.js +655 -0
- package/src/core/contract-presets.js +82 -0
- package/src/core/contract-revision.js +210 -0
- package/src/core/decision/artifact.js +69 -0
- package/src/core/decision/benchmarks.js +103 -0
- package/src/core/decision/cache.js +27 -0
- package/src/core/decision/constants.js +58 -0
- package/src/core/decision/cutover.js +34 -0
- package/src/core/decision/engine.js +22 -0
- package/src/core/decision/errors.js +68 -0
- package/src/core/decision/events.js +101 -0
- package/src/core/decision/freshness.js +19 -0
- package/src/core/decision/normalizers/index.js +115 -0
- package/src/core/decision/policy.js +18 -0
- package/src/core/decision/projection.js +16 -0
- package/src/core/decision/question-registry.js +201 -0
- package/src/core/decision/request.js +26 -0
- package/src/core/decision/resolver.js +130 -0
- package/src/core/decision/result.js +58 -0
- package/src/core/decision/service.js +156 -0
- package/src/core/decision/state-builder.js +65 -0
- package/src/core/decision/task-bindings.js +30 -0
- package/src/core/decision/test-provider.js +32 -0
- package/src/core/decision/thresholds.js +15 -0
- package/src/core/error-codes.js +281 -3
- package/src/core/events.js +226 -57
- package/src/core/evidence-readiness.js +9 -0
- package/src/core/execution-prerequisites.js +14 -0
- package/src/core/execution-profile.js +63 -38
- package/src/core/filesystem.js +1 -10
- package/src/core/gate-provenance.js +124 -0
- package/src/core/go-project.js +206 -0
- package/src/core/integration-invocation-policy.js +27 -4
- package/src/core/integration-resources.js +86 -61
- package/src/core/java-project.js +403 -0
- package/src/core/model-router/constants.js +10 -0
- package/src/core/model-router/policy.js +103 -0
- package/src/core/model-router/router.js +37 -0
- package/src/core/multi-language-project.js +117 -0
- package/src/core/next-action-model.js +58 -0
- package/src/core/next-action-phases.js +130 -42
- package/src/core/next-action-refresh.js +43 -9
- package/src/core/next-action-review-phase.js +7 -2
- package/src/core/next-action.js +35 -7
- package/src/core/next-explanation.js +63 -0
- package/src/core/phase.js +128 -10
- package/src/core/php-project.js +85 -0
- package/src/core/preflight-consistency.js +23 -9
- package/src/core/preflight-loaders.js +37 -5
- package/src/core/project-detection.js +1760 -52
- package/src/core/protocol-info.js +65 -0
- package/src/core/protocol.js +20 -0
- package/src/core/reconcile-closure.js +132 -53
- package/src/core/recovery-history.js +1 -0
- package/src/core/resumability.js +154 -44
- package/src/core/route-artifact.js +15 -1
- package/src/core/router.js +223 -4
- package/src/core/runtime-context.js +118 -61
- package/src/core/rust-project.js +400 -0
- package/src/core/schema-validation.js +3 -0
- package/src/core/security-review/constants.js +64 -0
- package/src/core/security-review/normalize.js +245 -0
- package/src/core/security-review/provider.js +204 -0
- package/src/core/security-review/service.js +134 -0
- package/src/core/semantic-planning/constants.js +19 -0
- package/src/core/semantic-planning/projection.js +94 -0
- package/src/core/semantic-planning/service.js +15 -0
- package/src/core/sources.js +37 -0
- package/src/core/sql-project.js +141 -0
- package/src/core/swift-project.js +200 -0
- package/src/core/task-claim-state.js +201 -1
- package/src/core/task-conflict-inspection.js +31 -5
- package/src/core/task-paths.js +13 -0
- package/src/core/task-recovery.js +1 -0
- package/src/core/templates.js +3 -0
- package/src/core/test-intelligence/benchmarks.js +68 -0
- package/src/core/test-intelligence/inventory.js +73 -0
- package/src/core/test-intelligence/prune.js +90 -0
- package/src/core/test-intelligence/semantic-state.js +15 -0
- package/src/core/test-intelligence/service.js +40 -0
- package/src/core/test-intelligence/utility.js +50 -0
- package/src/core/trace.js +11 -7
- package/src/core/transaction.js +1 -0
- package/src/core/typescript-project.js +349 -0
- package/src/core/xml-structure.js +123 -0
- package/src/integration.d.ts +492 -0
- package/src/integration.js +54 -0
- package/src/providers/README.md +47 -0
- package/src/providers/capabilities.js +46 -0
- package/src/providers/errors.js +15 -0
- package/src/providers/index.js +29 -0
- package/src/providers/json-snapshot.js +105 -0
- package/src/providers/registry.js +152 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { canonicalFingerprint } from "./artifacts.js";
|
|
2
|
+
|
|
3
|
+
export const GATE_SATISFIED_EVENT = "GATE_SATISFIED";
|
|
4
|
+
export const GATE_REVALIDATED_EVENT = "GATE_REVALIDATED";
|
|
5
|
+
const CONTRACT_REVISED_EVENT = "CONTRACT_REVISED";
|
|
6
|
+
const TRANSACTION_COMMITTED_EVENT = "TRANSACTION_COMMITTED";
|
|
7
|
+
|
|
8
|
+
function eventHash(event) {
|
|
9
|
+
const { hash, ...body } = event ?? {};
|
|
10
|
+
return canonicalFingerprint(body);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function assertGateSatisfiedDetails(details) {
|
|
14
|
+
if (!details || typeof details !== "object" || Array.isArray(details)
|
|
15
|
+
|| Object.keys(details).length !== 1
|
|
16
|
+
|| typeof details.gate !== "string"
|
|
17
|
+
|| details.gate.trim().length === 0) {
|
|
18
|
+
const error = new Error("GATE_SATISFIED requires exactly one non-empty gate detail");
|
|
19
|
+
error.code = "E_EVENT_INVALID";
|
|
20
|
+
throw error;
|
|
21
|
+
}
|
|
22
|
+
return details;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function assertGateRevalidatedDetails(details) {
|
|
26
|
+
const keys = ["gate", "previousGateFingerprint", "gateFingerprint", "stalePaths"];
|
|
27
|
+
if (!details || typeof details !== "object" || Array.isArray(details)
|
|
28
|
+
|| Object.keys(details).length !== keys.length
|
|
29
|
+
|| keys.some((key) => !Object.prototype.hasOwnProperty.call(details, key))
|
|
30
|
+
|| typeof details.gate !== "string"
|
|
31
|
+
|| details.gate.trim().length === 0
|
|
32
|
+
|| !/^[a-z0-9][a-z0-9-]*$/.test(details.gate)
|
|
33
|
+
|| !/^[a-f0-9]{64}$/.test(details.previousGateFingerprint)
|
|
34
|
+
|| !/^[a-f0-9]{64}$/.test(details.gateFingerprint)
|
|
35
|
+
|| !Array.isArray(details.stalePaths)
|
|
36
|
+
|| details.stalePaths.length === 0
|
|
37
|
+
|| details.stalePaths.some((value) => typeof value !== "string" || value.trim().length === 0)
|
|
38
|
+
|| [...details.stalePaths].sort().join("\0") !== details.stalePaths.join("\0")
|
|
39
|
+
|| new Set(details.stalePaths).size !== details.stalePaths.length) {
|
|
40
|
+
const error = new Error("GATE_REVALIDATED requires a gate, two fingerprints, and sorted stale paths");
|
|
41
|
+
error.code = "E_GATE_REVALIDATION_INVALID";
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
44
|
+
return details;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function gateIndex(events, gateEvent, eventName) {
|
|
48
|
+
return events.findIndex((event) => event === gateEvent
|
|
49
|
+
|| (event?.seq === gateEvent?.seq
|
|
50
|
+
&& event?.taskId === gateEvent?.taskId
|
|
51
|
+
&& event?.event === eventName));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function isValidGateCommit(gateEvent, commitEvent, operation) {
|
|
55
|
+
return commitEvent?.event === TRANSACTION_COMMITTED_EVENT
|
|
56
|
+
&& commitEvent.taskId === gateEvent.taskId
|
|
57
|
+
&& commitEvent.seq === gateEvent.seq + 1
|
|
58
|
+
&& commitEvent.previousHash === gateEvent.hash
|
|
59
|
+
&& gateEvent.hash === eventHash(gateEvent)
|
|
60
|
+
&& commitEvent.hash === eventHash(commitEvent)
|
|
61
|
+
&& commitEvent.details
|
|
62
|
+
&& typeof commitEvent.details === "object"
|
|
63
|
+
&& !Array.isArray(commitEvent.details)
|
|
64
|
+
&& Object.keys(commitEvent.details).length === 2
|
|
65
|
+
&& typeof commitEvent.details.transactionId === "string"
|
|
66
|
+
&& commitEvent.details.transactionId.length > 0
|
|
67
|
+
&& commitEvent.details.operation === operation;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function resolveGateRecordBoundary(events, gateEvent) {
|
|
71
|
+
if (!Array.isArray(events) || !gateEvent || gateEvent.event !== GATE_SATISFIED_EVENT) return null;
|
|
72
|
+
const index = gateIndex(events, gateEvent, GATE_SATISFIED_EVENT);
|
|
73
|
+
if (index < 0) return null;
|
|
74
|
+
const commitEvent = events[index + 1];
|
|
75
|
+
return isValidGateCommit(gateEvent, commitEvent, "gate-record")
|
|
76
|
+
? { gateEvent, transactionCommitEvent: commitEvent }
|
|
77
|
+
: null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function resolveGateRevalidationBoundary(events, gateEvent) {
|
|
81
|
+
if (!Array.isArray(events) || !gateEvent || gateEvent.event !== GATE_REVALIDATED_EVENT) return null;
|
|
82
|
+
const index = gateIndex(events, gateEvent, GATE_REVALIDATED_EVENT);
|
|
83
|
+
if (index < 0) return null;
|
|
84
|
+
const commitEvent = events[index + 1];
|
|
85
|
+
return isValidGateCommit(gateEvent, commitEvent, "gate-revalidate")
|
|
86
|
+
? { gateEvent, transactionCommitEvent: commitEvent }
|
|
87
|
+
: null;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function hasCurrentGateEvidence(events, taskId, gate, latestContractRevisionSeq = 0) {
|
|
91
|
+
return events.some((event) => [GATE_SATISFIED_EVENT, GATE_REVALIDATED_EVENT].includes(event.event)
|
|
92
|
+
&& event.taskId === taskId
|
|
93
|
+
&& event.details?.gate === gate
|
|
94
|
+
&& event.seq > latestContractRevisionSeq);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function validateGateSatisfactionBindings(events = []) {
|
|
98
|
+
const errors = [];
|
|
99
|
+
for (const [index, event] of events.entries()) {
|
|
100
|
+
if (![GATE_SATISFIED_EVENT, GATE_REVALIDATED_EVENT].includes(event.event)) continue;
|
|
101
|
+
const revalidated = event.event === GATE_REVALIDATED_EVENT;
|
|
102
|
+
try {
|
|
103
|
+
if (revalidated) assertGateRevalidatedDetails(event.details);
|
|
104
|
+
else assertGateSatisfiedDetails(event.details);
|
|
105
|
+
} catch (error) {
|
|
106
|
+
errors.push({ code: error.code ?? "E_EVENT_INVALID", message: `event ${event.seq} (${event.event}): ${error.message}` });
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
const revisedBeforeGate = events.slice(0, index).findLast((candidate) => candidate.taskId === event.taskId
|
|
110
|
+
&& candidate.event === CONTRACT_REVISED_EVENT);
|
|
111
|
+
const boundary = revalidated
|
|
112
|
+
? resolveGateRevalidationBoundary(events, event)
|
|
113
|
+
: resolveGateRecordBoundary(events, event);
|
|
114
|
+
if ((revalidated || revisedBeforeGate) && !boundary) {
|
|
115
|
+
errors.push({
|
|
116
|
+
code: revalidated ? "E_GATE_REVALIDATION_INVALID" : "E_EVENT_INVALID",
|
|
117
|
+
message: revalidated
|
|
118
|
+
? `event ${event.seq} must be immediately followed by its gate-revalidate transaction commit`
|
|
119
|
+
: `event ${event.seq} must be immediately followed by its gate-record transaction commit after contract revision`,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return errors;
|
|
124
|
+
}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
|
|
3
|
+
import { createLanguageProject, portablePath } from "./multi-language-project.js";
|
|
4
|
+
|
|
5
|
+
const GO_DIRECTIVE = /^(module|go|toolchain|godebug|require|replace|exclude|retract|tool|ignore)\b/u;
|
|
6
|
+
const GO_WORK_DIRECTIVES = new Set(["go", "toolchain", "godebug", "use", "replace", "tool"]);
|
|
7
|
+
|
|
8
|
+
function invalidGoResult() {
|
|
9
|
+
return {
|
|
10
|
+
valid: false,
|
|
11
|
+
module: null,
|
|
12
|
+
goVersion: null,
|
|
13
|
+
toolchain: null,
|
|
14
|
+
uses: [],
|
|
15
|
+
localReplacements: [],
|
|
16
|
+
ignorePaths: [],
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function stripGoComment(line) {
|
|
21
|
+
const index = line.indexOf("//");
|
|
22
|
+
return (index < 0 ? line : line.slice(0, index)).trim();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function parseGoDirective(line) {
|
|
26
|
+
const block = line.match(/^(module|go|toolchain|godebug|require|replace|exclude|retract|use|tool|ignore)\b\s*\(\s*$/u);
|
|
27
|
+
const match = line.match(/^(module|go|toolchain|godebug|require|replace|exclude|retract|use|tool|ignore)\b\s*(?:\(([^)]*)\)|(.+))$/u);
|
|
28
|
+
if (block) return { name: block[1], value: "" };
|
|
29
|
+
if (!match) return null;
|
|
30
|
+
return {
|
|
31
|
+
name: match[1],
|
|
32
|
+
value: (match[2] ?? match[3] ?? "").trim(),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function collectGoBlock(lines, start) {
|
|
37
|
+
const values = [];
|
|
38
|
+
for (let index = start + 1; index < lines.length; index += 1) {
|
|
39
|
+
const line = stripGoComment(lines[index]);
|
|
40
|
+
if (line === ")") return { values, end: index, valid: true };
|
|
41
|
+
if (line !== "") values.push(line);
|
|
42
|
+
}
|
|
43
|
+
return { values, end: lines.length, valid: false };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function validGoDirectiveValue(name, value) {
|
|
47
|
+
if (!value || /\s{2,}/u.test(value)) return false;
|
|
48
|
+
if (name === "ignore") {
|
|
49
|
+
const portable = value.replaceAll("\\", "/");
|
|
50
|
+
const segments = portable.split("/");
|
|
51
|
+
return !value.includes("\\")
|
|
52
|
+
&& !portable.startsWith("/")
|
|
53
|
+
&& !/^[A-Za-z]:\//u.test(portable)
|
|
54
|
+
&& !segments.includes("..")
|
|
55
|
+
&& !value.includes("=>");
|
|
56
|
+
}
|
|
57
|
+
if (["require", "exclude"].includes(name)) return /^\S+\s+v\S+$/u.test(value);
|
|
58
|
+
if (name === "replace") return /^\S+(?:\s+v\S+)?\s+=>\s+\S+(?:\s+v\S+)?$/u.test(value);
|
|
59
|
+
if (name === "retract") return /^\S+(?:\s*,\s*\S+)?$/u.test(value);
|
|
60
|
+
if (name === "godebug") return /^\S+=\S+$/u.test(value);
|
|
61
|
+
if (name === "tool") return /^\S+(?:\s+v\S+)?$/u.test(value);
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function parseGoModMetadataDirective(state, directive) {
|
|
66
|
+
if (directive.name === "module") {
|
|
67
|
+
if (state.module !== null || directive.value === "" || /\s/u.test(directive.value)) return false;
|
|
68
|
+
state.module = directive.value;
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
if (directive.name === "go") {
|
|
72
|
+
if (state.goVersion !== null || !/^\d+(?:\.\d+){1,2}$/u.test(directive.value)) return false;
|
|
73
|
+
state.goVersion = directive.value;
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
if (directive.name === "toolchain") {
|
|
77
|
+
if (state.toolchain !== null || !/^\S+$/u.test(directive.value)) return false;
|
|
78
|
+
state.toolchain = directive.value;
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function parseGoModBlockDirective(lines, index, directive) {
|
|
85
|
+
const block = collectGoBlock(lines, index);
|
|
86
|
+
const valid = block.valid && block.values.every((value) => validGoDirectiveValue(directive.name, value));
|
|
87
|
+
return {
|
|
88
|
+
valid,
|
|
89
|
+
end: block.end,
|
|
90
|
+
ignorePaths: valid && directive.name === "ignore" ? block.values : [],
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function parseGoModLine(lines, index, state) {
|
|
95
|
+
const line = stripGoComment(lines[index]);
|
|
96
|
+
if (line === "" || line.startsWith("//")) return { valid: true, end: index, ignorePaths: [] };
|
|
97
|
+
const directive = parseGoDirective(line);
|
|
98
|
+
if (!directive || !GO_DIRECTIVE.test(line)) return { valid: false, end: index, ignorePaths: [] };
|
|
99
|
+
const metadataValid = parseGoModMetadataDirective(state, directive);
|
|
100
|
+
if (metadataValid !== null) return { valid: metadataValid, end: index, ignorePaths: [] };
|
|
101
|
+
if (line.endsWith("(")) return parseGoModBlockDirective(lines, index, directive);
|
|
102
|
+
const valid = validGoDirectiveValue(directive.name, directive.value);
|
|
103
|
+
return {
|
|
104
|
+
valid,
|
|
105
|
+
end: index,
|
|
106
|
+
ignorePaths: valid && directive.name === "ignore" ? [directive.value] : [],
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function parseGoMod(text) {
|
|
111
|
+
if (typeof text !== "string" || text.length > 1024 * 1024 || /\r(?!\n)/u.test(text)) return invalidGoResult();
|
|
112
|
+
const lines = text.replaceAll("\r\n", "\n").split("\n");
|
|
113
|
+
const state = { module: null, goVersion: null, toolchain: null, valid: true };
|
|
114
|
+
const ignorePaths = [];
|
|
115
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
116
|
+
const parsed = parseGoModLine(lines, index, state);
|
|
117
|
+
state.valid &&= parsed.valid;
|
|
118
|
+
ignorePaths.push(...parsed.ignorePaths);
|
|
119
|
+
index = parsed.end;
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
valid: state.valid && state.module !== null,
|
|
123
|
+
module: state.module,
|
|
124
|
+
goVersion: state.goVersion,
|
|
125
|
+
toolchain: state.toolchain,
|
|
126
|
+
uses: [],
|
|
127
|
+
localReplacements: [],
|
|
128
|
+
ignorePaths: [...new Set(ignorePaths)],
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export function parseGoWork(text) {
|
|
133
|
+
if (typeof text !== "string" || text.length > 1024 * 1024 || /\r(?!\n)/u.test(text)) {
|
|
134
|
+
return { valid: false, goVersion: null, uses: [] };
|
|
135
|
+
}
|
|
136
|
+
const lines = text.replaceAll("\r\n", "\n").split("\n");
|
|
137
|
+
let goVersion = null;
|
|
138
|
+
const uses = [];
|
|
139
|
+
let valid = true;
|
|
140
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
141
|
+
const line = stripGoComment(lines[index]);
|
|
142
|
+
if (line === "") continue;
|
|
143
|
+
const directive = parseGoDirective(line);
|
|
144
|
+
if (!directive) {
|
|
145
|
+
valid = false;
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
if (directive.name === "go") {
|
|
149
|
+
if (goVersion !== null || !/^\d+(?:\.\d+){1,2}$/u.test(directive.value)) valid = false;
|
|
150
|
+
else goVersion = directive.value;
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
if (directive.name === "toolchain") {
|
|
154
|
+
if (!/^\S+$/u.test(directive.value)) valid = false;
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
if (!GO_WORK_DIRECTIVES.has(directive.name)) {
|
|
158
|
+
valid = false;
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
if (directive.name !== "use") {
|
|
162
|
+
if (line.endsWith("(")) {
|
|
163
|
+
const block = collectGoBlock(lines, index);
|
|
164
|
+
if (!block.valid || !block.values.every((value) => validGoDirectiveValue(directive.name, value))) valid = false;
|
|
165
|
+
index = block.end;
|
|
166
|
+
}
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
const values = line.endsWith("(") ? collectGoBlock(lines, index) : { values: [directive.value], end: index, valid: true };
|
|
170
|
+
if (!values.valid || values.values.some((value) => !validGoDirectiveValue("use", value)
|
|
171
|
+
|| value.startsWith("/") || /^[A-Za-z]:/u.test(value))) {
|
|
172
|
+
valid = false;
|
|
173
|
+
} else {
|
|
174
|
+
uses.push(...values.values);
|
|
175
|
+
}
|
|
176
|
+
index = values.end;
|
|
177
|
+
}
|
|
178
|
+
return { valid: valid && goVersion !== null && uses.length > 0, goVersion, uses: [...new Set(uses)] };
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export function inspectGoProject({ projectRoot, manifestRelative, manifestText, manifestName, targetRoot, projectFiles }) {
|
|
182
|
+
const parsed = manifestName === "go.work" ? parseGoWork(manifestText) : parseGoMod(manifestText);
|
|
183
|
+
const localUses = manifestName === "go.work"
|
|
184
|
+
? parsed.uses.filter((use) => projectFiles.some((file) => file.kind === "go"
|
|
185
|
+
&& parseGoMod(file.text).valid
|
|
186
|
+
&& portablePath(targetRoot, path.dirname(file.path)) === path.posix.normalize(path.posix.join(projectRoot, use))))
|
|
187
|
+
: [];
|
|
188
|
+
const primary = parsed.valid && (manifestName === "go.mod" || localUses.length > 0);
|
|
189
|
+
const primarySignals = primary
|
|
190
|
+
? [manifestName === "go.mod" ? `${manifestRelative}:module` : `${manifestRelative}:workspace`]
|
|
191
|
+
: [];
|
|
192
|
+
const supportingSignals = [];
|
|
193
|
+
if (parsed.goVersion) supportingSignals.push(`${manifestRelative}:go=${parsed.goVersion}`);
|
|
194
|
+
if (parsed.toolchain) supportingSignals.push(`${manifestRelative}:toolchain=${parsed.toolchain}`);
|
|
195
|
+
for (const use of localUses) supportingSignals.push(`${manifestRelative}:use=${use}`);
|
|
196
|
+
return createLanguageProject({
|
|
197
|
+
kind: "go",
|
|
198
|
+
root: projectRoot,
|
|
199
|
+
manifest: manifestRelative,
|
|
200
|
+
frameworks: primary ? ["go"] : [],
|
|
201
|
+
primary,
|
|
202
|
+
primarySignals,
|
|
203
|
+
supportingSignals,
|
|
204
|
+
internal: { ...parsed, valid: parsed.valid, manifestName, localUses },
|
|
205
|
+
});
|
|
206
|
+
}
|
|
@@ -24,7 +24,7 @@ export const INTEGRATION_RISK_CLASSES = Object.freeze({
|
|
|
24
24
|
});
|
|
25
25
|
|
|
26
26
|
const READ_ONLY_COMMANDS = Object.freeze(new Set([
|
|
27
|
-
"protocol-info", "status", "next", "continuity", "reconcile-continuity",
|
|
27
|
+
"protocol-info", "decision-status", "decision-show", "context-plan", "model-route", "semantic-plan", "test-inventory", "status", "next", "continuity", "reconcile-continuity",
|
|
28
28
|
"task-list", "task-show", "task-lock-status", "progress", "audit", "report",
|
|
29
29
|
"inspect", "validate-state", "validate-protocol", "validate-receipt",
|
|
30
30
|
"policy-status", "policy-diff", "rule-verify", "policy",
|
|
@@ -37,7 +37,7 @@ const READ_ONLY_COMMANDS = Object.freeze(new Set([
|
|
|
37
37
|
]));
|
|
38
38
|
|
|
39
39
|
const LOOP_MUTATION_COMMANDS = Object.freeze(new Set([
|
|
40
|
-
"route", "preflight", "advance", "task-create", "task-scope",
|
|
40
|
+
"discover", "contract-create", "route", "preflight", "advance", "task-create", "task-scope",
|
|
41
41
|
"record-continuity", "clear-continuity", "prepare-completion",
|
|
42
42
|
"record-check", "record-diagnosis", "record-decision-criterion",
|
|
43
43
|
"record-terminal-result", "complete",
|
|
@@ -86,7 +86,17 @@ const STATIC_RISK_CLASSES = Object.freeze({
|
|
|
86
86
|
bundle: INTEGRATION_RISK_CLASSES.MAINTENANCE,
|
|
87
87
|
"profile-interview": INTEGRATION_RISK_CLASSES.MAINTENANCE,
|
|
88
88
|
"task-recover": INTEGRATION_RISK_CLASSES.CLAIM_RELEASE_RECOVERY,
|
|
89
|
+
"task-abandon": INTEGRATION_RISK_CLASSES.CLAIM_RELEASE_RECOVERY,
|
|
89
90
|
"task-repair-legacy-recovery": INTEGRATION_RISK_CLASSES.LEGACY_MIGRATION,
|
|
91
|
+
"gate-record": INTEGRATION_RISK_CLASSES.MAINTENANCE,
|
|
92
|
+
"gate-revalidate": INTEGRATION_RISK_CLASSES.MAINTENANCE,
|
|
93
|
+
"test-utility": INTEGRATION_RISK_CLASSES.MAINTENANCE,
|
|
94
|
+
"test-prune-plan": INTEGRATION_RISK_CLASSES.READ_ONLY,
|
|
95
|
+
"test-prune-probe": INTEGRATION_RISK_CLASSES.EXTERNAL_EXECUTION,
|
|
96
|
+
"task-repair-contract-bootstrap": INTEGRATION_RISK_CLASSES.LEGACY_MIGRATION,
|
|
97
|
+
"task-migrate-contract-bootstrap-repair": INTEGRATION_RISK_CLASSES.LEGACY_MIGRATION,
|
|
98
|
+
"checkpoint-revalidate": INTEGRATION_RISK_CLASSES.MAINTENANCE,
|
|
99
|
+
"contract-revise": INTEGRATION_RISK_CLASSES.MAINTENANCE,
|
|
90
100
|
});
|
|
91
101
|
|
|
92
102
|
// Sparse input-dependent refinements over the static table.
|
|
@@ -169,6 +179,18 @@ export function getForgeLoopCapabilities({ packageVersion = null } = {}) {
|
|
|
169
179
|
commands: ["next", "task-show"],
|
|
170
180
|
preservesDefaultOutput: true,
|
|
171
181
|
},
|
|
182
|
+
auditUx: {
|
|
183
|
+
version: 1,
|
|
184
|
+
supported: true,
|
|
185
|
+
readOnly: true,
|
|
186
|
+
resource: "task/audit-view",
|
|
187
|
+
timeline: true,
|
|
188
|
+
lifecycleAuthority: false,
|
|
189
|
+
evidenceAuthority: false,
|
|
190
|
+
completionAuthority: false,
|
|
191
|
+
mutationAuthority: false,
|
|
192
|
+
externalExecution: false,
|
|
193
|
+
},
|
|
172
194
|
usageTelemetry: {
|
|
173
195
|
version: 1,
|
|
174
196
|
supported: true,
|
|
@@ -295,6 +317,7 @@ export function getForgeLoopCapabilities({ packageVersion = null } = {}) {
|
|
|
295
317
|
{ name: "task/approvals", scope: "TASK" },
|
|
296
318
|
{ name: "task/metrics", scope: "TASK" },
|
|
297
319
|
{ name: "task/context", scope: "TASK" },
|
|
320
|
+
{ name: "task/audit-view", scope: "TASK" },
|
|
298
321
|
{ name: "task/evaluations", scope: "TASK" },
|
|
299
322
|
{ name: "project/capability-policy", scope: "PROJECT" },
|
|
300
323
|
{ name: "repository/index-status", scope: "PROJECT" },
|
|
@@ -352,8 +375,8 @@ export function classifyForgeLoopInvocation(command, input = {}) {
|
|
|
352
375
|
removesArtifacts: definition.removes.length > 0,
|
|
353
376
|
executesExternalProcess: definition.mayExecuteExternalProcess === true,
|
|
354
377
|
affectsClaimAuthority: [
|
|
355
|
-
"task-resume", "task-recover", "task-repair-legacy-recovery",
|
|
356
|
-
"task-create", "task-scope", "complete",
|
|
378
|
+
"task-resume", "task-recover", "task-repair-legacy-recovery", "task-repair-contract-bootstrap",
|
|
379
|
+
"task-create", "task-scope", "complete", "task-migrate-contract-bootstrap-repair",
|
|
357
380
|
].includes(command),
|
|
358
381
|
destructive: [
|
|
359
382
|
INTEGRATION_RISK_CLASSES.AUTHORITY_MUTATION,
|
|
@@ -21,6 +21,12 @@ import { resolveAttestationStatus } from "./attestation.js";
|
|
|
21
21
|
import { buildExecutionProfileContext } from "./execution-profile-context.js";
|
|
22
22
|
import { projectStructuralQualityStatus } from "./structural-quality/service.js";
|
|
23
23
|
import { getRepositoryIndexStatus } from "../repository-index/status.js";
|
|
24
|
+
import { buildAuditUxView } from "./audit-ux.js";
|
|
25
|
+
import { runContextPlan } from "../commands/context-plan.js";
|
|
26
|
+
import { runModelRoute } from "../commands/model-route.js";
|
|
27
|
+
import { readPersistedRoute } from "./route-artifact.js";
|
|
28
|
+
import { readWorkState } from "./work-state.js";
|
|
29
|
+
import { readTestUtility } from "./test-intelligence/service.js";
|
|
24
30
|
|
|
25
31
|
/**
|
|
26
32
|
* Canonical integration resource allowlist.
|
|
@@ -86,11 +92,18 @@ export const INTEGRATION_RESOURCE_DEFINITIONS = Object.freeze({
|
|
|
86
92
|
"task/approvals": Object.freeze({ scope: "TASK", description: "Durable approval artifacts for one task." }),
|
|
87
93
|
"task/metrics": Object.freeze({ scope: "TASK", description: "Read-only trajectory metrics for one task." }),
|
|
88
94
|
"task/context": Object.freeze({ scope: "TASK", description: "Read-only profile-aware task context with bounded presentation policy." }),
|
|
95
|
+
"task/audit-view": Object.freeze({ scope: "TASK", description: "Bounded read-only Audit UX projection composed from canonical task resolvers." }),
|
|
89
96
|
"task/evaluations": Object.freeze({ scope: "TASK", description: "Persisted trajectory evaluations for one task." }),
|
|
97
|
+
"task/decisions": Object.freeze({ scope: "TASK", description: "Persisted, fingerprint-bound semantic decisions without lifecycle or evidence authority." }),
|
|
98
|
+
"task/context-plan": Object.freeze({ scope: "TASK", description: "Bounded non-authoritative semantic context-plan projection." }),
|
|
99
|
+
"task/model-route": Object.freeze({ scope: "TASK", description: "Deterministic model-routing floor with advisory semantic escalation." }),
|
|
100
|
+
"task/test-utility": Object.freeze({ scope: "TASK", description: "Non-evidence test inventory and utility analysis; never deletion authority." }),
|
|
90
101
|
"project/capability-policy": Object.freeze({ scope: "PROJECT", description: "Project capability policy, never host authority." }),
|
|
91
102
|
"repository/index-status": Object.freeze({ scope: "PROJECT", description: "Provider-neutral repository-index health and owned-server status." }),
|
|
92
103
|
});
|
|
93
104
|
|
|
105
|
+
const TASK_RESOURCE_URIS = new Set(Object.keys(INTEGRATION_RESOURCE_DEFINITIONS).filter((uri) => uri.startsWith("task/")));
|
|
106
|
+
|
|
94
107
|
function ownershipProjection(projection) {
|
|
95
108
|
return {
|
|
96
109
|
taskId: projection.taskId,
|
|
@@ -120,67 +133,20 @@ async function readForgeLoopIntegrationResourceCore(uri, {
|
|
|
120
133
|
throw error;
|
|
121
134
|
}
|
|
122
135
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
mutationAllowed: task.mutationAllowed !== false,
|
|
138
|
-
})),
|
|
139
|
-
},
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
case "task/status":
|
|
143
|
-
case "task/ownership":
|
|
144
|
-
case "task/contract":
|
|
145
|
-
case "task/continuity": {
|
|
146
|
-
if (typeof taskId !== "string" || !taskId) {
|
|
147
|
-
const error = new Error(`Resource ${uri} requires a taskId`);
|
|
148
|
-
error.code = "E_TASK_REQUIRED";
|
|
149
|
-
throw error;
|
|
150
|
-
}
|
|
151
|
-
break;
|
|
152
|
-
}
|
|
153
|
-
case "task/workspace-binding":
|
|
154
|
-
case "task/handoffs":
|
|
155
|
-
case "task/responsibility":
|
|
156
|
-
case "task/verification-scope":
|
|
157
|
-
case "task/attestation": {
|
|
158
|
-
if (typeof taskId !== "string" || !taskId) {
|
|
159
|
-
const error = new Error(`Resource ${uri} requires a taskId`);
|
|
160
|
-
error.code = "E_TASK_REQUIRED";
|
|
161
|
-
throw error;
|
|
162
|
-
}
|
|
163
|
-
break;
|
|
164
|
-
}
|
|
165
|
-
case "task/structural-quality": {
|
|
166
|
-
if (typeof taskId !== "string" || !taskId) {
|
|
167
|
-
const error = new Error(`Resource ${uri} requires a taskId`);
|
|
168
|
-
error.code = "E_TASK_REQUIRED";
|
|
169
|
-
throw error;
|
|
170
|
-
}
|
|
171
|
-
break;
|
|
172
|
-
}
|
|
173
|
-
case "task/actions":
|
|
174
|
-
case "task/action":
|
|
175
|
-
case "task/approvals":
|
|
176
|
-
case "task/metrics":
|
|
177
|
-
case "task/context":
|
|
178
|
-
case "task/evaluations": {
|
|
179
|
-
if (typeof taskId !== "string" || !taskId) {
|
|
180
|
-
const error = new Error(`Resource ${uri} requires a taskId`); error.code = "E_TASK_REQUIRED"; throw error;
|
|
181
|
-
}
|
|
182
|
-
break;
|
|
183
|
-
}
|
|
136
|
+
if (uri === "protocol/info") return { uri, data: await runProtocolInfo({ packageVersion }) };
|
|
137
|
+
if (uri === "project/tasks") {
|
|
138
|
+
const tasks = await discoverTasks(projectPath, packageRoot);
|
|
139
|
+
return { uri, data: { count: tasks.length, tasks: tasks.map((task) => ({
|
|
140
|
+
taskId: task.taskId,
|
|
141
|
+
healthy: task.healthy !== false,
|
|
142
|
+
phase: task.phase ?? null,
|
|
143
|
+
mutationAllowed: task.mutationAllowed !== false,
|
|
144
|
+
})) } };
|
|
145
|
+
}
|
|
146
|
+
if (TASK_RESOURCE_URIS.has(uri) && (typeof taskId !== "string" || !taskId)) {
|
|
147
|
+
const error = new Error(`Resource ${uri} requires a taskId`);
|
|
148
|
+
error.code = "E_TASK_REQUIRED";
|
|
149
|
+
throw error;
|
|
184
150
|
}
|
|
185
151
|
|
|
186
152
|
if (uri === "task/ownership") {
|
|
@@ -270,6 +236,45 @@ async function readForgeLoopIntegrationResourceCore(uri, {
|
|
|
270
236
|
}
|
|
271
237
|
return { uri, taskId, data: { evaluations } };
|
|
272
238
|
}
|
|
239
|
+
if (uri === "task/decisions") {
|
|
240
|
+
const dir = path.join(projectPath, taskDirectory(taskId), "decisions");
|
|
241
|
+
let names = []; try { names = await readdir(dir); } catch { /* absent is an empty projection */ }
|
|
242
|
+
const decisions = [];
|
|
243
|
+
for (const name of names.filter((entry) => /^[A-Za-z0-9][A-Za-z0-9_-]{0,127}\.json$/.test(entry)).sort()) {
|
|
244
|
+
decisions.push((await readJsonArtifact(projectPath, `${taskDirectory(taskId)}/decisions/${name}`, "semantic-decision", packageRoot)).value);
|
|
245
|
+
}
|
|
246
|
+
return { uri, taskId, data: { taskId, decisions } };
|
|
247
|
+
}
|
|
248
|
+
if (uri === "task/context-plan") {
|
|
249
|
+
return { uri, taskId, data: await runContextPlan({ target: projectPath, packageRoot, taskId, profile: runtimeContext?.contextProfile ?? "balanced", readOnly: true }) };
|
|
250
|
+
}
|
|
251
|
+
if (uri === "task/model-route") {
|
|
252
|
+
const state = await readWorkState(projectPath, { packageRoot, taskId });
|
|
253
|
+
const route = await readPersistedRoute(projectPath, packageRoot, { taskId });
|
|
254
|
+
return {
|
|
255
|
+
uri,
|
|
256
|
+
taskId,
|
|
257
|
+
data: await runModelRoute({
|
|
258
|
+
target: projectPath,
|
|
259
|
+
packageRoot,
|
|
260
|
+
taskId,
|
|
261
|
+
workType: route.value.input?.workType,
|
|
262
|
+
surfaces: route.value.input?.surfaces,
|
|
263
|
+
risks: route.value.input?.risks,
|
|
264
|
+
platforms: route.value.input?.platforms,
|
|
265
|
+
behaviorChange: route.value.input?.behaviorChange,
|
|
266
|
+
executableChange: route.value.input?.executableChange,
|
|
267
|
+
generationRequired: route.value.input?.generationRequired,
|
|
268
|
+
architectureChange: route.value.input?.architectureChange,
|
|
269
|
+
ambiguity: route.value.input?.ambiguity,
|
|
270
|
+
contract: { phase: state.phase },
|
|
271
|
+
}),
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
if (uri === "task/test-utility") {
|
|
275
|
+
const artifact = await readTestUtility({ target: projectPath, packageRoot, taskId });
|
|
276
|
+
return { uri, taskId, data: artifact.value };
|
|
277
|
+
}
|
|
273
278
|
if (uri === "project/capability-policy") {
|
|
274
279
|
return { uri, data: await loadCapabilityPolicy(projectPath, packageRoot) };
|
|
275
280
|
}
|
|
@@ -292,6 +297,26 @@ async function readForgeLoopIntegrationResourceCore(uri, {
|
|
|
292
297
|
}
|
|
293
298
|
|
|
294
299
|
export async function readForgeLoopIntegrationResource(uri, options = {}) {
|
|
300
|
+
if (uri === "task/audit-view") {
|
|
301
|
+
if (typeof options.taskId !== "string" || !options.taskId) {
|
|
302
|
+
const error = new Error("Resource task/audit-view requires a taskId"); error.code = "E_TASK_REQUIRED"; throw error;
|
|
303
|
+
}
|
|
304
|
+
return {
|
|
305
|
+
uri,
|
|
306
|
+
taskId: options.taskId,
|
|
307
|
+
data: await buildAuditUxView({
|
|
308
|
+
target: options.projectPath ?? ".",
|
|
309
|
+
packageRoot: options.packageRoot,
|
|
310
|
+
taskId: options.taskId,
|
|
311
|
+
limit: options.limit,
|
|
312
|
+
beforeSequence: options.beforeSequence,
|
|
313
|
+
afterSequence: options.afterSequence,
|
|
314
|
+
categories: options.categories,
|
|
315
|
+
authorityContext: options.runtimeContext?.authorityContext,
|
|
316
|
+
runtimeContext: options.runtimeContext,
|
|
317
|
+
}),
|
|
318
|
+
};
|
|
319
|
+
}
|
|
295
320
|
if (uri === "repository/index-status") {
|
|
296
321
|
return {
|
|
297
322
|
uri,
|