cc-codeconductor 1.4.0 → 1.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +24 -1
  2. package/dist/core/verification/rdd-receipt.d.ts +39 -0
  3. package/dist/core/verification/verification-runner.d.ts +8 -2
  4. package/dist/index.d.ts +2 -0
  5. package/dist/index.js +1108 -319
  6. package/dist/library.js +296 -27
  7. package/dist/utils/cli-bin.d.ts +16 -0
  8. package/dist/validation/schemas.d.ts +521 -26
  9. package/docs/generated/cli.md +37 -25
  10. package/package.json +1 -1
  11. package/presets/agy/AGENTS.md +6 -0
  12. package/presets/agy/workflows/cc-handoff.md +2 -1
  13. package/presets/agy/workflows/cc-odd.md +15 -0
  14. package/presets/claude/CLAUDE.md +6 -0
  15. package/presets/claude/commands/cc/handoff.md +2 -1
  16. package/presets/claude/commands/cc/odd.md +15 -0
  17. package/presets/codex/AGENTS.md +6 -0
  18. package/presets/codex/skills/cc-handoff/SKILL.md +3 -1
  19. package/presets/codex/skills/cc-odd/SKILL.md +25 -0
  20. package/presets/codex/skills/cc-openspec/SKILL.md +4 -0
  21. package/presets/codex/skills/cc-spec-mutation/SKILL.md +5 -0
  22. package/presets/codex/skills/cc-tdd-cycle/SKILL.md +8 -0
  23. package/presets/cursor/AGENTS.md +6 -0
  24. package/presets/cursor/commands/cc/handoff.md +3 -1
  25. package/presets/cursor/commands/cc/odd.md +20 -0
  26. package/presets/cursor/commands/cc/openspec.md +4 -0
  27. package/presets/cursor/commands/cc/spec-mutation.md +5 -0
  28. package/presets/cursor/commands/cc/tdd-cycle.md +8 -0
  29. package/presets/gemini/GEMINI.md +6 -0
  30. package/presets/gemini/commands/cc/handoff.toml +3 -1
  31. package/presets/gemini/commands/cc/odd.toml +20 -0
  32. package/presets/gemini/commands/cc/openspec.toml +4 -0
  33. package/presets/gemini/commands/cc/spec-mutation.toml +5 -0
  34. package/presets/gemini/commands/cc/tdd-cycle.toml +8 -0
  35. package/presets/opencode/agents/implementer.md +2 -0
  36. package/presets/opencode/agents/reviewer.md +2 -0
  37. package/presets/opencode/agents/tester.md +2 -0
  38. package/presets/opencode/commands/cc-handoff.md +2 -1
  39. package/presets/opencode/commands/cc-odd.md +15 -0
  40. package/presets/pi/AGENTS.md +6 -0
  41. package/src/presets/targets/pi.yml +1 -0
package/dist/index.js CHANGED
@@ -72,7 +72,7 @@ var package_default;
72
72
  var init_package = __esm(() => {
73
73
  package_default = {
74
74
  name: "cc-codeconductor",
75
- version: "1.4.0",
75
+ version: "1.4.2",
76
76
  description: "A multi-agent orchestration framework for AI-assisted software engineering workflows.",
77
77
  keywords: [
78
78
  "ai",
@@ -4145,6 +4145,38 @@ var init_runner_target = __esm(() => {
4145
4145
  INDIVIDUAL_TARGETS = ["opencode", "claude", "codex", "gemini", "cursor", "agy", "pi"];
4146
4146
  });
4147
4147
 
4148
+ // src/utils/cli-bin.ts
4149
+ import { basename } from "node:path";
4150
+ function resolveCliBin(env = process.env, argv = process.argv) {
4151
+ if (env.CC_CLI_BIN) {
4152
+ return env.CC_CLI_BIN;
4153
+ }
4154
+ if (env.npm_lifecycle_event === "npx" || env.npm_command === "exec" || env._?.endsWith("/npx") || env._ === "npx") {
4155
+ return "npx cc-codeconductor";
4156
+ }
4157
+ if (env._?.endsWith("/bunx") || env._ === "bunx") {
4158
+ return "bunx cc-codeconductor";
4159
+ }
4160
+ if (env.npm_lifecycle_event === "dev") {
4161
+ return env.npm_lifecycle_script?.startsWith("bun") ? "bun run dev" : "npm run dev";
4162
+ }
4163
+ if (argv && argv.length > 1 && argv[1]) {
4164
+ const script = argv[1];
4165
+ const binName = basename(script);
4166
+ if (binName === "main.ts") {
4167
+ return "bun run dev";
4168
+ }
4169
+ if (binName === "cc-codeconductor" || binName === "codeconductor") {
4170
+ return binName;
4171
+ }
4172
+ }
4173
+ return "cc-codeconductor";
4174
+ }
4175
+ function formatUsage(usage, bin = resolveCliBin()) {
4176
+ return usage.replace(/^(?:cc-codeconductor|codeconductor|cc)\b/, bin);
4177
+ }
4178
+ var init_cli_bin = () => {};
4179
+
4148
4180
  // node_modules/yaml/dist/nodes/identity.js
4149
4181
  var require_identity = __commonJS(function(exports) {
4150
4182
  var ALIAS = Symbol.for("yaml.alias");
@@ -11174,6 +11206,11 @@ __export(exports_schemas, {
11174
11206
  CouncilVerdictInputSchema: () => CouncilVerdictInputSchema,
11175
11207
  CouncilVerdictSchema: () => CouncilVerdictSchema,
11176
11208
  DecisionSchema: () => DecisionSchema,
11209
+ DeliveryLedgerRequestSchema: () => DeliveryLedgerRequestSchema,
11210
+ DeliveryLedgerSchema: () => DeliveryLedgerSchema,
11211
+ DeliveryLedgerTaskSchema: () => DeliveryLedgerTaskSchema,
11212
+ DeliveryRouteSchema: () => DeliveryRouteSchema,
11213
+ DeliveryTelemetrySchema: () => DeliveryTelemetrySchema,
11177
11214
  EvaluationIndexSchema: () => EvaluationIndexSchema,
11178
11215
  EvidenceSchema: () => EvidenceSchema,
11179
11216
  ExecutionContextSchema: () => ExecutionContextSchema,
@@ -11238,6 +11275,7 @@ __export(exports_schemas, {
11238
11275
  TaskOutcomeSourceSchema: () => TaskOutcomeSourceSchema,
11239
11276
  TaskOutcomeStatusSchema: () => TaskOutcomeStatusSchema,
11240
11277
  TechnicalPlanOutputSchema: () => TechnicalPlanOutputSchema,
11278
+ TokenUsageSchema: () => TokenUsageSchema,
11241
11279
  ToolProviderNamesSchema: () => ToolProviderNamesSchema,
11242
11280
  VerificationReportSchema: () => VerificationReportSchema,
11243
11281
  WorkflowCommandSchema: () => WorkflowCommandSchema,
@@ -11401,7 +11439,7 @@ function validateProductEvent(data) {
11401
11439
  function validateSkillsRegistry(data) {
11402
11440
  return SkillsRegistrySchema.parse(data);
11403
11441
  }
11404
- var CouncilAgentSpecSchema, CouncilSpecSchema, ProjectProfileSchema, CompileCheckConfigSchema, LoopConfigSchema, CodeConductorConfigSchema, RunnerTargetSchema, InstallStrategySchema, ManifestEntrySchema, InstallManifestSchema, ToolProviderNamesSchema, PermissionProviderNamesSchema, ModelConfigSchema, SkillFrontmatterSchema, CommandFrontmatterSchema, TargetCapabilitiesSchema, ContractTargetSchema, ContractFormatSchema, AgentContractSchema, CouncilFindingSchema, CouncilVerdictInputSchema, ConsensusConfigSchema, CouncilVerdictSchema, ClaudeAgentFileSchema, OpenCodeAgentFileSchema, SentryStackFrameSchema, SentryWebhookSchema, MemoryPointerSchema, MemoryIndexSchema, GoalTaskSchema, GoalGraphSchema, ConfidenceLevelSchema, ProductNodeTypeSchema, GraphRelationSchema, KnowledgeEntitySchema, DecisionSchema, EvidenceSchema, CanonicalTaskCardStatusSchema, CanonicalTaskCardSchema, ProductGraphNodeSchema, ProductGraphEdgeSchema, ProductGraphSchema, ProductMetaSchema, ProductEventTypeSchema, ProductEventSchema, OperationalStateSchema, StrategicMemorySchema, ImpactReportSchema, BusinessReviewOutputSchema, VerificationReportSchema, BacklogStatusSchema, BacklogTypeSchema, BacklogPrioritySchema, BacklogGlobalSchema, BacklogItemSchema, BacklogDocumentSchema, OpenspecTaskCardPhaseSchema, OpenspecTaskCardStatusSchema, OpenspecTaskCardSchema, OpenspecStateSchema, SpecAnalyzeFindingSchema, SpecAnalyzeReportSchema, WorkflowCommandSchema, CcepOutputFormatSchema, CommandEnvelopeSchema, WorkflowPhaseSchema, WorkflowRiskRuleSchema, WorkflowProfileSchema, ExecutionContextSchema, PlannerOutputSchema, AgentArtifactSchema, AgentOutputSchema, ImplementerTestsSchema, ImplementerOutputSchema, ReviewAxisSchema, ReviewFindingSchema, ReviewerOutputSchema, TechnicalPlanOutputSchema, ScorecardVerdictSchema, ScorecardCriterionIdSchema, ScorecardCriterionSchema, ScorecardRecordSchema, TaskOutcomeSourceSchema, TaskOutcomeStatusSchema, TaskOutcomeSchema, HarnessComponentIdSchema, HarnessComponentLayerSchema, HarnessToggleKindSchema, HarnessCatalogEntrySchema, HarnessCatalogSchema, HarnessOverlaySchema, HarnessExperimentSchema, HarnessSuiteTaskSchema, HarnessSuiteSchema, EvaluationIndexSchema, ExecutionProfileNameSchema, ExecutionProfileSchema, SkillsRegistrySchema;
11442
+ var CouncilAgentSpecSchema, CouncilSpecSchema, ProjectProfileSchema, CompileCheckConfigSchema, LoopConfigSchema, CodeConductorConfigSchema, RunnerTargetSchema, InstallStrategySchema, ManifestEntrySchema, InstallManifestSchema, ToolProviderNamesSchema, PermissionProviderNamesSchema, ModelConfigSchema, SkillFrontmatterSchema, CommandFrontmatterSchema, TargetCapabilitiesSchema, ContractTargetSchema, ContractFormatSchema, AgentContractSchema, CouncilFindingSchema, CouncilVerdictInputSchema, ConsensusConfigSchema, CouncilVerdictSchema, ClaudeAgentFileSchema, OpenCodeAgentFileSchema, SentryStackFrameSchema, SentryWebhookSchema, MemoryPointerSchema, MemoryIndexSchema, GoalTaskSchema, GoalGraphSchema, ConfidenceLevelSchema, ProductNodeTypeSchema, GraphRelationSchema, KnowledgeEntitySchema, DecisionSchema, EvidenceSchema, CanonicalTaskCardStatusSchema, CanonicalTaskCardSchema, ProductGraphNodeSchema, ProductGraphEdgeSchema, ProductGraphSchema, ProductMetaSchema, ProductEventTypeSchema, ProductEventSchema, OperationalStateSchema, StrategicMemorySchema, ImpactReportSchema, BusinessReviewOutputSchema, VerificationReportSchema, BacklogStatusSchema, BacklogTypeSchema, BacklogPrioritySchema, BacklogGlobalSchema, BacklogItemSchema, BacklogDocumentSchema, OpenspecTaskCardPhaseSchema, OpenspecTaskCardStatusSchema, OpenspecTaskCardSchema, OpenspecStateSchema, SpecAnalyzeFindingSchema, SpecAnalyzeReportSchema, WorkflowCommandSchema, CcepOutputFormatSchema, CommandEnvelopeSchema, WorkflowPhaseSchema, WorkflowRiskRuleSchema, WorkflowProfileSchema, ExecutionContextSchema, PlannerOutputSchema, AgentArtifactSchema, AgentOutputSchema, ImplementerTestsSchema, ImplementerOutputSchema, ReviewAxisSchema, ReviewFindingSchema, ReviewerOutputSchema, TechnicalPlanOutputSchema, ScorecardVerdictSchema, ScorecardCriterionIdSchema, ScorecardCriterionSchema, ScorecardRecordSchema, TaskOutcomeSourceSchema, TaskOutcomeStatusSchema, DeliveryRouteSchema, TokenUsageSchema, DeliveryTelemetrySchema, DeliveryLedgerTaskSchema, DeliveryLedgerSchema, DeliveryLedgerRequestSchema, TaskOutcomeSchema, HarnessComponentIdSchema, HarnessComponentLayerSchema, HarnessToggleKindSchema, HarnessCatalogEntrySchema, HarnessCatalogSchema, HarnessOverlaySchema, HarnessExperimentSchema, HarnessSuiteTaskSchema, HarnessSuiteSchema, EvaluationIndexSchema, ExecutionProfileNameSchema, ExecutionProfileSchema, SkillsRegistrySchema;
11405
11443
  var init_schemas = __esm(() => {
11406
11444
  init_zod();
11407
11445
  init_runner_target();
@@ -11566,7 +11604,8 @@ var init_schemas = __esm(() => {
11566
11604
  complianceVeto: exports_external.boolean().optional(),
11567
11605
  confidence: exports_external.number().min(0).max(1),
11568
11606
  findings: exports_external.array(CouncilFindingSchema),
11569
- summary: exports_external.string()
11607
+ summary: exports_external.string(),
11608
+ candidateHash: exports_external.string().min(1).optional()
11570
11609
  });
11571
11610
  ConsensusConfigSchema = exports_external.object({
11572
11611
  algorithm: exports_external.enum(["majority", "unanimous"]),
@@ -11574,7 +11613,8 @@ var init_schemas = __esm(() => {
11574
11613
  allowComplianceVeto: exports_external.boolean().optional(),
11575
11614
  expectedAgentIds: exports_external.array(exports_external.string().min(1).refine((id) => id.trim().length > 0)).min(1).refine((ids) => new Set(ids.map((id) => id.trim().toLowerCase())).size === ids.length).optional(),
11576
11615
  quorum: exports_external.number().int().positive().optional(),
11577
- criticalFindingsPolicy: exports_external.enum(["escalate", "reject", "ignore"]).optional()
11616
+ criticalFindingsPolicy: exports_external.enum(["escalate", "reject", "ignore"]).optional(),
11617
+ candidateHash: exports_external.string().min(1).optional()
11578
11618
  }).refine((config) => config.algorithm !== "unanimous" || config.expectedAgentIds !== undefined, {
11579
11619
  message: "unanimous consensus requires a non-empty expectedAgentIds roster",
11580
11620
  path: ["expectedAgentIds"]
@@ -11951,7 +11991,8 @@ var init_schemas = __esm(() => {
11951
11991
  "prototype",
11952
11992
  "handoff",
11953
11993
  "clarify",
11954
- "security"
11994
+ "security",
11995
+ "odd"
11955
11996
  ]);
11956
11997
  CcepOutputFormatSchema = exports_external.enum(["taskcard", "plan", "verdict"]);
11957
11998
  CommandEnvelopeSchema = exports_external.object({
@@ -12167,6 +12208,46 @@ var init_schemas = __esm(() => {
12167
12208
  "revise",
12168
12209
  "reject"
12169
12210
  ]);
12211
+ DeliveryRouteSchema = exports_external.enum(["read-only", "small", "tracked", "openspec"]);
12212
+ TokenUsageSchema = exports_external.union([
12213
+ exports_external.object({
12214
+ status: exports_external.literal("known"),
12215
+ total: exports_external.number().nonnegative()
12216
+ }),
12217
+ exports_external.object({ status: exports_external.literal("unknown") })
12218
+ ]);
12219
+ DeliveryTelemetrySchema = exports_external.object({
12220
+ route: DeliveryRouteSchema,
12221
+ contextBytes: exports_external.number().int().nonnegative().optional(),
12222
+ handoffs: exports_external.number().int().nonnegative().optional(),
12223
+ checks: exports_external.array(exports_external.string().min(1)).optional(),
12224
+ tokenUsage: TokenUsageSchema
12225
+ });
12226
+ DeliveryLedgerTaskSchema = exports_external.object({
12227
+ id: exports_external.string().min(1),
12228
+ title: exports_external.string().min(1),
12229
+ status: exports_external.enum(["pending", "done", "blocked"])
12230
+ });
12231
+ DeliveryLedgerSchema = exports_external.object({
12232
+ version: exports_external.literal(1),
12233
+ id: exports_external.string().regex(/^[a-z0-9][a-z0-9-]{0,63}$/),
12234
+ taskCard: CanonicalTaskCardSchema,
12235
+ tasks: exports_external.array(DeliveryLedgerTaskSchema).min(1),
12236
+ evidence: exports_external.array(exports_external.string().min(1)),
12237
+ nextStep: exports_external.string().min(1),
12238
+ memoryTopicKey: exports_external.string().min(1),
12239
+ workspace: exports_external.record(exports_external.string(), exports_external.string()),
12240
+ createdAt: exports_external.string().datetime(),
12241
+ updatedAt: exports_external.string().datetime()
12242
+ });
12243
+ DeliveryLedgerRequestSchema = exports_external.object({
12244
+ id: exports_external.string().regex(/^[a-z0-9][a-z0-9-]{0,63}$/),
12245
+ authorized: exports_external.boolean(),
12246
+ route: DeliveryRouteSchema,
12247
+ taskCard: CanonicalTaskCardSchema,
12248
+ tasks: exports_external.array(DeliveryLedgerTaskSchema).min(1),
12249
+ nextStep: exports_external.string().min(1)
12250
+ });
12170
12251
  TaskOutcomeSchema = exports_external.object({
12171
12252
  id: exports_external.string(),
12172
12253
  taskId: exports_external.string(),
@@ -12190,7 +12271,8 @@ var init_schemas = __esm(() => {
12190
12271
  variantId: exports_external.string().optional(),
12191
12272
  suiteTaskId: exports_external.string().optional(),
12192
12273
  harnessFingerprint: exports_external.string().optional(),
12193
- disabledComponents: exports_external.array(exports_external.string()).optional()
12274
+ disabledComponents: exports_external.array(exports_external.string()).optional(),
12275
+ delivery: DeliveryTelemetrySchema.optional()
12194
12276
  });
12195
12277
  HarnessComponentIdSchema = exports_external.enum([
12196
12278
  "wayfinding",
@@ -12670,7 +12752,7 @@ var init_safety = __esm(() => {
12670
12752
  // src/core/filesystem/path-containment.ts
12671
12753
  import { constants as constants2 } from "node:fs";
12672
12754
  import { lstat, mkdir, open, realpath } from "node:fs/promises";
12673
- import { basename, dirname as dirname2, isAbsolute, join as join2, relative, resolve as resolve3, sep as sep2 } from "node:path";
12755
+ import { basename as basename2, dirname as dirname2, isAbsolute, join as join2, relative, resolve as resolve3, sep as sep2 } from "node:path";
12674
12756
  function isInside(root, target) {
12675
12757
  const rel = relative(root, target);
12676
12758
  return rel !== "" && rel !== ".." && !rel.startsWith(`..${sep2}`) && !isAbsolute(rel);
@@ -12745,7 +12827,7 @@ async function canonicalizeExistingPrefix(target) {
12745
12827
  if (parent === current) {
12746
12828
  throw error;
12747
12829
  }
12748
- pending.unshift(basename(current));
12830
+ pending.unshift(basename2(current));
12749
12831
  current = parent;
12750
12832
  }
12751
12833
  }
@@ -13031,8 +13113,8 @@ function mergeDeep(target, source) {
13031
13113
  }
13032
13114
  function extractAgentRole(filePath) {
13033
13115
  const parts = filePath.replace(/\\/g, "/").split("/");
13034
- const basename2 = parts[parts.length - 1];
13035
- const name = basename2.replace(/\.md$/, "");
13116
+ const basename3 = parts[parts.length - 1];
13117
+ const name = basename3.replace(/\.md$/, "");
13036
13118
  const knownRoles = [
13037
13119
  "architect",
13038
13120
  "implementer",
@@ -14282,7 +14364,7 @@ var init_agy_installer = __esm(() => {
14282
14364
 
14283
14365
  // src/core/presets/update-checker.ts
14284
14366
  import { stat as stat2, readFile as readFile7 } from "node:fs/promises";
14285
- import { resolve as resolve7, join as join5, basename as basename2, dirname as dirname4 } from "node:path";
14367
+ import { resolve as resolve7, join as join5, basename as basename3, dirname as dirname4 } from "node:path";
14286
14368
  import { homedir as homedir3 } from "node:os";
14287
14369
  function getTargetInstallationPath(target, basePath, isGlobal) {
14288
14370
  if (target === "agy") {
@@ -14399,7 +14481,7 @@ async function validateSkillFrontmatterFiles(basePath, isGlobal) {
14399
14481
  }
14400
14482
  const files = await resolveEntryFiles(resolvedEntry, PRESETS_DIR, targetBaseDir);
14401
14483
  for (const { dest } of files) {
14402
- if (basename2(dest) !== "SKILL.md")
14484
+ if (basename3(dest) !== "SKILL.md")
14403
14485
  continue;
14404
14486
  let content;
14405
14487
  try {
@@ -14412,7 +14494,7 @@ async function validateSkillFrontmatterFiles(basePath, isGlobal) {
14412
14494
  results.push({ path: dest, error: `${parsed.error.kind}: ${parsed.error.message}` });
14413
14495
  continue;
14414
14496
  }
14415
- const dir = basename2(dirname4(dest));
14497
+ const dir = basename3(dirname4(dest));
14416
14498
  const ident = skillIdentifier(parsed.frontmatter);
14417
14499
  if (ident !== dir) {
14418
14500
  results.push({
@@ -15387,6 +15469,25 @@ var init_profiles = __esm(() => {
15387
15469
  routing: { default: ["validate-backlog", "discover", "design", "analyze", "test", "implement", "review"] },
15388
15470
  confirmationGate: baseGate
15389
15471
  },
15472
+ odd: {
15473
+ id: "odd",
15474
+ version: 1,
15475
+ command: "odd",
15476
+ taskCard: {
15477
+ type: "feature",
15478
+ requiredFields: ["title", "type", "risk", "scope", "context", "acceptanceCriteria"]
15479
+ },
15480
+ phases: [
15481
+ { id: "wayfinding", agent: "repo-explorer", outputSchema: "agent-output" },
15482
+ { id: "intake", agent: "task-coach", outputSchema: "planner-output", stopGate: "confirmation" },
15483
+ { id: "ledger", agent: "orchestrator", type: "cli-gate" },
15484
+ { id: "test", agent: "tester", dependsOn: ["intake"] },
15485
+ { id: "implement", agent: "implementer", dependsOn: ["test"] },
15486
+ { id: "review", agent: "reviewer" }
15487
+ ],
15488
+ routing: { default: ["wayfinding", "intake", "ledger", "test", "implement", "review"] },
15489
+ confirmationGate: baseGate
15490
+ },
15390
15491
  backlog: {
15391
15492
  id: "backlog",
15392
15493
  version: 1,
@@ -16149,7 +16250,7 @@ __export(exports_init_command, {
16149
16250
  });
16150
16251
  import { access as access4, mkdir as mkdir5, readFile as readFile10, writeFile as writeFile4 } from "node:fs/promises";
16151
16252
  import { homedir as homedir6 } from "node:os";
16152
- import { basename as basename3, resolve as resolve11 } from "node:path";
16253
+ import { basename as basename4, resolve as resolve11 } from "node:path";
16153
16254
  async function initCommand(options) {
16154
16255
  const { projectRoot, dryRun, force, global: isGlobal, output, locale } = options;
16155
16256
  const baseDir = isGlobal ? homedir6() : projectRoot;
@@ -16170,7 +16271,7 @@ async function initCommand(options) {
16170
16271
  }
16171
16272
  const config = profile ? {
16172
16273
  project: {
16173
- name: basename3(projectRoot) || "unnamed-project",
16274
+ name: basename4(projectRoot) || "unnamed-project",
16174
16275
  profile: profile.runtimes[0] || "unknown"
16175
16276
  },
16176
16277
  defaults: {
@@ -16887,7 +16988,7 @@ __export(exports_install_command, {
16887
16988
  });
16888
16989
  import { readFile as readFile11 } from "node:fs/promises";
16889
16990
  import { homedir as homedir7 } from "node:os";
16890
- import { basename as basename4, dirname as dirname6, resolve as resolve12, sep as sep3 } from "node:path";
16991
+ import { basename as basename5, dirname as dirname6, resolve as resolve12, sep as sep3 } from "node:path";
16891
16992
  async function installCommand(options) {
16892
16993
  const { target, dryRun, force, global: isGlobal, output, projectRoot } = options;
16893
16994
  const baseDir = isGlobal ? homedir7() : projectRoot;
@@ -17026,12 +17127,12 @@ async function verifyRenderedFiles(manifest, baseDir, results) {
17026
17127
  if (leaked.length > 0) {
17027
17128
  warnings.push(`${r.dest}: unresolved placeholder(s) ${leaked.join(", ")}`);
17028
17129
  }
17029
- if (basename4(r.dest) === "SKILL.md") {
17130
+ if (basename5(r.dest) === "SKILL.md") {
17030
17131
  const parsed = parseSkillFrontmatter(content);
17031
17132
  if (!parsed.ok) {
17032
17133
  warnings.push(`${r.dest}: ${parsed.error.kind} — ${parsed.error.message}`);
17033
17134
  } else {
17034
- const dir = basename4(dirname6(r.dest));
17135
+ const dir = basename5(dirname6(r.dest));
17035
17136
  const ident = skillIdentifier(parsed.frontmatter);
17036
17137
  if (ident !== dir) {
17037
17138
  warnings.push(`${r.dest}: identifier "${ident}" does not match its directory "${dir}"`);
@@ -17274,6 +17375,7 @@ __export(exports_status_command, {
17274
17375
  });
17275
17376
  import { resolve as resolve13 } from "node:path";
17276
17377
  async function statusCommand(options) {
17378
+ const bin = resolveCliBin();
17277
17379
  const [configResult, state] = await Promise.all([
17278
17380
  loadConfig(options.projectRoot),
17279
17381
  readInstallationState(options.projectRoot)
@@ -17316,7 +17418,7 @@ async function statusCommand(options) {
17316
17418
  ...modifiedFiles.length ? [` locally modified managed files: ${modifiedFiles.length}`] : [],
17317
17419
  ...data.updates?.conflicts.length ? [` conflicts: ${data.updates.conflicts.join(", ")}`] : [],
17318
17420
  "",
17319
- "Run `cc doctor` for diagnostics."
17421
+ `Run \`${bin} doctor\` for diagnostics.`
17320
17422
  ].join(`
17321
17423
  `);
17322
17424
  return { code: 0, data: { ...data, output } };
@@ -17326,6 +17428,7 @@ var init_status_command = __esm(() => {
17326
17428
  init_installation_state();
17327
17429
  init_update_checker();
17328
17430
  init_runner_target();
17431
+ init_cli_bin();
17329
17432
  });
17330
17433
 
17331
17434
  // src/commands/detect.command.ts
@@ -20118,7 +20221,7 @@ async function loadGraph(projectRoot) {
20118
20221
  return ok(ProductGraphSchema.parse(JSON.parse(raw)));
20119
20222
  } catch (e) {
20120
20223
  if (e.code === "ENOENT") {
20121
- return err(new Error("Product graph not found. Run `cc ingest` first."));
20224
+ return err(new Error(`Product graph not found. Run \`${resolveCliBin()} ingest\` first.`));
20122
20225
  }
20123
20226
  return err(e instanceof Error ? e : new Error(String(e)));
20124
20227
  }
@@ -20212,6 +20315,7 @@ function getNeighbors(graph, nodeId, relation) {
20212
20315
  }
20213
20316
  var init_graph_store = __esm(() => {
20214
20317
  init_schemas();
20318
+ init_cli_bin();
20215
20319
  init_paths();
20216
20320
  });
20217
20321
 
@@ -20740,9 +20844,9 @@ import { join as join15 } from "node:path";
20740
20844
  async function parseAdrFile(filePath) {
20741
20845
  try {
20742
20846
  const content = await readFile19(filePath, "utf-8");
20743
- const basename5 = filePath.split("/").pop() ?? "";
20744
- const idMatch = basename5.match(/adr-(\d+)/i);
20745
- const id = idMatch ? `adr-${idMatch[1]}` : slugify(basename5);
20847
+ const basename6 = filePath.split("/").pop() ?? "";
20848
+ const idMatch = basename6.match(/adr-(\d+)/i);
20849
+ const id = idMatch ? `adr-${idMatch[1]}` : slugify(basename6);
20746
20850
  const titleMatch = content.match(/^#\s+ADR-\d+:\s*(.+)$/m);
20747
20851
  const statusMatch = content.match(/\*\*Status:\*\*\s*(\w+)/i);
20748
20852
  const contextSection = extractSection(content, "Context");
@@ -20752,7 +20856,7 @@ async function parseAdrFile(filePath) {
20752
20856
  `).filter((l) => l.trim().startsWith("-") || l.trim().startsWith("*")).map((l) => l.replace(/^[\s*-]+/, "").trim()).filter(Boolean);
20753
20857
  return {
20754
20858
  id,
20755
- title: titleMatch?.[1]?.trim() ?? basename5,
20859
+ title: titleMatch?.[1]?.trim() ?? basename6,
20756
20860
  status: statusMatch?.[1]?.toLowerCase() ?? "unknown",
20757
20861
  context: contextSection.trim(),
20758
20862
  decision: decisionSection.trim(),
@@ -21452,7 +21556,10 @@ async function listScorecards(projectRoot, filter = {}) {
21452
21556
  }
21453
21557
  async function hasPassingScorecard(projectRoot, backlogId) {
21454
21558
  const listed = await listScorecards(projectRoot, { backlogId, verdict: "PASS" });
21455
- return listed.success && listed.data.length > 0;
21559
+ if (listed.success && listed.data.length > 0)
21560
+ return true;
21561
+ const outcomes = await listOutcomes(projectRoot, { backlogId, source: "review" });
21562
+ return outcomes.success && outcomes.data.some((outcome) => outcome.verdict === "PASS");
21456
21563
  }
21457
21564
  async function loadScorecard(projectRoot, id) {
21458
21565
  try {
@@ -21484,7 +21591,7 @@ function aggregateOutcomes(outcomes) {
21484
21591
  agentScoreCounts[o.agent] = (agentScoreCounts[o.agent] ?? 0) + 1;
21485
21592
  }
21486
21593
  if (!byModel[o.model])
21487
- byModel[o.model] = { count: 0, avgScore: 0 };
21594
+ byModel[o.model] = { count: 0, avgScore: 0, knownTokenMeasurements: 0 };
21488
21595
  byModel[o.model].count++;
21489
21596
  if (o.weightedScore !== undefined) {
21490
21597
  byModel[o.model].avgScore += o.weightedScore;
@@ -21494,10 +21601,11 @@ function aggregateOutcomes(outcomes) {
21494
21601
  byModel[o.model].avgCost = (byModel[o.model].avgCost ?? 0) + o.costUsd;
21495
21602
  modelCostCounts[o.model] = (modelCostCounts[o.model] ?? 0) + 1;
21496
21603
  }
21497
- if (o.tokensIn !== undefined || o.tokensOut !== undefined) {
21498
- const tokens = (o.tokensIn ?? 0) + (o.tokensOut ?? 0);
21499
- byModel[o.model].avgTokens = (byModel[o.model].avgTokens ?? 0) + tokens;
21604
+ const reportedTokens = o.delivery?.tokenUsage.status === "known" ? o.delivery.tokenUsage.total : o.tokensIn !== undefined || o.tokensOut !== undefined ? (o.tokensIn ?? 0) + (o.tokensOut ?? 0) : undefined;
21605
+ if (reportedTokens !== undefined) {
21606
+ byModel[o.model].avgTokens = (byModel[o.model].avgTokens ?? 0) + reportedTokens;
21500
21607
  modelTokenCounts[o.model] = (modelTokenCounts[o.model] ?? 0) + 1;
21608
+ byModel[o.model].knownTokenMeasurements++;
21501
21609
  }
21502
21610
  if (o.variantId) {
21503
21611
  if (!byVariant[o.variantId])
@@ -22147,11 +22255,140 @@ var init_compile_checker = __esm(() => {
22147
22255
  ];
22148
22256
  });
22149
22257
 
22258
+ // src/core/verification/rdd-receipt.ts
22259
+ var exports_rdd_receipt = {};
22260
+ __export(exports_rdd_receipt, {
22261
+ captureReceipt: () => captureReceipt,
22262
+ collectReceiptPaths: () => collectReceiptPaths,
22263
+ isRddReceipt: () => isRddReceipt,
22264
+ verifyReceipt: () => verifyReceipt
22265
+ });
22266
+ import { createHash as createHash4 } from "node:crypto";
22267
+ import { readdir as readdir7, readFile as readFile27 } from "node:fs/promises";
22268
+ import { join as join18, relative as relative7, resolve as resolve26, sep as sep5 } from "node:path";
22269
+ function sha2562(content) {
22270
+ return createHash4("sha256").update(content).digest("hex");
22271
+ }
22272
+ function canonicalPath(projectRoot, input) {
22273
+ const root = resolve26(projectRoot);
22274
+ const absolute = resolve26(root, input);
22275
+ if (absolute !== root && !absolute.startsWith(`${root}${sep5}`)) {
22276
+ throw new Error(`RDD receipt path "${input}" is outside the project root`);
22277
+ }
22278
+ const normalized = relative7(root, absolute);
22279
+ if (!normalized || normalized === ".") {
22280
+ throw new Error("RDD receipts require file paths, not the project root");
22281
+ }
22282
+ return { absolute, relative: normalized.split(sep5).join("/") };
22283
+ }
22284
+ async function fingerprint(projectRoot, paths) {
22285
+ const deduplicated = new Map;
22286
+ for (const path of paths) {
22287
+ const canonical = canonicalPath(projectRoot, path);
22288
+ deduplicated.set(canonical.relative, canonical.absolute);
22289
+ }
22290
+ const result = [];
22291
+ for (const [path, absolute] of [...deduplicated.entries()].sort(([left], [right]) => left.localeCompare(right))) {
22292
+ result.push({ path, hash: sha2562(await readFile27(absolute)) });
22293
+ }
22294
+ return result;
22295
+ }
22296
+ function manifestHash(paths) {
22297
+ return sha2562(paths.map((entry) => `${entry.path}\x00${entry.hash}`).join(`
22298
+ `));
22299
+ }
22300
+ function isRddReceipt(value) {
22301
+ if (!value || typeof value !== "object")
22302
+ return false;
22303
+ const receipt = value;
22304
+ return receipt.version === 1 && typeof receipt.taskId === "string" && typeof receipt.phase === "string" && Array.isArray(receipt.paths) && receipt.paths.every((entry) => Boolean(entry) && typeof entry.path === "string" && typeof entry.hash === "string") && (receipt.coverage === "paths" || receipt.coverage === "project") && typeof receipt.manifestHash === "string" && (receipt.outcome === "passed" || receipt.outcome === "failed") && typeof receipt.capturedAt === "string";
22305
+ }
22306
+ async function captureReceipt(projectRoot, input) {
22307
+ if (!input.taskId.trim())
22308
+ throw new Error("RDD receipts require a task id");
22309
+ if (input.paths.length === 0 && input.coverage !== "project") {
22310
+ throw new Error("RDD receipts require at least one protected path");
22311
+ }
22312
+ const paths = await fingerprint(projectRoot, input.paths);
22313
+ return {
22314
+ version: 1,
22315
+ taskId: input.taskId,
22316
+ phase: input.phase,
22317
+ paths,
22318
+ coverage: input.coverage ?? "paths",
22319
+ manifestHash: manifestHash(paths),
22320
+ command: input.command,
22321
+ outcome: input.outcome,
22322
+ capturedAt: new Date().toISOString()
22323
+ };
22324
+ }
22325
+ async function collectReceiptPaths(projectRoot) {
22326
+ const root = resolve26(projectRoot);
22327
+ const paths = [];
22328
+ async function visit2(current) {
22329
+ const entries = await readdir7(current, { withFileTypes: true });
22330
+ for (const entry of entries) {
22331
+ if (entry.isDirectory()) {
22332
+ if (!EXCLUDED_DIRECTORIES.has(entry.name))
22333
+ await visit2(join18(current, entry.name));
22334
+ continue;
22335
+ }
22336
+ if (entry.isFile())
22337
+ paths.push(relative7(root, join18(current, entry.name)).split(sep5).join("/"));
22338
+ }
22339
+ }
22340
+ await visit2(root);
22341
+ return paths.sort();
22342
+ }
22343
+ async function verifyReceipt(projectRoot, receipt) {
22344
+ const expected = new Map(receipt.paths.map((entry) => [entry.path, entry.hash]));
22345
+ const changedPaths = [];
22346
+ const current = [];
22347
+ const pathsToCheck = receipt.coverage === "project" ? await collectReceiptPaths(projectRoot) : receipt.paths.map((entry) => entry.path);
22348
+ const currentByPath = new Map;
22349
+ for (const path of pathsToCheck) {
22350
+ try {
22351
+ const canonical = canonicalPath(projectRoot, path);
22352
+ const hash = sha2562(await readFile27(canonical.absolute));
22353
+ const currentEntry = { path: canonical.relative, hash };
22354
+ current.push(currentEntry);
22355
+ currentByPath.set(currentEntry.path, currentEntry);
22356
+ if (hash !== expected.get(currentEntry.path))
22357
+ changedPaths.push(currentEntry.path);
22358
+ } catch {
22359
+ changedPaths.push(path);
22360
+ }
22361
+ }
22362
+ for (const path of expected.keys()) {
22363
+ if (!currentByPath.has(path) && !changedPaths.includes(path))
22364
+ changedPaths.push(path);
22365
+ }
22366
+ changedPaths.sort();
22367
+ const actualHash = manifestHash(current.sort((left, right) => left.path.localeCompare(right.path)));
22368
+ return {
22369
+ valid: changedPaths.length === 0 && actualHash === receipt.manifestHash,
22370
+ expectedHash: receipt.manifestHash,
22371
+ actualHash,
22372
+ changedPaths
22373
+ };
22374
+ }
22375
+ var EXCLUDED_DIRECTORIES;
22376
+ var init_rdd_receipt = __esm(() => {
22377
+ EXCLUDED_DIRECTORIES = new Set([
22378
+ ".git",
22379
+ ".codeconductor",
22380
+ "node_modules",
22381
+ "dist",
22382
+ "coverage",
22383
+ "graphify-out"
22384
+ ]);
22385
+ });
22386
+
22150
22387
  // src/core/verification/verification-runner.ts
22151
22388
  import { existsSync as existsSync3 } from "node:fs";
22152
- import { readFile as readFile27 } from "node:fs/promises";
22153
- import { dirname as dirname10, join as join18, resolve as resolve26 } from "node:path";
22154
- import { mkdir as mkdir18, readdir as readdir7, writeFile as writeFile18 } from "node:fs/promises";
22389
+ import { readFile as readFile28 } from "node:fs/promises";
22390
+ import { dirname as dirname10, join as join19, resolve as resolve27 } from "node:path";
22391
+ import { mkdir as mkdir18, readdir as readdir8, writeFile as writeFile18 } from "node:fs/promises";
22155
22392
  function isPassingEvidence(ev) {
22156
22393
  switch (ev.type) {
22157
22394
  case "verification":
@@ -22168,9 +22405,17 @@ function isPassingEvidence(ev) {
22168
22405
  return false;
22169
22406
  }
22170
22407
  }
22408
+ async function isCurrentPassingEvidence(projectRoot, ev) {
22409
+ if (!isPassingEvidence(ev))
22410
+ return false;
22411
+ const receipt = ev.data?.rddReceipt;
22412
+ if (!isRddReceipt(receipt))
22413
+ return false;
22414
+ return (await verifyReceipt(projectRoot, receipt)).valid;
22415
+ }
22171
22416
  function evidenceFilePath(evDir, id) {
22172
- const path = resolve26(evDir, `${id.replace(/[^A-Za-z0-9_-]/g, "_")}.json`);
22173
- if (dirname10(path) !== resolve26(evDir)) {
22417
+ const path = resolve27(evDir, `${id.replace(/[^A-Za-z0-9_-]/g, "_")}.json`);
22418
+ if (dirname10(path) !== resolve27(evDir)) {
22174
22419
  return err(new Error(`Refusing to write evidence for "${id}" outside ${evDir}`));
22175
22420
  }
22176
22421
  return ok(path);
@@ -22196,7 +22441,7 @@ async function collectTaskEvidence(projectRoot, taskId) {
22196
22441
  return ok({ records, invalid });
22197
22442
  let files;
22198
22443
  try {
22199
- files = await readdir7(evDir);
22444
+ files = await readdir8(evDir);
22200
22445
  } catch (e) {
22201
22446
  return err(e instanceof Error ? e : new Error(String(e)));
22202
22447
  }
@@ -22204,7 +22449,7 @@ async function collectTaskEvidence(projectRoot, taskId) {
22204
22449
  if (!file.endsWith(".json"))
22205
22450
  continue;
22206
22451
  try {
22207
- const raw = await readFile27(join18(evDir, file), "utf-8");
22452
+ const raw = await readFile28(join19(evDir, file), "utf-8");
22208
22453
  const ev = EvidenceSchema.parse(JSON.parse(raw));
22209
22454
  if (ev.relatedTask === taskId)
22210
22455
  records.push(ev);
@@ -22225,7 +22470,7 @@ async function validateEvidenceIds(projectRoot, taskId, evidenceIds) {
22225
22470
  if (!record) {
22226
22471
  return err(new Error(`Evidence "${id}" is not a record of task ${taskId}`));
22227
22472
  }
22228
- if (!isPassingEvidence(record)) {
22473
+ if (!await isCurrentPassingEvidence(projectRoot, record)) {
22229
22474
  return err(new Error(`Evidence "${id}" does not record a passing result`));
22230
22475
  }
22231
22476
  if (record.type === "verification")
@@ -22306,7 +22551,12 @@ async function runVerification(projectRoot, taskId, goal, options) {
22306
22551
  passed: collected.data.invalid === 0,
22307
22552
  message: collected.data.invalid === 0 ? "All evidence records are readable" : `${collected.data.invalid} unreadable evidence record(s)`
22308
22553
  });
22309
- const supporting = collected.data.records.filter((ev) => ev.type !== "verification" && isPassingEvidence(ev));
22554
+ const supporting = [];
22555
+ for (const candidate of collected.data.records) {
22556
+ if (candidate.type !== "verification" && await isCurrentPassingEvidence(projectRoot, candidate)) {
22557
+ supporting.push(candidate);
22558
+ }
22559
+ }
22310
22560
  evidenceIds.push(...supporting.map((ev) => ev.id));
22311
22561
  checks.push({
22312
22562
  name: "evidence_present",
@@ -22314,6 +22564,13 @@ async function runVerification(projectRoot, taskId, goal, options) {
22314
22564
  message: supporting.length > 0 ? `${supporting.length} passing evidence record(s) for task` : task.risk === "low" ? "Low risk task — evidence optional" : "No passing evidence records found for task"
22315
22565
  });
22316
22566
  const passed = checks.every((c) => c.passed);
22567
+ const receipt = await captureReceipt(projectRoot, {
22568
+ taskId,
22569
+ phase: "verification",
22570
+ paths: await collectReceiptPaths(projectRoot),
22571
+ outcome: passed ? "passed" : "failed",
22572
+ coverage: "project"
22573
+ });
22317
22574
  const evidence = {
22318
22575
  id: `ev-verify-${taskId}-${Date.now()}`,
22319
22576
  source: "cc verify",
@@ -22322,7 +22579,7 @@ async function runVerification(projectRoot, taskId, goal, options) {
22322
22579
  relatedTask: taskId,
22323
22580
  confidence: passed ? 0.9 : 0.3,
22324
22581
  summary: passed ? "Verification passed" : "Verification failed",
22325
- data: { passed, checks }
22582
+ data: { passed, checks, rddReceipt: receipt }
22326
22583
  };
22327
22584
  const persisted = await persistEvidence(projectRoot, evidence);
22328
22585
  if (!persisted.success)
@@ -22345,19 +22602,25 @@ async function gateTaskCompletion(projectRoot, taskId, evidenceRequired, evidenc
22345
22602
  if (collected.data.invalid > 0)
22346
22603
  return ok(false);
22347
22604
  const cited = evidenceIds ? new Set(evidenceIds) : undefined;
22348
- const hasPassing = (type) => collected.data.records.some((ev) => (!cited || cited.has(ev.id)) && ev.type === type && isPassingEvidence(ev));
22605
+ const hasPassing = async (type) => {
22606
+ for (const evidence of collected.data.records) {
22607
+ if ((!cited || cited.has(evidence.id)) && evidence.type === type && await isCurrentPassingEvidence(projectRoot, evidence))
22608
+ return true;
22609
+ }
22610
+ return false;
22611
+ };
22349
22612
  for (const req of evidenceRequired) {
22350
22613
  switch (req) {
22351
22614
  case "acceptance_criteria_met":
22352
- if (!hasPassing("verification"))
22615
+ if (!await hasPassing("verification"))
22353
22616
  return ok(false);
22354
22617
  break;
22355
22618
  case "tests_passed":
22356
- if (!hasPassing("test"))
22619
+ if (!await hasPassing("test"))
22357
22620
  return ok(false);
22358
22621
  break;
22359
22622
  case "review_approved":
22360
- if (!hasPassing("review"))
22623
+ if (!await hasPassing("review"))
22361
22624
  return ok(false);
22362
22625
  break;
22363
22626
  default:
@@ -22366,11 +22629,66 @@ async function gateTaskCompletion(projectRoot, taskId, evidenceRequired, evidenc
22366
22629
  }
22367
22630
  return ok(true);
22368
22631
  }
22369
- async function hasTddRunnerEvidence(projectRoot, taskId) {
22632
+ async function loadTddSuiteEvidence(projectRoot, taskId, evidenceId) {
22633
+ const evDir = evidenceDir(projectRoot);
22634
+ const path = evidenceFilePath(evDir, evidenceId);
22635
+ if (!path.success)
22636
+ return path;
22637
+ let raw;
22638
+ try {
22639
+ raw = await readFile28(path.data, "utf-8");
22640
+ } catch (e) {
22641
+ return err(e instanceof Error ? e : new Error(String(e)));
22642
+ }
22643
+ let ev;
22644
+ try {
22645
+ ev = EvidenceSchema.parse(JSON.parse(raw));
22646
+ } catch {
22647
+ return err(new Error(`Evidence "${evidenceId}" is not valid TDD evidence`));
22648
+ }
22649
+ if (ev.relatedTask !== taskId) {
22650
+ return err(new Error(`Evidence "${evidenceId}" is not a record of task ${taskId}`));
22651
+ }
22652
+ if (ev.type !== "tdd" || ev.source !== TDD_EVIDENCE_SOURCE) {
22653
+ return err(new Error(`Evidence "${evidenceId}" was not captured by the verification runner`));
22654
+ }
22655
+ const capturedBy = ev.data?.capturedBy;
22656
+ const suiteFailed = ev.data?.suiteFailed;
22657
+ const suitePassed = ev.data?.suitePassed;
22658
+ if (capturedBy !== TDD_CAPTURED_BY || typeof suiteFailed !== "boolean" || typeof suitePassed !== "boolean") {
22659
+ return err(new Error(`Evidence "${evidenceId}" was not captured by the verification runner`));
22660
+ }
22661
+ const receipt = ev.data?.rddReceipt;
22662
+ if (!isRddReceipt(receipt)) {
22663
+ return err(new Error(`Evidence "${evidenceId}" has no valid RDD receipt`));
22664
+ }
22665
+ if (receipt.taskId !== taskId) {
22666
+ return err(new Error(`Evidence "${evidenceId}" receipt belongs to another task`));
22667
+ }
22668
+ const verified = await verifyReceipt(projectRoot, receipt);
22669
+ if (!verified.valid) {
22670
+ return err(new Error(`Evidence "${evidenceId}" RDD receipt is stale: ${verified.changedPaths.join(", ")}`));
22671
+ }
22672
+ return ok({ capturedBy, suiteFailed, suitePassed, receipt });
22673
+ }
22674
+ async function hasTddRunnerEvidence(projectRoot, taskId, expectedPhase) {
22370
22675
  const collected = await collectTaskEvidence(projectRoot, taskId);
22371
22676
  if (!collected.success)
22372
22677
  return false;
22373
- return collected.data.records.some((ev) => ev.type === "tdd" && ev.source === TDD_EVIDENCE_SOURCE && ev.data?.capturedBy === TDD_CAPTURED_BY);
22678
+ for (const ev of collected.data.records) {
22679
+ if (ev.type !== "tdd" || ev.source !== TDD_EVIDENCE_SOURCE || ev.data?.capturedBy !== TDD_CAPTURED_BY) {
22680
+ continue;
22681
+ }
22682
+ const loaded = await loadTddSuiteEvidence(projectRoot, taskId, ev.id);
22683
+ if (!loaded.success)
22684
+ continue;
22685
+ if (expectedPhase === "red" && (!loaded.data.suiteFailed || loaded.data.suitePassed))
22686
+ continue;
22687
+ if (expectedPhase === "green" && (!loaded.data.suitePassed || loaded.data.suiteFailed))
22688
+ continue;
22689
+ return true;
22690
+ }
22691
+ return false;
22374
22692
  }
22375
22693
  var TDD_EVIDENCE_SOURCE = "cc verify", TDD_CAPTURED_BY = "verification-runner";
22376
22694
  var init_verification_runner = __esm(() => {
@@ -22379,6 +22697,7 @@ var init_verification_runner = __esm(() => {
22379
22697
  init_compile_checker();
22380
22698
  init_paths();
22381
22699
  init_episodic_store();
22700
+ init_rdd_receipt();
22382
22701
  });
22383
22702
 
22384
22703
  // src/core/orchestrator/runtime-orchestrator.ts
@@ -23230,7 +23549,7 @@ async function handleRun(projectRoot, output, taskId, complete, allowCompileChec
23230
23549
  data: {
23231
23550
  success: false,
23232
23551
  command: "orchestrate",
23233
- errors: ["Verification failed. Run `cc verify --task " + taskId + "`"]
23552
+ errors: ["Verification failed. Run `" + resolveCliBin() + " verify --task " + taskId + "`"]
23234
23553
  }
23235
23554
  };
23236
23555
  }
@@ -23294,6 +23613,7 @@ var init_orchestrate_command = __esm(() => {
23294
23613
  init_product_planner();
23295
23614
  init_graph_store();
23296
23615
  init_loop_engine();
23616
+ init_cli_bin();
23297
23617
  });
23298
23618
 
23299
23619
  // src/core/impact/impact-engine.ts
@@ -23500,6 +23820,163 @@ var init_verify_command = __esm(() => {
23500
23820
  init_verification_runner();
23501
23821
  });
23502
23822
 
23823
+ // src/commands/rdd.command.ts
23824
+ var exports_rdd_command = {};
23825
+ __export(exports_rdd_command, {
23826
+ rddCommand: () => rddCommand,
23827
+ rddStatus: () => rddStatus
23828
+ });
23829
+ import { execFile as execFile3 } from "node:child_process";
23830
+ import { existsSync as existsSync4 } from "node:fs";
23831
+ import { mkdir as mkdir19, readFile as readFile29, readdir as readdir9, rename as rename3, writeFile as writeFile19, chmod } from "node:fs/promises";
23832
+ import { dirname as dirname11, resolve as resolve28 } from "node:path";
23833
+ import { promisify as promisify3 } from "node:util";
23834
+ function receiptPath(projectRoot, id) {
23835
+ const directory = resolve28(evidenceDir(projectRoot));
23836
+ const path = resolve28(directory, `${id.replace(/[^A-Za-z0-9_-]/g, "_")}.json`);
23837
+ if (dirname11(path) !== directory)
23838
+ throw new Error(`Invalid RDD receipt id: ${id}`);
23839
+ return path;
23840
+ }
23841
+ async function loadReceipt(projectRoot, id) {
23842
+ const raw = await readFile29(receiptPath(projectRoot, id), "utf-8");
23843
+ const evidence = EvidenceSchema.parse(JSON.parse(raw));
23844
+ if (evidence.type !== "rdd")
23845
+ throw new Error(`Evidence "${id}" is not an RDD receipt`);
23846
+ return { evidence, receipt: assertReceipt(evidence.data?.rddReceipt) };
23847
+ }
23848
+ function assertReceipt(value) {
23849
+ if (!isRddReceipt(value))
23850
+ throw new Error("RDD receipt payload is invalid");
23851
+ return value;
23852
+ }
23853
+ async function rddStatus(projectRoot, taskId) {
23854
+ const directory = evidenceDir(projectRoot);
23855
+ if (!existsSync4(directory))
23856
+ return [];
23857
+ const receipts = [];
23858
+ for (const file of await readdir9(directory)) {
23859
+ if (!file.endsWith(".json"))
23860
+ continue;
23861
+ try {
23862
+ const id = file.slice(0, -".json".length);
23863
+ const { evidence, receipt } = await loadReceipt(projectRoot, id);
23864
+ if (taskId && evidence.relatedTask !== taskId)
23865
+ continue;
23866
+ const verification = await verifyReceipt(projectRoot, receipt);
23867
+ receipts.push({
23868
+ id: evidence.id,
23869
+ taskId: evidence.relatedTask,
23870
+ phase: receipt.phase,
23871
+ timestamp: evidence.timestamp,
23872
+ valid: verification.valid,
23873
+ changedPaths: verification.changedPaths
23874
+ });
23875
+ } catch {}
23876
+ }
23877
+ return receipts.sort((left, right) => right.timestamp.localeCompare(left.timestamp));
23878
+ }
23879
+ async function installHooks(projectRoot) {
23880
+ const { stdout } = await execFileAsync3("git", ["rev-parse", "--git-path", "hooks"], {
23881
+ cwd: projectRoot,
23882
+ encoding: "utf8"
23883
+ });
23884
+ const hooksDir = resolve28(projectRoot, stdout.trim());
23885
+ await mkdir19(hooksDir, { recursive: true });
23886
+ const installed = [];
23887
+ const skipped = [];
23888
+ for (const hook of ["pre-commit", "pre-push"]) {
23889
+ const path = resolve28(hooksDir, hook);
23890
+ const backup = resolve28(hooksDir, `${hook}.rdd-original`);
23891
+ const marker = "# codeconductor-rdd-hook";
23892
+ if (existsSync4(path)) {
23893
+ const existing = await readFile29(path, "utf8");
23894
+ if (existing.includes(marker)) {
23895
+ skipped.push(hook);
23896
+ continue;
23897
+ }
23898
+ if (existsSync4(backup)) {
23899
+ throw new Error(`Cannot preserve ${hook}: ${backup} already exists`);
23900
+ }
23901
+ await rename3(path, backup);
23902
+ }
23903
+ const script = `#!/bin/sh
23904
+ ${marker}
23905
+ set -e
23906
+ HOOK_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
23907
+ if [ -x "$HOOK_DIR/${hook}.rdd-original" ]; then
23908
+ "$HOOK_DIR/${hook}.rdd-original" "$@"
23909
+ fi
23910
+ cc-codeconductor rdd git-check
23911
+ `;
23912
+ await writeFile19(path, script, "utf8");
23913
+ await chmod(path, 493);
23914
+ installed.push(hook);
23915
+ }
23916
+ return { installed, skipped };
23917
+ }
23918
+ async function rddCommand(options) {
23919
+ try {
23920
+ if (options.subcommand === "capture") {
23921
+ if (!options.taskId)
23922
+ throw new Error("Missing task id. Use --task <id>.");
23923
+ const protectedPaths = options.paths?.length ? options.paths : await collectReceiptPaths(options.projectRoot);
23924
+ const receipt = await captureReceipt(options.projectRoot, {
23925
+ taskId: options.taskId,
23926
+ phase: options.phase ?? "verification",
23927
+ paths: protectedPaths,
23928
+ outcome: options.outcome ?? "passed",
23929
+ command: options.command,
23930
+ coverage: options.paths?.length ? "paths" : "project"
23931
+ });
23932
+ const id = `ev-rdd-${options.taskId}-${Date.now()}`;
23933
+ const evidence = {
23934
+ id,
23935
+ source: "cc rdd",
23936
+ type: "rdd",
23937
+ timestamp: new Date().toISOString(),
23938
+ relatedTask: options.taskId,
23939
+ confidence: 0.9,
23940
+ summary: `RDD ${receipt.phase} receipt captured`,
23941
+ data: { rddReceipt: receipt }
23942
+ };
23943
+ const directory = evidenceDir(options.projectRoot);
23944
+ await mkdir19(directory, { recursive: true });
23945
+ await writeFile19(receiptPath(options.projectRoot, id), JSON.stringify(evidence, null, 2), "utf-8");
23946
+ return { code: 0, data: { success: true, receiptId: id, receipt } };
23947
+ }
23948
+ if (options.subcommand === "verify") {
23949
+ if (!options.receiptId)
23950
+ throw new Error("Missing receipt id. Use --receipt <id>.");
23951
+ const { receipt } = await loadReceipt(options.projectRoot, options.receiptId);
23952
+ const verification = await verifyReceipt(options.projectRoot, receipt);
23953
+ return {
23954
+ code: verification.valid ? 0 : 1,
23955
+ data: { success: verification.valid, receiptId: options.receiptId, ...verification }
23956
+ };
23957
+ }
23958
+ if (options.subcommand === "status") {
23959
+ return { code: 0, data: { success: true, receipts: await rddStatus(options.projectRoot, options.taskId) } };
23960
+ }
23961
+ if (options.subcommand === "git-check") {
23962
+ const current = (await rddStatus(options.projectRoot))[0];
23963
+ if (!current)
23964
+ return { code: 1, data: { success: false, errors: ["No RDD receipt exists for the Git candidate."] } };
23965
+ return current.valid ? { code: 0, data: { success: true, receiptId: current.id } } : { code: 1, data: { success: false, receiptId: current.id, changedPaths: current.changedPaths } };
23966
+ }
23967
+ return { code: 0, data: { success: true, ...await installHooks(options.projectRoot) } };
23968
+ } catch (error) {
23969
+ return { code: 1, data: { success: false, errors: [error instanceof Error ? error.message : String(error)] } };
23970
+ }
23971
+ }
23972
+ var execFileAsync3;
23973
+ var init_rdd_command = __esm(() => {
23974
+ init_schemas();
23975
+ init_paths();
23976
+ init_rdd_receipt();
23977
+ execFileAsync3 = promisify3(execFile3);
23978
+ });
23979
+
23503
23980
  // src/core/ccep/confirmation-gate.ts
23504
23981
  function matchesRiskThreshold(severity, threshold) {
23505
23982
  const order = { low: 0, medium: 1, high: 2 };
@@ -23805,11 +24282,11 @@ var init_output_validator = __esm(() => {
23805
24282
  });
23806
24283
 
23807
24284
  // src/core/ccep/command-parser.ts
23808
- import { existsSync as existsSync4, readFileSync as readFileSync3 } from "node:fs";
23809
- import { join as join19 } from "node:path";
24285
+ import { existsSync as existsSync5, readFileSync as readFileSync3 } from "node:fs";
24286
+ import { join as join20 } from "node:path";
23810
24287
  function readProjectId(projectRoot) {
23811
- const packageJsonPath = join19(projectRoot, "package.json");
23812
- if (existsSync4(packageJsonPath)) {
24288
+ const packageJsonPath = join20(projectRoot, "package.json");
24289
+ if (existsSync5(packageJsonPath)) {
23813
24290
  try {
23814
24291
  const pkg = JSON.parse(readFileSync3(packageJsonPath, "utf-8"));
23815
24292
  if (pkg.name) {
@@ -23838,8 +24315,8 @@ function parseCommand(command, userRequest, projectRoot) {
23838
24315
  maxVariance: "low"
23839
24316
  }
23840
24317
  };
23841
- const packageJsonPath = join19(projectRoot, "package.json");
23842
- if (existsSync4(packageJsonPath)) {
24318
+ const packageJsonPath = join20(projectRoot, "package.json");
24319
+ if (existsSync5(packageJsonPath)) {
23843
24320
  try {
23844
24321
  const pkg = JSON.parse(readFileSync3(packageJsonPath, "utf-8"));
23845
24322
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
@@ -23883,7 +24360,8 @@ var init_command_parser = __esm(() => {
23883
24360
  prototype: { outputFormat: "taskcard", needConfirmation: true, riskThreshold: "medium" },
23884
24361
  handoff: { outputFormat: "plan", needConfirmation: false, riskThreshold: "low" },
23885
24362
  clarify: { outputFormat: "plan", needConfirmation: false, riskThreshold: "low" },
23886
- security: { outputFormat: "taskcard", needConfirmation: true, riskThreshold: "high" }
24363
+ security: { outputFormat: "taskcard", needConfirmation: true, riskThreshold: "high" },
24364
+ odd: { outputFormat: "taskcard", needConfirmation: true, riskThreshold: "medium" }
23887
24365
  };
23888
24366
  });
23889
24367
 
@@ -23910,10 +24388,10 @@ var init_workflow_profile_loader = __esm(() => {
23910
24388
  });
23911
24389
 
23912
24390
  // src/core/evaluation/harness-catalog.ts
23913
- import { createHash as createHash4 } from "node:crypto";
23914
- import { existsSync as existsSync5, readFileSync as readFileSync4 } from "node:fs";
23915
- import { copyFile as copyFile2, mkdir as mkdir19, readFile as readFile28, readdir as readdir8, rm as rm4, writeFile as writeFile19 } from "node:fs/promises";
23916
- import { dirname as dirname11, join as join20, resolve as resolve27 } from "node:path";
24391
+ import { createHash as createHash5 } from "node:crypto";
24392
+ import { existsSync as existsSync6, readFileSync as readFileSync4 } from "node:fs";
24393
+ import { copyFile as copyFile2, mkdir as mkdir20, readFile as readFile30, readdir as readdir10, rm as rm4, writeFile as writeFile20 } from "node:fs/promises";
24394
+ import { dirname as dirname12, join as join21, resolve as resolve29 } from "node:path";
23917
24395
  function catalogIds(catalog = DEFAULT_HARNESS_CATALOG) {
23918
24396
  return catalog.components.map((c) => c.id);
23919
24397
  }
@@ -23963,23 +24441,23 @@ function harnessFingerprint(disabled, contractVersion, ccepProfile = "feature",
23963
24441
  contractVersion,
23964
24442
  ccepProfile
23965
24443
  };
23966
- return createHash4("sha256").update(JSON.stringify(payload)).digest("hex").slice(0, 16);
24444
+ return createHash5("sha256").update(JSON.stringify(payload)).digest("hex").slice(0, 16);
23967
24445
  }
23968
24446
  async function loadHarnessCatalog(projectRoot) {
23969
- const overridePath = resolve27(projectRoot, EVAL_DIR2, CATALOG_FILE);
24447
+ const overridePath = resolve29(projectRoot, EVAL_DIR2, CATALOG_FILE);
23970
24448
  try {
23971
- const raw = await readFile28(overridePath, "utf-8");
24449
+ const raw = await readFile30(overridePath, "utf-8");
23972
24450
  return HarnessCatalogSchema.parse($parse(raw));
23973
24451
  } catch {
23974
24452
  return DEFAULT_HARNESS_CATALOG;
23975
24453
  }
23976
24454
  }
23977
24455
  function activeOverlayPath(projectRoot) {
23978
- return resolve27(projectRoot, EVAL_DIR2, ACTIVE_OVERLAY_FILE);
24456
+ return resolve29(projectRoot, EVAL_DIR2, ACTIVE_OVERLAY_FILE);
23979
24457
  }
23980
24458
  async function readActiveOverlay(projectRoot) {
23981
24459
  try {
23982
- const raw = await readFile28(activeOverlayPath(projectRoot), "utf-8");
24460
+ const raw = await readFile30(activeOverlayPath(projectRoot), "utf-8");
23983
24461
  return HarnessOverlaySchema.parse($parse(raw));
23984
24462
  } catch {
23985
24463
  return null;
@@ -23988,7 +24466,7 @@ async function readActiveOverlay(projectRoot) {
23988
24466
  function isProductGraphDisabled(projectRoot) {
23989
24467
  try {
23990
24468
  const path = activeOverlayPath(projectRoot);
23991
- if (!existsSync5(path))
24469
+ if (!existsSync6(path))
23992
24470
  return false;
23993
24471
  const overlay = HarnessOverlaySchema.parse($parse(readFileSync4(path, "utf-8")));
23994
24472
  return overlay.disableProductGraph === true || overlay.disabledComponents.includes("product_graph");
@@ -24033,55 +24511,55 @@ function applyCatalogToProfile(profile, disabled) {
24033
24511
  return next;
24034
24512
  }
24035
24513
  async function restoreOverlayBackup(projectRoot) {
24036
- const backupRoot = resolve27(projectRoot, EVAL_DIR2, OVERLAY_BACKUP_DIR);
24037
- if (!existsSync5(backupRoot))
24514
+ const backupRoot = resolve29(projectRoot, EVAL_DIR2, OVERLAY_BACKUP_DIR);
24515
+ if (!existsSync6(backupRoot))
24038
24516
  return;
24039
- const configBackup = join20(backupRoot, "config.yml");
24040
- const configDest = resolve27(projectRoot, ".codeconductor", "config.yml");
24041
- if (existsSync5(configBackup)) {
24042
- await mkdir19(dirname11(configDest), { recursive: true });
24517
+ const configBackup = join21(backupRoot, "config.yml");
24518
+ const configDest = resolve29(projectRoot, ".codeconductor", "config.yml");
24519
+ if (existsSync6(configBackup)) {
24520
+ await mkdir20(dirname12(configDest), { recursive: true });
24043
24521
  await copyFile2(configBackup, configDest);
24044
24522
  }
24045
- const workflowsBackup = join20(backupRoot, "workflows");
24046
- const workflowsDest = resolve27(projectRoot, ".codeconductor", "workflows");
24047
- if (existsSync5(workflowsBackup)) {
24048
- await mkdir19(workflowsDest, { recursive: true });
24049
- const files = await readdir8(workflowsBackup);
24523
+ const workflowsBackup = join21(backupRoot, "workflows");
24524
+ const workflowsDest = resolve29(projectRoot, ".codeconductor", "workflows");
24525
+ if (existsSync6(workflowsBackup)) {
24526
+ await mkdir20(workflowsDest, { recursive: true });
24527
+ const files = await readdir10(workflowsBackup);
24050
24528
  for (const file of files) {
24051
- await copyFile2(join20(workflowsBackup, file), join20(workflowsDest, file));
24529
+ await copyFile2(join21(workflowsBackup, file), join21(workflowsDest, file));
24052
24530
  }
24053
24531
  }
24054
- const overlayBackup = join20(backupRoot, ACTIVE_OVERLAY_FILE);
24532
+ const overlayBackup = join21(backupRoot, ACTIVE_OVERLAY_FILE);
24055
24533
  const overlayDest = activeOverlayPath(projectRoot);
24056
- if (existsSync5(overlayBackup)) {
24534
+ if (existsSync6(overlayBackup)) {
24057
24535
  await copyFile2(overlayBackup, overlayDest);
24058
- } else if (existsSync5(overlayDest)) {
24536
+ } else if (existsSync6(overlayDest)) {
24059
24537
  await rm4(overlayDest, { force: true });
24060
24538
  }
24061
24539
  }
24062
24540
  async function snapshotForBackup(projectRoot) {
24063
- const backupRoot = resolve27(projectRoot, EVAL_DIR2, OVERLAY_BACKUP_DIR);
24064
- if (existsSync5(backupRoot))
24541
+ const backupRoot = resolve29(projectRoot, EVAL_DIR2, OVERLAY_BACKUP_DIR);
24542
+ if (existsSync6(backupRoot))
24065
24543
  return;
24066
- await mkdir19(backupRoot, { recursive: true });
24067
- const configPath = resolve27(projectRoot, ".codeconductor", "config.yml");
24068
- if (existsSync5(configPath)) {
24069
- await copyFile2(configPath, join20(backupRoot, "config.yml"));
24070
- }
24071
- const workflowsDir = resolve27(projectRoot, ".codeconductor", "workflows");
24072
- if (existsSync5(workflowsDir)) {
24073
- const dest = join20(backupRoot, "workflows");
24074
- await mkdir19(dest, { recursive: true });
24075
- const files = await readdir8(workflowsDir);
24544
+ await mkdir20(backupRoot, { recursive: true });
24545
+ const configPath = resolve29(projectRoot, ".codeconductor", "config.yml");
24546
+ if (existsSync6(configPath)) {
24547
+ await copyFile2(configPath, join21(backupRoot, "config.yml"));
24548
+ }
24549
+ const workflowsDir = resolve29(projectRoot, ".codeconductor", "workflows");
24550
+ if (existsSync6(workflowsDir)) {
24551
+ const dest = join21(backupRoot, "workflows");
24552
+ await mkdir20(dest, { recursive: true });
24553
+ const files = await readdir10(workflowsDir);
24076
24554
  for (const file of files) {
24077
24555
  if (file.endsWith(".yml")) {
24078
- await copyFile2(join20(workflowsDir, file), join20(dest, file));
24556
+ await copyFile2(join21(workflowsDir, file), join21(dest, file));
24079
24557
  }
24080
24558
  }
24081
24559
  }
24082
24560
  const overlay = activeOverlayPath(projectRoot);
24083
- if (existsSync5(overlay)) {
24084
- await copyFile2(overlay, join20(backupRoot, ACTIVE_OVERLAY_FILE));
24561
+ if (existsSync6(overlay)) {
24562
+ await copyFile2(overlay, join21(backupRoot, ACTIVE_OVERLAY_FILE));
24085
24563
  }
24086
24564
  }
24087
24565
  async function applyHarnessOverlay(projectRoot, disabled, options = {}) {
@@ -24090,13 +24568,13 @@ async function applyHarnessOverlay(projectRoot, disabled, options = {}) {
24090
24568
  await restoreOverlayBackup(projectRoot);
24091
24569
  await snapshotForBackup(projectRoot);
24092
24570
  }
24093
- const workflowsDir = resolve27(projectRoot, ".codeconductor", "workflows");
24094
- await mkdir19(workflowsDir, { recursive: true });
24095
- await mkdir19(resolve27(projectRoot, EVAL_DIR2), { recursive: true });
24571
+ const workflowsDir = resolve29(projectRoot, ".codeconductor", "workflows");
24572
+ await mkdir20(workflowsDir, { recursive: true });
24573
+ await mkdir20(resolve29(projectRoot, EVAL_DIR2), { recursive: true });
24096
24574
  for (const command of WORKFLOW_OVERLAY_COMMANDS) {
24097
24575
  const base = loadWorkflowProfile(command);
24098
24576
  const next = applyCatalogToProfile(base, disabled);
24099
- await writeFile19(join20(workflowsDir, `${command}.yml`), $stringify(next), "utf-8");
24577
+ await writeFile20(join21(workflowsDir, `${command}.yml`), $stringify(next), "utf-8");
24100
24578
  }
24101
24579
  const needsConfig = disabled.includes("compile_loop") || disabled.includes("council");
24102
24580
  if (needsConfig) {
@@ -24124,7 +24602,7 @@ async function applyHarnessOverlay(projectRoot, disabled, options = {}) {
24124
24602
  contractVersion: options.contractVersion,
24125
24603
  ccepProfile: options.ccepProfile ?? "feature"
24126
24604
  });
24127
- await writeFile19(activeOverlayPath(projectRoot), $stringify(overlay), "utf-8");
24605
+ await writeFile20(activeOverlayPath(projectRoot), $stringify(overlay), "utf-8");
24128
24606
  return ok(overlay);
24129
24607
  } catch (e) {
24130
24608
  return err(e instanceof Error ? e : new Error(String(e)));
@@ -24235,9 +24713,9 @@ var init_harness_catalog = __esm(() => {
24235
24713
  });
24236
24714
 
24237
24715
  // src/core/openspec/openspec-state.ts
24238
- import { createHash as createHash5 } from "node:crypto";
24239
- import { mkdir as mkdir20, readFile as readFile29, rename as rename3, writeFile as writeFile20 } from "node:fs/promises";
24240
- import { resolve as resolve28 } from "node:path";
24716
+ import { createHash as createHash6 } from "node:crypto";
24717
+ import { mkdir as mkdir21, readFile as readFile31, rename as rename4, writeFile as writeFile21 } from "node:fs/promises";
24718
+ import { resolve as resolve30 } from "node:path";
24241
24719
  function canTransition(from, to) {
24242
24720
  return ALLOWED_TRANSITIONS[from]?.includes(to) ?? false;
24243
24721
  }
@@ -24258,13 +24736,13 @@ function applyBacklogTransition(content, itemId, from, to, progress) {
24258
24736
  }
24259
24737
  async function writeFileAtomic(path, content) {
24260
24738
  const tmp = `${path}.${process.pid}.${Date.now()}.tmp`;
24261
- await writeFile20(tmp, content, "utf-8");
24262
- await rename3(tmp, path);
24739
+ await writeFile21(tmp, content, "utf-8");
24740
+ await rename4(tmp, path);
24263
24741
  }
24264
24742
  async function loadOpenspecState(projectRoot) {
24265
24743
  try {
24266
- const filePath = resolve28(projectRoot, STATE_FILE);
24267
- const content = await readFile29(filePath, "utf-8");
24744
+ const filePath = resolve30(projectRoot, STATE_FILE);
24745
+ const content = await readFile31(filePath, "utf-8");
24268
24746
  const data = JSON.parse(content);
24269
24747
  return ok(OpenspecStateSchema.parse(data));
24270
24748
  } catch (e) {
@@ -24281,10 +24759,10 @@ async function loadOpenspecState(projectRoot) {
24281
24759
  }
24282
24760
  async function writeOpenspecState(projectRoot, state) {
24283
24761
  try {
24284
- const dir = resolve28(projectRoot, ".codeconductor");
24285
- await mkdir20(dir, { recursive: true });
24762
+ const dir = resolve30(projectRoot, ".codeconductor");
24763
+ await mkdir21(dir, { recursive: true });
24286
24764
  const validated = OpenspecStateSchema.parse(state);
24287
- await writeFileAtomic(resolve28(dir, "openspec-state.json"), JSON.stringify(validated, null, 2));
24765
+ await writeFileAtomic(resolve30(dir, "openspec-state.json"), JSON.stringify(validated, null, 2));
24288
24766
  return ok(undefined);
24289
24767
  } catch (e) {
24290
24768
  return err(e instanceof Error ? e : new Error(String(e)));
@@ -24306,7 +24784,7 @@ function getNextTaskCard(state) {
24306
24784
  return null;
24307
24785
  }
24308
24786
  function hashContent(content) {
24309
- return createHash5("sha256").update(content).digest("hex").slice(0, 16);
24787
+ return createHash6("sha256").update(content).digest("hex").slice(0, 16);
24310
24788
  }
24311
24789
  function serializeItemSnapshot(item) {
24312
24790
  return JSON.stringify({
@@ -24388,19 +24866,19 @@ var init_openspec_state = __esm(() => {
24388
24866
  });
24389
24867
 
24390
24868
  // src/core/ccep/context-resolver.ts
24391
- import { existsSync as existsSync6 } from "node:fs";
24392
- import { readFile as readFile30 } from "node:fs/promises";
24393
- import { join as join21 } from "node:path";
24869
+ import { existsSync as existsSync7 } from "node:fs";
24870
+ import { readFile as readFile32 } from "node:fs/promises";
24871
+ import { join as join22 } from "node:path";
24394
24872
  async function loadProductKnowledge(projectRoot) {
24395
24873
  if (isProductGraphDisabled(projectRoot)) {
24396
24874
  return {};
24397
24875
  }
24398
24876
  const graphPath = productGraphPath(projectRoot);
24399
- if (!existsSync6(graphPath)) {
24877
+ if (!existsSync7(graphPath)) {
24400
24878
  return {};
24401
24879
  }
24402
24880
  try {
24403
- const raw = await readFile30(graphPath, "utf-8");
24881
+ const raw = await readFile32(graphPath, "utf-8");
24404
24882
  const graph = ProductGraphSchema.parse(JSON.parse(raw));
24405
24883
  return {
24406
24884
  productName: graph.productName,
@@ -24416,18 +24894,18 @@ async function loadProductKnowledge(projectRoot) {
24416
24894
  }
24417
24895
  async function resolveAstSource(projectRoot) {
24418
24896
  if (isProductGraphDisabled(projectRoot)) {
24419
- const graphifyPath2 = join21(projectRoot, "graphify-out", "graph.json");
24420
- if (existsSync6(graphifyPath2)) {
24897
+ const graphifyPath2 = join22(projectRoot, "graphify-out", "graph.json");
24898
+ if (existsSync7(graphifyPath2)) {
24421
24899
  return { source: "graphify", confidence: "medium" };
24422
24900
  }
24423
24901
  return { source: "manual", confidence: "low" };
24424
24902
  }
24425
24903
  const graphPath = productGraphPath(projectRoot);
24426
- if (existsSync6(graphPath)) {
24904
+ if (existsSync7(graphPath)) {
24427
24905
  return { source: "product-graph", confidence: "high" };
24428
24906
  }
24429
- const graphifyPath = join21(projectRoot, "graphify-out", "graph.json");
24430
- if (existsSync6(graphifyPath)) {
24907
+ const graphifyPath = join22(projectRoot, "graphify-out", "graph.json");
24908
+ if (existsSync7(graphifyPath)) {
24431
24909
  return { source: "graphify", confidence: "medium" };
24432
24910
  }
24433
24911
  try {
@@ -24668,6 +25146,12 @@ function councilConsensus(verdicts, config = DEFAULT_CONFIG2) {
24668
25146
  individualVerdicts: verdicts
24669
25147
  };
24670
25148
  }
25149
+ if (config.candidateHash !== undefined) {
25150
+ const mismatched = verdicts.filter((verdict) => verdict.candidateHash !== config.candidateHash);
25151
+ if (mismatched.length > 0) {
25152
+ return escalated(verdicts, `Candidate receipt mismatch for ${mismatched.length} ballot(s) — escalated for human review.`, counts);
25153
+ }
25154
+ }
24671
25155
  const critical = allFindings.filter((f) => f.severity === "critical");
24672
25156
  if (critical.length > 0 && policy === "reject") {
24673
25157
  return {
@@ -25229,12 +25713,26 @@ async function ccepCommand(options) {
25229
25713
  }
25230
25714
  mergedConfig = { ...mergedConfig, ...parsedConfig.data };
25231
25715
  }
25716
+ let currentCandidateHash;
25717
+ if (mergedConfig?.candidateHash !== undefined) {
25718
+ const { captureReceipt: captureReceipt2, collectReceiptPaths: collectReceiptPaths2 } = await Promise.resolve().then(() => (init_rdd_receipt(), exports_rdd_receipt));
25719
+ const receipt = await captureReceipt2(projectRoot, {
25720
+ taskId: "council",
25721
+ phase: "review",
25722
+ paths: await collectReceiptPaths2(projectRoot),
25723
+ outcome: "passed",
25724
+ coverage: "project"
25725
+ });
25726
+ currentCandidateHash = receipt.manifestHash;
25727
+ mergedConfig = { ...mergedConfig, candidateHash: currentCandidateHash };
25728
+ }
25232
25729
  const verdict = councilConsensus(parsedBallots.verdicts, mergedConfig);
25233
25730
  return {
25234
25731
  code: consensusExitCode(verdict.status),
25235
25732
  data: {
25236
25733
  success: verdict.status === "APPROVED",
25237
25734
  command: "ccep consensus",
25735
+ candidateHash: currentCandidateHash,
25238
25736
  verdict
25239
25737
  }
25240
25738
  };
@@ -25472,8 +25970,8 @@ var init_backlog_validator = __esm(() => {
25472
25970
 
25473
25971
  // src/core/openspec/backlog-scanner.ts
25474
25972
  import { execFileSync as execFileSync2 } from "node:child_process";
25475
- import { readFile as readFile31 } from "node:fs/promises";
25476
- import { resolve as resolve29 } from "node:path";
25973
+ import { readFile as readFile33 } from "node:fs/promises";
25974
+ import { resolve as resolve31 } from "node:path";
25477
25975
  function itemSnapshot(items) {
25478
25976
  const snap = {};
25479
25977
  for (const item of items) {
@@ -25483,8 +25981,8 @@ function itemSnapshot(items) {
25483
25981
  }
25484
25982
  async function scanBacklog(projectRoot, previousSnapshot = {}) {
25485
25983
  try {
25486
- const filePath = resolve29(projectRoot, BACKLOG_FILENAME);
25487
- const content = await readFile31(filePath, "utf-8");
25984
+ const filePath = resolve31(projectRoot, BACKLOG_FILENAME);
25985
+ const content = await readFile33(filePath, "utf-8");
25488
25986
  const hash = hashContent(content);
25489
25987
  let fileChanged = true;
25490
25988
  try {
@@ -25721,8 +26219,8 @@ var init_backlog_planner = __esm(() => {
25721
26219
  });
25722
26220
 
25723
26221
  // src/core/openspec/openspec-generator.ts
25724
- import { mkdir as mkdir21, rename as rename4, writeFile as writeFile21 } from "node:fs/promises";
25725
- import { basename as basename5, resolve as resolve30 } from "node:path";
26222
+ import { mkdir as mkdir22, rename as rename5, writeFile as writeFile22 } from "node:fs/promises";
26223
+ import { basename as basename6, resolve as resolve32 } from "node:path";
25726
26224
  function pad3(n) {
25727
26225
  return String(n).padStart(3, "0");
25728
26226
  }
@@ -25787,7 +26285,7 @@ The system MUST ${criterion}.
25787
26285
 
25788
26286
  #### Scenario: SC-${n} ${criterion}
25789
26287
 
25790
- - GIVEN the current behavior in ${item.scope}
26288
+ - GIVEN the relevant scoped behavior
25791
26289
  - WHEN this change is applied
25792
26290
  - THEN ${criterion}
25793
26291
  `;
@@ -25801,8 +26299,8 @@ ${blocks.join(`
25801
26299
  `;
25802
26300
  }
25803
26301
  async function writeTasksMarkdown(projectRoot, changePath, cards, options = {}) {
25804
- await mkdir21(resolve30(projectRoot, changePath), { recursive: true });
25805
- await writeFile21(resolve30(projectRoot, changePath, "tasks.md"), tasksContent(cards, options), "utf-8");
26302
+ await mkdir22(resolve32(projectRoot, changePath), { recursive: true });
26303
+ await writeFile22(resolve32(projectRoot, changePath, "tasks.md"), tasksContent(cards, options), "utf-8");
25806
26304
  }
25807
26305
  function tasksContent(cards, options = {}) {
25808
26306
  const criteria = options.acceptanceCriteria ?? [];
@@ -25847,19 +26345,19 @@ function tasksContent(cards, options = {}) {
25847
26345
  }
25848
26346
  async function generateOpenspecChange(projectRoot, item, taskCards, options = {}) {
25849
26347
  const slug = buildChangeSlug(item);
25850
- const changeDir = resolve30(projectRoot, "openspec", "changes", slug);
25851
- await mkdir21(resolve30(changeDir, "specs"), { recursive: true });
26348
+ const changeDir = resolve32(projectRoot, "openspec", "changes", slug);
26349
+ await mkdir22(resolve32(changeDir, "specs"), { recursive: true });
25852
26350
  const taskOpts = {
25853
26351
  tddRequired: options.tddRequired,
25854
26352
  acceptanceCriteria: options.acceptanceCriteria ?? item.acceptanceCriteria
25855
26353
  };
25856
- await writeFile21(resolve30(changeDir, "proposal.md"), proposalContent(item), "utf-8");
25857
- await writeFile21(resolve30(changeDir, "design.md"), designContent(item), "utf-8");
25858
- await writeFile21(resolve30(changeDir, "tasks.md"), tasksContent(taskCards, taskOpts), "utf-8");
26354
+ await writeFile22(resolve32(changeDir, "proposal.md"), proposalContent(item), "utf-8");
26355
+ await writeFile22(resolve32(changeDir, "design.md"), designContent(item), "utf-8");
26356
+ await writeFile22(resolve32(changeDir, "tasks.md"), tasksContent(taskCards, taskOpts), "utf-8");
25859
26357
  const capability = capabilitySlug(item.title);
25860
- await mkdir21(resolve30(changeDir, "specs", capability), { recursive: true });
25861
- await writeFile21(resolve30(changeDir, "specs", capability, "spec.md"), specDelta(item), "utf-8");
25862
- await writeFile21(resolve30(changeDir, "change.yaml"), `version: 1
26358
+ await mkdir22(resolve32(changeDir, "specs", capability), { recursive: true });
26359
+ await writeFile22(resolve32(changeDir, "specs", capability, "spec.md"), specDelta(item), "utf-8");
26360
+ await writeFile22(resolve32(changeDir, "change.yaml"), `version: 1
25863
26361
  backlogId: ${item.id}
25864
26362
  profile: standard
25865
26363
  capabilities:
@@ -25868,25 +26366,25 @@ capabilities:
25868
26366
  return `openspec/changes/${slug}`;
25869
26367
  }
25870
26368
  async function archiveChangeFolder(projectRoot, changePath) {
25871
- const src = resolve30(projectRoot, changePath);
25872
- const slug = basename5(changePath);
25873
- const destDir = resolve30(projectRoot, "openspec", "changes", "archive");
25874
- await mkdir21(destDir, { recursive: true });
25875
- const dest = resolve30(destDir, slug);
25876
- await rename4(src, dest);
26369
+ const src = resolve32(projectRoot, changePath);
26370
+ const slug = basename6(changePath);
26371
+ const destDir = resolve32(projectRoot, "openspec", "changes", "archive");
26372
+ await mkdir22(destDir, { recursive: true });
26373
+ const dest = resolve32(destDir, slug);
26374
+ await rename5(src, dest);
25877
26375
  return `openspec/changes/archive/${slug}`;
25878
26376
  }
25879
26377
  async function ensureOpenspecConfig(projectRoot) {
25880
- const configPath = resolve30(projectRoot, "openspec", "config.yaml");
26378
+ const configPath = resolve32(projectRoot, "openspec", "config.yaml");
25881
26379
  try {
25882
26380
  const { access: access7 } = await import("node:fs/promises");
25883
26381
  await access7(configPath);
25884
26382
  } catch {
25885
- await mkdir21(resolve30(projectRoot, "openspec"), { recursive: true });
26383
+ await mkdir22(resolve32(projectRoot, "openspec"), { recursive: true });
25886
26384
  const stub = `# OpenSpec project config (CodeConductor native compatible)
25887
26385
  schema: spec-driven
25888
26386
  `;
25889
- await writeFile21(configPath, stub, "utf-8");
26387
+ await writeFile22(configPath, stub, "utf-8");
25890
26388
  }
25891
26389
  }
25892
26390
  var init_openspec_generator = __esm(() => {
@@ -25894,8 +26392,8 @@ var init_openspec_generator = __esm(() => {
25894
26392
  });
25895
26393
 
25896
26394
  // src/core/openspec/spec-quality.ts
25897
- import { readdir as readdir9, readFile as readFile32 } from "node:fs/promises";
25898
- import { join as join22, relative as relative7, resolve as resolve31 } from "node:path";
26395
+ import { readdir as readdir11, readFile as readFile34 } from "node:fs/promises";
26396
+ import { join as join23, relative as relative8, resolve as resolve33 } from "node:path";
25899
26397
  function uniqueIds(matches) {
25900
26398
  return [...new Set(matches ?? [])];
25901
26399
  }
@@ -26012,12 +26510,12 @@ async function walkMarkdown(dir) {
26012
26510
  const out = [];
26013
26511
  let entries;
26014
26512
  try {
26015
- entries = await readdir9(dir, { withFileTypes: true });
26513
+ entries = await readdir11(dir, { withFileTypes: true });
26016
26514
  } catch {
26017
26515
  return out;
26018
26516
  }
26019
26517
  for (const entry of entries) {
26020
- const full = join22(dir, entry.name);
26518
+ const full = join23(dir, entry.name);
26021
26519
  if (entry.isDirectory()) {
26022
26520
  out.push(...await walkMarkdown(full));
26023
26521
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
@@ -26027,8 +26525,8 @@ async function walkMarkdown(dir) {
26027
26525
  return out;
26028
26526
  }
26029
26527
  async function assessChangeFolder(projectRoot, changePath) {
26030
- const root = resolve31(projectRoot);
26031
- const changeRoot = resolve31(root, changePath);
26528
+ const root = resolve33(projectRoot);
26529
+ const changeRoot = resolve33(root, changePath);
26032
26530
  if (!changeRoot.startsWith(root)) {
26033
26531
  return {
26034
26532
  valid: false,
@@ -26046,22 +26544,22 @@ async function assessChangeFolder(projectRoot, changePath) {
26046
26544
  successCriteria: []
26047
26545
  };
26048
26546
  }
26049
- const specDir = join22(changeRoot, "specs");
26547
+ const specDir = join23(changeRoot, "specs");
26050
26548
  const specFiles = await walkMarkdown(specDir);
26051
- const extra = ["proposal.md", "design.md"].map((name) => join22(changeRoot, name));
26549
+ const extra = ["proposal.md", "design.md"].map((name) => join23(changeRoot, name));
26052
26550
  const reports = [];
26053
26551
  for (const file of specFiles) {
26054
- const content = await readFile32(file, "utf-8");
26055
- reports.push(assessSpecMarkdown(content, relative7(root, file).replace(/\\/g, "/")));
26552
+ const content = await readFile34(file, "utf-8");
26553
+ reports.push(assessSpecMarkdown(content, relative8(root, file).replace(/\\/g, "/")));
26056
26554
  }
26057
26555
  for (const file of extra) {
26058
26556
  let content;
26059
26557
  try {
26060
- content = await readFile32(file, "utf-8");
26558
+ content = await readFile34(file, "utf-8");
26061
26559
  } catch {
26062
26560
  continue;
26063
26561
  }
26064
- const rel = relative7(root, file).replace(/\\/g, "/");
26562
+ const rel = relative8(root, file).replace(/\\/g, "/");
26065
26563
  if (PLACEHOLDER.test(content)) {
26066
26564
  reports.push({
26067
26565
  valid: false,
@@ -26105,15 +26603,15 @@ var init_spec_quality = __esm(() => {
26105
26603
  FR_ID = /\bFR-\d{3}\b/g;
26106
26604
  SC_ID = /\bSC-\d{3}\b/g;
26107
26605
  US_AC = /\b(?:US|AC)#?\d+\b/g;
26108
- GWT = /\bGIVEN\b[\s\S]{0,400}\bWHEN\b[\s\S]{0,400}\bTHEN\b/i;
26606
+ GWT = /\bGIVEN\b[\s\S]*?\bWHEN\b[\s\S]*?\bTHEN\b/i;
26109
26607
  NEEDS_CLARIFICATION = /\[NEEDS CLARIFICATION:[^\]]*\]/gi;
26110
26608
  PLACEHOLDER = /\(To be completed/i;
26111
26609
  HOW_LEAK = /\b(TypeScript|PostgreSQL|Django|React|Spring Boot|package\.json|implements class)\b/i;
26112
26610
  });
26113
26611
 
26114
26612
  // src/core/openspec/spec-analyzer.ts
26115
- import { readFile as readFile33, readdir as readdir10 } from "node:fs/promises";
26116
- import { join as join23, resolve as resolve32 } from "node:path";
26613
+ import { readFile as readFile35, readdir as readdir12 } from "node:fs/promises";
26614
+ import { join as join24, resolve as resolve34 } from "node:path";
26117
26615
  function unique(ids) {
26118
26616
  return [...new Set(ids)];
26119
26617
  }
@@ -26140,17 +26638,17 @@ function testSection(tasksMarkdown) {
26140
26638
  async function readDeltaSpecs(specDir) {
26141
26639
  let entries;
26142
26640
  try {
26143
- entries = await readdir10(specDir, { withFileTypes: true });
26641
+ entries = await readdir12(specDir, { withFileTypes: true });
26144
26642
  } catch {
26145
26643
  return "";
26146
26644
  }
26147
26645
  const contents = [];
26148
26646
  for (const entry of entries) {
26149
- const path = join23(specDir, entry.name);
26647
+ const path = join24(specDir, entry.name);
26150
26648
  if (entry.isDirectory()) {
26151
26649
  contents.push(await readDeltaSpecs(path));
26152
26650
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
26153
- contents.push(await readFile33(path, "utf-8"));
26651
+ contents.push(await readFile35(path, "utf-8"));
26154
26652
  }
26155
26653
  }
26156
26654
  return contents.filter(Boolean).join(`
@@ -26228,17 +26726,17 @@ function analyzeSpecArtifacts(input) {
26228
26726
  };
26229
26727
  }
26230
26728
  async function analyzeChangeFolder(projectRoot, changePath, options) {
26231
- const changeRoot = resolve32(projectRoot, changePath);
26232
- const specMarkdown = await readDeltaSpecs(join23(changeRoot, "specs"));
26729
+ const changeRoot = resolve34(projectRoot, changePath);
26730
+ const specMarkdown = await readDeltaSpecs(join24(changeRoot, "specs"));
26233
26731
  let tasksMarkdown = "";
26234
26732
  try {
26235
- tasksMarkdown = await readFile33(join23(changeRoot, "tasks.md"), "utf-8");
26733
+ tasksMarkdown = await readFile35(join24(changeRoot, "tasks.md"), "utf-8");
26236
26734
  } catch {
26237
26735
  tasksMarkdown = "";
26238
26736
  }
26239
26737
  let designMarkdown;
26240
26738
  try {
26241
- designMarkdown = await readFile33(join23(changeRoot, "design.md"), "utf-8");
26739
+ designMarkdown = await readFile35(join24(changeRoot, "design.md"), "utf-8");
26242
26740
  } catch {
26243
26741
  designMarkdown = undefined;
26244
26742
  }
@@ -26257,18 +26755,18 @@ var init_spec_analyzer = __esm(() => {
26257
26755
  });
26258
26756
 
26259
26757
  // src/core/openspec/spec-sync.ts
26260
- import { mkdir as mkdir22, readFile as readFile34, readdir as readdir11 } from "node:fs/promises";
26261
- import { join as join24, relative as relative8, resolve as resolve33 } from "node:path";
26758
+ import { mkdir as mkdir23, readFile as readFile36, readdir as readdir13 } from "node:fs/promises";
26759
+ import { join as join25, relative as relative9, resolve as resolve35 } from "node:path";
26262
26760
  async function markdownFiles(dir) {
26263
26761
  let entries;
26264
26762
  try {
26265
- entries = await readdir11(dir, { withFileTypes: true });
26763
+ entries = await readdir13(dir, { withFileTypes: true });
26266
26764
  } catch {
26267
26765
  return [];
26268
26766
  }
26269
26767
  const files = [];
26270
26768
  for (const entry of entries) {
26271
- const path = join24(dir, entry.name);
26769
+ const path = join25(dir, entry.name);
26272
26770
  if (entry.isDirectory())
26273
26771
  files.push(...await markdownFiles(path));
26274
26772
  else if (entry.isFile() && entry.name.endsWith(".md"))
@@ -26344,9 +26842,9 @@ ${delta.markdown}`;
26344
26842
  ` };
26345
26843
  }
26346
26844
  async function syncChangeSpecs(projectRoot, changePath) {
26347
- const root = resolve33(projectRoot);
26348
- const changeRoot = resolve33(root, changePath);
26349
- const changeSpecs = join24(changeRoot, "specs");
26845
+ const root = resolve35(projectRoot);
26846
+ const changeRoot = resolve35(root, changePath);
26847
+ const changeSpecs = join25(changeRoot, "specs");
26350
26848
  if (changeRoot !== root && !changeRoot.startsWith(`${root}/`)) {
26351
26849
  return { success: false, syncedPaths: [], errors: ["Change path escapes project root"] };
26352
26850
  }
@@ -26356,34 +26854,34 @@ async function syncChangeSpecs(projectRoot, changePath) {
26356
26854
  }
26357
26855
  const writes = [];
26358
26856
  for (const file of files) {
26359
- const delta = await readFile34(file, "utf-8");
26857
+ const delta = await readFile36(file, "utf-8");
26360
26858
  const requirements = deltaRequirements(delta);
26361
26859
  if (requirements.length === 0) {
26362
26860
  return {
26363
26861
  success: false,
26364
26862
  syncedPaths: [],
26365
- errors: [`${relative8(root, file)}: no delta requirements found`]
26863
+ errors: [`${relative9(root, file)}: no delta requirements found`]
26366
26864
  };
26367
26865
  }
26368
- const relativeSpec = relative8(changeSpecs, file);
26369
- const target = join24(root, "openspec", "specs", relativeSpec);
26866
+ const relativeSpec = relative9(changeSpecs, file);
26867
+ const target = join25(root, "openspec", "specs", relativeSpec);
26370
26868
  let existing = `# ${relativeSpec.replace(/\\/g, "/")}
26371
26869
  `;
26372
26870
  try {
26373
- existing = await readFile34(target, "utf-8");
26871
+ existing = await readFile36(target, "utf-8");
26374
26872
  } catch {}
26375
- const merged = upsertRequirements(existing, requirements, relative8(root, file));
26873
+ const merged = upsertRequirements(existing, requirements, relative9(root, file));
26376
26874
  if (!merged.ok)
26377
26875
  return { success: false, syncedPaths: [], errors: [merged.error] };
26378
26876
  writes.push({ path: target, content: merged.content });
26379
26877
  }
26380
26878
  for (const write of writes) {
26381
- await mkdir22(resolve33(write.path, ".."), { recursive: true });
26879
+ await mkdir23(resolve35(write.path, ".."), { recursive: true });
26382
26880
  await writeFileAtomic(write.path, write.content);
26383
26881
  }
26384
26882
  return {
26385
26883
  success: true,
26386
- syncedPaths: writes.map((write) => relative8(root, write.path).replace(/\\/g, "/")),
26884
+ syncedPaths: writes.map((write) => relative9(root, write.path).replace(/\\/g, "/")),
26387
26885
  errors: []
26388
26886
  };
26389
26887
  }
@@ -26399,8 +26897,8 @@ var exports_openspec_command = {};
26399
26897
  __export(exports_openspec_command, {
26400
26898
  openspecCommand: () => openspecCommand
26401
26899
  });
26402
- import { readFile as readFile35 } from "node:fs/promises";
26403
- import { resolve as resolve34 } from "node:path";
26900
+ import { readFile as readFile37 } from "node:fs/promises";
26901
+ import { resolve as resolve36 } from "node:path";
26404
26902
  async function openspecCommand(options) {
26405
26903
  const { subcommand, itemId, projectRoot, output, reason } = options;
26406
26904
  switch (subcommand) {
@@ -26422,6 +26920,8 @@ async function openspecCommand(options) {
26422
26920
  return handleDone(projectRoot, itemId);
26423
26921
  case "block":
26424
26922
  return handleBlock(projectRoot, itemId, reason);
26923
+ case "unblock":
26924
+ return handleUnblock(projectRoot, itemId);
26425
26925
  case "archive":
26426
26926
  return handleArchive(projectRoot, itemId);
26427
26927
  default:
@@ -26444,7 +26944,7 @@ function fail(command, errors3, extra = {}) {
26444
26944
  };
26445
26945
  }
26446
26946
  async function persistBacklog(projectRoot, content) {
26447
- await writeFileAtomic(resolve34(projectRoot, BACKLOG_FILENAME), content);
26947
+ await writeFileAtomic(resolve36(projectRoot, BACKLOG_FILENAME), content);
26448
26948
  }
26449
26949
  async function persistState(projectRoot, state) {
26450
26950
  const written = await writeOpenspecState(projectRoot, state);
@@ -26454,7 +26954,7 @@ async function persistState(projectRoot, state) {
26454
26954
  return { ok: true };
26455
26955
  }
26456
26956
  async function readBacklogMarkdown(projectRoot) {
26457
- return readFile35(resolve34(projectRoot, BACKLOG_FILENAME), "utf-8");
26957
+ return readFile37(resolve36(projectRoot, BACKLOG_FILENAME), "utf-8");
26458
26958
  }
26459
26959
  async function transitionItem(projectRoot, item, to, progress) {
26460
26960
  const content = await readBacklogMarkdown(projectRoot);
@@ -26652,17 +27152,18 @@ async function handleAnalyze(projectRoot, itemId) {
26652
27152
  const policyParts = [];
26653
27153
  for (const name of ["AGENTS.md", "BACKLOG.md"]) {
26654
27154
  try {
26655
- policyParts.push(await readFile35(resolve34(projectRoot, name), "utf-8"));
27155
+ policyParts.push(await readFile37(resolve36(projectRoot, name), "utf-8"));
26656
27156
  } catch {}
26657
27157
  }
26658
27158
  const cards = itemCards(stateResult.data, targetId);
26659
27159
  const tddCards = cards.filter((c) => c.phase === "test" || c.phase === "implement");
26660
27160
  let hasTddEvidence;
26661
27161
  if (tddCards.length > 0) {
26662
- hasTddEvidence = false;
27162
+ hasTddEvidence = true;
26663
27163
  for (const card of tddCards) {
26664
- if (await hasTddRunnerEvidence(projectRoot, card.id)) {
26665
- hasTddEvidence = true;
27164
+ const expectedPhase = card.phase === "test" ? "red" : "green";
27165
+ if (!await hasTddRunnerEvidence(projectRoot, card.id, expectedPhase)) {
27166
+ hasTddEvidence = false;
26666
27167
  break;
26667
27168
  }
26668
27169
  }
@@ -26847,10 +27348,11 @@ async function handleDone(projectRoot, cardId) {
26847
27348
  const backlog = await loadBacklog(projectRoot);
26848
27349
  const tddRequired = backlog.success ? backlog.data.global.tddRequired : false;
26849
27350
  if (tddRequired && (card.phase === "test" || card.phase === "implement")) {
26850
- const evidenced = await hasTddRunnerEvidence(projectRoot, cardId);
27351
+ const expectedPhase = card.phase === "test" ? "red" : "green";
27352
+ const evidenced = await hasTddRunnerEvidence(projectRoot, cardId, expectedPhase);
26851
27353
  if (!evidenced) {
26852
27354
  return fail(command, [
26853
- `Card ${cardId} (${card.phase}) requires verification-runner TDD evidence. Run captureTddSuiteEvidence before openspec done.`
27355
+ `Card ${cardId} (${card.phase}) requires current ${expectedPhase.toUpperCase()} verification-runner TDD evidence. Run captureTddSuiteEvidence before openspec done.`
26854
27356
  ]);
26855
27357
  }
26856
27358
  }
@@ -26925,6 +27427,57 @@ async function handleBlock(projectRoot, cardId, reason) {
26925
27427
  }
26926
27428
  };
26927
27429
  }
27430
+ async function handleUnblock(projectRoot, cardId) {
27431
+ const command = "openspec unblock";
27432
+ if (!cardId) {
27433
+ return fail(command, ["Missing card id. Usage: openspec unblock <cardId>"]);
27434
+ }
27435
+ const loaded = await loadStateOrFail(projectRoot, command);
27436
+ if (!loaded.ok)
27437
+ return loaded.response;
27438
+ const card = findCard(loaded.state, cardId);
27439
+ if (!card) {
27440
+ return fail(command, [`Task card ${cardId} not found`]);
27441
+ }
27442
+ if (card.status !== "blocked") {
27443
+ return fail(command, [`Card ${cardId} must be blocked before unblock (got ${card.status})`]);
27444
+ }
27445
+ const itemLoaded = await loadItemOrFail(projectRoot, card.backlogId, command);
27446
+ if (!itemLoaded.ok)
27447
+ return itemLoaded.response;
27448
+ if (itemLoaded.item.status !== "BLOCKED") {
27449
+ return fail(command, [
27450
+ `Backlog item ${itemLoaded.item.id} must be BLOCKED before unblock (got ${itemLoaded.item.status})`
27451
+ ]);
27452
+ }
27453
+ const state = setTaskCardStatus(loaded.state, cardId, "pending");
27454
+ const written = await persistState(projectRoot, state);
27455
+ if (!written.ok)
27456
+ return fail(command, [written.error]);
27457
+ const changePath = state.changePaths[card.backlogId];
27458
+ if (changePath) {
27459
+ const backlog = await loadBacklog(projectRoot);
27460
+ await writeTasksMarkdown(projectRoot, changePath, itemCards(state, card.backlogId), {
27461
+ tddRequired: backlog.success ? backlog.data.global.tddRequired : false,
27462
+ acceptanceCriteria: itemLoaded.item.acceptanceCriteria
27463
+ });
27464
+ }
27465
+ const transition = await transitionItem(projectRoot, itemLoaded.item, "READY");
27466
+ if (!transition.ok)
27467
+ return fail(command, [transition.error]);
27468
+ return {
27469
+ code: 0,
27470
+ data: {
27471
+ success: true,
27472
+ command,
27473
+ cardId,
27474
+ cardStatus: "pending",
27475
+ itemId: itemLoaded.item.id,
27476
+ itemStatus: "READY",
27477
+ nextStep: `Run openspec plan ${itemLoaded.item.id}.`
27478
+ }
27479
+ };
27480
+ }
26928
27481
  async function handleArchive(projectRoot, itemId) {
26929
27482
  const command = "openspec archive";
26930
27483
  if (!itemId) {
@@ -27001,7 +27554,7 @@ async function handleArchive(projectRoot, itemId) {
27001
27554
  }
27002
27555
  };
27003
27556
  }
27004
- var KNOWN_SUBCOMMANDS = "validate, scan, plan, analyze, status, next, start, done, block, archive";
27557
+ var KNOWN_SUBCOMMANDS = "validate, scan, plan, analyze, status, next, start, done, block, unblock, archive";
27005
27558
  var init_openspec_command = __esm(() => {
27006
27559
  init_backlog_parser();
27007
27560
  init_backlog_validator();
@@ -27019,6 +27572,184 @@ var init_openspec_command = __esm(() => {
27019
27572
  init_loop_engine();
27020
27573
  });
27021
27574
 
27575
+ // src/core/ccep/context-assembly.ts
27576
+ function resumeDecision(changedPaths) {
27577
+ if (changedPaths.length === 0)
27578
+ return { status: "ready" };
27579
+ return {
27580
+ status: "needs_decision",
27581
+ changedPaths,
27582
+ question: `Workspace changed in ${changedPaths.join(", ")}. Continue with the current workspace?`
27583
+ };
27584
+ }
27585
+ var init_context_assembly = () => {};
27586
+
27587
+ // src/core/delivery/delivery-ledger.ts
27588
+ import { createHash as createHash7 } from "node:crypto";
27589
+ import { mkdir as mkdir24, readFile as readFile38, writeFile as writeFile23 } from "node:fs/promises";
27590
+ import { resolve as resolve37, sep as sep6 } from "node:path";
27591
+ function ledgerPath(projectRoot, id) {
27592
+ if (!/^[a-z0-9][a-z0-9-]{0,63}$/.test(id))
27593
+ throw new Error("Invalid delivery ledger id");
27594
+ return resolve37(projectRoot, DELIVERY_DIR, `${id}.md`);
27595
+ }
27596
+ async function fingerprintWorkspace(projectRoot, paths) {
27597
+ const root = resolve37(projectRoot);
27598
+ const fingerprints = {};
27599
+ for (const path of paths) {
27600
+ const candidate = resolve37(root, path);
27601
+ if (candidate !== root && !candidate.startsWith(`${root}${sep6}`)) {
27602
+ fingerprints[path] = "outside-root";
27603
+ continue;
27604
+ }
27605
+ try {
27606
+ fingerprints[path] = createHash7("sha256").update(await readFile38(candidate)).digest("hex");
27607
+ } catch {
27608
+ fingerprints[path] = "missing";
27609
+ }
27610
+ }
27611
+ return fingerprints;
27612
+ }
27613
+ function render(ledger) {
27614
+ return `# Delivery Ledger: ${ledger.id}
27615
+
27616
+ ${START}
27617
+ \`\`\`yaml
27618
+ ${$stringify(ledger)}\`\`\`
27619
+ ${END}
27620
+ `;
27621
+ }
27622
+ function parseLedger(content) {
27623
+ const match = content.match(/<!-- delivery-ledger-start -->\n```yaml\n([\s\S]*?)```\n<!-- delivery-ledger-end -->/);
27624
+ if (!match)
27625
+ throw new Error("Invalid delivery ledger format");
27626
+ return DeliveryLedgerSchema.parse($parse(match[1]));
27627
+ }
27628
+ async function loadDeliveryLedger(projectRoot, id) {
27629
+ return parseLedger(await readFile38(ledgerPath(projectRoot, id), "utf-8"));
27630
+ }
27631
+ async function createDeliveryLedger(projectRoot, input) {
27632
+ const request = DeliveryLedgerRequestSchema.parse(input);
27633
+ const path = ledgerPath(projectRoot, request.id);
27634
+ try {
27635
+ return { created: false, ledger: await loadDeliveryLedger(projectRoot, request.id) };
27636
+ } catch (error) {
27637
+ if (!(error instanceof Error) || !error.message.includes("ENOENT"))
27638
+ throw error;
27639
+ }
27640
+ const now = new Date().toISOString();
27641
+ const ledger = DeliveryLedgerSchema.parse({
27642
+ version: 1,
27643
+ id: request.id,
27644
+ taskCard: request.taskCard,
27645
+ tasks: request.tasks,
27646
+ evidence: request.taskCard.evidenceRequired,
27647
+ nextStep: request.nextStep,
27648
+ memoryTopicKey: `delivery:${request.id}`,
27649
+ workspace: await fingerprintWorkspace(projectRoot, request.taskCard.targetFiles),
27650
+ createdAt: now,
27651
+ updatedAt: now
27652
+ });
27653
+ await mkdir24(resolve37(projectRoot, DELIVERY_DIR), { recursive: true });
27654
+ try {
27655
+ await writeFile23(path, render(ledger), { encoding: "utf-8", flag: "wx" });
27656
+ return { created: true, ledger };
27657
+ } catch (error) {
27658
+ if (error instanceof Error && error.message.includes("EEXIST")) {
27659
+ return { created: false, ledger: await loadDeliveryLedger(projectRoot, request.id) };
27660
+ }
27661
+ throw error;
27662
+ }
27663
+ }
27664
+ async function reconcileDeliveryLedger(projectRoot, id) {
27665
+ const ledger = await loadDeliveryLedger(projectRoot, id);
27666
+ const current = await fingerprintWorkspace(projectRoot, Object.keys(ledger.workspace));
27667
+ const changedPaths = Object.keys(ledger.workspace).filter((path) => ledger.workspace[path] !== current[path]);
27668
+ return { ledger, changedPaths };
27669
+ }
27670
+ var DELIVERY_DIR = ".codeconductor/delivery", START = "<!-- delivery-ledger-start -->", END = "<!-- delivery-ledger-end -->";
27671
+ var init_delivery_ledger = __esm(() => {
27672
+ init_dist();
27673
+ init_schemas();
27674
+ });
27675
+
27676
+ // src/commands/odd.command.ts
27677
+ var exports_odd_command = {};
27678
+ __export(exports_odd_command, {
27679
+ oddCommand: () => oddCommand
27680
+ });
27681
+ async function oddCommand(options) {
27682
+ if (options.subcommand === "create") {
27683
+ let input = options.input;
27684
+ if (typeof input === "string") {
27685
+ try {
27686
+ input = JSON.parse(input);
27687
+ } catch {
27688
+ return { code: 1, data: { success: false, errors: ["Invalid JSON input"] } };
27689
+ }
27690
+ }
27691
+ const request = DeliveryLedgerRequestSchema.safeParse(input);
27692
+ if (!request.success)
27693
+ return { code: 1, data: { success: false, errors: request.error.issues } };
27694
+ if (!request.data.authorized || request.data.route !== "tracked") {
27695
+ return { code: 0, data: { success: true, created: false, reason: "route_not_tracked" } };
27696
+ }
27697
+ const issues = validateTaskCardForProfile(loadWorkflowProfile("odd", options.projectRoot), request.data.taskCard);
27698
+ if (issues.length > 0)
27699
+ return { code: 1, data: { success: false, errors: issues } };
27700
+ try {
27701
+ const result = await createDeliveryLedger(options.projectRoot, request.data);
27702
+ return { code: 0, data: { success: true, ...result, ...result.created ? {} : { existing: true } } };
27703
+ } catch (error) {
27704
+ return { code: 1, data: { success: false, errors: [String(error)] } };
27705
+ }
27706
+ }
27707
+ if (!options.id)
27708
+ return { code: 1, data: { success: false, errors: ["Missing ledger id"] } };
27709
+ try {
27710
+ if (options.subcommand === "read") {
27711
+ return { code: 0, data: { success: true, ledger: await loadDeliveryLedger(options.projectRoot, options.id) } };
27712
+ }
27713
+ if (options.subcommand === "reconcile") {
27714
+ const result = await reconcileDeliveryLedger(options.projectRoot, options.id);
27715
+ const memory = await loadMemoryIndex(options.projectRoot);
27716
+ const { rddCommand: rddCommand2 } = await Promise.resolve().then(() => (init_rdd_command(), exports_rdd_command));
27717
+ const rdd = await rddCommand2({
27718
+ subcommand: "status",
27719
+ projectRoot: options.projectRoot,
27720
+ taskId: result.ledger.taskCard.id
27721
+ });
27722
+ const receipts = rdd.data.receipts ?? [];
27723
+ const staleReceipt = receipts.some((receipt) => receipt.valid === false);
27724
+ const changedPaths = staleReceipt ? [...result.changedPaths, "RDD receipt"].sort() : result.changedPaths;
27725
+ return {
27726
+ code: 0,
27727
+ data: {
27728
+ success: true,
27729
+ status: changedPaths.length === 0 ? "ready" : "conflict",
27730
+ resume: resumeDecision(changedPaths),
27731
+ rdd,
27732
+ memory: memory.success ? "available" : "unavailable",
27733
+ memoryPointers: memory.success ? memory.data.pointers.filter((pointer) => pointer.topic_key === result.ledger.memoryTopicKey) : [],
27734
+ ...result,
27735
+ changedPaths
27736
+ }
27737
+ };
27738
+ }
27739
+ return { code: 1, data: { success: false, errors: [`Unknown odd subcommand: ${options.subcommand}`] } };
27740
+ } catch (error) {
27741
+ return { code: 1, data: { success: false, errors: [String(error)] } };
27742
+ }
27743
+ }
27744
+ var init_odd_command = __esm(() => {
27745
+ init_memory_index();
27746
+ init_context_assembly();
27747
+ init_task_card_validator();
27748
+ init_workflow_profile_loader();
27749
+ init_delivery_ledger();
27750
+ init_schemas();
27751
+ });
27752
+
27022
27753
  // src/core/hooks/hook-runner.ts
27023
27754
  function normalizeCommand(raw) {
27024
27755
  return raw.replace(/\s+/g, " ").trim();
@@ -27170,8 +27901,8 @@ __export(exports_hook_command, {
27170
27901
  readStdinText: () => readStdinText
27171
27902
  });
27172
27903
  import { spawnSync } from "node:child_process";
27173
- import { existsSync as existsSync7 } from "node:fs";
27174
- import { resolve as resolve35 } from "node:path";
27904
+ import { existsSync as existsSync8 } from "node:fs";
27905
+ import { resolve as resolve38 } from "node:path";
27175
27906
  function detectFormat(explicit, stdinText) {
27176
27907
  if (explicit)
27177
27908
  return explicit;
@@ -27198,13 +27929,13 @@ function resolvePreToolInput(options, stdinText) {
27198
27929
  };
27199
27930
  }
27200
27931
  async function sessionLines(projectRoot) {
27201
- const backlogPath = resolve35(projectRoot, "BACKLOG.md");
27202
- const profilePath = resolve35(projectRoot, ".codeconductor", "evaluation", "execution-profile.yml");
27932
+ const backlogPath = resolve38(projectRoot, "BACKLOG.md");
27933
+ const profilePath = resolve38(projectRoot, ".codeconductor", "evaluation", "execution-profile.yml");
27203
27934
  return [
27204
27935
  "[CodeConductor] Session start",
27205
27936
  "Skills: openspec, backlog, evaluation, testing-tdd — invoke via /cc-* then CLI.",
27206
- existsSync7(backlogPath) ? "BACKLOG.md present — run: bun run dev openspec status" : "No BACKLOG.md — author with /cc-backlog if you need an item queue.",
27207
- existsSync7(profilePath) ? "Scorecard profile on disk — run: bun run dev scorecard models" : "Scorecard: bun run dev scorecard create --task <id> --from-diff",
27937
+ existsSync8(backlogPath) ? "BACKLOG.md present — run: bun run dev openspec status" : "No BACKLOG.md — author with /cc-backlog if you need an item queue.",
27938
+ existsSync8(profilePath) ? "Scorecard profile on disk — run: bun run dev scorecard models" : "Scorecard: bun run dev scorecard create --task <id> --from-diff",
27208
27939
  "Hooks: bun run dev hook pre-tool | post-tool | session-start",
27209
27940
  "Eval suites: bun run dev scorecard suite-run --suite workflow-gates"
27210
27941
  ];
@@ -27248,7 +27979,7 @@ async function hookCommand(options) {
27248
27979
  };
27249
27980
  }
27250
27981
  function formatWrittenFile(filePath) {
27251
- if (!filePath || !existsSync7(filePath))
27982
+ if (!filePath || !existsSync8(filePath))
27252
27983
  return;
27253
27984
  const prettier = /\.(ts|tsx|js|jsx|mjs|cjs|json|jsonc|md|mdx|css|scss|html|astro|ya?ml)$/i;
27254
27985
  const eslint = /\.(ts|tsx|js|jsx|mjs|cjs)$/i;
@@ -27666,6 +28397,12 @@ function ccGainToScorecardImpact(result) {
27666
28397
 
27667
28398
  // src/core/evaluation/scorecard-signals.ts
27668
28399
  import { execFileSync as execFileSync3 } from "node:child_process";
28400
+ function parseScopeFiles(scope) {
28401
+ return scope.split(/[,;]/).map((entry) => entry.trim().replace(/[.;:]$/, "").replace(/^`|`$/g, "")).filter(Boolean);
28402
+ }
28403
+ function isGeneratedBuildCache(path) {
28404
+ return /(^|\/)\.gradle\//.test(path);
28405
+ }
27669
28406
  function collectScorecardSignals(projectRoot, scopeFiles, extra) {
27670
28407
  const findings = [];
27671
28408
  const overrides = {};
@@ -27712,7 +28449,7 @@ function collectScorecardSignals(projectRoot, scopeFiles, extra) {
27712
28449
  changedFiles.add(m[1]);
27713
28450
  }
27714
28451
  if (scopeFiles && scopeFiles.length > 0) {
27715
- const outOfScope = [...changedFiles].filter((f) => !scopeFiles.some((s) => f.includes(s.replace(/\*\*/g, ""))));
28452
+ const outOfScope = [...changedFiles].filter((file) => !isGeneratedBuildCache(file)).filter((f) => !scopeFiles.some((s) => f.includes(s.replace(/\*\*/g, ""))));
27716
28453
  if (outOfScope.length > 0) {
27717
28454
  overrides.minimal_diff = {
27718
28455
  score: 0,
@@ -27783,25 +28520,25 @@ var init_scorecard_signals = __esm(() => {
27783
28520
  });
27784
28521
 
27785
28522
  // src/core/evaluation/harness-experiment.ts
27786
- import { existsSync as existsSync8 } from "node:fs";
27787
- import { cp, mkdir as mkdir23, readFile as readFile36, readdir as readdir12, writeFile as writeFile22 } from "node:fs/promises";
27788
- import { dirname as dirname12, join as join25, resolve as resolve36 } from "node:path";
28523
+ import { existsSync as existsSync9 } from "node:fs";
28524
+ import { cp, mkdir as mkdir25, readFile as readFile39, readdir as readdir14, writeFile as writeFile24 } from "node:fs/promises";
28525
+ import { dirname as dirname13, join as join26, resolve as resolve39 } from "node:path";
27789
28526
  function experimentDir(projectRoot, experimentId) {
27790
- return resolve36(projectRoot, EVAL_DIR2, EXPERIMENTS_DIR, experimentId);
28527
+ return resolve39(projectRoot, EVAL_DIR2, EXPERIMENTS_DIR, experimentId);
27791
28528
  }
27792
28529
  function experimentYamlPath(projectRoot, experimentId) {
27793
- return join25(experimentDir(projectRoot, experimentId), "experiment.yml");
28530
+ return join26(experimentDir(projectRoot, experimentId), "experiment.yml");
27794
28531
  }
27795
28532
  async function loadHarnessSuite(projectRoot, suiteId, suitePath) {
27796
28533
  const candidates = suitePath ? [suitePath] : [
27797
- resolve36(projectRoot, "eval", "suites", suiteId, "suite.yml"),
27798
- resolve36(projectRoot, EVAL_DIR2, "suites", suiteId, "suite.yml")
28534
+ resolve39(projectRoot, "eval", "suites", suiteId, "suite.yml"),
28535
+ resolve39(projectRoot, EVAL_DIR2, "suites", suiteId, "suite.yml")
27799
28536
  ];
27800
28537
  for (const path of candidates) {
27801
- if (!existsSync8(path))
28538
+ if (!existsSync9(path))
27802
28539
  continue;
27803
28540
  try {
27804
- const suite = HarnessSuiteSchema.parse($parse(await readFile36(path, "utf-8")));
28541
+ const suite = HarnessSuiteSchema.parse($parse(await readFile39(path, "utf-8")));
27805
28542
  return ok({ ...suite, path });
27806
28543
  } catch (e) {
27807
28544
  return err(e instanceof Error ? e : new Error(String(e)));
@@ -27811,7 +28548,7 @@ async function loadHarnessSuite(projectRoot, suiteId, suitePath) {
27811
28548
  }
27812
28549
  async function loadExperiment(projectRoot, experimentId) {
27813
28550
  try {
27814
- const raw = await readFile36(experimentYamlPath(projectRoot, experimentId), "utf-8");
28551
+ const raw = await readFile39(experimentYamlPath(projectRoot, experimentId), "utf-8");
27815
28552
  return ok(HarnessExperimentSchema.parse($parse(raw)));
27816
28553
  } catch (e) {
27817
28554
  if (e.code === "ENOENT") {
@@ -27821,10 +28558,10 @@ async function loadExperiment(projectRoot, experimentId) {
27821
28558
  }
27822
28559
  }
27823
28560
  async function listExperiments(projectRoot) {
27824
- const root = resolve36(projectRoot, EVAL_DIR2, EXPERIMENTS_DIR);
27825
- if (!existsSync8(root))
28561
+ const root = resolve39(projectRoot, EVAL_DIR2, EXPERIMENTS_DIR);
28562
+ if (!existsSync9(root))
27826
28563
  return [];
27827
- const ids = await readdir12(root);
28564
+ const ids = await readdir14(root);
27828
28565
  const experiments = [];
27829
28566
  for (const id of ids) {
27830
28567
  const loaded = await loadExperiment(projectRoot, id);
@@ -27900,9 +28637,9 @@ function generateExperimentId(suiteId, now = new Date) {
27900
28637
  return `abl-${date}-${suiteId}-${rand}`;
27901
28638
  }
27902
28639
  async function copyFixture(suitePath, fixtureDir, dest) {
27903
- const source = fixtureDir ? resolve36(dirname12(suitePath), fixtureDir) : join25(dirname12(suitePath), "fixture");
27904
- await mkdir23(dest, { recursive: true });
27905
- if (existsSync8(source)) {
28640
+ const source = fixtureDir ? resolve39(dirname13(suitePath), fixtureDir) : join26(dirname13(suitePath), "fixture");
28641
+ await mkdir25(dest, { recursive: true });
28642
+ if (existsSync9(source)) {
27906
28643
  await cp(source, dest, { recursive: true });
27907
28644
  }
27908
28645
  }
@@ -27923,12 +28660,12 @@ async function startHarnessExperiment(projectRoot, options) {
27923
28660
  suitePath: suite.data.path
27924
28661
  };
27925
28662
  const root = experimentDir(projectRoot, experimentId);
27926
- await mkdir23(root, { recursive: true });
27927
- await writeFile22(experimentYamlPath(projectRoot, experimentId), $stringify(experiment), "utf-8");
27928
- await writeFile22(join25(root, "EXPERIMENT.md"), formatExperimentMarkdown(experiment), "utf-8");
28663
+ await mkdir25(root, { recursive: true });
28664
+ await writeFile24(experimentYamlPath(projectRoot, experimentId), $stringify(experiment), "utf-8");
28665
+ await writeFile24(join26(root, "EXPERIMENT.md"), formatExperimentMarkdown(experiment), "utf-8");
27929
28666
  for (const task of suite.data.tasks) {
27930
28667
  for (const variantId of variants) {
27931
- const runRoot = join25(root, "runs", task.id, variantDirName(variantId));
28668
+ const runRoot = join26(root, "runs", task.id, variantDirName(variantId));
27932
28669
  await copyFixture(suite.data.path, suite.data.fixtureDir, runRoot);
27933
28670
  await writeConfig(runRoot, structuredClone(DEFAULT_CONFIG), true);
27934
28671
  const disabled = variantId === "baseline" ? [] : options.components.filter((id) => variantIdFor(id) === variantId);
@@ -27940,7 +28677,7 @@ async function startHarnessExperiment(projectRoot, options) {
27940
28677
  });
27941
28678
  if (!overlay.success)
27942
28679
  return overlay;
27943
- await writeFile22(join25(runRoot, "TASK.md"), formatTaskCard(task, experimentId, variantId), "utf-8");
28680
+ await writeFile24(join26(runRoot, "TASK.md"), formatTaskCard(task, experimentId, variantId), "utf-8");
27944
28681
  }
27945
28682
  }
27946
28683
  return ok(experiment);
@@ -27974,8 +28711,8 @@ var init_harness_experiment = __esm(() => {
27974
28711
 
27975
28712
  // src/core/evaluation/suite-run.ts
27976
28713
  import { spawnSync as spawnSync2 } from "node:child_process";
27977
- import { existsSync as existsSync9 } from "node:fs";
27978
- import { resolve as resolve37 } from "node:path";
28714
+ import { existsSync as existsSync10 } from "node:fs";
28715
+ import { resolve as resolve40 } from "node:path";
27979
28716
  async function runHarnessSuiteTasks(projectRoot, suiteId, suitePath) {
27980
28717
  const suite = await loadHarnessSuite(projectRoot, suiteId, suitePath);
27981
28718
  if (!suite.success) {
@@ -28035,7 +28772,7 @@ function runTaskCommand(projectRoot, task) {
28035
28772
  if (parts.length === 0) {
28036
28773
  return { ok: false, detail: "Empty testCommand" };
28037
28774
  }
28038
- const bin = parts[0] === "bun" && existsSync9(resolve37(projectRoot, "src/cli/main.ts")) ? "bun" : parts[0];
28775
+ const bin = parts[0] === "bun" && existsSync10(resolve40(projectRoot, "src/cli/main.ts")) ? "bun" : parts[0];
28039
28776
  const args = parts[0] === "bun" ? parts.slice(1) : parts.slice(1);
28040
28777
  const result = spawnSync2(bin, args, {
28041
28778
  cwd: projectRoot,
@@ -28086,11 +28823,11 @@ var init_suite_run = __esm(() => {
28086
28823
  });
28087
28824
 
28088
28825
  // src/core/evaluation/execution-profile.ts
28089
- import { readFile as readFile37 } from "node:fs/promises";
28090
- import { resolve as resolve38 } from "node:path";
28826
+ import { readFile as readFile40 } from "node:fs/promises";
28827
+ import { resolve as resolve41 } from "node:path";
28091
28828
  async function loadExecutionProfile(projectRoot, defaultTarget = "opencode") {
28092
28829
  try {
28093
- const content = await readFile37(resolve38(projectRoot, PROFILE_FILE), "utf-8");
28830
+ const content = await readFile40(resolve41(projectRoot, PROFILE_FILE), "utf-8");
28094
28831
  const data = $parse(content);
28095
28832
  return ExecutionProfileSchema.parse(data);
28096
28833
  } catch {
@@ -28170,14 +28907,14 @@ var init_execution_profile = __esm(() => {
28170
28907
  });
28171
28908
 
28172
28909
  // src/core/evaluation/prompt-diff.ts
28173
- import { readFile as readFile38, readdir as readdir13 } from "node:fs/promises";
28174
- import { join as join26, resolve as resolve39 } from "node:path";
28910
+ import { readFile as readFile41, readdir as readdir15 } from "node:fs/promises";
28911
+ import { join as join27, resolve as resolve42 } from "node:path";
28175
28912
  function normalizeVersion(v) {
28176
28913
  return v.startsWith("v") ? v : `v${v}`;
28177
28914
  }
28178
28915
  async function listPromptFiles(dir) {
28179
28916
  try {
28180
- const entries = await readdir13(dir, { withFileTypes: true });
28917
+ const entries = await readdir15(dir, { withFileTypes: true });
28181
28918
  return entries.filter((e) => e.isFile() && e.name.endsWith(".md")).map((e) => e.name);
28182
28919
  } catch {
28183
28920
  return [];
@@ -28220,30 +28957,30 @@ async function diffPromptVersions(fromVersion, toVersion, options = {}) {
28220
28957
  const fromV = normalizeVersion(fromVersion);
28221
28958
  const toV = normalizeVersion(toVersion);
28222
28959
  const searchRoots = [
28223
- resolve39(options.projectRoot ?? PACKAGE_ROOT, ".agents", "prompts"),
28224
- join26(ROOT_PRESETS_DIR, target, "prompts"),
28225
- join26(ROOT_PRESETS_DIR, "opencode", "prompts")
28960
+ resolve42(options.projectRoot ?? PACKAGE_ROOT, ".agents", "prompts"),
28961
+ join27(ROOT_PRESETS_DIR, target, "prompts"),
28962
+ join27(ROOT_PRESETS_DIR, "opencode", "prompts")
28226
28963
  ];
28227
28964
  let fromDir = "";
28228
28965
  let toDir = "";
28229
28966
  for (const root of searchRoots) {
28230
- const f = join26(root, fromV);
28231
- const t = join26(root, toV);
28967
+ const f = join27(root, fromV);
28968
+ const t = join27(root, toV);
28232
28969
  try {
28233
- await readFile38(join26(f, "orchestrator.md"), "utf-8");
28970
+ await readFile41(join27(f, "orchestrator.md"), "utf-8");
28234
28971
  fromDir = f;
28235
28972
  toDir = t;
28236
28973
  break;
28237
28974
  } catch {}
28238
28975
  }
28239
28976
  if (!fromDir) {
28240
- fromDir = join26(ROOT_PRESETS_DIR, "opencode", "prompts", fromV);
28241
- toDir = join26(ROOT_PRESETS_DIR, "opencode", "prompts", toV);
28977
+ fromDir = join27(ROOT_PRESETS_DIR, "opencode", "prompts", fromV);
28978
+ toDir = join27(ROOT_PRESETS_DIR, "opencode", "prompts", toV);
28242
28979
  } else {
28243
28980
  try {
28244
- await readFile38(join26(toDir, "orchestrator.md"), "utf-8");
28981
+ await readFile41(join27(toDir, "orchestrator.md"), "utf-8");
28245
28982
  } catch {
28246
- toDir = join26(ROOT_PRESETS_DIR, "opencode", "prompts", toV);
28983
+ toDir = join27(ROOT_PRESETS_DIR, "opencode", "prompts", toV);
28247
28984
  }
28248
28985
  }
28249
28986
  const fromFiles = await listPromptFiles(fromDir);
@@ -28261,12 +28998,12 @@ async function diffPromptVersions(fromVersion, toVersion, options = {}) {
28261
28998
  let oldText = "";
28262
28999
  let newText = "";
28263
29000
  try {
28264
- oldText = await readFile38(join26(fromDir, name), "utf-8");
29001
+ oldText = await readFile41(join27(fromDir, name), "utf-8");
28265
29002
  } catch {
28266
29003
  oldText = "";
28267
29004
  }
28268
29005
  try {
28269
- newText = await readFile38(join26(toDir, name), "utf-8");
29006
+ newText = await readFile41(join27(toDir, name), "utf-8");
28270
29007
  } catch {
28271
29008
  newText = "";
28272
29009
  }
@@ -28306,12 +29043,12 @@ var init_prompt_diff = __esm(() => {
28306
29043
 
28307
29044
  // src/core/evaluation/regression-checklist.ts
28308
29045
  import { execFileSync as execFileSync4 } from "node:child_process";
28309
- import { mkdir as mkdir24, readFile as readFile39, writeFile as writeFile23 } from "node:fs/promises";
28310
- import { dirname as dirname13, resolve as resolve40 } from "node:path";
29046
+ import { mkdir as mkdir26, readFile as readFile42, writeFile as writeFile25 } from "node:fs/promises";
29047
+ import { dirname as dirname14, resolve as resolve43 } from "node:path";
28311
29048
  async function loadRegressionChecklist() {
28312
29049
  try {
28313
- const path = resolve40(ROOT_PRESETS_DIR, "templates", "regression-checklist.yml");
28314
- const content = await readFile39(path, "utf-8");
29050
+ const path = resolve43(ROOT_PRESETS_DIR, "templates", "regression-checklist.yml");
29051
+ const content = await readFile42(path, "utf-8");
28315
29052
  const data = $parse(content);
28316
29053
  return data.checks ?? [];
28317
29054
  } catch {
@@ -28366,9 +29103,9 @@ async function runRegressionChecklist(projectRoot, options = {}) {
28366
29103
  checks,
28367
29104
  timestamp: new Date().toISOString()
28368
29105
  };
28369
- const outPath = resolve40(projectRoot, ".codeconductor/evaluation/regression-last.json");
28370
- await mkdir24(dirname13(outPath), { recursive: true });
28371
- await writeFile23(outPath, JSON.stringify(report, null, 2), "utf-8");
29106
+ const outPath = resolve43(projectRoot, ".codeconductor/evaluation/regression-last.json");
29107
+ await mkdir26(dirname14(outPath), { recursive: true });
29108
+ await writeFile25(outPath, JSON.stringify(report, null, 2), "utf-8");
28372
29109
  return ok(report);
28373
29110
  } catch (e) {
28374
29111
  return err(e instanceof Error ? e : new Error(String(e)));
@@ -28410,8 +29147,8 @@ var init_model_comparison = __esm(() => {
28410
29147
  });
28411
29148
 
28412
29149
  // src/core/evaluation/cost-quality-matrix.ts
28413
- import { writeFile as writeFile24 } from "node:fs/promises";
28414
- import { resolve as resolve41 } from "node:path";
29150
+ import { writeFile as writeFile26 } from "node:fs/promises";
29151
+ import { resolve as resolve44 } from "node:path";
28415
29152
  async function buildCostQualityMatrix(projectRoot, outcomes) {
28416
29153
  const agg = aggregateOutcomes(outcomes);
28417
29154
  const rows = Object.entries(agg.byModel).map(([model, entry]) => {
@@ -28431,7 +29168,7 @@ async function buildCostQualityMatrix(projectRoot, outcomes) {
28431
29168
  rows
28432
29169
  };
28433
29170
  const dir = await ensureEvaluationDir(projectRoot);
28434
- await writeFile24(resolve41(dir, "matrix.yml"), $stringify(matrix), "utf-8");
29171
+ await writeFile26(resolve44(dir, "matrix.yml"), $stringify(matrix), "utf-8");
28435
29172
  return matrix;
28436
29173
  }
28437
29174
  function formatMatrixMarkdown(matrix) {
@@ -28455,8 +29192,8 @@ var init_cost_quality_matrix = __esm(() => {
28455
29192
  });
28456
29193
 
28457
29194
  // src/core/evaluation/ablation-report.ts
28458
- import { mkdir as mkdir25, writeFile as writeFile25 } from "node:fs/promises";
28459
- import { resolve as resolve42 } from "node:path";
29195
+ import { mkdir as mkdir27, writeFile as writeFile27 } from "node:fs/promises";
29196
+ import { resolve as resolve45 } from "node:path";
28460
29197
  function isPass(o) {
28461
29198
  return o.verdict === "PASS" || o.status === "pass";
28462
29199
  }
@@ -28624,10 +29361,10 @@ function formatAblationMarkdown(report) {
28624
29361
  `);
28625
29362
  }
28626
29363
  async function persistAblationReport(projectRoot, markdown) {
28627
- const dir = resolve42(projectRoot, EVAL_DIR2);
28628
- await mkdir25(dir, { recursive: true });
28629
- const path = resolve42(dir, "ablation-last.md");
28630
- await writeFile25(path, markdown, "utf-8");
29364
+ const dir = resolve45(projectRoot, EVAL_DIR2);
29365
+ await mkdir27(dir, { recursive: true });
29366
+ const path = resolve45(dir, "ablation-last.md");
29367
+ await writeFile27(path, markdown, "utf-8");
28631
29368
  return path;
28632
29369
  }
28633
29370
  var SCORE_THRESHOLD = 0.1, PASS_RATE_THRESHOLD = 0.05;
@@ -28641,8 +29378,8 @@ var exports_scorecard_command = {};
28641
29378
  __export(exports_scorecard_command, {
28642
29379
  scorecardCommand: () => scorecardCommand
28643
29380
  });
28644
- import { readFile as readFile40 } from "node:fs/promises";
28645
- import { resolve as resolve43 } from "node:path";
29381
+ import { readFile as readFile43 } from "node:fs/promises";
29382
+ import { resolve as resolve46 } from "node:path";
28646
29383
  function contractVersion() {
28647
29384
  return package_default.version;
28648
29385
  }
@@ -28703,7 +29440,7 @@ async function handleCreate(projectRoot, options) {
28703
29440
  if (backlog.success && options.taskId) {
28704
29441
  const item = backlog.data.items.find((i) => i.id === options.taskId);
28705
29442
  if (item) {
28706
- scopeFiles = item.scope.split(/[,;]/).map((s) => s.trim()).filter(Boolean);
29443
+ scopeFiles = parseScopeFiles(item.scope);
28707
29444
  }
28708
29445
  }
28709
29446
  let hints = collectScorecardSignals(projectRoot, scopeFiles);
@@ -28787,7 +29524,7 @@ async function handleRecord(projectRoot, options) {
28787
29524
  const variantId = options.variantId ?? overlay?.variantId;
28788
29525
  const suiteTaskId = options.suiteTaskId;
28789
29526
  const disabled = overlay?.disabledComponents ?? (variantId ? parseVariantId(variantId) : undefined);
28790
- const fingerprint = experimentId || variantId ? harnessFingerprint(disabled ?? [], overlay?.contractVersion ?? contractVersion(), overlay?.ccepProfile ?? "feature") : undefined;
29527
+ const fingerprint2 = experimentId || variantId ? harnessFingerprint(disabled ?? [], overlay?.contractVersion ?? contractVersion(), overlay?.ccepProfile ?? "feature") : undefined;
28791
29528
  const outcome = {
28792
29529
  id: generateEvalId("out"),
28793
29530
  taskId,
@@ -28802,10 +29539,17 @@ async function handleRecord(projectRoot, options) {
28802
29539
  costUsd: options.costUsd,
28803
29540
  tokensIn: options.tokens,
28804
29541
  durationMs: options.durationMs,
29542
+ delivery: options.deliveryRoute ? {
29543
+ route: options.deliveryRoute,
29544
+ contextBytes: options.contextBytes,
29545
+ handoffs: options.handoffs,
29546
+ checks: options.checks,
29547
+ tokenUsage: options.tokens !== undefined ? { status: "known", total: options.tokens } : { status: "unknown" }
29548
+ } : undefined,
28805
29549
  experimentId,
28806
29550
  variantId,
28807
29551
  suiteTaskId,
28808
- harnessFingerprint: fingerprint,
29552
+ harnessFingerprint: fingerprint2,
28809
29553
  disabledComponents: disabled && disabled.length > 0 ? [...disabled] : disabled ? [] : undefined,
28810
29554
  status: options.verdict === "PASS" ? "pass" : options.verdict === "REJECT" ? "reject" : undefined
28811
29555
  };
@@ -28923,13 +29667,13 @@ async function handleCompareModels(projectRoot, options) {
28923
29667
  outcomes = outcomes.filter((o) => options.modelsFilter.includes(o.model));
28924
29668
  }
28925
29669
  const markdown = generateModelComparisonMarkdown(outcomes, options.modelsFilter);
28926
- const templatePath = resolve43(projectRoot, ".codeconductor/evaluation/model-comparison-last.md");
29670
+ const templatePath = resolve46(projectRoot, ".codeconductor/evaluation/model-comparison-last.md");
28927
29671
  try {
28928
- await readFile40(templatePath);
29672
+ await readFile43(templatePath);
28929
29673
  } catch {}
28930
- const { writeFile: writeFile26, mkdir: mkdir26 } = await import("node:fs/promises");
28931
- await mkdir26(resolve43(projectRoot, ".codeconductor/evaluation"), { recursive: true });
28932
- await writeFile26(templatePath, markdown, "utf-8");
29674
+ const { writeFile: writeFile28, mkdir: mkdir28 } = await import("node:fs/promises");
29675
+ await mkdir28(resolve46(projectRoot, ".codeconductor/evaluation"), { recursive: true });
29676
+ await writeFile28(templatePath, markdown, "utf-8");
28933
29677
  return {
28934
29678
  code: 0,
28935
29679
  data: {
@@ -30398,7 +31142,7 @@ var exports_seo_audit_command = {};
30398
31142
  __export(exports_seo_audit_command, {
30399
31143
  seoAuditCommand: () => seoAuditCommand
30400
31144
  });
30401
- import { join as join27 } from "node:path";
31145
+ import { join as join28 } from "node:path";
30402
31146
  async function seoAuditCommand(options) {
30403
31147
  const { url, sitemap, format, failOn, delay: delay2, output, followRedirects, force } = options;
30404
31148
  if (!url && !sitemap) {
@@ -30411,7 +31155,7 @@ async function seoAuditCommand(options) {
30411
31155
  }
30412
31156
  };
30413
31157
  }
30414
- const defaultMarkdownPath = output === undefined && format === "markdown" ? join27("seo-reports", `audit-report-${new Date().toISOString().replace(/[:.]/g, "-").slice(0, 19)}.md`) : undefined;
31158
+ const defaultMarkdownPath = output === undefined && format === "markdown" ? join28("seo-reports", `audit-report-${new Date().toISOString().replace(/[:.]/g, "-").slice(0, 19)}.md`) : undefined;
30415
31159
  const outputPathToWrite = output ?? defaultMarkdownPath;
30416
31160
  if (outputPathToWrite !== undefined) {
30417
31161
  const preflightError = await preflightContainedOutput(options.projectRoot, outputPathToWrite, { force });
@@ -30680,6 +31424,7 @@ __export(exports_onboarding_command, {
30680
31424
  onboardingCommand: () => onboardingCommand
30681
31425
  });
30682
31426
  async function onboardingCommand(projectRoot) {
31427
+ const bin = resolveCliBin();
30683
31428
  const [config, profile, state] = await Promise.all([
30684
31429
  loadConfig(projectRoot),
30685
31430
  detectProject(projectRoot),
@@ -30703,18 +31448,18 @@ async function onboardingCommand(projectRoot) {
30703
31448
  "",
30704
31449
  "Get started:",
30705
31450
  " 1. Inspect what will be installed",
30706
- " cc setup --dry-run",
31451
+ ` ${bin} setup --dry-run`,
30707
31452
  " 2. Configure the harness",
30708
- " cc setup",
31453
+ ` ${bin} setup`,
30709
31454
  " 3. Verify the installation",
30710
- " cc doctor",
31455
+ ` ${bin} doctor`,
30711
31456
  "",
30712
31457
  `Detected project: ${[...profile.runtimes, ...profile.frameworks].join(", ") || "unknown"}`,
30713
31458
  `Recommended preset: ${recommendation.stack}`,
30714
31459
  "",
30715
31460
  "Documentation:",
30716
- " cc help setup",
30717
- " cc docs getting-started"
31461
+ ` ${bin} help setup`,
31462
+ ` ${bin} docs getting-started`
30718
31463
  ].join(`
30719
31464
  `)
30720
31465
  }
@@ -30737,12 +31482,12 @@ async function onboardingCommand(projectRoot) {
30737
31482
  ` locale ${config.data.defaults.locale}`,
30738
31483
  "",
30739
31484
  "Run:",
30740
- " cc status",
30741
- " cc doctor",
30742
- " cc update --check",
31485
+ ` ${bin} status`,
31486
+ ` ${bin} doctor`,
31487
+ ` ${bin} update --check`,
30743
31488
  "",
30744
31489
  "Other commands:",
30745
- " cc help"
31490
+ ` ${bin} help`
30746
31491
  ].join(`
30747
31492
  `)
30748
31493
  }
@@ -30753,6 +31498,7 @@ var init_onboarding_command = __esm(() => {
30753
31498
  init_config_loader();
30754
31499
  init_project_detector();
30755
31500
  init_installation_state();
31501
+ init_cli_bin();
30756
31502
  });
30757
31503
 
30758
31504
  // src/cli/execute.ts
@@ -30765,36 +31511,38 @@ init_runner_target();
30765
31511
 
30766
31512
  // src/cli/command-registry.ts
30767
31513
  init_package();
31514
+ init_cli_bin();
30768
31515
  var COMMANDS = [
30769
- { name: "setup", group: "getting-started", summary: "Configure and install CodeConductor.", usage: ["cc setup [--target <target>] [--locale en|es] [--yes] [--dry-run]"] },
30770
- { name: "detect", group: "getting-started", summary: "Inspect the project stack and recommended presets.", usage: ["cc detect"] },
30771
- { name: "init", group: "getting-started", summary: "Initialize low-level CodeConductor configuration.", usage: ["cc init [--locale en|es]"] },
30772
- { name: "install", group: "getting-started", summary: "Install harness components.", usage: ["cc install preset --target <target>"], options: ["--target opencode|claude|codex|gemini|cursor|agy|pi|all"], subcommands: [
30773
- { name: "preset", group: "getting-started", summary: "Install agents, prompts, skills, and commands.", usage: ["cc install preset --target <target> [--locale en|es]"] },
30774
- { name: "council", group: "getting-started", summary: "Install generated council files.", usage: ["cc install council --target <target>"] },
30775
- { name: "lsp", group: "getting-started", summary: "Install supported language servers.", usage: ["cc install lsp --target <target> [--lang typescript,python]"] }
31516
+ { name: "setup", group: "getting-started", summary: "Configure and install CodeConductor.", usage: ["cc-codeconductor setup [--target <target>] [--locale en|es] [--yes] [--dry-run]"] },
31517
+ { name: "detect", group: "getting-started", summary: "Inspect the project stack and recommended presets.", usage: ["cc-codeconductor detect"] },
31518
+ { name: "init", group: "getting-started", summary: "Initialize low-level CodeConductor configuration.", usage: ["cc-codeconductor init [--locale en|es]"] },
31519
+ { name: "install", group: "getting-started", summary: "Install harness components.", usage: ["cc-codeconductor install preset --target <target>"], options: ["--target opencode|claude|codex|gemini|cursor|agy|pi|all"], subcommands: [
31520
+ { name: "preset", group: "getting-started", summary: "Install agents, prompts, skills, and commands.", usage: ["cc-codeconductor install preset --target <target> [--locale en|es]"] },
31521
+ { name: "council", group: "getting-started", summary: "Install generated council files.", usage: ["cc-codeconductor install council --target <target>"] },
31522
+ { name: "lsp", group: "getting-started", summary: "Install supported language servers.", usage: ["cc-codeconductor install lsp --target <target> [--lang typescript,python]"] }
30776
31523
  ] },
30777
- { name: "version", group: "maintenance", summary: "Show CLI and project harness versions.", usage: ["cc version [--json]"] },
30778
- { name: "status", group: "maintenance", summary: "Show installed harness state.", usage: ["cc status [--json]"] },
30779
- { name: "doctor", group: "maintenance", summary: "Diagnose the installation.", usage: ["cc doctor"] },
30780
- { name: "update", group: "maintenance", summary: "Safely reconcile managed harness files.", usage: ["cc update [--dry-run] [--force]"] },
30781
- { name: "migrate", group: "maintenance", summary: "Apply compatibility migrations.", usage: ["cc migrate [--dry-run]"] },
30782
- { name: "docs", group: "maintenance", summary: "Read bundled command documentation.", usage: ["cc docs [command]"] },
30783
- { name: "completion", group: "maintenance", summary: "Generate shell completion.", usage: ["cc completion <bash|zsh|fish|powershell>"] },
30784
- { name: "hook", group: "maintenance", summary: "Run installed agent hooks.", usage: ["cc hook <pre-tool|post-tool|session-start>"] },
30785
- { name: "cc-help", group: "maintenance", summary: "Show a target preset inventory.", usage: ["cc cc-help --target <target>"] },
30786
- { name: "ask", group: "workflow", summary: "Recommend a slash-command workflow.", usage: ['cc ask "problem"'] },
30787
- { name: "goal", aliases: ["cc-goal"], group: "workflow", summary: "Plan a goal into dependent tasks.", usage: ['cc goal "objective"'] },
30788
- { name: "ingest", group: "workflow", summary: "Ingest repository knowledge into the product graph.", usage: ["cc ingest"] },
30789
- { name: "product", group: "workflow", summary: "Explore the product graph and memory.", usage: ["cc product <subcommand>"] },
30790
- { name: "ccep", group: "workflow", summary: "Run CCEP contract workflows.", usage: ["cc ccep <subcommand>"] },
30791
- { name: "openspec", group: "workflow", summary: "Run the OpenSpec delivery loop.", usage: ["cc openspec <subcommand>"] },
30792
- { name: "scorecard", group: "workflow", summary: "Record and aggregate outcomes.", usage: ["cc scorecard <subcommand>"] },
30793
- { name: "orchestrate", group: "workflow", summary: "Run goal execution orchestration.", usage: ["cc orchestrate <subcommand>"] },
30794
- { name: "impact", group: "workflow", summary: "Analyze change impact.", usage: ["cc impact [--files <paths>]"] },
30795
- { name: "verify", group: "workflow", summary: "Verify task completion with evidence.", usage: ["cc verify --task <id>"] },
30796
- { name: "seo", group: "tool", summary: "Audit SEO and generate llms.txt.", usage: ["cc seo audit --url <url>"] },
30797
- { name: "debt-harvest", aliases: ["harvest"], group: "tool", summary: "Scan source files for deferred debt.", usage: ["cc debt-harvest"] }
31524
+ { name: "version", group: "maintenance", summary: "Show CLI and project harness versions.", usage: ["cc-codeconductor version [--json]"] },
31525
+ { name: "status", group: "maintenance", summary: "Show installed harness state.", usage: ["cc-codeconductor status [--json]"] },
31526
+ { name: "doctor", group: "maintenance", summary: "Diagnose the installation.", usage: ["cc-codeconductor doctor"] },
31527
+ { name: "update", group: "maintenance", summary: "Safely reconcile managed harness files.", usage: ["cc-codeconductor update [--dry-run] [--force]"] },
31528
+ { name: "migrate", group: "maintenance", summary: "Apply compatibility migrations.", usage: ["cc-codeconductor migrate [--dry-run]"] },
31529
+ { name: "docs", group: "maintenance", summary: "Read bundled command documentation.", usage: ["cc-codeconductor docs [command]"] },
31530
+ { name: "completion", group: "maintenance", summary: "Generate shell completion.", usage: ["cc-codeconductor completion <bash|zsh|fish|powershell>"] },
31531
+ { name: "hook", group: "maintenance", summary: "Run installed agent hooks.", usage: ["cc-codeconductor hook <pre-tool|post-tool|session-start>"] },
31532
+ { name: "cc-help", group: "maintenance", summary: "Show a target preset inventory.", usage: ["cc-codeconductor cc-help --target <target>"] },
31533
+ { name: "ask", group: "workflow", summary: "Recommend a slash-command workflow.", usage: ['cc-codeconductor ask "problem"'] },
31534
+ { name: "goal", aliases: ["cc-goal"], group: "workflow", summary: "Plan a goal into dependent tasks.", usage: ['cc-codeconductor goal "objective"'] },
31535
+ { name: "ingest", group: "workflow", summary: "Ingest repository knowledge into the product graph.", usage: ["cc-codeconductor ingest"] },
31536
+ { name: "product", group: "workflow", summary: "Explore the product graph and memory.", usage: ["cc-codeconductor product <subcommand>"] },
31537
+ { name: "ccep", group: "workflow", summary: "Run CCEP contract workflows.", usage: ["cc-codeconductor ccep <subcommand>"] },
31538
+ { name: "openspec", group: "workflow", summary: "Run the OpenSpec delivery loop.", usage: ["cc-codeconductor openspec <subcommand>"] },
31539
+ { name: "scorecard", group: "workflow", summary: "Record and aggregate outcomes.", usage: ["cc-codeconductor scorecard <subcommand>"] },
31540
+ { name: "orchestrate", group: "workflow", summary: "Run goal execution orchestration.", usage: ["cc-codeconductor orchestrate <subcommand>"] },
31541
+ { name: "impact", group: "workflow", summary: "Analyze change impact.", usage: ["cc-codeconductor impact [--files <paths>]"] },
31542
+ { name: "verify", group: "workflow", summary: "Verify task completion with evidence.", usage: ["cc-codeconductor verify --task <id>"] },
31543
+ { name: "rdd", group: "workflow", summary: "Capture and validate Receipt-Driven Development evidence.", usage: ["cc-codeconductor rdd capture --task <id> [--phase red|green|review]", "cc-codeconductor rdd verify --receipt <id>", "cc-codeconductor rdd status [--task <id>]", "cc-codeconductor rdd git-check", "cc-codeconductor rdd install-hooks"] },
31544
+ { name: "seo", group: "tool", summary: "Audit SEO and generate llms.txt.", usage: ["cc-codeconductor seo audit --url <url>"] },
31545
+ { name: "debt-harvest", aliases: ["harvest"], group: "tool", summary: "Scan source files for deferred debt.", usage: ["cc-codeconductor debt-harvest"] }
30798
31546
  ];
30799
31547
  var GROUP_LABELS = {
30800
31548
  "getting-started": "GETTING STARTED",
@@ -30806,7 +31554,7 @@ function findCommand(name, subcommand) {
30806
31554
  const command = COMMANDS.find((candidate) => candidate.name === name || candidate.aliases?.includes(name ?? ""));
30807
31555
  return subcommand ? command?.subcommands?.find((candidate) => candidate.name === subcommand) : command;
30808
31556
  }
30809
- function renderHelp(command, subcommand, all = false) {
31557
+ function renderHelp(command, subcommand, all = false, bin = resolveCliBin()) {
30810
31558
  const definition = findCommand(command, subcommand);
30811
31559
  if (definition) {
30812
31560
  return [
@@ -30815,11 +31563,11 @@ function renderHelp(command, subcommand, all = false) {
30815
31563
  definition.summary,
30816
31564
  "",
30817
31565
  "Usage:",
30818
- ...definition.usage.map((usage) => ` ${usage}`),
31566
+ ...definition.usage.map((usage) => ` ${formatUsage(usage, bin)}`),
30819
31567
  ...definition.options?.length ? ["", "Options:", ...definition.options.map((option) => ` ${option}`)] : [],
30820
31568
  ...definition.subcommands?.length ? ["", "Subcommands:", ...definition.subcommands.map((item) => ` ${item.name.padEnd(12)} ${item.summary}`)] : [],
30821
31569
  "",
30822
- "Run `cc help --all` for every command."
31570
+ `Run \`${bin} help --all\` for every command.`
30823
31571
  ].join(`
30824
31572
  `);
30825
31573
  }
@@ -30830,14 +31578,14 @@ function renderHelp(command, subcommand, all = false) {
30830
31578
  ]);
30831
31579
  const details = all ? COMMANDS.flatMap((item) => [
30832
31580
  `## ${item.name}`,
30833
- ...item.usage.map((usage) => ` ${usage}`),
31581
+ ...item.usage.map((usage) => ` ${formatUsage(usage, bin)}`),
30834
31582
  ...item.subcommands?.map((sub) => ` ${item.name} ${sub.name} — ${sub.summary}`) ?? [],
30835
31583
  ""
30836
31584
  ]) : [];
30837
- return [`CodeConductor CLI v${package_default.version}`, "", "Usage: cc <command> [options]", "", ...grouped, ...details, "Run `cc help <command>` for details."].join(`
31585
+ return [`CodeConductor CLI v${package_default.version}`, "", `Usage: ${bin} <command> [options]`, "", ...grouped, ...details, `Run \`${bin} help <command>\` for details.`].join(`
30838
31586
  `);
30839
31587
  }
30840
- function renderDocs(command) {
31588
+ function renderDocs(command, bin = "cc-codeconductor") {
30841
31589
  const groupAliases = {
30842
31590
  "getting-started": "getting-started",
30843
31591
  maintenance: "maintenance",
@@ -30853,7 +31601,7 @@ function renderDocs(command) {
30853
31601
  item.summary,
30854
31602
  "",
30855
31603
  "```text",
30856
- ...item.usage,
31604
+ ...item.usage.map((usage) => formatUsage(usage, bin)),
30857
31605
  "```",
30858
31606
  ""
30859
31607
  ])].join(`
@@ -30864,15 +31612,20 @@ function renderCompletion(shell) {
30864
31612
  const targets = "opencode claude codex gemini cursor agy pi all";
30865
31613
  if (shell === "bash")
30866
31614
  return `_cc(){ local cur="${"${COMP_WORDS[COMP_CWORD]}"}"; local prev="${"${COMP_WORDS[COMP_CWORD-1]}"}"; if [[ "$prev" == "--target" ]]; then COMPREPLY=( $(compgen -W "${targets}" -- "$cur") ); else COMPREPLY=( $(compgen -W "${names}" -- "$cur") ); fi; }
30867
- complete -F _cc cc codeconductor`;
31615
+ complete -F _cc cc-codeconductor codeconductor cc`;
30868
31616
  if (shell === "zsh")
30869
- return `#compdef cc codeconductor
31617
+ return `#compdef cc-codeconductor codeconductor cc
30870
31618
  _arguments '1:command:(${names})' '--target[target]:target:(${targets})'`;
30871
31619
  if (shell === "fish")
30872
- return [...COMMANDS.map((item) => `complete -c cc -a ${item.name} -d '${item.summary}'`), `complete -c cc -l target -a '${targets}'`].join(`
31620
+ return [
31621
+ ...["cc-codeconductor", "codeconductor", "cc"].flatMap((bin) => [
31622
+ ...COMMANDS.map((item) => `complete -c ${bin} -a ${item.name} -d '${item.summary}'`),
31623
+ `complete -c ${bin} -l target -a '${targets}'`
31624
+ ])
31625
+ ].join(`
30873
31626
  `);
30874
31627
  if (shell === "powershell")
30875
- return `Register-ArgumentCompleter -CommandName cc,codeconductor -ScriptBlock { param($wordToComplete,$commandAst,$cursorPosition) $values = if ($commandAst.ToString() -match '--target\\s+$') { '${targets}' } else { '${names}' }; $values.Split(' ') | Where-Object { $_ -like "$wordToComplete*" } }`;
31628
+ return `Register-ArgumentCompleter -CommandName cc-codeconductor,codeconductor,cc -ScriptBlock { param($wordToComplete,$commandAst,$cursorPosition) $values = if ($commandAst.ToString() -match '--target\\s+$') { '${targets}' } else { '${names}' }; $values.Split(' ') | Where-Object { $_ -like "$wordToComplete*" } }`;
30876
31629
  return null;
30877
31630
  }
30878
31631
 
@@ -31266,6 +32019,24 @@ async function routeCommand(args, projectRoot) {
31266
32019
  allowCompileCheck: options["allow-compile-check"] === true || options["allow-compile-check"] === "true"
31267
32020
  });
31268
32021
  }
32022
+ case "rdd": {
32023
+ const validSubs = ["capture", "verify", "status", "git-check", "install-hooks"];
32024
+ if (!subcommand || !validSubs.includes(subcommand)) {
32025
+ return unknownSubcommand("rdd", subcommand ?? "", [...validSubs]);
32026
+ }
32027
+ const { rddCommand: rddCommand2 } = await Promise.resolve().then(() => (init_rdd_command(), exports_rdd_command));
32028
+ const paths = typeof options.paths === "string" ? options.paths.split(",").map((path) => path.trim()).filter(Boolean) : undefined;
32029
+ return rddCommand2({
32030
+ subcommand,
32031
+ projectRoot,
32032
+ taskId: options.task ?? args.rest?.[0],
32033
+ receiptId: options.receipt,
32034
+ phase: options.phase,
32035
+ paths,
32036
+ outcome: options.outcome,
32037
+ command: options.command
32038
+ });
32039
+ }
31269
32040
  case "ccep": {
31270
32041
  const validSubs = ["parse", "profile", "resolve", "compile", "validate", "evaluate", "consensus", "taskcard"];
31271
32042
  if (subcommand && !validSubs.includes(subcommand)) {
@@ -31304,6 +32075,7 @@ async function routeCommand(args, projectRoot) {
31304
32075
  "start",
31305
32076
  "done",
31306
32077
  "block",
32078
+ "unblock",
31307
32079
  "archive"
31308
32080
  ];
31309
32081
  let openspecSub = "validate";
@@ -31326,6 +32098,19 @@ async function routeCommand(args, projectRoot) {
31326
32098
  output: flags.output
31327
32099
  });
31328
32100
  }
32101
+ case "odd": {
32102
+ const validSubs = ["create", "read", "reconcile"];
32103
+ if (!subcommand || !validSubs.includes(subcommand)) {
32104
+ return unknownSubcommand(command, subcommand ?? "", validSubs);
32105
+ }
32106
+ const { oddCommand: oddCommand2 } = await Promise.resolve().then(() => (init_odd_command(), exports_odd_command));
32107
+ return oddCommand2({
32108
+ subcommand,
32109
+ projectRoot,
32110
+ input: options.input,
32111
+ id: options.id ?? args.rest?.[0]
32112
+ });
32113
+ }
31329
32114
  case "hook": {
31330
32115
  const validHookEvents = ["pre-tool", "post-tool", "session-start"];
31331
32116
  if (subcommand && !validHookEvents.includes(subcommand)) {
@@ -31389,6 +32174,10 @@ async function routeCommand(args, projectRoot) {
31389
32174
  costUsd: options.cost ? parseFloat(String(options.cost)) : undefined,
31390
32175
  tokens: options.tokens ? parseInt(String(options.tokens), 10) : undefined,
31391
32176
  durationMs: options.duration ? parseInt(String(options.duration), 10) : undefined,
32177
+ deliveryRoute: options.route,
32178
+ contextBytes: options["context-bytes"] ? parseInt(String(options["context-bytes"]), 10) : undefined,
32179
+ handoffs: options.handoffs ? parseInt(String(options.handoffs), 10) : undefined,
32180
+ checks: typeof options.checks === "string" ? options.checks.split(",").map((check) => check.trim()).filter(Boolean) : undefined,
31392
32181
  verdict: options.verdict,
31393
32182
  weightedScore: options.score ? parseFloat(String(options.score)) : undefined,
31394
32183
  source: options.source,