omnius 1.0.571 → 1.0.573

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/dist/index.js CHANGED
@@ -468840,7 +468840,7 @@ ${newComment.split("\n").map((c9) => ` * ${c9}`).join("\n")}
468840
468840
  }
468841
468841
  }
468842
468842
  return result;
468843
- function escapeRegExp3(str) {
468843
+ function escapeRegExp4(str) {
468844
468844
  return str.replace(/[-[\]/{}()*+?.\\^$|]/g, "\\$&");
468845
468845
  }
468846
468846
  function getTodoCommentsRegExp() {
@@ -468848,7 +468848,7 @@ ${newComment.split("\n").map((c9) => ` * ${c9}`).join("\n")}
468848
468848
  const multiLineCommentStart = /(?:\/\*+\s*)/.source;
468849
468849
  const anyNumberOfSpacesAndAsterisksAtStartOfLine = /(?:^(?:\s|\*)*)/.source;
468850
468850
  const preamble = "(" + anyNumberOfSpacesAndAsterisksAtStartOfLine + "|" + singleLineCommentStart + "|" + multiLineCommentStart + ")";
468851
- const literals = "(?:" + map2(descriptors, (d2) => "(" + escapeRegExp3(d2.text) + ")").join("|") + ")";
468851
+ const literals = "(?:" + map2(descriptors, (d2) => "(" + escapeRegExp4(d2.text) + ")").join("|") + ")";
468852
468852
  const endOfLineOrEndOfComment = /(?:$|\*\/)/.source;
468853
468853
  const messageRemainder = /(?:.*?)/.source;
468854
468854
  const messagePortion = "(" + literals + messageRemainder + ")";
@@ -567847,6 +567847,36 @@ function clip2(value2, max = 500) {
567847
567847
  function listLines(items, empty2 = "- none observed") {
567848
567848
  return items.length > 0 ? items.map((item) => `- ${item}`) : [empty2];
567849
567849
  }
567850
+ function formatWorkspaceInventorySummary(inventory) {
567851
+ if (!inventory)
567852
+ return ["- no bounded workspace inventory was provided"];
567853
+ const files = (inventory.files ?? []).slice(0, 40).map((file) => `${file.path}${file.bytes !== void 0 ? ` (bytes=${file.bytes}` : ""}${file.mtimeMs !== void 0 ? `${file.bytes !== void 0 ? ", " : " ("}mtimeMs=${file.mtimeMs})` : file.bytes !== void 0 ? ")" : ""}`);
567854
+ const dirs = (inventory.dirs ?? []).slice(0, 40).map((dir) => `dir:${dir}`);
567855
+ const summary = [
567856
+ `workspace_root=${inventory.root}`,
567857
+ `files=${inventory.files.length}${inventory.truncated ? "+" : ""}`,
567858
+ `dirs=${(inventory.dirs ?? []).length}`,
567859
+ `requested_max=${inventory.maxFiles}x${inventory.maxDirs}`
567860
+ ];
567861
+ if (!inventory.truncated)
567862
+ summary.push(`inventory_complete=${inventory.files.length > 0 || (inventory.dirs ?? []).length > 0 ? "yes" : "no"}`);
567863
+ const out = [
567864
+ `Generated at: ${inventory.generatedAtIso}`,
567865
+ summary.join("; ")
567866
+ ];
567867
+ if (files.length > 0) {
567868
+ out.push("Representative files:");
567869
+ out.push(...files.map((item) => `- ${item}`));
567870
+ }
567871
+ if (dirs.length > 0) {
567872
+ out.push("Representative directories:");
567873
+ out.push(...dirs.map((item) => `- ${item}`));
567874
+ }
567875
+ if (inventory.truncated) {
567876
+ out.push("- inventory_truncated: run a fresh scan with higher limits to inspect additional paths");
567877
+ }
567878
+ return out;
567879
+ }
567850
567880
  function formatEvidenceEntry(entry) {
567851
567881
  const parts = [
567852
567882
  entry.success === true ? "ok" : entry.success === false ? "failed" : "unknown",
@@ -567892,6 +567922,7 @@ ${String(input.answerText).trim()}` : ""
567892
567922
  ].filter(Boolean).join(" ");
567893
567923
  return `${clip2(file.path, 220)}${meta ? ` (${meta})` : ""}`;
567894
567924
  });
567925
+ const workspaceInventory = formatWorkspaceInventorySummary(input.workspaceInventory);
567895
567926
  const scenarioSeed = deriveScenarioSeed(input);
567896
567927
  const lines = [];
567897
567928
  lines.push(`[COMPLETION META-DECOMPOSITION]`);
@@ -567903,11 +567934,14 @@ ${String(input.answerText).trim()}` : ""
567903
567934
  lines.push(`Proposed completion claim text:`);
567904
567935
  lines.push(proposedClaimText || "(no proposed completion text yet)");
567905
567936
  lines.push(``);
567937
+ lines.push(`Open loops and remaining blockers:`);
567938
+ lines.push(...listLines(unresolvedSignals, "- no open loop / blocker signals currently reported"));
567939
+ lines.push(``);
567906
567940
  lines.push(`Observed run evidence:`);
567907
567941
  lines.push(...listLines(observedEvidence, "- no tool evidence recorded"));
567908
567942
  lines.push(``);
567909
- lines.push(`Unresolved or caution signals:`);
567910
- lines.push(...listLines(unresolvedSignals, "- none recorded"));
567943
+ lines.push(`Workspace inventory (bounded to prevent scan drift):`);
567944
+ lines.push(...workspaceInventory);
567911
567945
  lines.push(``);
567912
567946
  lines.push(`Modified artifact digest:`);
567913
567947
  lines.push(...listLines(modifiedFiles, "- no modified artifacts listed"));
@@ -567953,6 +567987,56 @@ var init_completionContract = __esm({
567953
567987
  // packages/orchestrator/dist/completionLedger.js
567954
567988
  import { mkdirSync as mkdirSync51, readFileSync as readFileSync66, writeFileSync as writeFileSync42 } from "node:fs";
567955
567989
  import { dirname as dirname29 } from "node:path";
567990
+ function setClaimDiscoveryState(ledger, state) {
567991
+ return {
567992
+ ...ledger,
567993
+ claimDiscovery: {
567994
+ ...state,
567995
+ generatedAtIso: nowIso3(),
567996
+ resolvedEvidenceHandles: state.resolvedEvidenceHandles ?? []
567997
+ },
567998
+ updatedAtIso: nowIso3()
567999
+ };
568000
+ }
568001
+ function claimDiscoveryStateFromSurvey(input) {
568002
+ const normalizedInventory = input.boundedInventory;
568003
+ const paths = [...new Set((Array.isArray(input.candidatePaths) ? input.candidatePaths : []).map((value2) => normalizeEvidencePath(value2)).filter(Boolean).slice(0, 16))];
568004
+ const requestedRequiredPaths = input.requiredArtifactPaths === void 0 ? paths : input.requiredArtifactPaths;
568005
+ const requiredPathSet = new Set((Array.isArray(requestedRequiredPaths) ? requestedRequiredPaths : []).map((value2) => normalizeEvidencePath(value2)).filter((path16) => paths.includes(path16)));
568006
+ const requiredArtifactPaths = paths.filter((path16) => requiredPathSet.has(path16));
568007
+ const reasons = /* @__PURE__ */ Object.create(null);
568008
+ for (const [rawPath, rawReason] of Object.entries(input.pathReasons ?? {})) {
568009
+ const path16 = normalizeEvidencePath(rawPath);
568010
+ const reason = cleanText(rawReason, 220);
568011
+ if (path16)
568012
+ reasons[path16] = reason || "candidate selected from bounded workspace inventory";
568013
+ }
568014
+ const openDeltas = requiredArtifactPaths.map((path16) => ({
568015
+ path: path16,
568016
+ reason: reasons[path16] || "candidate selected from bounded workspace inventory"
568017
+ }));
568018
+ const unresolved = Array.isArray(input.unresolvedQuestions) ? input.unresolvedQuestions.map((item) => cleanText(item, 260)).filter(Boolean) : [];
568019
+ const blockers = Array.isArray(input.survivingBlockers) ? input.survivingBlockers.map((item) => cleanText(item, 220)).filter(Boolean) : [];
568020
+ const hasBlockers = blockers.length > 0;
568021
+ const hasQuestions = unresolved.length > 0;
568022
+ const resolvedStatus = requiredArtifactPaths.length === 0 ? hasBlockers || hasQuestions ? "blocked" : "skipped" : hasBlockers || hasQuestions ? "blocked" : "active";
568023
+ return {
568024
+ status: resolvedStatus,
568025
+ generatedAtIso: nowIso3(),
568026
+ request: cleanText(input.request, 600),
568027
+ context: cleanText(input.context, 480),
568028
+ boundedInventory: normalizedInventory,
568029
+ candidatePaths: paths,
568030
+ requiredArtifactPaths,
568031
+ pathReasons: reasons,
568032
+ unresolvedQuestions: unresolved.slice(0, 10),
568033
+ openDeltas,
568034
+ survivingBlockers: blockers.slice(0, 8),
568035
+ evidenceHandles: [...new Set(requiredArtifactPaths.map((path16) => `workspace:${path16}`))],
568036
+ resolvedEvidenceHandles: [],
568037
+ requiresEvidence: typeof input.requiresEvidence === "boolean" ? input.requiresEvidence : requiredArtifactPaths.length > 0
568038
+ };
568039
+ }
567956
568040
  function nowIso3(now2 = /* @__PURE__ */ new Date()) {
567957
568041
  return now2 instanceof Date ? now2.toISOString() : new Date(now2).toISOString();
567958
568042
  }
@@ -568002,6 +568086,184 @@ function formatEvidenceSummary(summary) {
568002
568086
  function nextId2(prefix, count) {
568003
568087
  return `${prefix}_${String(count + 1).padStart(4, "0")}`;
568004
568088
  }
568089
+ function extractWorkspaceTokens(text2) {
568090
+ const raw = String(text2 ?? "").toLowerCase().replace(/["'`]/g, " ").replace(/[^\w./@-]+/g, " ");
568091
+ return raw.split(/\s+/).filter((value2) => value2.length >= 4);
568092
+ }
568093
+ function extractPathFragments(text2) {
568094
+ const out = [];
568095
+ const pathPattern = /(?:[\w.-]+\/[\w./-]+\.[A-Za-z0-9]+|[\w.-]+\.(?:ts|tsx|js|jsx|mjs|cjs|py|go|rs|cpp|c|h|hpp|java|kt|json|yml|yaml|toml|md|mdx|sh|bash|cxx|swift|rb|php)|[\w./-]+\.[A-Za-z0-9]+)/g;
568096
+ for (const hit of text2.matchAll(pathPattern)) {
568097
+ const value2 = String(hit[0] ?? "").trim();
568098
+ if (!value2)
568099
+ continue;
568100
+ const normalized = value2.replace(/^\.\/+/, "");
568101
+ if (normalized.length > 2)
568102
+ out.push(normalized);
568103
+ }
568104
+ return [...new Set(out)].slice(0, 12);
568105
+ }
568106
+ function tokenizeClaims(text2) {
568107
+ return String(text2 ?? "").split(/[.\n\r!?;]+/).map((item) => item.trim()).filter((item) => item.length > 6).filter((item) => item.length < 260).slice(0, 30);
568108
+ }
568109
+ function estimateClaimMateriality(text2) {
568110
+ const normalized = text2.toLowerCase();
568111
+ if (/\b(blocker|critical|security|production|release|deploy|migrate|migration|regression|customer|public)\b/.test(normalized)) {
568112
+ return "high";
568113
+ }
568114
+ if (/\b(implement|fix|refactor|resolve|wire|integrat|add|remove|change|update)\b/.test(normalized)) {
568115
+ return "medium";
568116
+ }
568117
+ return "low";
568118
+ }
568119
+ function classifyClaimAttainedState(text2) {
568120
+ const normalized = text2.toLowerCase();
568121
+ if (/\b(block|blocked|blocker|cannot verify|unverified|not verified|hold)\b/.test(normalized)) {
568122
+ return "blocked";
568123
+ }
568124
+ if (/\b(simulat|dry.?run|mock|unit test|paper|offline|software.?in.?loop)\b/.test(normalized)) {
568125
+ return "simulation_only";
568126
+ }
568127
+ if (/\b(hil|hardware.?in.?the.?loop|hardware.?test|on.?device|real.?hardware|physical)\b/.test(normalized)) {
568128
+ return "hardware_verified";
568129
+ }
568130
+ if (/\b(integrat|integrated|bridge|transport|serial|can|hardware|device|physical)\b/.test(normalized)) {
568131
+ return "hardware_integrated";
568132
+ }
568133
+ return "unproven";
568134
+ }
568135
+ function deriveClaimRisks(text2) {
568136
+ const normalized = text2.toLowerCase();
568137
+ if (/\b(start|running|daemon|process|service|alive|ready)\b/.test(normalized)) {
568138
+ return {
568139
+ riskCategory: "process_liveness",
568140
+ requiresIndependentEvidence: true,
568141
+ requiredCheck: "Independent runtime state/health check with process or endpoint probe."
568142
+ };
568143
+ }
568144
+ if (/\b(instal|pip|npm|pnpm|apt|brew|cargo|go install|pip install|docker pull)\b/.test(normalized)) {
568145
+ return {
568146
+ riskCategory: "installation",
568147
+ requiresIndependentEvidence: true,
568148
+ requiredCheck: "Independent command query/inspection proving the toolchain exists after the installation claim."
568149
+ };
568150
+ }
568151
+ if (/\b(fixed|repair|resolved|passed|test pass|fix|bug|regression)\b/.test(normalized)) {
568152
+ return {
568153
+ riskCategory: "fix_confirmation",
568154
+ requiresIndependentEvidence: true,
568155
+ requiredCheck: "Re-run the same failure path or equivalent check and capture the successful evidence."
568156
+ };
568157
+ }
568158
+ if (/\b(simulat|dry.?run|mock|fake|virtual)\b/.test(normalized)) {
568159
+ return {
568160
+ riskCategory: "reality",
568161
+ requiresIndependentEvidence: false,
568162
+ requiredCheck: "Label and preserve as simulation-only unless hardware-path evidence exists."
568163
+ };
568164
+ }
568165
+ return {
568166
+ riskCategory: "coverage",
568167
+ requiresIndependentEvidence: false,
568168
+ requiredCheck: "Collect evidence per claim from supported tool outputs and source observations."
568169
+ };
568170
+ }
568171
+ function claimEvidenceNeeds(text2) {
568172
+ const normalized = text2.toLowerCase();
568173
+ const needs = [];
568174
+ const kind = /\b(test|verify|validate|coverage|run|build|lint|check|execute)\b/.test(normalized) ? "tool_result" : /\b(create|write|modify|edit|delete|remove|add|updated|implemented|fix)\b/.test(normalized) ? "file_change" : "runtime_observation";
568175
+ needs.push({
568176
+ handle: `${kind}:in_scope`,
568177
+ evidenceKind: kind,
568178
+ rationale: `Evidence supporting the in-scope portion of: ${cleanText(text2, 120)}`
568179
+ });
568180
+ if (/\b(runtime|process|service|daemon|endpoint|server)\b/.test(normalized)) {
568181
+ needs.push({
568182
+ handle: "verification:post-change",
568183
+ evidenceKind: "runtime_observation",
568184
+ rationale: "Observed runtime confirmation after the claimed change."
568185
+ });
568186
+ }
568187
+ if (/\b(serial|hardware|device|controller|transport)\b/.test(normalized)) {
568188
+ needs.push({
568189
+ handle: "delivery:hardware-path",
568190
+ evidenceKind: "delivery",
568191
+ rationale: "Hardware-path or transport evidence that clarifies simulation/hardware status."
568192
+ });
568193
+ }
568194
+ return needs;
568195
+ }
568196
+ function findInventoryMatches(statement, workspaceInventory) {
568197
+ if (!workspaceInventory)
568198
+ return [];
568199
+ const tokens = extractWorkspaceTokens(statement);
568200
+ const candidatePaths = workspaceInventory.files.map((entry) => entry.path);
568201
+ const seen = /* @__PURE__ */ new Set();
568202
+ const matches = [];
568203
+ const literalPathHints = extractPathFragments(statement);
568204
+ for (const hint of literalPathHints) {
568205
+ const normalized = hint.toLowerCase();
568206
+ const exact = candidatePaths.find((path16) => path16.toLowerCase() === normalized);
568207
+ if (exact)
568208
+ seen.add(exact);
568209
+ }
568210
+ for (const path16 of candidatePaths) {
568211
+ if (matches.length >= 5 || seen.size >= 8)
568212
+ break;
568213
+ const lower = path16.toLowerCase();
568214
+ const tokenHits = tokens.filter((token) => lower.includes(token));
568215
+ if (tokenHits.length >= 2 || tokenHits.length >= 1 && literalPathHints.length === 0) {
568216
+ if (!seen.has(path16)) {
568217
+ seen.add(path16);
568218
+ }
568219
+ }
568220
+ }
568221
+ for (const path16 of seen)
568222
+ matches.push(path16);
568223
+ if (literalPathHints.length > 0 && matches.length === 0) {
568224
+ for (const path16 of candidatePaths) {
568225
+ for (const hint of literalPathHints) {
568226
+ if (path16.toLowerCase().includes(hint.toLowerCase())) {
568227
+ matches.push(path16);
568228
+ break;
568229
+ }
568230
+ }
568231
+ if (matches.length >= 6)
568232
+ break;
568233
+ }
568234
+ }
568235
+ return matches.slice(0, 6);
568236
+ }
568237
+ function claimDiscoveryControllerSignals(stage2) {
568238
+ if (!stage2)
568239
+ return [];
568240
+ const openDeltas = (stage2.openDeltas ?? []).slice(0, 10);
568241
+ const evidenceHandles = stage2.evidenceHandles ?? [];
568242
+ const resolvedEvidenceHandles = stage2.resolvedEvidenceHandles ?? [];
568243
+ const survivingBlockers = stage2.survivingBlockers ?? [];
568244
+ const unresolvedQuestions = stage2.unresolvedQuestions ?? [];
568245
+ const boundedInventory = stage2.boundedInventory;
568246
+ const boundedDirs = boundedInventory?.dirs ?? [];
568247
+ const requiredArtifactPaths = stage2.requiredArtifactPaths ?? stage2.candidatePaths ?? [];
568248
+ const requiredSet = new Set(requiredArtifactPaths);
568249
+ const exploratoryPaths = (stage2.candidatePaths ?? []).filter((path16) => !requiredSet.has(path16));
568250
+ const resolvedCount = Math.min(evidenceHandles.length, new Set(resolvedEvidenceHandles).size);
568251
+ const unresolvedEvidenceCount = Math.max(evidenceHandles.length - resolvedCount, 0);
568252
+ return [
568253
+ "[COMPLETION CLAIM DISCOVERY]",
568254
+ `status=${stage2.status ?? "skipped"} generated_at=${stage2.generatedAtIso ?? ""}`,
568255
+ `requires_evidence=${stage2.requiresEvidence ? "true" : "false"}`,
568256
+ `bounded_inventory=${boundedInventory ? `${boundedInventory.root}|files=${boundedInventory.files.length}|dirs=${boundedDirs.length}|truncated=${Boolean(boundedInventory.truncated)}` : "none"}`,
568257
+ `required_artifact_paths=${requiredArtifactPaths.join(",") || "none"}`,
568258
+ `exploratory_paths=${exploratoryPaths.join(",") || "none"}`,
568259
+ `open_deltas=${openDeltas.map((delta) => `${delta.path} :: ${delta.reason}`.replace(/\s+/g, " ")).join(" | ") || "none"}`,
568260
+ `open_delta_count=${openDeltas.length} unresolved_evidence_count=${unresolvedEvidenceCount}`,
568261
+ `surviving_blockers=${survivingBlockers.join(" | ") || "none"}`,
568262
+ `unresolved_questions=${unresolvedQuestions.join(" | ") || "none"}`,
568263
+ `evidence_handles=${evidenceHandles.join(",") || "none"}`,
568264
+ `resolved_evidence_handles=${resolvedEvidenceHandles.join(",") || "none"}`
568265
+ ];
568266
+ }
568005
568267
  function createCompletionLedger(input) {
568006
568268
  const ts = nowIso3(input.now);
568007
568269
  return {
@@ -568018,28 +568280,68 @@ function createCompletionLedger(input) {
568018
568280
  };
568019
568281
  }
568020
568282
  function deriveClaimsFromProposedText(input) {
568021
- const raw = String(input.text ?? "").trim();
568022
- if (!raw)
568283
+ return deriveStructuredClaims({
568284
+ taskText: input.taskText,
568285
+ proposedSummary: input.text,
568286
+ source: input.source,
568287
+ existing: input.existing,
568288
+ workspaceInventory: input.workspaceInventory,
568289
+ maxClaims: 12
568290
+ });
568291
+ }
568292
+ function deriveStructuredClaims(input) {
568293
+ const proposed = String(input.proposedSummary ?? "").trim();
568294
+ const task = String(input.taskText ?? "").trim();
568295
+ const baseText = [proposed, task].filter(Boolean).join("\n");
568296
+ const statements = tokenizeClaims(baseText);
568297
+ if (statements.length === 0)
568023
568298
  return [];
568024
568299
  const existingIds = new Set((input.existing ?? []).map((claim) => claim.id));
568025
- const text2 = cleanText(raw, 1200);
568026
- const base3 = normalizeCompletionKey(text2, "claim").slice(0, 64);
568027
- let id2 = base3 || "claim";
568028
- let suffix = 2;
568029
- while (existingIds.has(id2)) {
568030
- id2 = `${base3}_${suffix++}`;
568031
- }
568032
- return [
568033
- {
568300
+ const maxClaims = Math.max(1, Math.min(32, input.maxClaims ?? 12));
568301
+ const seen = /* @__PURE__ */ new Set();
568302
+ const claims = [];
568303
+ for (const statementRaw of statements) {
568304
+ if (claims.length >= maxClaims)
568305
+ break;
568306
+ const text2 = cleanText(statementRaw, 220);
568307
+ if (!text2)
568308
+ continue;
568309
+ const base3 = normalizeCompletionKey(text2, "claim").slice(0, 64) || "claim";
568310
+ let id2 = base3;
568311
+ let suffix = 2;
568312
+ while (existingIds.has(id2) || seen.has(id2)) {
568313
+ id2 = `${base3}_${suffix++}`;
568314
+ }
568315
+ const risk = deriveClaimRisks(text2);
568316
+ const needs = claimEvidenceNeeds(text2);
568317
+ const evidenceHandles = [
568318
+ ...needs.map((need) => need.handle),
568319
+ ...findInventoryMatches(text2, input.workspaceInventory).map((path16) => `workspace:${path16}`)
568320
+ ];
568321
+ const workspaceSignals = findInventoryMatches(text2, input.workspaceInventory);
568322
+ const sourceSignals = [
568323
+ input.taskText ? "task" : "proposed_text",
568324
+ ...extractPathFragments(statementRaw).slice(0, 2)
568325
+ ].filter(Boolean);
568326
+ claims.push({
568034
568327
  id: id2,
568035
568328
  text: text2,
568036
- source: input.source,
568037
- materiality: "high",
568038
- evidenceRequirement: "Explicit evidenceIds must be attached by the caller, or the claim remains unverified for critic review.",
568329
+ source: input.source ?? "derived",
568330
+ materiality: estimateClaimMateriality(statementRaw),
568331
+ evidenceRequirement: "Attach explicit evidenceIds that match the listed evidence handles and state.",
568332
+ attainedState: classifyClaimAttainedState(text2),
568333
+ riskCategory: risk.riskCategory,
568334
+ requiresIndependentEvidence: risk.requiresIndependentEvidence,
568335
+ requiredCheck: risk.requiredCheck,
568336
+ evidenceNeeds: needs,
568337
+ sourceSignals,
568338
+ workspaceSignals,
568039
568339
  evidenceIds: [],
568040
568340
  status: "unverified"
568041
- }
568042
- ];
568341
+ });
568342
+ seen.add(id2);
568343
+ }
568344
+ return claims;
568043
568345
  }
568044
568346
  function recordCompletionEvidence(ledger, evidence) {
568045
568347
  const targetPaths = cleanTargetPaths(evidence.targetPaths);
@@ -568138,14 +568440,45 @@ function buildCriticPacketFromLedger(ledger) {
568138
568440
  lines.push(`Run: ${ledger.runId}`);
568139
568441
  lines.push(`Goal: ${ledger.goal || "(not recorded)"}`);
568140
568442
  lines.push(`Status: ${ledger.status}`);
568443
+ lines.push(`Claims discovered: ${ledger.proposedClaims.length}`);
568444
+ if (ledger.claimDiscovery) {
568445
+ lines.push("");
568446
+ lines.push("Claim Discovery:");
568447
+ lines.push(` status=${ledger.claimDiscovery.status}`);
568448
+ lines.push(` generated_at=${ledger.claimDiscovery.generatedAtIso}`);
568449
+ const requiredArtifactPaths = ledger.claimDiscovery.requiredArtifactPaths ?? ledger.claimDiscovery.candidatePaths;
568450
+ const exploratoryPaths = ledger.claimDiscovery.candidatePaths.filter((path16) => !requiredArtifactPaths.includes(path16));
568451
+ lines.push(` exploratory_paths=${exploratoryPaths.join(",") || "none"}`);
568452
+ lines.push(` required_artifact_paths=${requiredArtifactPaths.join(",") || "none"}`);
568453
+ lines.push(` open_deltas=${ledger.claimDiscovery.openDeltas.map((delta) => `${delta.path} :: ${delta.reason}`).slice(0, 10).join(" | ") || "none"}`);
568454
+ lines.push(` surviving_blockers=${ledger.claimDiscovery.survivingBlockers.join(" | ") || "none"}`);
568455
+ lines.push(` unresolved_questions=${ledger.claimDiscovery.unresolvedQuestions.join(" | ") || "none"}`);
568456
+ lines.push(` evidence_handles=${ledger.claimDiscovery.evidenceHandles.join(",") || "none"}`);
568457
+ lines.push(` resolved_evidence_handles=${ledger.claimDiscovery.resolvedEvidenceHandles.join(",") || "none"}`);
568458
+ }
568141
568459
  lines.push("");
568142
568460
  lines.push("Claims:");
568143
568461
  if (ledger.proposedClaims.length === 0)
568144
568462
  lines.push("- none recorded");
568145
568463
  for (const claim of ledger.proposedClaims) {
568146
- lines.push(`- [${claim.status}] ${claim.id}: ${claim.text}`);
568464
+ const handles = claim.evidenceNeeds.length === 0 ? "none" : claim.evidenceNeeds.map((need) => need.handle).join(", ");
568465
+ lines.push(`- [${claim.status}] ${claim.id} (${claim.attainedState}): ${claim.text}`);
568466
+ lines.push(` source: ${claim.source} materiality:${claim.materiality}`);
568147
568467
  lines.push(` evidence: ${claim.evidenceIds.length > 0 ? claim.evidenceIds.join(", ") : "none"}`);
568148
- lines.push(` requirement: ${claim.evidenceRequirement}`);
568468
+ lines.push(` evidence_handles: ${handles}`);
568469
+ if (claim.workspaceSignals.length > 0) {
568470
+ lines.push(` workspace_signals: ${claim.workspaceSignals.join(", ")}`);
568471
+ }
568472
+ if (claim.sourceSignals.length > 0) {
568473
+ lines.push(` source_signals: ${claim.sourceSignals.join(", ")}`);
568474
+ }
568475
+ lines.push(` requirement: ${claim.evidenceRequirement} ${claim.requiresIndependentEvidence ? "[independent evidence required]" : ""}`);
568476
+ if (claim.riskCategory && claim.riskCategory !== "unknown") {
568477
+ lines.push(` risk: ${claim.riskCategory}`);
568478
+ if (claim.requiredCheck) {
568479
+ lines.push(` required_check: ${claim.requiredCheck}`);
568480
+ }
568481
+ }
568149
568482
  }
568150
568483
  lines.push("");
568151
568484
  lines.push("Evidence:");
@@ -568232,6 +568565,27 @@ function evidenceTargetPaths(entry) {
568232
568565
  }
568233
568566
  return cleanTargetPaths(paths);
568234
568567
  }
568568
+ function claimDiscoveryResolvedHandles(ledger, state) {
568569
+ if (!state)
568570
+ return [];
568571
+ const inspected = /* @__PURE__ */ new Set();
568572
+ const candidatePaths = [...state.requiredArtifactPaths ?? state.candidatePaths].map((value2) => normalizeEvidencePath(value2)).filter(Boolean).map((path16) => path16.replace(/^\/+/, ""));
568573
+ for (const entry of ledger.evidence) {
568574
+ if (entry.success !== true)
568575
+ continue;
568576
+ for (const rawPath of evidenceTargetPaths(entry)) {
568577
+ const path16 = normalizeEvidencePath(rawPath);
568578
+ if (!path16)
568579
+ continue;
568580
+ const normalized = path16.replace(/^\/+/, "");
568581
+ const matched = candidatePaths.find((candidate) => pathsEquivalent(candidate, normalized));
568582
+ if (matched) {
568583
+ inspected.add(`workspace:${matched}`);
568584
+ }
568585
+ }
568586
+ }
568587
+ return [...inspected];
568588
+ }
568235
568589
  function pathsEquivalent(a2, b) {
568236
568590
  const left = normalizeEvidencePath(a2);
568237
568591
  const right = normalizeEvidencePath(b);
@@ -568802,19 +569156,47 @@ import { createHash as createHash28 } from "node:crypto";
568802
569156
  function clean3(value2, max) {
568803
569157
  return String(value2 ?? "").replace(/\s+/g, " ").trim().slice(0, max);
568804
569158
  }
569159
+ function isValidObservationReceipt(entry) {
569160
+ const receipt = entry.receipt;
569161
+ return entry.success === true && entry.role === "observation" && receipt?.schema === "omnius.command-evidence-receipt.v1" && Boolean(receipt.canonicalCommand.trim()) && Boolean(receipt.cwd.trim()) && receipt.exitCode === 0 && receipt.timedOut === false;
569162
+ }
568805
569163
  function selectedEvidence(ledger) {
568806
- if (!ledger)
568807
- return { evidenceIds: [], artifactHashes: [] };
568808
- const candidates = ledger.evidence.filter((entry) => entry.success === true && (entry.role === "verification" || entry.role === "mutation")).slice(-16);
569164
+ if (!ledger) {
569165
+ return {
569166
+ evidenceIds: [],
569167
+ commandReceipts: [],
569168
+ artifactHashes: []
569169
+ };
569170
+ }
569171
+ const candidates = ledger.evidence.filter((entry) => entry.success === true && (entry.role === "verification" || entry.role === "mutation" || isValidObservationReceipt(entry))).slice(-16);
568809
569172
  const artifacts = /* @__PURE__ */ new Map();
569173
+ const commandReceipts = [];
568810
569174
  for (const entry of candidates) {
568811
569175
  for (const item of entry.receipt?.artifactHashes ?? []) {
568812
569176
  if (item.path && item.sha256)
568813
569177
  artifacts.set(item.path, item.sha256);
568814
569178
  }
569179
+ if (entry.receipt) {
569180
+ const receipt = entry.receipt;
569181
+ commandReceipts.push({
569182
+ evidenceId: entry.id,
569183
+ toolName: entry.toolName ?? "unknown",
569184
+ role: entry.role ?? "unknown",
569185
+ command: receipt.command ?? "",
569186
+ canonicalCommand: receipt.canonicalCommand ?? "",
569187
+ cwd: receipt.cwd ?? "",
569188
+ exitCode: receipt.exitCode ?? null,
569189
+ timedOut: Boolean(receipt.timedOut),
569190
+ startedAtIso: receipt.startedAtIso ?? "",
569191
+ finishedAtIso: receipt.finishedAtIso ?? "",
569192
+ observedPaths: receipt.observedPaths ?? [],
569193
+ artifactHashes: entry.receipt.artifactHashes?.length ? entry.receipt.artifactHashes : []
569194
+ });
569195
+ }
568815
569196
  }
568816
569197
  return {
568817
569198
  evidenceIds: candidates.map((entry) => entry.id),
569199
+ commandReceipts,
568818
569200
  artifactHashes: [...artifacts.entries()].map(([path16, sha2567]) => ({
568819
569201
  path: path16,
568820
569202
  sha256: sha2567
@@ -568842,6 +569224,7 @@ function buildCompletionFinalizationRecord(input) {
568842
569224
  summary: clean3(input.summary, 4e3),
568843
569225
  committedAtIso,
568844
569226
  evidenceIds: evidence.evidenceIds,
569227
+ commandReceipts: evidence.commandReceipts,
568845
569228
  artifactHashes: evidence.artifactHashes,
568846
569229
  projections: {
568847
569230
  ledger: "pending",
@@ -577895,16 +578278,90 @@ var init_consolidation_runtime = __esm({
577895
578278
  });
577896
578279
 
577897
578280
  // packages/orchestrator/dist/completion-evidence-gate.js
578281
+ function normalizedEvidenceText(text2) {
578282
+ return String(text2 ?? "").toLowerCase();
578283
+ }
577898
578284
  function classifyCompletionClaim(text2) {
577899
- void text2;
578285
+ const normalized = normalizedEvidenceText(text2);
578286
+ if (!normalized) {
578287
+ return {
578288
+ category: null,
578289
+ requiresIndependentEvidence: false,
578290
+ requiredCheck: ""
578291
+ };
578292
+ }
578293
+ const processLiveness = /\b(daemon|service|process|server|port|listener|runtime|pid|socket|endpoint)\b/.test(normalized) && /\b(start(ed|ing)?|run(ning)?|up|ready|alive|online|boot(ed|ing)?|initialized|listening)\b/.test(normalized);
578294
+ if (processLiveness) {
578295
+ return {
578296
+ category: "process_liveness",
578297
+ requiresIndependentEvidence: true,
578298
+ requiredCheck: "Independent runtime verification (process/pid/health/port check) after the claimed state change."
578299
+ };
578300
+ }
578301
+ if (/\b(instal|npm|pnpm|yarn|pip\s+install|go\s+install|cargo\s+install|apt\s+get|brew\s+install|dnf|yum|apk add|make\s+install)\b/.test(normalized)) {
578302
+ return {
578303
+ category: "installation",
578304
+ requiresIndependentEvidence: true,
578305
+ requiredCheck: "Independent command-level availability check for the installed artifact after change."
578306
+ };
578307
+ }
578308
+ const fixHint = /(fix|fixed|resolved|repair|patched|correct|address|addressed)\b/.test(normalized);
578309
+ const fixTarget = /(bug|regression|failure|error|issue|test|build|lint|crash|exception|pass|coverage)\b/.test(normalized);
578310
+ if (fixHint && fixTarget) {
578311
+ return {
578312
+ category: "fix_confirmation",
578313
+ requiresIndependentEvidence: true,
578314
+ requiredCheck: "Rerun the original failing command path and capture a passing result as evidence."
578315
+ };
578316
+ }
578317
+ if (/(simulat|dry.?run|mock|mocked|virtual|paper|emulat)\b/.test(normalized)) {
578318
+ return {
578319
+ category: "reality",
578320
+ requiresIndependentEvidence: false,
578321
+ requiredCheck: "Mark as simulation-only unless paired with a grounded hardware/live execution claim."
578322
+ };
578323
+ }
577900
578324
  return {
577901
578325
  category: null,
577902
578326
  requiresIndependentEvidence: false,
577903
578327
  requiredCheck: ""
577904
578328
  };
577905
578329
  }
577906
- function detectExitCodeMisread(text2) {
577907
- void text2;
578330
+ function detectExitCodeMisread(input) {
578331
+ const source = typeof input === "string" ? {
578332
+ statement: input,
578333
+ command: "",
578334
+ output: "",
578335
+ exitCode: null,
578336
+ canonicalCommand: ""
578337
+ } : {
578338
+ statement: input.statement ?? "",
578339
+ command: input.command ?? input.canonicalCommand ?? "",
578340
+ output: input.output ?? "",
578341
+ exitCode: typeof input.exitCode === "number" && Number.isFinite(input.exitCode) ? input.exitCode : null,
578342
+ canonicalCommand: ""
578343
+ };
578344
+ const statement = normalizedEvidenceText(source.statement);
578345
+ const command = normalizedEvidenceText(source.command);
578346
+ const output = normalizedEvidenceText(source.output);
578347
+ const exitCode = source.exitCode;
578348
+ if (exitCode !== null && exitCode !== 0 && /\b(success|pass(?:ed|es)?|succeed(?:ed|s)?|ok|completed|done|finished|verified)\b/.test(statement)) {
578349
+ return true;
578350
+ }
578351
+ if (/\|\|\s*(true|:|exit\s+0)/.test(command))
578352
+ return true;
578353
+ if (/\bset\s*\+e\b/.test(command))
578354
+ return true;
578355
+ if (/;\s*\(\s*/.test(command))
578356
+ return true;
578357
+ if (command.includes("|") && !/\bset\s+-o\s+pipefail\b/.test(statement + " " + command)) {
578358
+ return true;
578359
+ }
578360
+ if (/\b\S+\s&\s*$/.test(command.trim()))
578361
+ return true;
578362
+ if (/\bexit(ed|ion)?\s+code\s*[1-9]\d*/.test(statement + " " + output)) {
578363
+ return true;
578364
+ }
577908
578365
  return false;
577909
578366
  }
577910
578367
  function auditCompletionClaims(claims) {
@@ -581059,8 +581516,8 @@ var init_evidenceLedger = __esm({
581059
581516
  }
581060
581517
  /**
581061
581518
  * Return a bounded, read-only projection for components that need to make a
581062
- * routing decision from observed workspace state (for example Feature Loop
581063
- * survey grounding). Callers cannot mutate ledger entries through this
581519
+ * routing decision from observed workspace state (for example claim-discovery
581520
+ * grounding). Callers cannot mutate ledger entries through this
581064
581521
  * result, preserving the ledger as the single freshness authority.
581065
581522
  */
581066
581523
  snapshot(maxEntries = 24) {
@@ -586977,7 +587434,7 @@ var init_longhaul_integration = __esm({
586977
587434
  }
586978
587435
  /**
586979
587436
  * WO-6 (spec §2.5): seed the locked contract from the planner's
586980
- * `LockedContract` at PLAN time. The Feature Loop calls this after the
587437
+ * `LockedContract` at PLAN time. The claim-discovery planner path calls this after the
586981
587438
  * planner emits its artefact, so the breaker's "regenerate from the locked
586982
587439
  * contract" guidance has a real target from the first boundary unit — without
586983
587440
  * waiting for coherent code to accumulate one. Idempotent + fault-tolerant.
@@ -589248,515 +589705,6 @@ var init_git_progress = __esm({
589248
589705
  }
589249
589706
  });
589250
589707
 
589251
- // packages/orchestrator/dist/featurePlanner.js
589252
- import fs7 from "node:fs";
589253
- import path9 from "node:path";
589254
- function classifyKind(survey) {
589255
- const files = survey.files ?? [];
589256
- const newSym = (survey.newSymbols ?? []).length;
589257
- const req3 = survey.request.toLowerCase();
589258
- if (/\b(investigat|why does|how does|trace|understand|root cause|diagnos|explain)\b/.test(req3) && newSym === 0 && files.length <= 2) {
589259
- return "investigation";
589260
- }
589261
- if (/\b(bug|fix|broken|regression|crash|incorrect|fails?|misbehav)/.test(req3) && newSym === 0) {
589262
- return "bugfix";
589263
- }
589264
- if (/\b(refactor|restructure|rename|clean up|simplif|migrate|consolidate)\b/.test(req3) && newSym === 0) {
589265
- return "refactor";
589266
- }
589267
- if (/\b(wir|connect|integrate|hook up|plumb|bridge|glue)\b/.test(req3) && files.length >= 2) {
589268
- return "wiring";
589269
- }
589270
- if (newSym > 0 || /\b(new|create|add|implement|build|introduce|scaffold)\b/.test(req3)) {
589271
- return "new-module";
589272
- }
589273
- return "new-module";
589274
- }
589275
- function guessKind(name10) {
589276
- if (/^(I[A-Z]|.*Interface|.*Contract|.*Spec|.*Event|.*Meta|.*Config|.*State)$/.test(name10)) {
589277
- return "interface";
589278
- }
589279
- if (/^(T|Type|.*Type)$/.test(name10))
589280
- return "type";
589281
- if (/^(E|Enum|.*Kind|.*Status|.*Mode)$/.test(name10))
589282
- return "enum";
589283
- if (/^[A-Z]/.test(name10))
589284
- return "class";
589285
- return "function";
589286
- }
589287
- function buildLockedContract(kind, survey) {
589288
- const symbols = [];
589289
- if (kind === "refactor") {
589290
- for (const name10 of survey.existingSymbols ?? []) {
589291
- symbols.push({ name: name10, kind: guessKind(name10), fields: [] });
589292
- }
589293
- } else if (kind === "new-module") {
589294
- for (const name10 of survey.newSymbols ?? []) {
589295
- symbols.push({ name: name10, kind: guessKind(name10), fields: [] });
589296
- }
589297
- }
589298
- return { symbols };
589299
- }
589300
- function decomposeFeature(survey, kind) {
589301
- const units = [];
589302
- const evidenceRefs = featureEvidenceRefs(survey);
589303
- const unresolvedQuestion = survey.unresolvedQuestions?.[0] ?? (evidenceRefs.length === 0 ? "Which current files, symbols, and tests govern this unit? Inspect them before proposing a mutation." : void 0);
589304
- const returnContract = "Return the direct result with cited observations, relevant/changed paths, verification or blocker, and the next parent decision.";
589305
- const withGrounding = (unit) => ({
589306
- ...unit,
589307
- evidenceRefs,
589308
- ...unresolvedQuestion ? { unresolvedQuestion } : {},
589309
- returnContract
589310
- });
589311
- if (kind === "new-module") {
589312
- const syms = survey.newSymbols ?? [];
589313
- if (syms.length === 0) {
589314
- units.push(withGrounding({
589315
- label: "Establish the module boundary and implement the evidenced unit",
589316
- size: "large",
589317
- detail: "Do not scaffold from the request alone. First identify the owning entry point, adjacent contract, and test surface from current evidence."
589318
- }));
589319
- } else {
589320
- for (const name10 of syms) {
589321
- units.push({
589322
- ...withGrounding({
589323
- label: `Implement ${name10} within its evidenced owner`,
589324
- size: "small",
589325
- detail: "Confirm the symbol's owning module and contract before editing; do not infer a file path from the feature label."
589326
- }),
589327
- expectedSymbols: [name10]
589328
- });
589329
- }
589330
- }
589331
- } else if (kind === "refactor") {
589332
- units.push(withGrounding({
589333
- label: "Refactor only the evidenced public surface",
589334
- size: survey.files.length > 1 ? "large" : "small"
589335
- }));
589336
- } else if (kind === "bugfix") {
589337
- units.push(withGrounding({
589338
- label: "Reproduce the evidenced failure, make the smallest justified fix, and verify it",
589339
- size: "small"
589340
- }));
589341
- } else if (kind === "wiring") {
589342
- units.push(withGrounding({
589343
- label: "Connect the evidenced module boundaries",
589344
- size: survey.files.length > 2 ? "large" : "small"
589345
- }));
589346
- } else {
589347
- units.push(withGrounding({
589348
- label: "Investigate the evidence gap and report the next justified action",
589349
- size: "small"
589350
- }));
589351
- }
589352
- return units;
589353
- }
589354
- function featureEvidenceRefs(survey) {
589355
- const declared = (survey.evidence ?? []).map((item) => item.ref.trim()).filter(Boolean).slice(0, 6);
589356
- if (declared.length > 0)
589357
- return declared;
589358
- return survey.files.map((file) => `survey:file:${file.path}`).filter(Boolean).slice(0, 6);
589359
- }
589360
- function buildFeatureUnitRequest(input) {
589361
- const evidence = (input.survey.evidence ?? []).filter((item) => !input.unit.evidenceRefs?.length || input.unit.evidenceRefs.includes(item.ref)).slice(0, 6);
589362
- const fallbackEvidence = evidence.length > 0 ? evidence : input.survey.files.slice(0, 6).map((file) => ({
589363
- ref: `survey:file:${file.path}`,
589364
- detail: `${file.path}${file.role ? ` — ${file.role}` : ""}`,
589365
- freshness: "unknown"
589366
- }));
589367
- const lines = [
589368
- "[FEATURE UNIT EVIDENCE BRIEF]",
589369
- `Parent request: ${input.parentRequest.slice(0, 900)}`,
589370
- `Requested unit: ${input.unit.label}`,
589371
- `Why now: this unit was selected from the current feature survey, not from a task label alone.`,
589372
- "Evidence:",
589373
- ...fallbackEvidence.length > 0 ? fallbackEvidence.map((item) => `- [${item.freshness ?? "unknown"}] ${item.ref}: ${item.detail.slice(0, 360)}`) : ["- No current code observation is available; discovery is required before mutation."],
589374
- input.unit.unresolvedQuestion ? `Open question: ${input.unit.unresolvedQuestion}` : null,
589375
- "Scope: stay within this unit and directly implicated code; do not broaden the feature without returning to the parent.",
589376
- `Return contract: ${input.unit.returnContract ?? "Return evidence, verification or blocker, and the next parent decision."}`,
589377
- "",
589378
- "Work protocol: inspect the cited files/contracts first. Only mutate after a fresh observation identifies the exact target; if the evidence does not support a target, report the gap instead of fabricating one."
589379
- ];
589380
- return lines.filter((line) => Boolean(line)).join("\n");
589381
- }
589382
- function renderSpecMarkdown(input) {
589383
- const { kind, survey, lockedContract, completionContract, decomposition, prose } = input;
589384
- const lines = [];
589385
- lines.push(`# Feature Plan — ${kind}`);
589386
- lines.push("");
589387
- lines.push(`**Request:** ${survey.request}`);
589388
- lines.push("");
589389
- lines.push(`**Node kind:** \`${kind}\` (selected by CLASSIFY over the survey signals)`);
589390
- lines.push("");
589391
- if (prose) {
589392
- lines.push(`## 1. Intent`);
589393
- lines.push("");
589394
- lines.push(prose.trim());
589395
- lines.push("");
589396
- }
589397
- lines.push(`## 2. Survey (codebase as-is)`);
589398
- lines.push("");
589399
- if (survey.files.length > 0) {
589400
- for (const f2 of survey.files) {
589401
- const refs = f2.lineRefs?.length ? `:${f2.lineRefs.join(",")}` : "";
589402
- lines.push(`- \`${f2.path}${refs}\`${f2.role ? ` — ${f2.role}` : ""}`);
589403
- }
589404
- } else {
589405
- lines.push("- (no files enumerated in survey)");
589406
- }
589407
- if (survey.evidence?.length) {
589408
- for (const item of survey.evidence.slice(0, 8)) {
589409
- lines.push(`- evidence [${item.freshness ?? "unknown"}] ${item.ref}: ${item.detail}`);
589410
- }
589411
- }
589412
- if (survey.unresolvedQuestions?.length) {
589413
- lines.push(`- unresolved: ${survey.unresolvedQuestions.join("; ")}`);
589414
- }
589415
- lines.push(`- new symbols: ${(survey.newSymbols ?? []).join(", ") || "none"}`);
589416
- lines.push(`- public surface changes: ${survey.publicSurfaceChanges ? "yes" : "no"}`);
589417
- lines.push(`- tests exist: ${survey.testsExist ? "yes" : "no"}`);
589418
- lines.push("");
589419
- lines.push(`## 3. Locked contract (executable gate)`);
589420
- lines.push("");
589421
- if (lockedContract.symbols.length === 0) {
589422
- lines.push("- (no locked symbols for this kind — disciplined but permissive)");
589423
- } else {
589424
- for (const s2 of lockedContract.symbols) {
589425
- lines.push(`- \`${s2.kind} ${s2.name}\``);
589426
- }
589427
- }
589428
- lines.push("");
589429
- lines.push(`## 4. Definition of done (CompletionContract)`);
589430
- lines.push("");
589431
- lines.push(`- goal: ${completionContract.goalSummary || "(none)"}`);
589432
- for (const p2 of completionContract.phases ?? []) {
589433
- lines.push(`- phase: ${p2.label}`);
589434
- }
589435
- lines.push("");
589436
- lines.push(`## 5. Decomposition (SPLIT seed)`);
589437
- lines.push("");
589438
- for (const u of decomposition) {
589439
- lines.push(`- [${u.size}] ${u.label}${u.expectedSymbols?.length ? ` (symbols: ${u.expectedSymbols.join(", ")})` : ""}${u.evidenceRefs?.length ? ` [evidence: ${u.evidenceRefs.join(", ")}]` : ""}`);
589440
- }
589441
- lines.push("");
589442
- lines.push(`## 6. Verification bar`);
589443
- lines.push("");
589444
- lines.push("- planner emits real artefacts (this file + locked contract + completion contract)");
589445
- lines.push("- approval gate blocks before any source edit");
589446
- lines.push("- WO-6 executor gate activates on locked symbols");
589447
- lines.push("- recursion + eviction keep context bounded");
589448
- lines.push("- scope token re-prompts on out-of-scope work");
589449
- lines.push("");
589450
- lines.push(`## 7. Handoff notes`);
589451
- lines.push("");
589452
- lines.push("- Compose, do not rebuild: this plan reuses spec-gate + completionContract primitives.");
589453
- lines.push("- Fail-closed: if planning errors, the run falls back to the general agentic loop.");
589454
- lines.push("");
589455
- return lines.join("\n");
589456
- }
589457
- async function planFeature(survey, options2 = {}) {
589458
- const kind = classifyKind(survey);
589459
- const lockedContract = buildLockedContract(kind, survey);
589460
- const completionContract = inferCompletionContractFromTexts([survey.request, ...survey.rawTexts ?? [], ...survey.signals ?? []], survey.request);
589461
- const decomposition = decomposeFeature(survey, kind);
589462
- let prose = "";
589463
- try {
589464
- if (options2.proseGenerator) {
589465
- prose = await options2.proseGenerator({ request: survey.request, kind, survey });
589466
- }
589467
- } catch {
589468
- prose = "";
589469
- }
589470
- const specMarkdown = renderSpecMarkdown({
589471
- kind,
589472
- survey,
589473
- lockedContract,
589474
- completionContract,
589475
- decomposition,
589476
- prose
589477
- });
589478
- return { kind, specMarkdown, lockedContract, completionContract, decomposition };
589479
- }
589480
- function persistPlannerArtefacts(rootId, artefact, stateDir) {
589481
- try {
589482
- const dir = path9.join(stateDir, "feature-tree", rootId);
589483
- fs7.mkdirSync(dir, { recursive: true });
589484
- fs7.writeFileSync(path9.join(dir, "spec.md"), artefact.specMarkdown, "utf8");
589485
- fs7.writeFileSync(path9.join(dir, "locked-contract.json"), JSON.stringify(artefact.lockedContract, null, 2), "utf8");
589486
- fs7.writeFileSync(path9.join(dir, "completion-contract.json"), JSON.stringify(artefact.completionContract, null, 2), "utf8");
589487
- } catch {
589488
- }
589489
- }
589490
- var init_featurePlanner = __esm({
589491
- "packages/orchestrator/dist/featurePlanner.js"() {
589492
- "use strict";
589493
- init_completionContract();
589494
- }
589495
- });
589496
-
589497
- // packages/orchestrator/dist/featureApprovalGate.js
589498
- function mintScopeToken(input) {
589499
- return {
589500
- rootId: input.rootId,
589501
- files: [...input.files ?? []],
589502
- symbols: input.lockedContract.symbols.map((s2) => s2.name),
589503
- nodeKinds: input.nodeKinds ?? ["new-module", "refactor", "bugfix", "wiring", "investigation"],
589504
- depthCap: input.depthCap
589505
- };
589506
- }
589507
- function isWithinScope(input) {
589508
- const { token } = input;
589509
- if (typeof input.depth === "number" && input.depth > token.depthCap) {
589510
- return false;
589511
- }
589512
- if (input.nodeKind && !token.nodeKinds.includes(input.nodeKind)) {
589513
- return false;
589514
- }
589515
- if (input.newSymbol && !token.symbols.includes(input.newSymbol)) {
589516
- return false;
589517
- }
589518
- if (input.file) {
589519
- const file = input.file;
589520
- const allowed = token.files.some((f2) => {
589521
- if (f2 === file)
589522
- return true;
589523
- if (f2.endsWith("/") && file.startsWith(f2))
589524
- return true;
589525
- if (f2.includes("*") && globMatch(f2, file))
589526
- return true;
589527
- return false;
589528
- });
589529
- if (!allowed)
589530
- return false;
589531
- }
589532
- return true;
589533
- }
589534
- function globMatch(pattern, value2) {
589535
- const re = new RegExp("^" + pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*") + "$");
589536
- return re.test(value2);
589537
- }
589538
- async function requestApproval(req3, ask2, options2 = {}) {
589539
- let decision2;
589540
- try {
589541
- const raw = await ask2(req3);
589542
- decision2 = raw === "approve" || raw === "edit" || raw === "reject" ? raw : "reject";
589543
- } catch {
589544
- decision2 = "reject";
589545
- }
589546
- if (decision2 === "approve") {
589547
- const token = mintScopeToken({
589548
- rootId: req3.rootId,
589549
- lockedContract: req3.lockedContract,
589550
- decomposition: req3.decomposition,
589551
- depthCap: req3.depthCap,
589552
- files: options2.files,
589553
- nodeKinds: options2.nodeKinds
589554
- });
589555
- return { decision: decision2, token };
589556
- }
589557
- return { decision: decision2 };
589558
- }
589559
- var init_featureApprovalGate = __esm({
589560
- "packages/orchestrator/dist/featureApprovalGate.js"() {
589561
- "use strict";
589562
- }
589563
- });
589564
-
589565
- // packages/orchestrator/dist/featureNode.js
589566
- import fs8 from "node:fs";
589567
- import path10 from "node:path";
589568
- function treePath(stateDir, rootId) {
589569
- return path10.join(stateDir, "feature-tree", `${rootId}.json`);
589570
- }
589571
- function saveFeatureTree(stateDir, rootId, nodes) {
589572
- try {
589573
- const file = treePath(stateDir, rootId);
589574
- fs8.mkdirSync(path10.dirname(file), { recursive: true });
589575
- fs8.writeFileSync(file, JSON.stringify(nodes, null, 2), "utf8");
589576
- } catch {
589577
- }
589578
- }
589579
- function loadFeatureTree(stateDir, rootId) {
589580
- try {
589581
- const file = treePath(stateDir, rootId);
589582
- if (!fs8.existsSync(file))
589583
- return null;
589584
- const raw = JSON.parse(fs8.readFileSync(file, "utf8"));
589585
- return raw && typeof raw === "object" ? raw : null;
589586
- } catch {
589587
- return null;
589588
- }
589589
- }
589590
- function newNodeId(depth, seed) {
589591
- const h = String(Math.abs(hashString2(seed)) % 1e9).padStart(9, "0");
589592
- return `fn-d${depth}-${h}`;
589593
- }
589594
- function hashString2(s2) {
589595
- let h = 0;
589596
- for (let i2 = 0; i2 < s2.length; i2++)
589597
- h = h * 31 + s2.charCodeAt(i2) | 0;
589598
- return h;
589599
- }
589600
- async function evictNode(node, ctx3, transcript) {
589601
- try {
589602
- await runTodoChunker({
589603
- inputs: {
589604
- todoId: node.id,
589605
- todoContent: node.request,
589606
- turnRange: [0, 0],
589607
- transcript: transcript || node.request,
589608
- toolCalls: [],
589609
- workingDirectory: ctx3.workingDirectory,
589610
- sessionId: ctx3.sessionId
589611
- },
589612
- callable: ctx3.summarizer ?? (async () => "")
589613
- });
589614
- } catch {
589615
- }
589616
- }
589617
- async function execUnit(unit, node, ctx3, contract, maxRegenerate) {
589618
- let result = await ctx3.executeUnit(unit, node);
589619
- if (!result.ok)
589620
- return false;
589621
- const expected = unit.expectedSymbols ?? [];
589622
- if (expected.length === 0) {
589623
- return true;
589624
- }
589625
- for (let attempt = 0; attempt <= maxRegenerate; attempt++) {
589626
- if (!result.path || result.source === void 0)
589627
- return false;
589628
- const verdict = evaluateExecutorStep({
589629
- unit: { path: result.path, source: result.source },
589630
- contract,
589631
- expectedSymbols: expected
589632
- });
589633
- if (verdict.decision === "accept")
589634
- return true;
589635
- if (verdict.decision === "replan")
589636
- return false;
589637
- result = await ctx3.executeUnit(unit, node);
589638
- if (!result.ok)
589639
- return false;
589640
- }
589641
- return false;
589642
- }
589643
- async function runFeatureNode(node, ctx3, options2, tree2 = {}) {
589644
- const maxRegenerate = options2.maxRegenerate ?? 2;
589645
- tree2[node.id] = node;
589646
- try {
589647
- const artefact = await planFeature(options2.survey, {
589648
- proseGenerator: options2.proseGenerator
589649
- });
589650
- node.kind = artefact.kind;
589651
- if (ctx3.onPlan) {
589652
- try {
589653
- await ctx3.onPlan(artefact);
589654
- } catch {
589655
- }
589656
- }
589657
- persistPlannerArtefacts(ctx3.rootId, artefact, ctx3.stateDir);
589658
- const mustAsk = node.depth === 0 || !node.scopeToken;
589659
- if (mustAsk && ctx3.askApproval) {
589660
- node.status = "awaiting_approval";
589661
- const outcome = await requestApproval({
589662
- rootId: ctx3.rootId,
589663
- request: node.request,
589664
- specMarkdown: artefact.specMarkdown,
589665
- lockedContract: artefact.lockedContract,
589666
- decomposition: artefact.decomposition,
589667
- depthCap: ctx3.depthCap
589668
- }, ctx3.askApproval, { files: options2.survey.files.map((f2) => f2.path) });
589669
- if (outcome.decision !== "approve") {
589670
- node.status = outcome.decision === "edit" ? "planned" : "rejected";
589671
- saveFeatureTree(ctx3.stateDir, ctx3.rootId, tree2);
589672
- return node;
589673
- }
589674
- node.scopeToken = outcome.token;
589675
- }
589676
- node.status = "approved";
589677
- node.status = "executing";
589678
- let allOk = true;
589679
- for (const unit of artefact.decomposition) {
589680
- if (unit.size === "large" && node.depth < ctx3.depthCap) {
589681
- const childId = newNodeId(node.depth + 1, unit.label + node.id);
589682
- const childRequest = buildFeatureUnitRequest({
589683
- unit,
589684
- parentRequest: node.request,
589685
- survey: options2.survey
589686
- });
589687
- const child = {
589688
- id: childId,
589689
- parentId: node.id,
589690
- depth: node.depth + 1,
589691
- request: childRequest,
589692
- kind: artefact.kind,
589693
- status: "planned",
589694
- scopeToken: node.scopeToken,
589695
- children: []
589696
- };
589697
- node.children.push(childId);
589698
- const childSurvey = {
589699
- ...options2.survey,
589700
- request: child.request
589701
- };
589702
- const childCtx = {
589703
- ...ctx3,
589704
- // children inherit the token; re-prompt only if they exceed scope
589705
- askApproval: (req3) => isWithinScope({
589706
- token: node.scopeToken,
589707
- depth: node.depth + 1,
589708
- nodeKind: artefact.kind
589709
- }) ? "approve" : ctx3.askApproval(req3)
589710
- };
589711
- const res = await runFeatureNode(child, childCtx, { ...options2, survey: childSurvey }, tree2);
589712
- if (res.status !== "completed")
589713
- allOk = false;
589714
- await evictNode(child, ctx3, child.request);
589715
- } else {
589716
- const ok3 = await execUnit(unit, node, ctx3, artefact.lockedContract, maxRegenerate);
589717
- if (!ok3)
589718
- allOk = false;
589719
- }
589720
- }
589721
- if (allOk) {
589722
- node.status = "completed";
589723
- } else {
589724
- node.status = "failed";
589725
- }
589726
- saveFeatureTree(ctx3.stateDir, ctx3.rootId, tree2);
589727
- return node;
589728
- } catch {
589729
- if (ctx3.runGeneralLoop) {
589730
- await ctx3.runGeneralLoop(node.request);
589731
- node.status = "completed";
589732
- } else {
589733
- node.status = "failed";
589734
- }
589735
- saveFeatureTree(ctx3.stateDir, ctx3.rootId, tree2);
589736
- return node;
589737
- }
589738
- }
589739
- function createRootFeatureNode(request) {
589740
- return {
589741
- id: newNodeId(0, request),
589742
- parentId: null,
589743
- depth: 0,
589744
- request,
589745
- kind: "new-module",
589746
- status: "planned",
589747
- children: []
589748
- };
589749
- }
589750
- var init_featureNode = __esm({
589751
- "packages/orchestrator/dist/featureNode.js"() {
589752
- "use strict";
589753
- init_featurePlanner();
589754
- init_featureApprovalGate();
589755
- init_spec_gate();
589756
- init_todo_context_chunker();
589757
- }
589758
- });
589759
-
589760
589708
  // packages/orchestrator/dist/preflightSnapshot.js
589761
589709
  var preflightSnapshot_exports = {};
589762
589710
  __export(preflightSnapshot_exports, {
@@ -590875,6 +590823,161 @@ function stripShellQuotedSegments(command) {
590875
590823
  }
590876
590824
  return out;
590877
590825
  }
590826
+ function extractClaimPathFragments(text2) {
590827
+ const out = [];
590828
+ const pathPattern = /\b(?:[\w.-]+\/[\w./-]+(?:\.[A-Za-z0-9]+)?|[\w.-]+\.[A-Za-z0-9]+)\b/g;
590829
+ for (const match of text2.matchAll(pathPattern)) {
590830
+ const value2 = sanitizeDelegationText(String(match[0] ?? ""), 260).trim();
590831
+ if (!value2)
590832
+ continue;
590833
+ out.push(value2);
590834
+ }
590835
+ return [...new Set(out)];
590836
+ }
590837
+ function normalizeClaimPathSignal(raw) {
590838
+ const normalized = raw.replace(/["'`]+/g, "").replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+/g, "/").trim().toLowerCase();
590839
+ if (!normalized)
590840
+ return "";
590841
+ if (normalized.length < 4)
590842
+ return "";
590843
+ if (normalized.includes(".."))
590844
+ return "";
590845
+ if (/[\\s]/.test(normalized))
590846
+ return "";
590847
+ return normalized;
590848
+ }
590849
+ function isLikelyPathSignal(value2) {
590850
+ if (!value2)
590851
+ return false;
590852
+ return value2.includes("/") || /\.[a-z0-9]+$/i.test(value2);
590853
+ }
590854
+ function collectClaimPathSignals(text2) {
590855
+ const direct = extractClaimPathFragments(text2).map((value2) => normalizeClaimPathSignal(value2)).filter(isLikelyPathSignal);
590856
+ const quoted = [...text2.matchAll(/["'`](.*?)["'`]/g)].map((match) => normalizeClaimPathSignal(String(match[1] ?? ""))).filter((value2) => isLikelyPathSignal(value2));
590857
+ return [.../* @__PURE__ */ new Set([...direct, ...quoted])];
590858
+ }
590859
+ function matchHintToInventoryPath(path16, hint) {
590860
+ const normalizedPath = normalizeClaimPathSignal(path16);
590861
+ const normalizedHint = normalizeClaimPathSignal(hint);
590862
+ if (!normalizedPath || !normalizedHint)
590863
+ return false;
590864
+ if (normalizedPath === normalizedHint)
590865
+ return true;
590866
+ if (normalizedPath.endsWith(`/${normalizedHint}`))
590867
+ return true;
590868
+ if (normalizedPath.endsWith(normalizedHint))
590869
+ return true;
590870
+ if (normalizedHint.includes("/") && normalizedPath.includes(normalizedHint))
590871
+ return true;
590872
+ const base3 = normalizedPath.split("/").at(-1) ?? "";
590873
+ return base3 === normalizedHint;
590874
+ }
590875
+ function claimDiscoveryFallbackCandidates(files, maxCandidates) {
590876
+ const ranked = [];
590877
+ const nowMs = Date.now();
590878
+ const maxAgeMs = 30 * 24 * 60 * 60 * 1e3;
590879
+ for (const raw of files) {
590880
+ const rawPath = String(raw.path ?? "").trim();
590881
+ if (!rawPath || rawPath.startsWith(".omnius/"))
590882
+ continue;
590883
+ const normalized = rawPath.replace(/\s+/g, " ").trim().replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+/g, "/").toLowerCase();
590884
+ if (normalized.length < 4 || normalized.includes(".."))
590885
+ continue;
590886
+ const chunks = normalized.split("/").filter(Boolean);
590887
+ const depth = chunks.length || 1;
590888
+ const reasons = [];
590889
+ let score = 0;
590890
+ score += Math.max(1, 12 - Math.min(depth, 10));
590891
+ reasons.push("generic workspace proximity");
590892
+ if (raw.bytes !== void 0) {
590893
+ if (raw.bytes > 5e5)
590894
+ score -= 3;
590895
+ else if (raw.bytes > 8e4)
590896
+ score -= 1;
590897
+ if (raw.bytes > 5e5)
590898
+ reasons.push("large artifact");
590899
+ else if (raw.bytes > 8e4)
590900
+ reasons.push("moderate artifact");
590901
+ else
590902
+ reasons.push("light payload");
590903
+ }
590904
+ if (raw.mtimeMs !== void 0 && raw.mtimeMs > 0) {
590905
+ const age = nowMs - raw.mtimeMs;
590906
+ if (age >= 0 && age < maxAgeMs) {
590907
+ score += 2;
590908
+ reasons.push("recently modified");
590909
+ } else if (age < 0) {
590910
+ score += 1;
590911
+ reasons.push("fresh metadata");
590912
+ } else {
590913
+ reasons.push("older artifact");
590914
+ }
590915
+ }
590916
+ const pathSignal = chunks.join("/");
590917
+ if (!pathSignal)
590918
+ continue;
590919
+ ranked.push({
590920
+ path: pathSignal,
590921
+ score,
590922
+ reasons: [...new Set(reasons)].slice(0, 3)
590923
+ });
590924
+ }
590925
+ ranked.sort((left, right) => right.score !== left.score ? right.score - left.score : left.path.localeCompare(right.path));
590926
+ const fallback = [];
590927
+ for (const entry of ranked) {
590928
+ if (fallback.length >= maxCandidates)
590929
+ break;
590930
+ const canonical2 = entry.path.replace(/\\/g, "/").replace(/\/+/g, "/").replace(/^\.\//, "").trim().toLowerCase();
590931
+ if (canonical2.length < 4 || canonical2.includes(".."))
590932
+ continue;
590933
+ if (fallback.some((candidate) => candidate.path === canonical2))
590934
+ continue;
590935
+ fallback.push({
590936
+ path: canonical2,
590937
+ reasons: entry.reasons.length > 0 ? entry.reasons : ["generic workspace candidate"]
590938
+ });
590939
+ }
590940
+ return fallback;
590941
+ }
590942
+ function extractClaimTaskTokens(text2) {
590943
+ return String(text2 ?? "").toLowerCase().replace(/["'`]/g, " ").replace(/[^\w./-]+/g, " ").split(/\s+/).map((value2) => value2.trim()).filter((value2) => value2.length >= 4 && value2.length <= 80 && /[a-z0-9]/i.test(value2)).slice(0, 80);
590944
+ }
590945
+ function isMeaningfulClaimTaskToken(token) {
590946
+ if (!token)
590947
+ return false;
590948
+ const normalized = token.toLowerCase();
590949
+ if (normalized.length < 4 || normalized.length > 80)
590950
+ return false;
590951
+ if (!/[a-z0-9]/i.test(normalized))
590952
+ return false;
590953
+ if (CLAIM_TASK_STOPWORDS.has(normalized))
590954
+ return false;
590955
+ return true;
590956
+ }
590957
+ function chunkHasSymbolMatch(token, text2) {
590958
+ const haystack = text2.toLowerCase().replace(/[^a-z0-9]+/g, " ");
590959
+ const tokens = haystack.split(" ").filter(Boolean);
590960
+ return tokens.includes(token);
590961
+ }
590962
+ function escapeRegExp3(value2) {
590963
+ return value2.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
590964
+ }
590965
+ function shellCommandLooksLikeInspection(command) {
590966
+ const outsideQuotes = stripShellQuotedSegments(command);
590967
+ return /\b(?:cat|sed|head|tail|less|more|awk|grep|rg|file|stat|wc|sha(?:1|224|256|384|512)sum|md5sum|git\s+(?:show|diff))\b/i.test(outsideQuotes);
590968
+ }
590969
+ function shellCommandReferencesExactPath(command, path16, workspaceRoot) {
590970
+ const normalized = path16.replace(/\\/g, "/").replace(/^\.\//, "").trim();
590971
+ if (!normalized || normalized.includes(".."))
590972
+ return false;
590973
+ const absolute = _pathResolve(workspaceRoot, normalized).replace(/\\/g, "/");
590974
+ const candidates = [normalized, `./${normalized}`, absolute];
590975
+ return candidates.some((candidate) => {
590976
+ const escaped = escapeRegExp3(candidate);
590977
+ const matcher = new RegExp(`(?:^|[\\s"'\`=:(])${escaped}(?=$|[\\s"'\`;|)&,])`);
590978
+ return matcher.test(command);
590979
+ });
590980
+ }
590878
590981
  function isCompilerLikeVerifierCommand(command) {
590879
590982
  const normalized = command.toLowerCase();
590880
590983
  return /\b(?:pio|platformio|tsc|gcc|g\+\+|clang\+\+?|clang|cargo\s+(?:build|check)|go\s+(?:build|test)|javac|gradle|mvn|msbuild|dotnet\s+build|python(?:3)?\s+-m\s+(?:py_compile|compileall)|mypy|pyright)\b/.test(normalized);
@@ -591617,7 +591720,7 @@ function classifyThinkOutcome(raw) {
591617
591720
  }
591618
591721
  return null;
591619
591722
  }
591620
- var PRESERVE_MODEL_VISIBLE_HISTORY, TOOL_SUBSETS, TOOL_AUTO_DEMOTE_TURNS, LEGACY_ACTION_REASON_KEYS, SYSTEM_PROMPT, SYSTEM_PROMPT_MEDIUM, SYSTEM_PROMPT_SMALL, VISUAL_TOOLS, AUDIO_TOOLS, SOCIAL_TOOLS, SPATIAL_TOOLS, CODE_TOOLS, AgenticRunner, OllamaAgenticBackend;
591723
+ var PRESERVE_MODEL_VISIBLE_HISTORY, TOOL_SUBSETS, TOOL_AUTO_DEMOTE_TURNS, LEGACY_ACTION_REASON_KEYS, CLAIM_TASK_STOPWORDS, SYSTEM_PROMPT, SYSTEM_PROMPT_MEDIUM, SYSTEM_PROMPT_SMALL, VISUAL_TOOLS, AUDIO_TOOLS, SOCIAL_TOOLS, SPATIAL_TOOLS, CODE_TOOLS, AgenticRunner, OllamaAgenticBackend;
591621
591724
  var init_agenticRunner = __esm({
591622
591725
  "packages/orchestrator/dist/agenticRunner.js"() {
591623
591726
  "use strict";
@@ -591699,8 +591802,6 @@ var init_agenticRunner = __esm({
591699
591802
  init_prompt_cache();
591700
591803
  init_compile_error_fix_loop();
591701
591804
  init_git_progress();
591702
- init_featurePlanner();
591703
- init_featureNode();
591704
591805
  PRESERVE_MODEL_VISIBLE_HISTORY = /* @__PURE__ */ Symbol("omnius.preserveModelVisibleHistory");
591705
591806
  TOOL_SUBSETS = {
591706
591807
  web: ["web_search", "web_fetch", "web_crawl"],
@@ -591727,6 +591828,79 @@ var init_agenticRunner = __esm({
591727
591828
  };
591728
591829
  TOOL_AUTO_DEMOTE_TURNS = 10;
591729
591830
  LEGACY_ACTION_REASON_KEYS = /* @__PURE__ */ new Set(["action_reason", "actionReason"]);
591831
+ CLAIM_TASK_STOPWORDS = /* @__PURE__ */ new Set([
591832
+ "this",
591833
+ "that",
591834
+ "these",
591835
+ "those",
591836
+ "there",
591837
+ "where",
591838
+ "from",
591839
+ "with",
591840
+ "what",
591841
+ "when",
591842
+ "then",
591843
+ "help",
591844
+ "please",
591845
+ "request",
591846
+ "about",
591847
+ "their",
591848
+ "would",
591849
+ "could",
591850
+ "should",
591851
+ "might",
591852
+ "issue",
591853
+ "issues",
591854
+ "bug",
591855
+ "problem",
591856
+ "problems",
591857
+ "task",
591858
+ "tasks",
591859
+ "run",
591860
+ "build",
591861
+ "make",
591862
+ "need",
591863
+ "needs",
591864
+ "also",
591865
+ "only",
591866
+ "same",
591867
+ "other",
591868
+ "code",
591869
+ "file",
591870
+ "files",
591871
+ "repo",
591872
+ "project",
591873
+ "workspace",
591874
+ "read",
591875
+ "fix",
591876
+ "add",
591877
+ "remove",
591878
+ "create",
591879
+ "review",
591880
+ "check",
591881
+ "report",
591882
+ "inspect",
591883
+ "update",
591884
+ "implement",
591885
+ "setup",
591886
+ "install",
591887
+ "deploy",
591888
+ "run",
591889
+ "get",
591890
+ "set",
591891
+ "open",
591892
+ "close",
591893
+ "start",
591894
+ "stop",
591895
+ "turn",
591896
+ "off",
591897
+ "on",
591898
+ "enable",
591899
+ "disable",
591900
+ "add",
591901
+ "new",
591902
+ "old"
591903
+ ]);
591730
591904
  SYSTEM_PROMPT = loadPrompt("agentic/system-large.md");
591731
591905
  SYSTEM_PROMPT_MEDIUM = loadPrompt("agentic/system-medium.md");
591732
591906
  SYSTEM_PROMPT_SMALL = loadPrompt("agentic/system-small.md");
@@ -592024,8 +592198,6 @@ var init_agenticRunner = __esm({
592024
592198
  _wideExplorationCooldownUntilTurn = -1;
592025
592199
  /** REG-44: how many times the stuck detector has fired (for adaptive cooldown). */
592026
592200
  _reg44FireCount = 0;
592027
- /** Guard against re-entering the feature loop. */
592028
- _inFeatureLoop = false;
592029
592201
  // REG-45: sticky cross-turn escalation. The dispatch-time reflection
592030
592202
  // surface (REG-26) only fires when the agent re-emits the exact same
592031
592203
  // failed stem. If the agent thrashes on OTHER tools (wide-exploration
@@ -592145,6 +592317,7 @@ var init_agenticRunner = __esm({
592145
592317
  */
592146
592318
  _completionCaveat = null;
592147
592319
  _completionLedger = null;
592320
+ _claimDiscoveryInitialized = false;
592148
592321
  _staleEditFamilies = /* @__PURE__ */ new Map();
592149
592322
  /** Semantic retry counter for blocked full-file writes (payload-independent). */
592150
592323
  _blockedFullWriteAttempts = /* @__PURE__ */ new Map();
@@ -593518,7 +593691,9 @@ ${parts.join("\n")}
593518
593691
  success: input.status === "completed",
593519
593692
  output: `terminal_receipt=${record.id}
593520
593693
  marker=${markerPath}
593521
- evidence=${record.evidenceIds.join(",") || "none"}`
593694
+ evidence=${record.evidenceIds.join(",") || "none"}
593695
+ command_receipts=${record.commandReceipts.length}
593696
+ ` + (record.commandReceipts.length > 0 ? `command_receipts_summary=${record.commandReceipts.map((entry) => `${entry.canonicalCommand || entry.command || "n/a"}:${entry.exitCode}`).join(" | ")}` : "command_receipts_summary=none")
593522
593697
  });
593523
593698
  commitTerminalTrajectoryProjection(stateDir, record, input.trajectoryPayload);
593524
593699
  const committed = {
@@ -593610,6 +593785,7 @@ evidence=${record.evidenceIds.join(",") || "none"}`
593610
593785
  disableAdversaryCritic,
593611
593786
  disableStepCritic: disableAdversaryCritic,
593612
593787
  modelTier: options2?.modelTier ?? "large",
593788
+ claimDiscovery: options2?.claimDiscovery,
593613
593789
  referenceContractModules: options2?.referenceContractModules ?? [],
593614
593790
  contextWindowSize: options2?.contextWindowSize ?? 0,
593615
593791
  recursionDepth: options2?.recursionDepth ?? 0,
@@ -597037,7 +597213,7 @@ ${extras.join("\n")}`;
597037
597213
  const paths = args["edits"].map((edit) => edit && typeof edit === "object" ? edit["path"] : null).filter((p3) => typeof p3 === "string" && p3.trim().length > 0);
597038
597214
  return [...new Set(paths)];
597039
597215
  }
597040
- const p2 = args?.["path"] ?? args?.["file_path"] ?? args?.["file"] ?? args?.["filename"] ?? args?.["filepath"] ?? args?.["filePath"];
597216
+ const p2 = args?.["path"] ?? args?.["file_path"] ?? args?.["file"] ?? args?.["filename"] ?? args?.["filepath"] ?? args?.["filePath"] ?? args?.["input"] ?? args?.["target"];
597041
597217
  return typeof p2 === "string" && p2.trim().length > 0 ? [p2.trim()] : [];
597042
597218
  }
597043
597219
  _isRealProjectMutation(toolName, result) {
@@ -597150,11 +597326,17 @@ ${modelVisible}` : modelVisible || result.error || displayOutput || "";
597150
597326
  return;
597151
597327
  const realFileMutation = input.realFileMutation ?? this._isRealProjectMutation(input.toolName, input.result);
597152
597328
  const attemptedTargetPaths = this._extractToolTargetPaths(input.toolName, input.args, input.result);
597329
+ const explicitInspectionPaths = this._successfulShellInspectionAnchorPaths(input.toolName, input.result);
597330
+ const evidenceTargetPaths2 = [
597331
+ .../* @__PURE__ */ new Set([...attemptedTargetPaths, ...explicitInspectionPaths])
597332
+ ];
597153
597333
  const realMutationPaths = input.realMutationPaths ?? (realFileMutation ? attemptedTargetPaths : []);
597154
597334
  const receipt = input.result.executionReceipt ? {
597155
597335
  ...input.result.executionReceipt,
597336
+ ...explicitInspectionPaths.length > 0 ? { observedPaths: explicitInspectionPaths } : {},
597156
597337
  artifactHashes: this._completionArtifactHashes([
597157
597338
  ...attemptedTargetPaths,
597339
+ ...explicitInspectionPaths,
597158
597340
  ...realMutationPaths
597159
597341
  ])
597160
597342
  } : void 0;
@@ -597171,13 +597353,16 @@ ${modelVisible}` : modelVisible || result.error || displayOutput || "";
597171
597353
  success: input.result.success,
597172
597354
  outputPreview: (input.outputPreview ?? this._toolEvidencePreview(input.result, void 0, 1200, input.toolName)).toString().slice(0, input.toolName === "audio_analyze" || input.toolName === "video_understand" ? 1200 : 500),
597173
597355
  argsKey: input.argsKey.slice(0, 300),
597174
- targetPaths: attemptedTargetPaths,
597175
- role: input.result.completionEvidenceRole ?? (input.result.alreadyApplied === true ? "mutation" : realFileMutation ? "mutation" : input.result.runtimeAuthored === true && !shellVerification ? "blocker" : shellVerification ? "verification" : void 0),
597356
+ targetPaths: evidenceTargetPaths2,
597357
+ role: input.result.completionEvidenceRole ?? (input.result.alreadyApplied === true ? "mutation" : realFileMutation ? "mutation" : input.result.runtimeAuthored === true && !shellVerification ? "blocker" : shellVerification ? "verification" : input.result.success === true ? "observation" : void 0),
597176
597358
  family: input.result.completionEvidenceFamily ?? (input.result.runtimeAuthored === true && !shellVerification ? "runtime_control" : shellVerification ? shellVerificationFamily : void 0),
597177
597359
  verificationImpact: input.result.completionVerificationImpact ?? (input.result.alreadyApplied === true ? "neutral" : realFileMutation ? "invalidates" : void 0),
597178
597360
  metrics: input.result.completionEvidenceMetrics,
597179
597361
  receipt
597180
597362
  });
597363
+ if (this._completionLedger?.claimDiscovery) {
597364
+ this._refreshClaimDiscoveryStateFromEvidence();
597365
+ }
597181
597366
  if (realFileMutation && realMutationPaths.length > 0) {
597182
597367
  for (const filePath of realMutationPaths) {
597183
597368
  this._completionLedger = recordCompletionEvidence(this._completionLedger, {
@@ -597194,6 +597379,76 @@ ${modelVisible}` : modelVisible || result.error || displayOutput || "";
597194
597379
  }
597195
597380
  this._saveCompletionLedgerSafe();
597196
597381
  }
597382
+ /**
597383
+ * Credit a shell read only when it has a trusted successful local receipt
597384
+ * and mentions one of the user's explicit, inventory-resolved artifact
597385
+ * anchors. This prevents filename/token guesses, echoed path strings, and
597386
+ * arbitrary shell output from becoming discovery evidence.
597387
+ */
597388
+ _successfulShellInspectionAnchorPaths(toolName, result) {
597389
+ if (toolName !== "shell" || result.success !== true)
597390
+ return [];
597391
+ const receipt = result.executionReceipt;
597392
+ if (!receipt || receipt.schema !== "omnius.command-evidence-receipt.v1" || receipt.exitCode !== 0 || receipt.timedOut || !receipt.command.trim() || !receipt.canonicalCommand.trim() || !receipt.cwd.trim()) {
597393
+ return [];
597394
+ }
597395
+ const command = receipt.command;
597396
+ if (!shellCommandLooksLikeInspection(command))
597397
+ return [];
597398
+ const anchors = this._completionLedger?.claimDiscovery?.requiredArtifactPaths ?? [];
597399
+ if (anchors.length === 0)
597400
+ return [];
597401
+ const root = this.authoritativeWorkingDirectory();
597402
+ return anchors.filter((path16) => shellCommandReferencesExactPath(command, path16, root)).slice(0, 16);
597403
+ }
597404
+ _refreshClaimDiscoveryStateFromEvidence() {
597405
+ if (!this._completionLedger?.claimDiscovery)
597406
+ return;
597407
+ const state = this._completionLedger.claimDiscovery;
597408
+ const legacyUnclassifiedCandidates = !Array.isArray(state.requiredArtifactPaths);
597409
+ const requiredArtifactPaths = legacyUnclassifiedCandidates ? [] : state.requiredArtifactPaths;
597410
+ const evidenceHandles = legacyUnclassifiedCandidates ? [] : state.evidenceHandles ?? [];
597411
+ const survivingBlockers = state.survivingBlockers ?? [];
597412
+ const unresolvedQuestions = state.unresolvedQuestions ?? [];
597413
+ const openDeltas = legacyUnclassifiedCandidates ? [] : state.openDeltas ?? [];
597414
+ const resolved = claimDiscoveryResolvedHandles(this._completionLedger, state);
597415
+ const unresolvedEvidence = evidenceHandles.filter((handle2) => !resolved.includes(handle2));
597416
+ const unresolvedHandleSet = new Set(unresolvedEvidence);
597417
+ const unresolvedOpenDeltas = openDeltas.filter((delta) => {
597418
+ const normalizedDeltaPath = this._normalizeEvidencePath(delta.path).replace(/^\/+/, "");
597419
+ const handle2 = `workspace:${normalizedDeltaPath}`;
597420
+ return unresolvedHandleSet.has(handle2);
597421
+ });
597422
+ const hasBlockers = survivingBlockers.length > 0;
597423
+ const hasRequiredAnchors = evidenceHandles.length > 0;
597424
+ const hasOpenQuestions = unresolvedQuestions.length > 0;
597425
+ const hasOpenEvidence = unresolvedEvidence.length > 0;
597426
+ let status;
597427
+ if (!hasRequiredAnchors) {
597428
+ status = hasBlockers || hasOpenQuestions ? "blocked" : "skipped";
597429
+ } else if (hasOpenEvidence || hasOpenQuestions || hasBlockers) {
597430
+ status = hasOpenQuestions || hasBlockers ? "blocked" : "active";
597431
+ } else {
597432
+ status = "complete";
597433
+ }
597434
+ const updated = {
597435
+ ...this._completionLedger,
597436
+ claimDiscovery: {
597437
+ ...state,
597438
+ requiredArtifactPaths,
597439
+ openDeltas: unresolvedOpenDeltas,
597440
+ resolvedEvidenceHandles: resolved,
597441
+ evidenceHandles,
597442
+ survivingBlockers,
597443
+ unresolvedQuestions,
597444
+ status,
597445
+ requiresEvidence: legacyUnclassifiedCandidates ? false : state.requiresEvidence
597446
+ }
597447
+ };
597448
+ this._completionLedger = updated;
597449
+ this._saveCompletionLedgerSafe();
597450
+ return updated.claimDiscovery;
597451
+ }
597197
597452
  _completionArtifactHashes(paths) {
597198
597453
  const unique3 = [...new Set(paths.map((path16) => this._normalizeEvidencePath(path16)).filter(Boolean))].slice(0, 20);
597199
597454
  const out = [];
@@ -597946,15 +598201,18 @@ ${readOnlyLines.join("\n")}` : "Successful read-only evidence: none"
597946
598201
  }
597947
598202
  const timeoutMs = parseInt(process.env["OMNIUS_COMPLETION_VERIFY_TIMEOUT_MS"] || "180000", 10) || 18e4;
597948
598203
  const wd = this._workingDirectory || process.cwd();
598204
+ const hasPipe = cmd.includes("|");
598205
+ const startedAtIso = (/* @__PURE__ */ new Date()).toISOString();
597949
598206
  this.emit({
597950
598207
  type: "status",
597951
598208
  content: `completion verify gate: running '${cmd}' (cwd=${wd})`,
597952
598209
  turn,
597953
598210
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
597954
598211
  });
597955
- const { exitCode, outTail } = await new Promise((resolve84) => {
598212
+ const { exitCode, outTail, timedOut, finishedAtIso } = await new Promise((resolve84) => {
597956
598213
  const chunks = [];
597957
598214
  let settled = false;
598215
+ let hitTimeout = false;
597958
598216
  const child = _spawn(cmd, {
597959
598217
  cwd: wd,
597960
598218
  shell: true,
@@ -597970,6 +598228,7 @@ ${readOnlyLines.join("\n")}` : "Successful read-only evidence: none"
597970
598228
  child.stderr?.on("data", onData);
597971
598229
  const killTimer = setTimeout(() => {
597972
598230
  try {
598231
+ hitTimeout = true;
597973
598232
  child.kill("SIGKILL");
597974
598233
  } catch {
597975
598234
  }
@@ -597980,11 +598239,31 @@ ${readOnlyLines.join("\n")}` : "Successful read-only evidence: none"
597980
598239
  return;
597981
598240
  settled = true;
597982
598241
  clearTimeout(killTimer);
597983
- resolve84({ exitCode: code8, outTail: chunks.join("").slice(-4e3) });
598242
+ resolve84({
598243
+ exitCode: code8,
598244
+ outTail: chunks.join("").slice(-4e3),
598245
+ timedOut: hitTimeout,
598246
+ finishedAtIso: (/* @__PURE__ */ new Date()).toISOString()
598247
+ });
597984
598248
  };
597985
598249
  child.on("error", () => finish(1));
597986
598250
  child.on("close", (code8) => finish(code8 ?? 1));
597987
598251
  });
598252
+ const commandReceipt = {
598253
+ schema: "omnius.command-evidence-receipt.v1",
598254
+ command: cmd,
598255
+ canonicalCommand: "",
598256
+ cwd: wd,
598257
+ exitCode,
598258
+ pipefail: hasPipe,
598259
+ timedOut,
598260
+ startedAtIso,
598261
+ finishedAtIso,
598262
+ artifactHashes: this._completionArtifactHashes([
598263
+ ...this._taskState.modifiedFiles.keys()
598264
+ ])
598265
+ };
598266
+ commandReceipt.canonicalCommand = canonicalVerificationIdentity(cmd, commandReceipt) ?? normalizeShellCommand(cmd) ?? cmd;
597988
598267
  if (this._completionLedger) {
597989
598268
  this._completionLedger = recordCompletionEvidence(this._completionLedger, {
597990
598269
  kind: "tool_result",
@@ -597992,9 +598271,11 @@ ${readOnlyLines.join("\n")}` : "Successful read-only evidence: none"
597992
598271
  success: exitCode === 0,
597993
598272
  summary: `completion verify command exited ${exitCode}: ${cmd}
597994
598273
  ${outTail || "(no output captured)"}`,
598274
+ receipt: commandReceipt,
597995
598275
  role: "verification",
597996
598276
  family: "completion_verify"
597997
598277
  });
598278
+ this._refreshClaimDiscoveryResolvedHandles();
597998
598279
  this._saveCompletionLedgerSafe();
597999
598280
  }
598000
598281
  const compileGuidance = this._observeCompileVerifierResult({
@@ -598052,7 +598333,8 @@ ${compileGuidance}` : ""
598052
598333
  const _newClaims = deriveClaimsFromProposedText({
598053
598334
  text: proposedSummary,
598054
598335
  source: "task_complete_summary",
598055
- existing: this._completionLedger.proposedClaims
598336
+ existing: this._completionLedger.proposedClaims,
598337
+ workspaceInventory: this._completionLedger.claimDiscovery?.boundedInventory
598056
598338
  });
598057
598339
  if (_newClaims.length > 0) {
598058
598340
  this._completionLedger = addCompletionClaims(this._completionLedger, _newClaims);
@@ -598062,7 +598344,10 @@ ${compileGuidance}` : ""
598062
598344
  try {
598063
598345
  const _audit = auditCompletionClaims(this._completionLedger.proposedClaims.map((c9) => ({
598064
598346
  text: c9.text,
598065
- status: c9.status
598347
+ status: c9.status,
598348
+ riskCategory: c9.riskCategory === "unknown" || c9.riskCategory === "coverage" ? null : c9.riskCategory,
598349
+ requiresIndependentEvidence: c9.requiresIndependentEvidence,
598350
+ requiredCheck: c9.requiredCheck
598066
598351
  })));
598067
598352
  if (!_audit.ok) {
598068
598353
  const _checks = _audit.blockers.map((b) => `• [${b.category}] "${b.claim}" → ${b.requiredCheck}`).join("\n");
@@ -598286,8 +598571,9 @@ ${_checks}`
598286
598571
  verdict: "approve",
598287
598572
  rationale: result.verdict.rationale
598288
598573
  });
598289
- this._saveCompletionLedgerSafe();
598290
598574
  }
598575
+ this._saveCompletionLedgerSafe();
598576
+ this._refreshClaimDiscoveryResolvedHandles();
598291
598577
  this._lastBackwardPassCritique = null;
598292
598578
  return { proceed: true };
598293
598579
  }
@@ -598357,6 +598643,9 @@ ${_checks}`
598357
598643
  }
598358
598644
  return { proceed: false, feedback };
598359
598645
  }
598646
+ _refreshClaimDiscoveryResolvedHandles() {
598647
+ this._refreshClaimDiscoveryStateFromEvidence();
598648
+ }
598360
598649
  /**
598361
598650
  * WO-META-TRACK — Hannover-style turn-counter reminder.
598362
598651
  *
@@ -602241,6 +602530,7 @@ ${notice}`;
602241
602530
  runId: this.currentArtifactRunId(),
602242
602531
  goal: record.content
602243
602532
  }) : null;
602533
+ this._claimDiscoveryInitialized = false;
602244
602534
  if (this._completionLedger) {
602245
602535
  this._completionLedger.taskEpoch = this._taskEpoch;
602246
602536
  }
@@ -603270,111 +603560,212 @@ ${rawTask}`;
603270
603560
  return next;
603271
603561
  }
603272
603562
  /**
603273
- * Feature Loop used to classify and split from the raw user sentence. Build
603274
- * a small, model-selected survey first instead: the model sees only an
603275
- * inventory of paths (not invented contents), chooses candidate files, and
603276
- * names the facts that still require file_read before any unit can mutate.
603277
- * Returning null deliberately falls back to the ordinary tool loop rather
603278
- * than recreating the old task-label-only Feature Loop.
603563
+ * Claim-discovery uses task + bounded workspace inventory before any mutation.
603564
+ * It remains task-centered and product-agnostic: no protocol-specific
603565
+ * heuristics, no model-inferred domain taxonomy, no filename-category
603566
+ * inference. Candidate grounding is deterministic from task + bounded inventory
603567
+ * signals only.
603279
603568
  */
603280
- async _resolveFeatureSurvey(task, context2, turn) {
603281
- if (process.env["OMNIUS_FEATURE_SURVEY_GROUNDING"] === "0")
603282
- return null;
603569
+ async _resolveClaimDiscoverySurvey(task, turn) {
603570
+ if (process.env["OMNIUS_FEATURE_SURVEY_GROUNDING"] === "0") {
603571
+ return claimDiscoveryStateFromSurvey({
603572
+ request: task,
603573
+ boundedInventory: {
603574
+ root: this.authoritativeWorkingDirectory(),
603575
+ files: [],
603576
+ dirs: [],
603577
+ truncated: true,
603578
+ maxFiles: 0,
603579
+ maxDirs: 0,
603580
+ generatedAtIso: (/* @__PURE__ */ new Date()).toISOString()
603581
+ },
603582
+ candidatePaths: [],
603583
+ pathReasons: {},
603584
+ unresolvedQuestions: [],
603585
+ survivingBlockers: [
603586
+ "Claim discovery is currently disabled by OMNIUS_FEATURE_SURVEY_GROUNDING=0."
603587
+ ],
603588
+ requiresEvidence: false
603589
+ });
603590
+ }
603283
603591
  const root = this.authoritativeWorkingDirectory();
603284
- let workspaceFiles = [];
603285
- try {
603286
- workspaceFiles = scanWorkspace({ root, maxFiles: 320, maxDirs: 800 }).files.map((file) => ({ rel: file.rel, bytes: file.bytes }));
603592
+ const maxFiles = Math.max(80, Math.min(420, Number.parseInt(process.env["OMNIUS_CLAIM_DISCOVERY_MAX_FILES"] || "240", 10) || 240));
603593
+ const maxDirs = Math.max(60, Math.min(1200, Number.parseInt(process.env["OMNIUS_CLAIM_DISCOVERY_MAX_DIRS"] || "300", 10) || 300));
603594
+ let boundedInventory = null;
603595
+ try {
603596
+ const workspace = scanWorkspace({ root, maxFiles, maxDirs });
603597
+ const files = workspace.files.slice(0, maxFiles).map((file) => ({
603598
+ path: file.rel,
603599
+ bytes: file.bytes,
603600
+ mtimeMs: file.mtimeMs
603601
+ })).filter((file) => !file.path.startsWith(".omnius/"));
603602
+ boundedInventory = {
603603
+ root,
603604
+ files,
603605
+ dirs: workspace.dirs.slice(0, maxDirs).map((dir) => dir.rel),
603606
+ truncated: workspace.truncated,
603607
+ maxFiles,
603608
+ maxDirs,
603609
+ generatedAtIso: (/* @__PURE__ */ new Date()).toISOString()
603610
+ };
603287
603611
  } catch {
603288
- return null;
603289
- }
603290
- if (workspaceFiles.length === 0)
603291
- return null;
603292
- const allowedPaths = new Set(workspaceFiles.map((file) => file.rel));
603293
- const ledgerEvidence = this._evidenceLedger.snapshot(12).map((entry) => ({
603294
- ref: `read:${entry.path}`,
603295
- detail: `${entry.path} was read at turn ${entry.lastReadTurn}${entry.stale ? " and is now stale" : ""}.`,
603296
- freshness: entry.stale ? "stale" : "fresh"
603297
- }));
603298
- const inventory = workspaceFiles.slice(0, 320).map((file) => `${file.rel} (${file.bytes} bytes)`).join("\n");
603299
- const prompt = [
603300
- "You are Omnius's feature survey grounder. Return JSON only; do not provide chain-of-thought.",
603301
- "You have file-existence metadata, not source contents. Select only candidate paths from the provided inventory and state what must be inspected before any mutation. Do not claim code behavior, APIs, or test results from a filename.",
603302
- "Schema:",
603303
- JSON.stringify({
603304
- candidate_paths: ["exact allowed relative path, 1-8 items"],
603305
- path_reasons: { "path": "why this is a candidate, based only on request/inventory" },
603306
- unresolved_questions: ["specific source fact to inspect before edit"],
603307
- new_symbols: ["only explicitly requested symbols, if any"],
603308
- existing_symbols: ["only symbols named in supplied context, if any"],
603309
- tests_exist: false,
603310
- public_surface_changes: false
603311
- }),
603312
- `Task:
603313
- ${sanitizeDelegationText(task, 1400)}`,
603314
- context2 ? `Parent context (may be stale; verify):
603315
- ${sanitizeDelegationText(context2, 1200)}` : "",
603316
- ledgerEvidence.length ? `Fresh/stale reads already observed:
603317
- ${ledgerEvidence.map((item) => `- [${item.freshness}] ${item.ref}: ${item.detail}`).join("\n")}` : "No source files have been read in this run yet.",
603318
- `Allowed workspace inventory:
603319
- ${inventory}`
603320
- ].filter(Boolean).join("\n\n");
603321
- try {
603322
- this._emitModelResolutionTelemetry("feature_survey_grounding", turn);
603323
- const backend = this._auxInferenceBackend({
603324
- dumpStage: "feature_survey_grounding"
603325
- });
603326
- const response = await backend.chatCompletion({
603327
- messages: [
603328
- {
603329
- role: "system",
603330
- content: "Return only valid JSON matching the requested schema. Never invent a path or infer file content from its name."
603331
- },
603332
- { role: "user", content: prompt }
603612
+ return claimDiscoveryStateFromSurvey({
603613
+ request: task,
603614
+ boundedInventory: {
603615
+ root,
603616
+ files: [],
603617
+ dirs: [],
603618
+ truncated: true,
603619
+ maxFiles,
603620
+ maxDirs,
603621
+ generatedAtIso: (/* @__PURE__ */ new Date()).toISOString()
603622
+ },
603623
+ candidatePaths: [],
603624
+ pathReasons: {},
603625
+ unresolvedQuestions: [
603626
+ "Workspace scan failed for bounded inventory grounding; retry with explicit target paths."
603333
603627
  ],
603334
- tools: [],
603335
- temperature: 0.1,
603336
- maxTokens: 900,
603337
- timeoutMs: Math.max(5e3, Math.min(this.options.requestTimeoutMs, 25e3)),
603338
- think: false
603628
+ survivingBlockers: [
603629
+ "Claim discovery cannot anchor evidence without a successful workspace inventory scan."
603630
+ ],
603631
+ requiresEvidence: false
603339
603632
  });
603340
- const raw = response.choices?.[0]?.message?.content ?? "";
603341
- const json = raw.match(/```(?:json)?\s*([\s\S]*?)```/)?.[1] ?? raw.match(/\{[\s\S]*\}/)?.[0] ?? "";
603342
- const parsed = JSON.parse(json);
603343
- const requestedPaths = Array.isArray(parsed["candidate_paths"]) ? parsed["candidate_paths"].map((value2) => String(value2).trim()).filter((value2) => allowedPaths.has(value2)).slice(0, 8) : [];
603344
- if (requestedPaths.length === 0)
603345
- return null;
603346
- const reasons = parsed["path_reasons"] && typeof parsed["path_reasons"] === "object" ? parsed["path_reasons"] : {};
603347
- const stringList3 = (value2, cap, maxChars) => Array.isArray(value2) ? value2.map((item) => sanitizeDelegationText(item, maxChars)).filter(Boolean).slice(0, cap) : [];
603348
- const selectedEvidence2 = requestedPaths.map((file) => ({
603349
- ref: `workspace:${file}`,
603350
- detail: sanitizeDelegationText(reasons[file], 280) || "Selected from the workspace inventory; source contents remain uninspected.",
603351
- freshness: "unknown"
603352
- }));
603353
- const unresolvedQuestions = stringList3(parsed["unresolved_questions"], 6, 260);
603354
- if (unresolvedQuestions.length === 0) {
603355
- unresolvedQuestions.push("Read the selected source and its nearest tests/callers to establish the exact implementation contract before editing.");
603356
- }
603357
- return {
603633
+ }
603634
+ if (!boundedInventory || boundedInventory.files.length === 0) {
603635
+ return claimDiscoveryStateFromSurvey({
603358
603636
  request: task,
603359
- files: requestedPaths.map((path16) => ({
603360
- path: path16,
603361
- role: sanitizeDelegationText(reasons[path16], 180) || "candidate selected from workspace inventory"
603362
- })),
603363
- signals: [
603364
- "Feature survey candidates were generated from the current workspace inventory.",
603365
- ...unresolvedQuestions
603637
+ boundedInventory: boundedInventory ?? {
603638
+ root,
603639
+ files: [],
603640
+ dirs: [],
603641
+ truncated: true,
603642
+ maxFiles,
603643
+ maxDirs,
603644
+ generatedAtIso: (/* @__PURE__ */ new Date()).toISOString()
603645
+ },
603646
+ candidatePaths: [],
603647
+ pathReasons: {},
603648
+ unresolvedQuestions: [
603649
+ "Bounded workspace inventory was empty; provide concrete target artifacts before claiming completion."
603366
603650
  ],
603367
- rawTexts: [task, context2 ?? ""],
603368
- evidence: [...ledgerEvidence, ...selectedEvidence2].slice(0, 14),
603369
- unresolvedQuestions,
603370
- newSymbols: stringList3(parsed["new_symbols"], 8, 120),
603371
- existingSymbols: stringList3(parsed["existing_symbols"], 8, 120),
603372
- testsExist: parsed["tests_exist"] === true,
603373
- publicSurfaceChanges: parsed["public_surface_changes"] === true
603374
- };
603375
- } catch {
603376
- return null;
603651
+ survivingBlockers: ["No bounded inventory files were discoverable."],
603652
+ requiresEvidence: false
603653
+ });
603654
+ }
603655
+ const boundedInventoryPaths = boundedInventory.files.map((file) => file.path);
603656
+ const allowedPaths = new Set(boundedInventoryPaths);
603657
+ const pathReasons = /* @__PURE__ */ Object.create(null);
603658
+ const normalizedTask = sanitizeDelegationText(task, 1500);
603659
+ const taskTokens = extractClaimTaskTokens(task);
603660
+ const meaningfulTaskTokens = taskTokens.filter(isMeaningfulClaimTaskToken);
603661
+ const explicitPathHints = collectClaimPathSignals(task).map((token) => token.toLowerCase()).slice(0, 80);
603662
+ const unmatchedHints = new Set(explicitPathHints);
603663
+ const scored = [];
603664
+ for (const path16 of boundedInventoryPaths) {
603665
+ const lowerPath = path16.toLowerCase();
603666
+ const lowerBase = (path16.split("/").at(-1) ?? "").toLowerCase();
603667
+ const chunks = lowerPath.split("/").filter(Boolean);
603668
+ let score = 0;
603669
+ const reasons = [];
603670
+ for (const hint of explicitPathHints) {
603671
+ if (!matchHintToInventoryPath(path16, hint))
603672
+ continue;
603673
+ unmatchedHints.delete(hint);
603674
+ score += 120;
603675
+ reasons.push(`explicit path hint "${hint}" matches path`);
603676
+ }
603677
+ for (const token of meaningfulTaskTokens) {
603678
+ const lowerToken = token.toLowerCase();
603679
+ if (lowerToken.length < 4)
603680
+ continue;
603681
+ if (chunks.some((chunk) => chunk === lowerToken)) {
603682
+ score += 40;
603683
+ reasons.push(`segment token match (${lowerToken})`);
603684
+ } else if (lowerPath.includes(lowerToken)) {
603685
+ score += 14;
603686
+ reasons.push(`path includes task token (${lowerToken})`);
603687
+ } else if (chunkHasSymbolMatch(lowerToken, lowerBase)) {
603688
+ score += 6;
603689
+ reasons.push(`base symbol overlap (${lowerToken})`);
603690
+ }
603691
+ }
603692
+ if (score > 0) {
603693
+ scored.push({
603694
+ path: path16,
603695
+ score,
603696
+ reasons: [...new Set(reasons)].slice(0, 3)
603697
+ });
603698
+ }
603377
603699
  }
603700
+ scored.sort((left, right) => right.score !== left.score ? right.score - left.score : left.path.localeCompare(right.path));
603701
+ const rankedCandidates = scored.filter((entry) => entry.score > 0).map((entry) => entry.path).slice(0, 12);
603702
+ const explicitCandidates = explicitPathHints.flatMap((token) => boundedInventoryPaths.filter((path16) => matchHintToInventoryPath(path16, token))).filter((path16) => allowedPaths.has(path16)).slice(0, 12);
603703
+ const candidateSeeds = explicitCandidates.length > 0 ? explicitCandidates : rankedCandidates;
603704
+ const candidatePaths = [.../* @__PURE__ */ new Set([...candidateSeeds, ...rankedCandidates])].slice(0, 8);
603705
+ const shouldUseFallbackCandidates = explicitPathHints.length === 0 && candidatePaths.length === 0;
603706
+ const fallbackCandidates = shouldUseFallbackCandidates ? claimDiscoveryFallbackCandidates(boundedInventory.files, Math.max(4, Math.min(8, maxFiles ? Math.min(8, maxFiles) : 8))) : [];
603707
+ let finalCandidatePaths = candidatePaths.length > 0 ? candidatePaths : fallbackCandidates.map((entry) => entry.path);
603708
+ if (candidatePaths.length === 0 && fallbackCandidates.length > 0) {
603709
+ for (const candidate of fallbackCandidates) {
603710
+ if (!pathReasons[candidate.path]) {
603711
+ pathReasons[candidate.path] = candidate.reasons.join("; ");
603712
+ }
603713
+ }
603714
+ }
603715
+ if (finalCandidatePaths.length === 0 && boundedInventory.files.length > 0) {
603716
+ const boundedPaths = boundedInventory.files.map((file) => String(file.path ?? "")).map((path16) => path16.trim()).filter((path16) => path16.length >= 4 && path16.length <= 800).filter((path16) => !path16.startsWith(".omnius/"));
603717
+ const candidateWithDir = boundedPaths.filter((path16) => path16.includes("/")).slice(0, 4);
603718
+ finalCandidatePaths = (candidateWithDir.length > 0 ? candidateWithDir : boundedPaths).slice(0, 4);
603719
+ for (const candidate of finalCandidatePaths) {
603720
+ if (!pathReasons[candidate]) {
603721
+ pathReasons[candidate] = "selected from bounded inventory fallback";
603722
+ }
603723
+ }
603724
+ }
603725
+ if (finalCandidatePaths.length === 0) {
603726
+ const hasUnmatchedHints = unmatchedHints.size > 0;
603727
+ const unresolvedQuestions2 = hasUnmatchedHints ? [
603728
+ normalizedTask.length < 5 ? "Task text is too short to anchor evidence safely." : `No grounded candidate source path was identified for explicit task hints (${[...unmatchedHints].slice(0, 4).join(", ")}).`,
603729
+ "Read from declared artifacts before claiming completion."
603730
+ ] : [];
603731
+ const survivingBlockers2 = unmatchedHints.size > 0 ? [
603732
+ `No bounded inventory artifact matched explicit task hints: ${[...unmatchedHints].slice(0, 4).join(", ")}`
603733
+ ] : [];
603734
+ return claimDiscoveryStateFromSurvey({
603735
+ request: task,
603736
+ boundedInventory,
603737
+ candidatePaths: [],
603738
+ pathReasons: {},
603739
+ unresolvedQuestions: unresolvedQuestions2,
603740
+ survivingBlockers: survivingBlockers2,
603741
+ requiresEvidence: explicitPathHints.length > 0
603742
+ });
603743
+ }
603744
+ for (const candidate of finalCandidatePaths) {
603745
+ const details = scored.find((entry) => entry.path === candidate);
603746
+ if (!pathReasons[candidate]) {
603747
+ pathReasons[candidate] = details && details.reasons.length > 0 ? details.reasons.join("; ") : unmatchedHints.size > 0 ? "selected from explicit task hints plus inventory" : meaningfulTaskTokens.length === 0 ? "selected from bounded inventory fallback" : "selected from bounded request signals and inventory";
603748
+ }
603749
+ }
603750
+ const unresolvedQuestions = unmatchedHints.size > 0 ? [
603751
+ `Unresolved explicit task hints remain unmatched: ${[...unmatchedHints].slice(0, 3).join(", ")}.`,
603752
+ "If task intent changed, restate target artifacts in the user message."
603753
+ ] : [];
603754
+ const survivingBlockers = unmatchedHints.size > 0 ? [
603755
+ `Unmatched explicit task hints: ${[...unmatchedHints].slice(0, 3).join(", ")}`
603756
+ ] : [];
603757
+ const requiredArtifactPaths = [...new Set(explicitCandidates)].slice(0, 8);
603758
+ const shouldRequireEvidence = requiredArtifactPaths.length > 0 || unmatchedHints.size > 0;
603759
+ return claimDiscoveryStateFromSurvey({
603760
+ request: task,
603761
+ boundedInventory,
603762
+ candidatePaths: finalCandidatePaths,
603763
+ requiredArtifactPaths,
603764
+ pathReasons,
603765
+ unresolvedQuestions,
603766
+ survivingBlockers,
603767
+ requiresEvidence: shouldRequireEvidence
603768
+ });
603378
603769
  }
603379
603770
  /**
603380
603771
  * Rebuild the one current checkpoint at the context boundary. This shared
@@ -603701,6 +604092,7 @@ Respond with the assessment and take the selected evidence-backed action.`;
603701
604092
  this._completionIncompleteVerification = null;
603702
604093
  this._completionCaveat = null;
603703
604094
  this._completionLedger = null;
604095
+ this._claimDiscoveryInitialized = false;
603704
604096
  this._focusTerminalLedgerRecorded = false;
603705
604097
  this._resetTaskScopedVerifierState();
603706
604098
  this._staleEditFamilies.clear();
@@ -604001,6 +604393,7 @@ Respond with the assessment and take the selected evidence-backed action.`;
604001
604393
  runId: this._activeRunId || this._sessionId,
604002
604394
  goal: userGoal
604003
604395
  });
604396
+ this._claimDiscoveryInitialized = false;
604004
604397
  this._completionLedger.taskEpoch = this._taskEpoch;
604005
604398
  } else {
604006
604399
  this._completionContract = null;
@@ -604685,6 +605078,44 @@ ${dynamicProjectContext}`
604685
605078
  });
604686
605079
  return true;
604687
605080
  };
605081
+ const holdClaimDiscoveryTaskComplete = (turn) => {
605082
+ const ledger = this._completionLedger;
605083
+ if (!ledger?.claimDiscovery)
605084
+ return false;
605085
+ this._refreshClaimDiscoveryStateFromEvidence();
605086
+ const state = this._completionLedger?.claimDiscovery;
605087
+ if (!state)
605088
+ return false;
605089
+ const evidenceHandles = state.evidenceHandles ?? [];
605090
+ const unresolvedQuestions = state.unresolvedQuestions ?? [];
605091
+ const resolved = claimDiscoveryResolvedHandles(ledger, state);
605092
+ const unresolved = evidenceHandles.filter((handle2) => !resolved.includes(handle2));
605093
+ const blockers = state.survivingBlockers ?? [];
605094
+ const openDeltas = state.openDeltas ?? [];
605095
+ const hasOpenDiscoveryWork = unresolved.length > 0 || blockers.length > 0 || unresolvedQuestions.length > 0;
605096
+ const shouldHold = (state.status === "active" || state.status === "blocked") && hasOpenDiscoveryWork && state.requiresEvidence !== false;
605097
+ if (!shouldHold) {
605098
+ return false;
605099
+ }
605100
+ const feedback = [
605101
+ "[COMPLETION BLOCKED — evidence discovery incomplete]",
605102
+ `Open claim-discovery deltas: ${openDeltas.map((item) => `${item.path} :: ${item.reason}`).join(" | ") || "none"}`,
605103
+ `Outstanding evidence handles: ${unresolved.join(" | ") || "none"}`,
605104
+ ...blockers.length > 0 ? [`Surviving blockers: ${blockers.join(" | ")}`] : [],
605105
+ state.unresolvedQuestions.length > 0 ? `Outstanding question(s): ${state.unresolvedQuestions.slice(0, 4).join(" | ")}` : ""
605106
+ ].filter(Boolean).join("\n");
605107
+ lastCompletionGateReason = unresolved.length > 0 ? `claim discovery evidence pending (${unresolved.length})` : "claim discovery is still waiting on blockers/questions";
605108
+ lastCompletionGateFeedback = feedback;
605109
+ lastCompletionGateCode = "claim_discovery";
605110
+ messages2.push({ role: "system", content: feedback });
605111
+ this.emit({
605112
+ type: "status",
605113
+ content: `task_complete held by claim discovery gate: ${lastCompletionGateReason}`,
605114
+ turn,
605115
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
605116
+ });
605117
+ return true;
605118
+ };
604688
605119
  const completionHoldEscapeMax = (() => {
604689
605120
  const raw = Number(process.env["OMNIUS_COMPLETION_HOLD_MAX"]);
604690
605121
  return Number.isFinite(raw) && raw >= 1 ? Math.floor(raw) : 3;
@@ -604733,7 +605164,7 @@ ${lastCompletionGateFeedback.trim().slice(0, 4e3)}` : ""
604733
605164
  lastCompletionGateCode = "";
604734
605165
  return true;
604735
605166
  }
604736
- const held = holdDeliveryCoverageTaskComplete(turn) || holdCompileFixLoopTaskComplete(turn) || holdUnresolvedVerificationTaskComplete(turn) || holdNoProgressTaskComplete(args, turn) || holdProvenanceTaskComplete(args, turn);
605167
+ const held = holdDeliveryCoverageTaskComplete(turn) || holdCompileFixLoopTaskComplete(turn) || holdUnresolvedVerificationTaskComplete(turn) || holdNoProgressTaskComplete(args, turn) || holdProvenanceTaskComplete(args, turn) || holdClaimDiscoveryTaskComplete(turn);
604737
605168
  if (!held) {
604738
605169
  this._completionHoldState.count = 0;
604739
605170
  this._completionHoldState.lastKey = "";
@@ -604828,94 +605259,41 @@ ${lastCompletionGateFeedback.trim().slice(0, 4e3)}` : ""
604828
605259
  };
604829
605260
  let executeSingle = async () => null;
604830
605261
  const turnCap = this.options.maxTurns && this.options.maxTurns > 0 ? this.options.maxTurns : Number.MAX_SAFE_INTEGER;
604831
- const _featureLoopHandled = process.env["OMNIUS_FEATURE_LOOP"] === "1" && !this._inFeatureLoop && !this.options.subAgent;
604832
- if (_featureLoopHandled) {
604833
- try {
604834
- const _survey = await this._resolveFeatureSurvey(task, context2, 0);
604835
- if (!_survey) {
604836
- this.emit({
604837
- type: "status",
604838
- content: "[FEATURE LOOP] deferred: no model-grounded workspace survey was available; continuing with the normal discovery loop",
604839
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
604840
- });
604841
- } else {
604842
- const _kind = classifyKind(_survey);
604843
- if (_kind === "investigation") {
604844
- this.emit({
604845
- type: "status",
604846
- content: "[FEATURE LOOP] survey classified this as investigation; continuing with the normal evidence-gathering loop",
604847
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
604848
- });
604849
- } else {
604850
- this._inFeatureLoop = true;
604851
- this.emit({
604852
- type: "status",
604853
- content: `[FEATURE LOOP] evidence-grounded survey classified "${_kind}" – entering recursive driver...`,
604854
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
604855
- });
604856
- const _root = createRootFeatureNode(task);
604857
- const _startMs = Date.now();
604858
- const _resultNode = await runFeatureNode(_root, {
604859
- rootId: _root.id,
604860
- stateDir: this.omniusStateDir(),
604861
- workingDirectory: this.authoritativeWorkingDirectory() || process.cwd(),
604862
- sessionId: this._sessionId,
604863
- depthCap: 4,
604864
- askApproval: async () => "approve",
604865
- executeUnit: async (unit, node) => {
604866
- const _unitRequest = buildFeatureUnitRequest({
604867
- unit,
604868
- parentRequest: node.request,
604869
- survey: _survey
604870
- });
604871
- const _sub = await this.run(_unitRequest, unit.detail || "Feature unit request is grounded in the parent survey; verify the cited source before mutation.", unit.label);
604872
- return { ok: _sub.status === "completed" };
604873
- },
604874
- runGeneralLoop: async (request) => {
604875
- await this.run(request, void 0, request);
604876
- },
604877
- onPlan: async (artefact) => {
604878
- if (this._longHaul && artefact.lockedContract?.symbols?.length) {
604879
- this._longHaul.seedLockedContract(artefact.lockedContract);
604880
- this.emit({
604881
- type: "status",
604882
- content: `[FEATURE LOOP] seeded ${artefact.lockedContract.symbols.length} locked symbols into WO-6 contract`,
604883
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
604884
- });
604885
- }
604886
- }
604887
- }, { survey: _survey });
604888
- this._inFeatureLoop = false;
604889
- const _completed = _resultNode.status === "completed";
604890
- const _durMs = Date.now() - _startMs;
604891
- this.emit({
604892
- type: _completed ? "complete" : "error",
604893
- content: `[FEATURE LOOP] ${_completed ? "completed" : "failed"} after ${_durMs}ms — ${_resultNode.children.length} child nodes`,
604894
- success: _completed,
604895
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
604896
- });
604897
- return {
604898
- status: _completed ? "completed" : "incomplete",
604899
- completed: _completed,
604900
- turns: 0,
604901
- toolCalls: 0,
604902
- totalTokens: 0,
604903
- promptTokens: 0,
604904
- completionTokens: 0,
604905
- estimatedTokens: 0,
604906
- summary: `[FEATURE LOOP] ${_completed ? "completed" : "failed"}: ${task.slice(0, 200)}`,
604907
- durationMs: _durMs
604908
- };
604909
- }
604910
- }
604911
- } catch (e2) {
604912
- this._inFeatureLoop = false;
604913
- this.emit({
604914
- type: "status",
604915
- content: `[FEATURE LOOP] error, falling back to general loop: ${e2}`,
604916
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
604917
- });
605262
+ const _claimDiscoveryEnabled = (() => {
605263
+ if (typeof this.options.claimDiscovery === "boolean") {
605264
+ return this.options.claimDiscovery;
604918
605265
  }
605266
+ const parse3 = (raw) => {
605267
+ if (raw === void 0)
605268
+ return void 0;
605269
+ const lowered = raw.toLowerCase();
605270
+ if (raw === "1" || lowered === "true" || lowered === "on")
605271
+ return true;
605272
+ if (raw === "0" || lowered === "false" || lowered === "off")
605273
+ return false;
605274
+ return void 0;
605275
+ };
605276
+ const explicit = parse3(process.env["OMNIUS_CLAIM_DISCOVERY"]);
605277
+ if (explicit !== void 0)
605278
+ return explicit;
605279
+ const legacy = parse3(process.env["OMNIUS_FEATURE_LOOP"]);
605280
+ return legacy ?? true;
605281
+ })();
605282
+ const _claimDiscoveryNeedsInit = _claimDiscoveryEnabled && !this._claimDiscoveryInitialized && !this.options.subAgent && this._completionLedger !== null;
605283
+ if (_claimDiscoveryNeedsInit && this._completionLedger) {
605284
+ this._claimDiscoveryInitialized = true;
605285
+ const _survey = await this._resolveClaimDiscoverySurvey(task, 0);
605286
+ this._completionLedger = setClaimDiscoveryState(this._completionLedger, _survey);
605287
+ messages2.push({
605288
+ role: "system",
605289
+ content: "[CLAIM DISCOVERY] Grounding signals (compact):\n" + claimDiscoveryControllerSignals(this._completionLedger.claimDiscovery).join("\n")
605290
+ });
605291
+ this.emit({
605292
+ type: "status",
605293
+ content: `[CLAIM DISCOVERY] initialized from bounded inventory: ${this._completionLedger.claimDiscovery?.candidatePaths.length ?? 0} candidate path(s), status=${this._completionLedger.claimDiscovery?.status ?? "skipped"}`,
605294
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
605295
+ });
605296
+ this._saveCompletionLedgerSafe();
604919
605297
  }
604920
605298
  if (process.env["OMNIUS_DISABLE_TEXT_ECHO_GUARD"] !== "1") {
604921
605299
  const restoredCollapsed = this._textEchoGuard.collapseEchoes(messages2);
@@ -615134,6 +615512,9 @@ ${trimmedNew}`;
615134
615512
  `next_claim_inspection=${coverage?.nextInspection?.replace(/\s+/g, " ").slice(0, 420) || "none"}`,
615135
615513
  `evidence_handles=${evidenceHandles.join(",") || "none"}`
615136
615514
  ];
615515
+ if (this._completionLedger?.claimDiscovery) {
615516
+ lines.push(...claimDiscoveryControllerSignals(this._completionLedger.claimDiscovery));
615517
+ }
615137
615518
  const tier = this.options.modelTier ?? "large";
615138
615519
  const directive = this._focusSupervisor?.snapshot().directive;
615139
615520
  if (directive && tier === "small") {
@@ -622530,8 +622911,8 @@ var init_skill_fork = __esm({
622530
622911
  });
622531
622912
 
622532
622913
  // packages/orchestrator/dist/missionArtifacts.js
622533
- import * as fs9 from "node:fs";
622534
- import * as path11 from "node:path";
622914
+ import * as fs7 from "node:fs";
622915
+ import * as path9 from "node:path";
622535
622916
  function createValidationContract(missionId, assertions) {
622536
622917
  return {
622537
622918
  missionId,
@@ -622711,33 +623092,33 @@ function checkMilestoneComplete(state, manifest, milestoneId) {
622711
623092
  return true;
622712
623093
  }
622713
623094
  function writeFeaturesManifest(missionDir, manifest) {
622714
- fs9.mkdirSync(missionDir, { recursive: true });
622715
- const filePath = path11.join(missionDir, "features.json");
622716
- fs9.writeFileSync(filePath, JSON.stringify(manifest, null, 2), "utf-8");
623095
+ fs7.mkdirSync(missionDir, { recursive: true });
623096
+ const filePath = path9.join(missionDir, "features.json");
623097
+ fs7.writeFileSync(filePath, JSON.stringify(manifest, null, 2), "utf-8");
622717
623098
  }
622718
623099
  function writeValidationContract(missionDir, contract) {
622719
- fs9.mkdirSync(missionDir, { recursive: true });
622720
- const filePath = path11.join(missionDir, "validation-contract.md");
622721
- fs9.writeFileSync(filePath, renderValidationContract(contract), "utf-8");
623100
+ fs7.mkdirSync(missionDir, { recursive: true });
623101
+ const filePath = path9.join(missionDir, "validation-contract.md");
623102
+ fs7.writeFileSync(filePath, renderValidationContract(contract), "utf-8");
622722
623103
  }
622723
623104
  function writeValidationState(missionDir, state) {
622724
- fs9.mkdirSync(missionDir, { recursive: true });
622725
- const filePath = path11.join(missionDir, "validation-state.json");
622726
- fs9.writeFileSync(filePath, JSON.stringify(state, null, 2), "utf-8");
623105
+ fs7.mkdirSync(missionDir, { recursive: true });
623106
+ const filePath = path9.join(missionDir, "validation-state.json");
623107
+ fs7.writeFileSync(filePath, JSON.stringify(state, null, 2), "utf-8");
622727
623108
  }
622728
623109
  function readFeaturesManifest(missionDir) {
622729
- const filePath = path11.join(missionDir, "features.json");
622730
- const content = fs9.readFileSync(filePath, "utf-8");
623110
+ const filePath = path9.join(missionDir, "features.json");
623111
+ const content = fs7.readFileSync(filePath, "utf-8");
622731
623112
  return JSON.parse(content);
622732
623113
  }
622733
623114
  function readValidationState(missionDir) {
622734
- const filePath = path11.join(missionDir, "validation-state.json");
622735
- const content = fs9.readFileSync(filePath, "utf-8");
623115
+ const filePath = path9.join(missionDir, "validation-state.json");
623116
+ const content = fs7.readFileSync(filePath, "utf-8");
622736
623117
  return JSON.parse(content);
622737
623118
  }
622738
623119
  function readValidationContract(missionDir) {
622739
- const filePath = path11.join(missionDir, "validation-contract.md");
622740
- const content = fs9.readFileSync(filePath, "utf-8");
623120
+ const filePath = path9.join(missionDir, "validation-contract.md");
623121
+ const content = fs7.readFileSync(filePath, "utf-8");
622741
623122
  const assertions = [];
622742
623123
  const lines = content.split("\n");
622743
623124
  let inTable = false;
@@ -623075,8 +623456,8 @@ var init_adversarialHandoffs = __esm({
623075
623456
  });
623076
623457
 
623077
623458
  // packages/orchestrator/dist/autoValidators.js
623078
- import * as fs10 from "node:fs";
623079
- import * as path12 from "node:path";
623459
+ import * as fs8 from "node:fs";
623460
+ import * as path10 from "node:path";
623080
623461
  function generateScrutinyValidatorSkill() {
623081
623462
  return `# Scrutiny Validator
623082
623463
 
@@ -623193,22 +623574,22 @@ function combineValidatorResults(missionId, milestoneId, scrutiny, userTesting)
623193
623574
  };
623194
623575
  }
623195
623576
  function writeValidatorResults(missionDir, results) {
623196
- fs10.mkdirSync(missionDir, { recursive: true });
623197
- const filePath = path12.join(missionDir, "validator-results.json");
623198
- fs10.writeFileSync(filePath, JSON.stringify(results, null, 2), "utf-8");
623577
+ fs8.mkdirSync(missionDir, { recursive: true });
623578
+ const filePath = path10.join(missionDir, "validator-results.json");
623579
+ fs8.writeFileSync(filePath, JSON.stringify(results, null, 2), "utf-8");
623199
623580
  }
623200
623581
  function readValidatorResults(missionDir) {
623201
- const filePath = path12.join(missionDir, "validator-results.json");
623202
- const content = fs10.readFileSync(filePath, "utf-8");
623582
+ const filePath = path10.join(missionDir, "validator-results.json");
623583
+ const content = fs8.readFileSync(filePath, "utf-8");
623203
623584
  return JSON.parse(content);
623204
623585
  }
623205
623586
  function writeValidatorSkill(missionDir, skillName, content) {
623206
- const dir = path12.join(missionDir, "skills", "auto-injected");
623207
- if (!fs10.existsSync(dir)) {
623208
- fs10.mkdirSync(dir, { recursive: true });
623587
+ const dir = path10.join(missionDir, "skills", "auto-injected");
623588
+ if (!fs8.existsSync(dir)) {
623589
+ fs8.mkdirSync(dir, { recursive: true });
623209
623590
  }
623210
- const filePath = path12.join(dir, `${skillName}.md`);
623211
- fs10.writeFileSync(filePath, content, "utf-8");
623591
+ const filePath = path10.join(dir, `${skillName}.md`);
623592
+ fs8.writeFileSync(filePath, content, "utf-8");
623212
623593
  }
623213
623594
  var init_autoValidators = __esm({
623214
623595
  "packages/orchestrator/dist/autoValidators.js"() {
@@ -623217,8 +623598,8 @@ var init_autoValidators = __esm({
623217
623598
  });
623218
623599
 
623219
623600
  // packages/orchestrator/dist/serviceManifest.js
623220
- import * as fs11 from "node:fs";
623221
- import * as path13 from "node:path";
623601
+ import * as fs9 from "node:fs";
623602
+ import * as path11 from "node:path";
623222
623603
  function quoteScalar(value2) {
623223
623604
  return JSON.stringify(value2);
623224
623605
  }
@@ -623349,8 +623730,8 @@ function getCommand(manifest, name10) {
623349
623730
  return cmd.command;
623350
623731
  }
623351
623732
  function writeServicesManifest(missionDir, manifest) {
623352
- fs11.mkdirSync(missionDir, { recursive: true });
623353
- const filePath = path13.join(missionDir, "services.yaml");
623733
+ fs9.mkdirSync(missionDir, { recursive: true });
623734
+ const filePath = path11.join(missionDir, "services.yaml");
623354
623735
  const lines = [
623355
623736
  `missionId: ${manifest.missionId}`,
623356
623737
  `createdAt: ${manifest.createdAt}`,
@@ -623398,11 +623779,11 @@ function writeServicesManifest(missionDir, manifest) {
623398
623779
  lines.push(` min: ${manifest.ports.range.min}`);
623399
623780
  lines.push(` max: ${manifest.ports.range.max}`);
623400
623781
  lines.push(` offLimits: [${manifest.ports.offLimits.join(", ")}]`);
623401
- fs11.writeFileSync(filePath, lines.join("\n"), "utf-8");
623782
+ fs9.writeFileSync(filePath, lines.join("\n"), "utf-8");
623402
623783
  }
623403
623784
  function readServicesManifest(missionDir) {
623404
- const filePath = path13.join(missionDir, "services.yaml");
623405
- const content = fs11.readFileSync(filePath, "utf-8");
623785
+ const filePath = path11.join(missionDir, "services.yaml");
623786
+ const content = fs9.readFileSync(filePath, "utf-8");
623406
623787
  const services = [];
623407
623788
  const commands = [];
623408
623789
  let missionId = "";
@@ -624839,6 +625220,549 @@ var init_conversational_scrutiny = __esm({
624839
625220
  }
624840
625221
  });
624841
625222
 
625223
+ // packages/orchestrator/dist/featurePlanner.js
625224
+ import fs10 from "node:fs";
625225
+ import path12 from "node:path";
625226
+ function classifyKind(survey) {
625227
+ const files = survey.files ?? [];
625228
+ const newSym = (survey.newSymbols ?? []).length;
625229
+ const req3 = survey.request.toLowerCase();
625230
+ if (/\b(investigat|why does|how does|trace|understand|root cause|diagnos|explain)\b/.test(req3) && newSym === 0 && files.length <= 2) {
625231
+ return "investigation";
625232
+ }
625233
+ if (/\b(bug|fix|broken|regression|crash|incorrect|fails?|misbehav)/.test(req3) && newSym === 0) {
625234
+ return "bugfix";
625235
+ }
625236
+ if (/\b(refactor|restructure|rename|clean up|simplif|migrate|consolidate)\b/.test(req3) && newSym === 0) {
625237
+ return "refactor";
625238
+ }
625239
+ if (/\b(wir|connect|integrate|hook up|plumb|bridge|glue)\b/.test(req3) && files.length >= 2) {
625240
+ return "wiring";
625241
+ }
625242
+ if (newSym > 0 || /\b(new|create|add|implement|build|introduce|scaffold)\b/.test(req3)) {
625243
+ return "new-module";
625244
+ }
625245
+ return "new-module";
625246
+ }
625247
+ function guessKind(name10) {
625248
+ if (/^(I[A-Z]|.*Interface|.*Contract|.*Spec|.*Event|.*Meta|.*Config|.*State)$/.test(name10)) {
625249
+ return "interface";
625250
+ }
625251
+ if (/^(T|Type|.*Type)$/.test(name10))
625252
+ return "type";
625253
+ if (/^(E|Enum|.*Kind|.*Status|.*Mode)$/.test(name10))
625254
+ return "enum";
625255
+ if (/^[A-Z]/.test(name10))
625256
+ return "class";
625257
+ return "function";
625258
+ }
625259
+ function buildLockedContract(kind, survey) {
625260
+ const symbols = [];
625261
+ if (kind === "refactor") {
625262
+ for (const name10 of survey.existingSymbols ?? []) {
625263
+ symbols.push({ name: name10, kind: guessKind(name10), fields: [] });
625264
+ }
625265
+ } else if (kind === "new-module") {
625266
+ for (const name10 of survey.newSymbols ?? []) {
625267
+ symbols.push({ name: name10, kind: guessKind(name10), fields: [] });
625268
+ }
625269
+ }
625270
+ return { symbols };
625271
+ }
625272
+ function decomposeFeature(survey, kind) {
625273
+ const units = [];
625274
+ const evidenceRefs = claimEvidenceRefs(survey);
625275
+ const unresolvedQuestion = survey.unresolvedQuestions?.[0] ?? (evidenceRefs.length === 0 ? "Which current files, symbols, and tests govern this unit? Inspect them before proposing a mutation." : void 0);
625276
+ const returnContract = "Return the direct result with cited observations, relevant/changed paths, verification or blocker, and the next parent decision.";
625277
+ const withGrounding = (unit) => ({
625278
+ ...unit,
625279
+ evidenceRefs,
625280
+ ...unresolvedQuestion ? { unresolvedQuestion } : {},
625281
+ returnContract
625282
+ });
625283
+ if (kind === "new-module") {
625284
+ const syms = survey.newSymbols ?? [];
625285
+ if (syms.length === 0) {
625286
+ units.push(withGrounding({
625287
+ label: "Establish the module boundary and implement the evidenced unit",
625288
+ size: "large",
625289
+ detail: "Do not scaffold from the request alone. First identify the owning entry point, adjacent contract, and test surface from current evidence."
625290
+ }));
625291
+ } else {
625292
+ for (const name10 of syms) {
625293
+ units.push({
625294
+ ...withGrounding({
625295
+ label: `Implement ${name10} within its evidenced owner`,
625296
+ size: "small",
625297
+ detail: "Confirm the symbol's owning module and contract before editing; do not infer a file path from the request label."
625298
+ }),
625299
+ expectedSymbols: [name10]
625300
+ });
625301
+ }
625302
+ }
625303
+ } else if (kind === "refactor") {
625304
+ units.push(withGrounding({
625305
+ label: "Refactor only the evidenced public surface",
625306
+ size: survey.files.length > 1 ? "large" : "small"
625307
+ }));
625308
+ } else if (kind === "bugfix") {
625309
+ units.push(withGrounding({
625310
+ label: "Reproduce the evidenced failure, make the smallest justified fix, and verify it",
625311
+ size: "small"
625312
+ }));
625313
+ } else if (kind === "wiring") {
625314
+ units.push(withGrounding({
625315
+ label: "Connect the evidenced module boundaries",
625316
+ size: survey.files.length > 2 ? "large" : "small"
625317
+ }));
625318
+ } else {
625319
+ units.push(withGrounding({
625320
+ label: "Investigate the evidence gap and report the next justified action",
625321
+ size: "small"
625322
+ }));
625323
+ }
625324
+ return units;
625325
+ }
625326
+ function claimEvidenceRefs(survey) {
625327
+ const declared = (survey.evidence ?? []).map((item) => item.ref.trim()).filter(Boolean).slice(0, 6);
625328
+ if (declared.length > 0)
625329
+ return declared;
625330
+ return survey.files.map((file) => `survey:file:${file.path}`).filter(Boolean).slice(0, 6);
625331
+ }
625332
+ function buildFeatureUnitRequest(input) {
625333
+ const evidence = (input.survey.evidence ?? []).filter((item) => !input.unit.evidenceRefs?.length || input.unit.evidenceRefs.includes(item.ref)).slice(0, 6);
625334
+ const fallbackEvidence = evidence.length > 0 ? evidence : input.survey.files.slice(0, 6).map((file) => ({
625335
+ ref: `survey:file:${file.path}`,
625336
+ detail: `${file.path}${file.role ? ` — ${file.role}` : ""}`,
625337
+ freshness: "unknown"
625338
+ }));
625339
+ const explicitOpenDeltas = [
625340
+ ...input.unit.unresolvedQuestion ? [input.unit.unresolvedQuestion] : [],
625341
+ ...input.survey.unresolvedQuestions ?? []
625342
+ ].slice(0, 6);
625343
+ const lines = [
625344
+ "[CLAIM UNIT EVIDENCE BRIEF]",
625345
+ `Parent request: ${input.parentRequest.slice(0, 900)}`,
625346
+ `Requested unit: ${input.unit.label}`,
625347
+ `Why now: this unit was selected from the current claim discovery survey, not from a task label alone.`,
625348
+ `Open deltas: ${explicitOpenDeltas.length > 0 ? explicitOpenDeltas.join(" | ") : "none"}`,
625349
+ `Surviving blockers: ${input.unit.unresolvedQuestion ? "blocker carried from planner: open question" : "none"}`,
625350
+ `Evidence handles: ${fallbackEvidence.map((item) => item.ref).join(", ")}`,
625351
+ "Evidence:",
625352
+ ...fallbackEvidence.length > 0 ? fallbackEvidence.map((item) => `- [${item.freshness ?? "unknown"}] ${item.ref}: ${item.detail.slice(0, 360)}`) : ["- No current code observation is available; discovery is required before mutation."],
625353
+ `Open question: ${input.unit.unresolvedQuestion ?? "none"}`,
625354
+ "Scope: stay within this unit and directly implicated code; do not broaden the claim without returning to the parent.",
625355
+ `Return contract: ${input.unit.returnContract ?? "Return evidence, verification or blocker, and the next parent decision."}`,
625356
+ "",
625357
+ "Work protocol: inspect the cited files/contracts first. Only mutate after a fresh observation identifies the exact target; if the evidence does not support a target, report the gap instead of fabricating one."
625358
+ ];
625359
+ return lines.filter((line) => Boolean(line)).join("\n");
625360
+ }
625361
+ function renderSpecMarkdown(input) {
625362
+ const { kind, survey, lockedContract, completionContract, decomposition, prose } = input;
625363
+ const lines = [];
625364
+ lines.push(`# Claim Discovery Plan — ${kind}`);
625365
+ lines.push("");
625366
+ lines.push(`**Request:** ${survey.request}`);
625367
+ lines.push("");
625368
+ lines.push(`**Node kind:** \`${kind}\` (selected by CLASSIFY over the survey signals)`);
625369
+ lines.push("");
625370
+ if (prose) {
625371
+ lines.push(`## 1. Intent`);
625372
+ lines.push("");
625373
+ lines.push(prose.trim());
625374
+ lines.push("");
625375
+ }
625376
+ lines.push(`## 2. Survey (codebase as-is)`);
625377
+ lines.push("");
625378
+ if (survey.files.length > 0) {
625379
+ for (const f2 of survey.files) {
625380
+ const refs = f2.lineRefs?.length ? `:${f2.lineRefs.join(",")}` : "";
625381
+ lines.push(`- \`${f2.path}${refs}\`${f2.role ? ` — ${f2.role}` : ""}`);
625382
+ }
625383
+ } else {
625384
+ lines.push("- (no files enumerated in survey)");
625385
+ }
625386
+ if (survey.evidence?.length) {
625387
+ for (const item of survey.evidence.slice(0, 8)) {
625388
+ lines.push(`- evidence [${item.freshness ?? "unknown"}] ${item.ref}: ${item.detail}`);
625389
+ }
625390
+ }
625391
+ if (survey.unresolvedQuestions?.length) {
625392
+ lines.push(`- unresolved: ${survey.unresolvedQuestions.join("; ")}`);
625393
+ }
625394
+ lines.push(`- new symbols: ${(survey.newSymbols ?? []).join(", ") || "none"}`);
625395
+ lines.push(`- public surface changes: ${survey.publicSurfaceChanges ? "yes" : "no"}`);
625396
+ lines.push(`- tests exist: ${survey.testsExist ? "yes" : "no"}`);
625397
+ lines.push("");
625398
+ lines.push(`## 3. Locked contract (executable gate)`);
625399
+ lines.push("");
625400
+ if (lockedContract.symbols.length === 0) {
625401
+ lines.push("- (no locked symbols for this kind — disciplined but permissive)");
625402
+ } else {
625403
+ for (const s2 of lockedContract.symbols) {
625404
+ lines.push(`- \`${s2.kind} ${s2.name}\``);
625405
+ }
625406
+ }
625407
+ lines.push("");
625408
+ lines.push(`## 4. Definition of done (CompletionContract)`);
625409
+ lines.push("");
625410
+ lines.push(`- goal: ${completionContract.goalSummary || "(none)"}`);
625411
+ for (const p2 of completionContract.phases ?? []) {
625412
+ lines.push(`- phase: ${p2.label}`);
625413
+ }
625414
+ lines.push("");
625415
+ lines.push(`## 5. Decomposition (SPLIT seed)`);
625416
+ lines.push("");
625417
+ for (const u of decomposition) {
625418
+ lines.push(`- [${u.size}] ${u.label}${u.expectedSymbols?.length ? ` (symbols: ${u.expectedSymbols.join(", ")})` : ""}${u.evidenceRefs?.length ? ` [evidence: ${u.evidenceRefs.join(", ")}]` : ""}`);
625419
+ }
625420
+ lines.push("");
625421
+ lines.push(`## 6. Verification bar`);
625422
+ lines.push("");
625423
+ lines.push("- planner emits real artefacts (this file + locked contract + completion contract)");
625424
+ lines.push("- approval gate blocks before any source edit");
625425
+ lines.push("- WO-6 executor gate activates on locked symbols");
625426
+ lines.push("- recursion + eviction keep context bounded");
625427
+ lines.push("- scope token re-prompts on out-of-scope work");
625428
+ lines.push("");
625429
+ lines.push(`## 7. Handoff notes`);
625430
+ lines.push("");
625431
+ lines.push("- Compose, do not rebuild: this plan reuses spec-gate + completionContract primitives.");
625432
+ lines.push("- Fail-closed: if planning errors, the run falls back to the general agentic loop.");
625433
+ lines.push("");
625434
+ return lines.join("\n");
625435
+ }
625436
+ async function planFeature(survey, options2 = {}) {
625437
+ const kind = classifyKind(survey);
625438
+ const lockedContract = buildLockedContract(kind, survey);
625439
+ const completionContract = inferCompletionContractFromTexts([survey.request, ...survey.rawTexts ?? [], ...survey.signals ?? []], survey.request);
625440
+ const decomposition = decomposeFeature(survey, kind);
625441
+ let prose = "";
625442
+ try {
625443
+ if (options2.proseGenerator) {
625444
+ prose = await options2.proseGenerator({ request: survey.request, kind, survey });
625445
+ }
625446
+ } catch {
625447
+ prose = "";
625448
+ }
625449
+ const specMarkdown = renderSpecMarkdown({
625450
+ kind,
625451
+ survey,
625452
+ lockedContract,
625453
+ completionContract,
625454
+ decomposition,
625455
+ prose
625456
+ });
625457
+ return { kind, specMarkdown, lockedContract, completionContract, decomposition };
625458
+ }
625459
+ function persistPlannerArtefacts(rootId, artefact, stateDir, survey) {
625460
+ try {
625461
+ const dir = path12.join(stateDir, "feature-tree", rootId);
625462
+ fs10.mkdirSync(dir, { recursive: true });
625463
+ fs10.writeFileSync(path12.join(dir, "spec.md"), artefact.specMarkdown, "utf8");
625464
+ fs10.writeFileSync(path12.join(dir, "locked-contract.json"), JSON.stringify(artefact.lockedContract, null, 2), "utf8");
625465
+ fs10.writeFileSync(path12.join(dir, "completion-contract.json"), JSON.stringify(artefact.completionContract, null, 2), "utf8");
625466
+ if (survey) {
625467
+ fs10.writeFileSync(path12.join(dir, "claim-discovery-survey.json"), JSON.stringify({
625468
+ request: survey.request,
625469
+ requestSource: "bound_workspace_inventory",
625470
+ files: survey.files,
625471
+ unresolvedQuestions: survey.unresolvedQuestions ?? [],
625472
+ evidenceRefs: survey.evidence?.map((item) => item.ref) ?? [],
625473
+ signals: survey.signals ?? [],
625474
+ requiredVerificationCommands: survey.requiredVerificationCommands ?? [],
625475
+ testsExist: survey.testsExist ?? false,
625476
+ publicSurfaceChanges: survey.publicSurfaceChanges ?? false,
625477
+ newSymbols: survey.newSymbols ?? [],
625478
+ existingSymbols: survey.existingSymbols ?? []
625479
+ }, null, 2), "utf8");
625480
+ }
625481
+ } catch {
625482
+ }
625483
+ }
625484
+ var classifyClaimKind, buildClaimPlan, buildClaimUnitRequest, buildClaimLockedContract;
625485
+ var init_featurePlanner = __esm({
625486
+ "packages/orchestrator/dist/featurePlanner.js"() {
625487
+ "use strict";
625488
+ init_completionContract();
625489
+ classifyClaimKind = classifyKind;
625490
+ buildClaimPlan = planFeature;
625491
+ buildClaimUnitRequest = buildFeatureUnitRequest;
625492
+ buildClaimLockedContract = buildLockedContract;
625493
+ }
625494
+ });
625495
+
625496
+ // packages/orchestrator/dist/featureApprovalGate.js
625497
+ function mintScopeToken(input) {
625498
+ return {
625499
+ rootId: input.rootId,
625500
+ files: [...input.files ?? []],
625501
+ symbols: input.lockedContract.symbols.map((s2) => s2.name),
625502
+ nodeKinds: input.nodeKinds ?? ["new-module", "refactor", "bugfix", "wiring", "investigation"],
625503
+ depthCap: input.depthCap
625504
+ };
625505
+ }
625506
+ function isWithinScope(input) {
625507
+ const { token } = input;
625508
+ if (typeof input.depth === "number" && input.depth > token.depthCap) {
625509
+ return false;
625510
+ }
625511
+ if (input.nodeKind && !token.nodeKinds.includes(input.nodeKind)) {
625512
+ return false;
625513
+ }
625514
+ if (input.newSymbol && !token.symbols.includes(input.newSymbol)) {
625515
+ return false;
625516
+ }
625517
+ if (input.file) {
625518
+ const file = input.file;
625519
+ const allowed = token.files.some((f2) => {
625520
+ if (f2 === file)
625521
+ return true;
625522
+ if (f2.endsWith("/") && file.startsWith(f2))
625523
+ return true;
625524
+ if (f2.includes("*") && globMatch(f2, file))
625525
+ return true;
625526
+ return false;
625527
+ });
625528
+ if (!allowed)
625529
+ return false;
625530
+ }
625531
+ return true;
625532
+ }
625533
+ function globMatch(pattern, value2) {
625534
+ const re = new RegExp("^" + pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*") + "$");
625535
+ return re.test(value2);
625536
+ }
625537
+ async function requestApproval(req3, ask2, options2 = {}) {
625538
+ let decision2;
625539
+ try {
625540
+ const raw = await ask2(req3);
625541
+ decision2 = raw === "approve" || raw === "edit" || raw === "reject" ? raw : "reject";
625542
+ } catch {
625543
+ decision2 = "reject";
625544
+ }
625545
+ if (decision2 === "approve") {
625546
+ const token = mintScopeToken({
625547
+ rootId: req3.rootId,
625548
+ lockedContract: req3.lockedContract,
625549
+ decomposition: req3.decomposition,
625550
+ depthCap: req3.depthCap,
625551
+ files: options2.files,
625552
+ nodeKinds: options2.nodeKinds
625553
+ });
625554
+ return { decision: decision2, token };
625555
+ }
625556
+ return { decision: decision2 };
625557
+ }
625558
+ var mintClaimScopeToken, isWithinClaimScope, requestClaimApproval;
625559
+ var init_featureApprovalGate = __esm({
625560
+ "packages/orchestrator/dist/featureApprovalGate.js"() {
625561
+ "use strict";
625562
+ mintClaimScopeToken = mintScopeToken;
625563
+ isWithinClaimScope = isWithinScope;
625564
+ requestClaimApproval = requestApproval;
625565
+ }
625566
+ });
625567
+
625568
+ // packages/orchestrator/dist/featureNode.js
625569
+ import fs11 from "node:fs";
625570
+ import path13 from "node:path";
625571
+ function treePath(stateDir, rootId) {
625572
+ return path13.join(stateDir, "feature-tree", `${rootId}.json`);
625573
+ }
625574
+ function saveFeatureTree(stateDir, rootId, nodes) {
625575
+ try {
625576
+ const file = treePath(stateDir, rootId);
625577
+ fs11.mkdirSync(path13.dirname(file), { recursive: true });
625578
+ fs11.writeFileSync(file, JSON.stringify(nodes, null, 2), "utf8");
625579
+ } catch {
625580
+ }
625581
+ }
625582
+ function loadFeatureTree(stateDir, rootId) {
625583
+ try {
625584
+ const file = treePath(stateDir, rootId);
625585
+ if (!fs11.existsSync(file))
625586
+ return null;
625587
+ const raw = JSON.parse(fs11.readFileSync(file, "utf8"));
625588
+ return raw && typeof raw === "object" ? raw : null;
625589
+ } catch {
625590
+ return null;
625591
+ }
625592
+ }
625593
+ function newNodeId(depth, seed) {
625594
+ const h = String(Math.abs(hashString2(seed)) % 1e9).padStart(9, "0");
625595
+ return `fn-d${depth}-${h}`;
625596
+ }
625597
+ function hashString2(s2) {
625598
+ let h = 0;
625599
+ for (let i2 = 0; i2 < s2.length; i2++)
625600
+ h = h * 31 + s2.charCodeAt(i2) | 0;
625601
+ return h;
625602
+ }
625603
+ async function evictNode(node, ctx3, transcript) {
625604
+ try {
625605
+ await runTodoChunker({
625606
+ inputs: {
625607
+ todoId: node.id,
625608
+ todoContent: node.request,
625609
+ turnRange: [0, 0],
625610
+ transcript: transcript || node.request,
625611
+ toolCalls: [],
625612
+ workingDirectory: ctx3.workingDirectory,
625613
+ sessionId: ctx3.sessionId
625614
+ },
625615
+ callable: ctx3.summarizer ?? (async () => "")
625616
+ });
625617
+ } catch {
625618
+ }
625619
+ }
625620
+ async function execUnit(unit, node, ctx3, contract, maxRegenerate) {
625621
+ let result = await ctx3.executeUnit(unit, node);
625622
+ if (!result.ok)
625623
+ return false;
625624
+ const expected = unit.expectedSymbols ?? [];
625625
+ if (expected.length === 0) {
625626
+ return true;
625627
+ }
625628
+ for (let attempt = 0; attempt <= maxRegenerate; attempt++) {
625629
+ if (!result.path || result.source === void 0)
625630
+ return false;
625631
+ const verdict = evaluateExecutorStep({
625632
+ unit: { path: result.path, source: result.source },
625633
+ contract,
625634
+ expectedSymbols: expected
625635
+ });
625636
+ if (verdict.decision === "accept")
625637
+ return true;
625638
+ if (verdict.decision === "replan")
625639
+ return false;
625640
+ result = await ctx3.executeUnit(unit, node);
625641
+ if (!result.ok)
625642
+ return false;
625643
+ }
625644
+ return false;
625645
+ }
625646
+ async function runFeatureNode(node, ctx3, options2, tree2 = {}) {
625647
+ const maxRegenerate = options2.maxRegenerate ?? 2;
625648
+ tree2[node.id] = node;
625649
+ try {
625650
+ const artefact = await planFeature(options2.survey, {
625651
+ proseGenerator: options2.proseGenerator
625652
+ });
625653
+ node.kind = artefact.kind;
625654
+ if (ctx3.onPlan) {
625655
+ try {
625656
+ await ctx3.onPlan(artefact);
625657
+ } catch {
625658
+ }
625659
+ }
625660
+ persistPlannerArtefacts(ctx3.rootId, artefact, ctx3.stateDir, options2.survey);
625661
+ const mustAsk = node.depth === 0 || !node.scopeToken;
625662
+ if (mustAsk && ctx3.askApproval) {
625663
+ node.status = "awaiting_approval";
625664
+ const outcome = await requestApproval({
625665
+ rootId: ctx3.rootId,
625666
+ request: node.request,
625667
+ specMarkdown: artefact.specMarkdown,
625668
+ lockedContract: artefact.lockedContract,
625669
+ decomposition: artefact.decomposition,
625670
+ depthCap: ctx3.depthCap
625671
+ }, ctx3.askApproval, { files: options2.survey.files.map((f2) => f2.path) });
625672
+ if (outcome.decision !== "approve") {
625673
+ node.status = outcome.decision === "edit" ? "planned" : "rejected";
625674
+ saveFeatureTree(ctx3.stateDir, ctx3.rootId, tree2);
625675
+ return node;
625676
+ }
625677
+ node.scopeToken = outcome.token;
625678
+ }
625679
+ node.status = "approved";
625680
+ node.status = "executing";
625681
+ let allOk = true;
625682
+ for (const unit of artefact.decomposition) {
625683
+ if (unit.size === "large" && node.depth < ctx3.depthCap) {
625684
+ const childId = newNodeId(node.depth + 1, unit.label + node.id);
625685
+ const childRequest = buildFeatureUnitRequest({
625686
+ unit,
625687
+ parentRequest: node.request,
625688
+ survey: options2.survey
625689
+ });
625690
+ const child = {
625691
+ id: childId,
625692
+ parentId: node.id,
625693
+ depth: node.depth + 1,
625694
+ request: childRequest,
625695
+ kind: artefact.kind,
625696
+ status: "planned",
625697
+ scopeToken: node.scopeToken,
625698
+ children: []
625699
+ };
625700
+ node.children.push(childId);
625701
+ const childSurvey = {
625702
+ ...options2.survey,
625703
+ request: child.request
625704
+ };
625705
+ const childCtx = {
625706
+ ...ctx3,
625707
+ // children inherit the token; re-prompt only if they exceed scope
625708
+ askApproval: (req3) => isWithinScope({
625709
+ token: node.scopeToken,
625710
+ depth: node.depth + 1,
625711
+ nodeKind: artefact.kind
625712
+ }) ? "approve" : ctx3.askApproval(req3)
625713
+ };
625714
+ const res = await runFeatureNode(child, childCtx, { ...options2, survey: childSurvey }, tree2);
625715
+ if (res.status !== "completed")
625716
+ allOk = false;
625717
+ await evictNode(child, ctx3, child.request);
625718
+ } else {
625719
+ const ok3 = await execUnit(unit, node, ctx3, artefact.lockedContract, maxRegenerate);
625720
+ if (!ok3)
625721
+ allOk = false;
625722
+ }
625723
+ }
625724
+ if (allOk) {
625725
+ node.status = "completed";
625726
+ } else {
625727
+ node.status = "failed";
625728
+ }
625729
+ saveFeatureTree(ctx3.stateDir, ctx3.rootId, tree2);
625730
+ return node;
625731
+ } catch {
625732
+ if (ctx3.runGeneralLoop) {
625733
+ await ctx3.runGeneralLoop(node.request);
625734
+ node.status = "completed";
625735
+ } else {
625736
+ node.status = "failed";
625737
+ }
625738
+ saveFeatureTree(ctx3.stateDir, ctx3.rootId, tree2);
625739
+ return node;
625740
+ }
625741
+ }
625742
+ function createRootFeatureNode(request) {
625743
+ return {
625744
+ id: newNodeId(0, request),
625745
+ parentId: null,
625746
+ depth: 0,
625747
+ request,
625748
+ kind: "new-module",
625749
+ status: "planned",
625750
+ children: []
625751
+ };
625752
+ }
625753
+ var runClaimNode, createClaimRootNode;
625754
+ var init_featureNode = __esm({
625755
+ "packages/orchestrator/dist/featureNode.js"() {
625756
+ "use strict";
625757
+ init_featurePlanner();
625758
+ init_featureApprovalGate();
625759
+ init_spec_gate();
625760
+ init_todo_context_chunker();
625761
+ runClaimNode = runFeatureNode;
625762
+ createClaimRootNode = createRootFeatureNode;
625763
+ }
625764
+ });
625765
+
624842
625766
  // packages/orchestrator/dist/causalAblation.js
624843
625767
  function _identifyAblationTargets(messages2, dimension) {
624844
625768
  const targets = [];
@@ -625364,6 +626288,9 @@ __export(dist_exports3, {
625364
626288
  buildAgentDeploymentPatternSummary: () => buildAgentDeploymentPatternSummary,
625365
626289
  buildAgentNotification: () => buildAgentNotification,
625366
626290
  buildAgentTypeSummary: () => buildAgentTypeSummary,
626291
+ buildClaimLockedContract: () => buildClaimLockedContract,
626292
+ buildClaimPlan: () => buildClaimPlan,
626293
+ buildClaimUnitRequest: () => buildClaimUnitRequest,
625367
626294
  buildCompletionFinalizationRecord: () => buildCompletionFinalizationRecord,
625368
626295
  buildCompletionScenarioDecomposition: () => buildCompletionScenarioDecomposition,
625369
626296
  buildCoordinatorPrompt: () => buildCoordinatorPrompt,
@@ -625390,6 +626317,7 @@ __export(dist_exports3, {
625390
626317
  chooseCheapModelRoute: () => chooseCheapModelRoute,
625391
626318
  claimAssertion: () => claimAssertion,
625392
626319
  classifyBreadth: () => classifyBreadth,
626320
+ classifyClaimKind: () => classifyClaimKind,
625393
626321
  classifyCompletionClaim: () => classifyCompletionClaim,
625394
626322
  classifyHandoff: () => classifyHandoff,
625395
626323
  classifyKind: () => classifyKind,
@@ -625424,6 +626352,7 @@ __export(dist_exports3, {
625424
626352
  countDefinitions: () => countDefinitions,
625425
626353
  createAppState: () => createAppState,
625426
626354
  createChildAbortController: () => createChildAbortController,
626355
+ createClaimRootNode: () => createClaimRootNode,
625427
626356
  createCompletionLedger: () => createCompletionLedger,
625428
626357
  createDefaultContextEngine: () => createDefaultContextEngine,
625429
626358
  createFeaturesManifest: () => createFeaturesManifest,
@@ -625517,6 +626446,7 @@ __export(dist_exports3, {
625517
626446
  isSuccessfulRunFinished: () => isSuccessfulRunFinished,
625518
626447
  isTerminalRunEvent: () => isTerminalRunEvent,
625519
626448
  isTerminalTaskStatus: () => isTerminalTaskStatus,
626449
+ isWithinClaimScope: () => isWithinClaimScope,
625520
626450
  isWithinScope: () => isWithinScope,
625521
626451
  legacyAgenticEventToRunEvent: () => legacyAgenticEventToRunEvent,
625522
626452
  listContextWindowDumps: () => listContextWindowDumps,
@@ -625533,6 +626463,7 @@ __export(dist_exports3, {
625533
626463
  measureContextSNR: () => measureContextSNR,
625534
626464
  memoryCosine: () => cosine4,
625535
626465
  mergeDigests: () => mergeDigests,
626466
+ mintClaimScopeToken: () => mintClaimScopeToken,
625536
626467
  mintScopeToken: () => mintScopeToken,
625537
626468
  normalizeCompletionKey: () => normalizeCompletionKey,
625538
626469
  normalizeMemoryCompilationPlanAudit: () => normalizeMemoryCompilationPlanAudit,
@@ -625551,6 +626482,7 @@ __export(dist_exports3, {
625551
626482
  persistAgentTaskSidecar: () => persistAgentTaskSidecar,
625552
626483
  persistPlannerArtefacts: () => persistPlannerArtefacts,
625553
626484
  planAgentDeploymentPattern: () => planAgentDeploymentPattern,
626485
+ planClaim: () => buildClaimPlan,
625554
626486
  planConsolidation: () => planConsolidation,
625555
626487
  planFeature: () => planFeature,
625556
626488
  prepareCompletionFinalization: () => prepareCompletionFinalization,
@@ -625598,6 +626530,7 @@ __export(dist_exports3, {
625598
626530
  renderValidationContract: () => renderValidationContract,
625599
626531
  renderWorkerSkill: () => renderWorkerSkill,
625600
626532
  requestApproval: () => requestApproval,
626533
+ requestClaimApproval: () => requestClaimApproval,
625601
626534
  resetPluginRegistry: () => resetPluginRegistry,
625602
626535
  resolveAgentTools: () => resolveAgentTools,
625603
626536
  resolveDefaultPoolConfig: () => resolveDefaultPoolConfig,
@@ -625605,6 +626538,7 @@ __export(dist_exports3, {
625605
626538
  resolveModelProfile: () => resolveModelProfile,
625606
626539
  restoreAgentTasks: () => restoreAgentTasks,
625607
626540
  retentionStrength: () => retentionStrength,
626541
+ runClaimNode: () => runClaimNode,
625608
626542
  runFeatureNode: () => runFeatureNode,
625609
626543
  runMemoryCompilerReplay: () => runMemoryCompilerReplay,
625610
626544
  runMemoryCompilerReplaySuite: () => runMemoryCompilerReplaySuite,
@@ -633601,7 +634535,11 @@ function mapExecutionToolResult(result) {
633601
634535
  partial: result.partial,
633602
634536
  beforeHash: result.beforeHash,
633603
634537
  afterHash: result.afterHash,
633604
- evidenceEvents: result.evidenceEvents
634538
+ evidenceEvents: result.evidenceEvents,
634539
+ // Preserve process facts separately from display text. The orchestrator
634540
+ // uses this receipt for completion evidence; reconstructing it from a
634541
+ // truncated/streamed transcript would be unsound.
634542
+ executionReceipt: result.executionReceipt
633605
634543
  };
633606
634544
  }
633607
634545
  function adaptExecutionTool(tool, options2 = {}) {
@@ -772018,6 +772956,8 @@ async function runCommand2(opts, config) {
772018
772956
  await runBackground(opts.task, mergedConfig, opts);
772019
772957
  } else if (opts.json) {
772020
772958
  await runJson(opts.task, mergedConfig, opts.repoPath);
772959
+ } else if (opts.verbose) {
772960
+ await runConsole(opts.task, mergedConfig, opts.repoPath);
772021
772961
  } else {
772022
772962
  await runWithTUI(opts.task, mergedConfig, opts.repoPath);
772023
772963
  if (shouldForceSingleRunExit()) process.exit(0);
@@ -772117,6 +773057,95 @@ async function runJson(task, config, repoPath2) {
772117
773057
  if (result.exitCode !== 0) process.exit(result.exitCode);
772118
773058
  if (shouldForceJsonExit()) process.exit(0);
772119
773059
  }
773060
+ async function runConsole(task, config, repoPath2) {
773061
+ const startTime = Date.now();
773062
+ const origWrite = process.stdout.write.bind(process.stdout);
773063
+ const origStderr = process.stderr.write.bind(process.stderr);
773064
+ process.stdout.write = (() => true);
773065
+ process.stderr.write = (() => true);
773066
+ let runnerResult = null;
773067
+ let toolCount = 0;
773068
+ const fmtArgs = (args) => {
773069
+ if (args === void 0 || args === null) return "";
773070
+ if (typeof args !== "object") return ` (${String(args)})`;
773071
+ const entries = Object.entries(args);
773072
+ if (entries.length === 0) return "";
773073
+ const parts = entries.map(([k, v]) => {
773074
+ let s2;
773075
+ if (typeof v === "string") {
773076
+ s2 = v.length > 200 ? `${v.slice(0, 197)}…` : v;
773077
+ } else if (v === void 0 || v === null) {
773078
+ s2 = String(v);
773079
+ } else {
773080
+ try {
773081
+ s2 = JSON.stringify(v);
773082
+ } catch {
773083
+ s2 = String(v);
773084
+ }
773085
+ if (s2.length > 200) s2 = `${s2.slice(0, 197)}…`;
773086
+ }
773087
+ return `${k}=${s2}`;
773088
+ });
773089
+ return ` (${parts.join(", ")})`;
773090
+ };
773091
+ const emit2 = (line) => {
773092
+ origWrite(line + "\n");
773093
+ };
773094
+ try {
773095
+ emit2(`▶ Task: ${task}`);
773096
+ await runWithTUI(task, config, repoPath2, {
773097
+ onToolCall: (tool, args) => {
773098
+ toolCount += 1;
773099
+ emit2(`[${toolCount}] 🔧 ${tool}${fmtArgs(args)}`);
773100
+ },
773101
+ onToolResult: (tool, output, success) => {
773102
+ const redacted = getSecretRedactor().redactText(output || "");
773103
+ const capped = redacted && redacted.length > 400 ? redacted.slice(0, 380) + `… [+${redacted.length - 380} chars]` : redacted;
773104
+ const mark = success ? "✓" : "✗";
773105
+ emit2(` ${mark} ${tool} → ${capped || "(no output)"}`);
773106
+ },
773107
+ onStatus: (content) => {
773108
+ if (content && content.trim()) {
773109
+ emit2(`ℹ ${content.trim()}`);
773110
+ }
773111
+ },
773112
+ onAssistantText: (text2) => {
773113
+ const clean6 = sanitizeAgentOutputForUser(text2).trim();
773114
+ if (clean6) emit2(`💬 ${clean6.replace(/\n/g, "\n ")}`);
773115
+ },
773116
+ onRunResult: (result) => {
773117
+ runnerResult = {
773118
+ status: result.status,
773119
+ completed: result.completed,
773120
+ summary: result.summary,
773121
+ turns: result.turns,
773122
+ toolCalls: result.toolCalls
773123
+ };
773124
+ }
773125
+ });
773126
+ } catch (err) {
773127
+ process.stdout.write = origWrite;
773128
+ process.stderr.write = origStderr;
773129
+ emit2(`✗ Error: ${err instanceof Error ? err.message : String(err)}`);
773130
+ if (config.verbose && err instanceof Error && err.stack) {
773131
+ emit2(err.stack);
773132
+ }
773133
+ process.exit(1);
773134
+ }
773135
+ process.stdout.write = origWrite;
773136
+ process.stderr.write = origStderr;
773137
+ const durationMs = Date.now() - startTime;
773138
+ const rr = runnerResult;
773139
+ const status = rr?.completed ? "completed" : rr?.status ?? "completed";
773140
+ emit2("");
773141
+ emit2(
773142
+ `✓ Done — status: ${status} | ${rr?.turns ?? "?"} turns | ${toolCount} tool calls | ${(durationMs / 1e3).toFixed(1)}s`
773143
+ );
773144
+ if (rr?.summary) {
773145
+ emit2(`Summary: ${rr.summary.slice(0, 400)}`);
773146
+ }
773147
+ if (shouldForceSingleRunExit()) process.exit(0);
773148
+ }
772120
773149
  function shouldForceJsonExit() {
772121
773150
  if (process.env["OMNIUS_JSON_NO_FORCE_EXIT"] === "1") return false;
772122
773151
  if (process.env["VITEST"] === "true" || process.env["NODE_ENV"] === "test")
@@ -773408,7 +774437,7 @@ Flags:
773408
774437
  --dry-run Validate patches, don't write to disk
773409
774438
  --offline Use FakeBackend, no backend connection needed
773410
774439
  -l, --local Save settings to .omnius/settings.json (project-local)
773411
- -v, --verbose Verbose output
774440
+ -v, --verbose Lightweight console mode: print each tool call, result, and reasoning step as plain text (no TUI)
773412
774441
  --max-retries <n> Max retries per model request
773413
774442
  --timeout-ms <ms> Overall task timeout
773414
774443
  --suite <name> Eval suite: basic (default) or full