cc-codeconductor 1.4.1 → 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 (40) 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 +996 -251
  6. package/dist/library.js +267 -26
  7. package/dist/validation/schemas.d.ts +521 -26
  8. package/docs/generated/cli.md +12 -0
  9. package/package.json +1 -1
  10. package/presets/agy/AGENTS.md +6 -0
  11. package/presets/agy/workflows/cc-handoff.md +2 -1
  12. package/presets/agy/workflows/cc-odd.md +15 -0
  13. package/presets/claude/CLAUDE.md +6 -0
  14. package/presets/claude/commands/cc/handoff.md +2 -1
  15. package/presets/claude/commands/cc/odd.md +15 -0
  16. package/presets/codex/AGENTS.md +6 -0
  17. package/presets/codex/skills/cc-handoff/SKILL.md +3 -1
  18. package/presets/codex/skills/cc-odd/SKILL.md +25 -0
  19. package/presets/codex/skills/cc-openspec/SKILL.md +4 -0
  20. package/presets/codex/skills/cc-spec-mutation/SKILL.md +5 -0
  21. package/presets/codex/skills/cc-tdd-cycle/SKILL.md +8 -0
  22. package/presets/cursor/AGENTS.md +6 -0
  23. package/presets/cursor/commands/cc/handoff.md +3 -1
  24. package/presets/cursor/commands/cc/odd.md +20 -0
  25. package/presets/cursor/commands/cc/openspec.md +4 -0
  26. package/presets/cursor/commands/cc/spec-mutation.md +5 -0
  27. package/presets/cursor/commands/cc/tdd-cycle.md +8 -0
  28. package/presets/gemini/GEMINI.md +6 -0
  29. package/presets/gemini/commands/cc/handoff.toml +3 -1
  30. package/presets/gemini/commands/cc/odd.toml +20 -0
  31. package/presets/gemini/commands/cc/openspec.toml +4 -0
  32. package/presets/gemini/commands/cc/spec-mutation.toml +5 -0
  33. package/presets/gemini/commands/cc/tdd-cycle.toml +8 -0
  34. package/presets/opencode/agents/implementer.md +2 -0
  35. package/presets/opencode/agents/reviewer.md +2 -0
  36. package/presets/opencode/agents/tester.md +2 -0
  37. package/presets/opencode/commands/cc-handoff.md +2 -1
  38. package/presets/opencode/commands/cc-odd.md +15 -0
  39. package/presets/pi/AGENTS.md +6 -0
  40. 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.1",
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",
@@ -11206,6 +11206,11 @@ __export(exports_schemas, {
11206
11206
  CouncilVerdictInputSchema: () => CouncilVerdictInputSchema,
11207
11207
  CouncilVerdictSchema: () => CouncilVerdictSchema,
11208
11208
  DecisionSchema: () => DecisionSchema,
11209
+ DeliveryLedgerRequestSchema: () => DeliveryLedgerRequestSchema,
11210
+ DeliveryLedgerSchema: () => DeliveryLedgerSchema,
11211
+ DeliveryLedgerTaskSchema: () => DeliveryLedgerTaskSchema,
11212
+ DeliveryRouteSchema: () => DeliveryRouteSchema,
11213
+ DeliveryTelemetrySchema: () => DeliveryTelemetrySchema,
11209
11214
  EvaluationIndexSchema: () => EvaluationIndexSchema,
11210
11215
  EvidenceSchema: () => EvidenceSchema,
11211
11216
  ExecutionContextSchema: () => ExecutionContextSchema,
@@ -11270,6 +11275,7 @@ __export(exports_schemas, {
11270
11275
  TaskOutcomeSourceSchema: () => TaskOutcomeSourceSchema,
11271
11276
  TaskOutcomeStatusSchema: () => TaskOutcomeStatusSchema,
11272
11277
  TechnicalPlanOutputSchema: () => TechnicalPlanOutputSchema,
11278
+ TokenUsageSchema: () => TokenUsageSchema,
11273
11279
  ToolProviderNamesSchema: () => ToolProviderNamesSchema,
11274
11280
  VerificationReportSchema: () => VerificationReportSchema,
11275
11281
  WorkflowCommandSchema: () => WorkflowCommandSchema,
@@ -11433,7 +11439,7 @@ function validateProductEvent(data) {
11433
11439
  function validateSkillsRegistry(data) {
11434
11440
  return SkillsRegistrySchema.parse(data);
11435
11441
  }
11436
- 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;
11437
11443
  var init_schemas = __esm(() => {
11438
11444
  init_zod();
11439
11445
  init_runner_target();
@@ -11598,7 +11604,8 @@ var init_schemas = __esm(() => {
11598
11604
  complianceVeto: exports_external.boolean().optional(),
11599
11605
  confidence: exports_external.number().min(0).max(1),
11600
11606
  findings: exports_external.array(CouncilFindingSchema),
11601
- summary: exports_external.string()
11607
+ summary: exports_external.string(),
11608
+ candidateHash: exports_external.string().min(1).optional()
11602
11609
  });
11603
11610
  ConsensusConfigSchema = exports_external.object({
11604
11611
  algorithm: exports_external.enum(["majority", "unanimous"]),
@@ -11606,7 +11613,8 @@ var init_schemas = __esm(() => {
11606
11613
  allowComplianceVeto: exports_external.boolean().optional(),
11607
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(),
11608
11615
  quorum: exports_external.number().int().positive().optional(),
11609
- 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()
11610
11618
  }).refine((config) => config.algorithm !== "unanimous" || config.expectedAgentIds !== undefined, {
11611
11619
  message: "unanimous consensus requires a non-empty expectedAgentIds roster",
11612
11620
  path: ["expectedAgentIds"]
@@ -11983,7 +11991,8 @@ var init_schemas = __esm(() => {
11983
11991
  "prototype",
11984
11992
  "handoff",
11985
11993
  "clarify",
11986
- "security"
11994
+ "security",
11995
+ "odd"
11987
11996
  ]);
11988
11997
  CcepOutputFormatSchema = exports_external.enum(["taskcard", "plan", "verdict"]);
11989
11998
  CommandEnvelopeSchema = exports_external.object({
@@ -12199,6 +12208,46 @@ var init_schemas = __esm(() => {
12199
12208
  "revise",
12200
12209
  "reject"
12201
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
+ });
12202
12251
  TaskOutcomeSchema = exports_external.object({
12203
12252
  id: exports_external.string(),
12204
12253
  taskId: exports_external.string(),
@@ -12222,7 +12271,8 @@ var init_schemas = __esm(() => {
12222
12271
  variantId: exports_external.string().optional(),
12223
12272
  suiteTaskId: exports_external.string().optional(),
12224
12273
  harnessFingerprint: exports_external.string().optional(),
12225
- disabledComponents: exports_external.array(exports_external.string()).optional()
12274
+ disabledComponents: exports_external.array(exports_external.string()).optional(),
12275
+ delivery: DeliveryTelemetrySchema.optional()
12226
12276
  });
12227
12277
  HarnessComponentIdSchema = exports_external.enum([
12228
12278
  "wayfinding",
@@ -15419,6 +15469,25 @@ var init_profiles = __esm(() => {
15419
15469
  routing: { default: ["validate-backlog", "discover", "design", "analyze", "test", "implement", "review"] },
15420
15470
  confirmationGate: baseGate
15421
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
+ },
15422
15491
  backlog: {
15423
15492
  id: "backlog",
15424
15493
  version: 1,
@@ -21487,7 +21556,10 @@ async function listScorecards(projectRoot, filter = {}) {
21487
21556
  }
21488
21557
  async function hasPassingScorecard(projectRoot, backlogId) {
21489
21558
  const listed = await listScorecards(projectRoot, { backlogId, verdict: "PASS" });
21490
- 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");
21491
21563
  }
21492
21564
  async function loadScorecard(projectRoot, id) {
21493
21565
  try {
@@ -21519,7 +21591,7 @@ function aggregateOutcomes(outcomes) {
21519
21591
  agentScoreCounts[o.agent] = (agentScoreCounts[o.agent] ?? 0) + 1;
21520
21592
  }
21521
21593
  if (!byModel[o.model])
21522
- byModel[o.model] = { count: 0, avgScore: 0 };
21594
+ byModel[o.model] = { count: 0, avgScore: 0, knownTokenMeasurements: 0 };
21523
21595
  byModel[o.model].count++;
21524
21596
  if (o.weightedScore !== undefined) {
21525
21597
  byModel[o.model].avgScore += o.weightedScore;
@@ -21529,10 +21601,11 @@ function aggregateOutcomes(outcomes) {
21529
21601
  byModel[o.model].avgCost = (byModel[o.model].avgCost ?? 0) + o.costUsd;
21530
21602
  modelCostCounts[o.model] = (modelCostCounts[o.model] ?? 0) + 1;
21531
21603
  }
21532
- if (o.tokensIn !== undefined || o.tokensOut !== undefined) {
21533
- const tokens = (o.tokensIn ?? 0) + (o.tokensOut ?? 0);
21534
- 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;
21535
21607
  modelTokenCounts[o.model] = (modelTokenCounts[o.model] ?? 0) + 1;
21608
+ byModel[o.model].knownTokenMeasurements++;
21536
21609
  }
21537
21610
  if (o.variantId) {
21538
21611
  if (!byVariant[o.variantId])
@@ -22182,11 +22255,140 @@ var init_compile_checker = __esm(() => {
22182
22255
  ];
22183
22256
  });
22184
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
+
22185
22387
  // src/core/verification/verification-runner.ts
22186
22388
  import { existsSync as existsSync3 } from "node:fs";
22187
- import { readFile as readFile27 } from "node:fs/promises";
22188
- import { dirname as dirname10, join as join18, resolve as resolve26 } from "node:path";
22189
- 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";
22190
22392
  function isPassingEvidence(ev) {
22191
22393
  switch (ev.type) {
22192
22394
  case "verification":
@@ -22203,9 +22405,17 @@ function isPassingEvidence(ev) {
22203
22405
  return false;
22204
22406
  }
22205
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
+ }
22206
22416
  function evidenceFilePath(evDir, id) {
22207
- const path = resolve26(evDir, `${id.replace(/[^A-Za-z0-9_-]/g, "_")}.json`);
22208
- if (dirname10(path) !== resolve26(evDir)) {
22417
+ const path = resolve27(evDir, `${id.replace(/[^A-Za-z0-9_-]/g, "_")}.json`);
22418
+ if (dirname10(path) !== resolve27(evDir)) {
22209
22419
  return err(new Error(`Refusing to write evidence for "${id}" outside ${evDir}`));
22210
22420
  }
22211
22421
  return ok(path);
@@ -22231,7 +22441,7 @@ async function collectTaskEvidence(projectRoot, taskId) {
22231
22441
  return ok({ records, invalid });
22232
22442
  let files;
22233
22443
  try {
22234
- files = await readdir7(evDir);
22444
+ files = await readdir8(evDir);
22235
22445
  } catch (e) {
22236
22446
  return err(e instanceof Error ? e : new Error(String(e)));
22237
22447
  }
@@ -22239,7 +22449,7 @@ async function collectTaskEvidence(projectRoot, taskId) {
22239
22449
  if (!file.endsWith(".json"))
22240
22450
  continue;
22241
22451
  try {
22242
- const raw = await readFile27(join18(evDir, file), "utf-8");
22452
+ const raw = await readFile28(join19(evDir, file), "utf-8");
22243
22453
  const ev = EvidenceSchema.parse(JSON.parse(raw));
22244
22454
  if (ev.relatedTask === taskId)
22245
22455
  records.push(ev);
@@ -22260,7 +22470,7 @@ async function validateEvidenceIds(projectRoot, taskId, evidenceIds) {
22260
22470
  if (!record) {
22261
22471
  return err(new Error(`Evidence "${id}" is not a record of task ${taskId}`));
22262
22472
  }
22263
- if (!isPassingEvidence(record)) {
22473
+ if (!await isCurrentPassingEvidence(projectRoot, record)) {
22264
22474
  return err(new Error(`Evidence "${id}" does not record a passing result`));
22265
22475
  }
22266
22476
  if (record.type === "verification")
@@ -22341,7 +22551,12 @@ async function runVerification(projectRoot, taskId, goal, options) {
22341
22551
  passed: collected.data.invalid === 0,
22342
22552
  message: collected.data.invalid === 0 ? "All evidence records are readable" : `${collected.data.invalid} unreadable evidence record(s)`
22343
22553
  });
22344
- 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
+ }
22345
22560
  evidenceIds.push(...supporting.map((ev) => ev.id));
22346
22561
  checks.push({
22347
22562
  name: "evidence_present",
@@ -22349,6 +22564,13 @@ async function runVerification(projectRoot, taskId, goal, options) {
22349
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"
22350
22565
  });
22351
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
+ });
22352
22574
  const evidence = {
22353
22575
  id: `ev-verify-${taskId}-${Date.now()}`,
22354
22576
  source: "cc verify",
@@ -22357,7 +22579,7 @@ async function runVerification(projectRoot, taskId, goal, options) {
22357
22579
  relatedTask: taskId,
22358
22580
  confidence: passed ? 0.9 : 0.3,
22359
22581
  summary: passed ? "Verification passed" : "Verification failed",
22360
- data: { passed, checks }
22582
+ data: { passed, checks, rddReceipt: receipt }
22361
22583
  };
22362
22584
  const persisted = await persistEvidence(projectRoot, evidence);
22363
22585
  if (!persisted.success)
@@ -22380,19 +22602,25 @@ async function gateTaskCompletion(projectRoot, taskId, evidenceRequired, evidenc
22380
22602
  if (collected.data.invalid > 0)
22381
22603
  return ok(false);
22382
22604
  const cited = evidenceIds ? new Set(evidenceIds) : undefined;
22383
- 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
+ };
22384
22612
  for (const req of evidenceRequired) {
22385
22613
  switch (req) {
22386
22614
  case "acceptance_criteria_met":
22387
- if (!hasPassing("verification"))
22615
+ if (!await hasPassing("verification"))
22388
22616
  return ok(false);
22389
22617
  break;
22390
22618
  case "tests_passed":
22391
- if (!hasPassing("test"))
22619
+ if (!await hasPassing("test"))
22392
22620
  return ok(false);
22393
22621
  break;
22394
22622
  case "review_approved":
22395
- if (!hasPassing("review"))
22623
+ if (!await hasPassing("review"))
22396
22624
  return ok(false);
22397
22625
  break;
22398
22626
  default:
@@ -22401,11 +22629,66 @@ async function gateTaskCompletion(projectRoot, taskId, evidenceRequired, evidenc
22401
22629
  }
22402
22630
  return ok(true);
22403
22631
  }
22404
- 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) {
22405
22675
  const collected = await collectTaskEvidence(projectRoot, taskId);
22406
22676
  if (!collected.success)
22407
22677
  return false;
22408
- 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;
22409
22692
  }
22410
22693
  var TDD_EVIDENCE_SOURCE = "cc verify", TDD_CAPTURED_BY = "verification-runner";
22411
22694
  var init_verification_runner = __esm(() => {
@@ -22414,6 +22697,7 @@ var init_verification_runner = __esm(() => {
22414
22697
  init_compile_checker();
22415
22698
  init_paths();
22416
22699
  init_episodic_store();
22700
+ init_rdd_receipt();
22417
22701
  });
22418
22702
 
22419
22703
  // src/core/orchestrator/runtime-orchestrator.ts
@@ -23536,6 +23820,163 @@ var init_verify_command = __esm(() => {
23536
23820
  init_verification_runner();
23537
23821
  });
23538
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
+
23539
23980
  // src/core/ccep/confirmation-gate.ts
23540
23981
  function matchesRiskThreshold(severity, threshold) {
23541
23982
  const order = { low: 0, medium: 1, high: 2 };
@@ -23841,11 +24282,11 @@ var init_output_validator = __esm(() => {
23841
24282
  });
23842
24283
 
23843
24284
  // src/core/ccep/command-parser.ts
23844
- import { existsSync as existsSync4, readFileSync as readFileSync3 } from "node:fs";
23845
- 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";
23846
24287
  function readProjectId(projectRoot) {
23847
- const packageJsonPath = join19(projectRoot, "package.json");
23848
- if (existsSync4(packageJsonPath)) {
24288
+ const packageJsonPath = join20(projectRoot, "package.json");
24289
+ if (existsSync5(packageJsonPath)) {
23849
24290
  try {
23850
24291
  const pkg = JSON.parse(readFileSync3(packageJsonPath, "utf-8"));
23851
24292
  if (pkg.name) {
@@ -23874,8 +24315,8 @@ function parseCommand(command, userRequest, projectRoot) {
23874
24315
  maxVariance: "low"
23875
24316
  }
23876
24317
  };
23877
- const packageJsonPath = join19(projectRoot, "package.json");
23878
- if (existsSync4(packageJsonPath)) {
24318
+ const packageJsonPath = join20(projectRoot, "package.json");
24319
+ if (existsSync5(packageJsonPath)) {
23879
24320
  try {
23880
24321
  const pkg = JSON.parse(readFileSync3(packageJsonPath, "utf-8"));
23881
24322
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
@@ -23919,7 +24360,8 @@ var init_command_parser = __esm(() => {
23919
24360
  prototype: { outputFormat: "taskcard", needConfirmation: true, riskThreshold: "medium" },
23920
24361
  handoff: { outputFormat: "plan", needConfirmation: false, riskThreshold: "low" },
23921
24362
  clarify: { outputFormat: "plan", needConfirmation: false, riskThreshold: "low" },
23922
- security: { outputFormat: "taskcard", needConfirmation: true, riskThreshold: "high" }
24363
+ security: { outputFormat: "taskcard", needConfirmation: true, riskThreshold: "high" },
24364
+ odd: { outputFormat: "taskcard", needConfirmation: true, riskThreshold: "medium" }
23923
24365
  };
23924
24366
  });
23925
24367
 
@@ -23946,10 +24388,10 @@ var init_workflow_profile_loader = __esm(() => {
23946
24388
  });
23947
24389
 
23948
24390
  // src/core/evaluation/harness-catalog.ts
23949
- import { createHash as createHash4 } from "node:crypto";
23950
- import { existsSync as existsSync5, readFileSync as readFileSync4 } from "node:fs";
23951
- import { copyFile as copyFile2, mkdir as mkdir19, readFile as readFile28, readdir as readdir8, rm as rm4, writeFile as writeFile19 } from "node:fs/promises";
23952
- 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";
23953
24395
  function catalogIds(catalog = DEFAULT_HARNESS_CATALOG) {
23954
24396
  return catalog.components.map((c) => c.id);
23955
24397
  }
@@ -23999,23 +24441,23 @@ function harnessFingerprint(disabled, contractVersion, ccepProfile = "feature",
23999
24441
  contractVersion,
24000
24442
  ccepProfile
24001
24443
  };
24002
- 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);
24003
24445
  }
24004
24446
  async function loadHarnessCatalog(projectRoot) {
24005
- const overridePath = resolve27(projectRoot, EVAL_DIR2, CATALOG_FILE);
24447
+ const overridePath = resolve29(projectRoot, EVAL_DIR2, CATALOG_FILE);
24006
24448
  try {
24007
- const raw = await readFile28(overridePath, "utf-8");
24449
+ const raw = await readFile30(overridePath, "utf-8");
24008
24450
  return HarnessCatalogSchema.parse($parse(raw));
24009
24451
  } catch {
24010
24452
  return DEFAULT_HARNESS_CATALOG;
24011
24453
  }
24012
24454
  }
24013
24455
  function activeOverlayPath(projectRoot) {
24014
- return resolve27(projectRoot, EVAL_DIR2, ACTIVE_OVERLAY_FILE);
24456
+ return resolve29(projectRoot, EVAL_DIR2, ACTIVE_OVERLAY_FILE);
24015
24457
  }
24016
24458
  async function readActiveOverlay(projectRoot) {
24017
24459
  try {
24018
- const raw = await readFile28(activeOverlayPath(projectRoot), "utf-8");
24460
+ const raw = await readFile30(activeOverlayPath(projectRoot), "utf-8");
24019
24461
  return HarnessOverlaySchema.parse($parse(raw));
24020
24462
  } catch {
24021
24463
  return null;
@@ -24024,7 +24466,7 @@ async function readActiveOverlay(projectRoot) {
24024
24466
  function isProductGraphDisabled(projectRoot) {
24025
24467
  try {
24026
24468
  const path = activeOverlayPath(projectRoot);
24027
- if (!existsSync5(path))
24469
+ if (!existsSync6(path))
24028
24470
  return false;
24029
24471
  const overlay = HarnessOverlaySchema.parse($parse(readFileSync4(path, "utf-8")));
24030
24472
  return overlay.disableProductGraph === true || overlay.disabledComponents.includes("product_graph");
@@ -24069,55 +24511,55 @@ function applyCatalogToProfile(profile, disabled) {
24069
24511
  return next;
24070
24512
  }
24071
24513
  async function restoreOverlayBackup(projectRoot) {
24072
- const backupRoot = resolve27(projectRoot, EVAL_DIR2, OVERLAY_BACKUP_DIR);
24073
- if (!existsSync5(backupRoot))
24514
+ const backupRoot = resolve29(projectRoot, EVAL_DIR2, OVERLAY_BACKUP_DIR);
24515
+ if (!existsSync6(backupRoot))
24074
24516
  return;
24075
- const configBackup = join20(backupRoot, "config.yml");
24076
- const configDest = resolve27(projectRoot, ".codeconductor", "config.yml");
24077
- if (existsSync5(configBackup)) {
24078
- 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 });
24079
24521
  await copyFile2(configBackup, configDest);
24080
24522
  }
24081
- const workflowsBackup = join20(backupRoot, "workflows");
24082
- const workflowsDest = resolve27(projectRoot, ".codeconductor", "workflows");
24083
- if (existsSync5(workflowsBackup)) {
24084
- await mkdir19(workflowsDest, { recursive: true });
24085
- 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);
24086
24528
  for (const file of files) {
24087
- await copyFile2(join20(workflowsBackup, file), join20(workflowsDest, file));
24529
+ await copyFile2(join21(workflowsBackup, file), join21(workflowsDest, file));
24088
24530
  }
24089
24531
  }
24090
- const overlayBackup = join20(backupRoot, ACTIVE_OVERLAY_FILE);
24532
+ const overlayBackup = join21(backupRoot, ACTIVE_OVERLAY_FILE);
24091
24533
  const overlayDest = activeOverlayPath(projectRoot);
24092
- if (existsSync5(overlayBackup)) {
24534
+ if (existsSync6(overlayBackup)) {
24093
24535
  await copyFile2(overlayBackup, overlayDest);
24094
- } else if (existsSync5(overlayDest)) {
24536
+ } else if (existsSync6(overlayDest)) {
24095
24537
  await rm4(overlayDest, { force: true });
24096
24538
  }
24097
24539
  }
24098
24540
  async function snapshotForBackup(projectRoot) {
24099
- const backupRoot = resolve27(projectRoot, EVAL_DIR2, OVERLAY_BACKUP_DIR);
24100
- if (existsSync5(backupRoot))
24541
+ const backupRoot = resolve29(projectRoot, EVAL_DIR2, OVERLAY_BACKUP_DIR);
24542
+ if (existsSync6(backupRoot))
24101
24543
  return;
24102
- await mkdir19(backupRoot, { recursive: true });
24103
- const configPath = resolve27(projectRoot, ".codeconductor", "config.yml");
24104
- if (existsSync5(configPath)) {
24105
- await copyFile2(configPath, join20(backupRoot, "config.yml"));
24106
- }
24107
- const workflowsDir = resolve27(projectRoot, ".codeconductor", "workflows");
24108
- if (existsSync5(workflowsDir)) {
24109
- const dest = join20(backupRoot, "workflows");
24110
- await mkdir19(dest, { recursive: true });
24111
- 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);
24112
24554
  for (const file of files) {
24113
24555
  if (file.endsWith(".yml")) {
24114
- await copyFile2(join20(workflowsDir, file), join20(dest, file));
24556
+ await copyFile2(join21(workflowsDir, file), join21(dest, file));
24115
24557
  }
24116
24558
  }
24117
24559
  }
24118
24560
  const overlay = activeOverlayPath(projectRoot);
24119
- if (existsSync5(overlay)) {
24120
- await copyFile2(overlay, join20(backupRoot, ACTIVE_OVERLAY_FILE));
24561
+ if (existsSync6(overlay)) {
24562
+ await copyFile2(overlay, join21(backupRoot, ACTIVE_OVERLAY_FILE));
24121
24563
  }
24122
24564
  }
24123
24565
  async function applyHarnessOverlay(projectRoot, disabled, options = {}) {
@@ -24126,13 +24568,13 @@ async function applyHarnessOverlay(projectRoot, disabled, options = {}) {
24126
24568
  await restoreOverlayBackup(projectRoot);
24127
24569
  await snapshotForBackup(projectRoot);
24128
24570
  }
24129
- const workflowsDir = resolve27(projectRoot, ".codeconductor", "workflows");
24130
- await mkdir19(workflowsDir, { recursive: true });
24131
- 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 });
24132
24574
  for (const command of WORKFLOW_OVERLAY_COMMANDS) {
24133
24575
  const base = loadWorkflowProfile(command);
24134
24576
  const next = applyCatalogToProfile(base, disabled);
24135
- await writeFile19(join20(workflowsDir, `${command}.yml`), $stringify(next), "utf-8");
24577
+ await writeFile20(join21(workflowsDir, `${command}.yml`), $stringify(next), "utf-8");
24136
24578
  }
24137
24579
  const needsConfig = disabled.includes("compile_loop") || disabled.includes("council");
24138
24580
  if (needsConfig) {
@@ -24160,7 +24602,7 @@ async function applyHarnessOverlay(projectRoot, disabled, options = {}) {
24160
24602
  contractVersion: options.contractVersion,
24161
24603
  ccepProfile: options.ccepProfile ?? "feature"
24162
24604
  });
24163
- await writeFile19(activeOverlayPath(projectRoot), $stringify(overlay), "utf-8");
24605
+ await writeFile20(activeOverlayPath(projectRoot), $stringify(overlay), "utf-8");
24164
24606
  return ok(overlay);
24165
24607
  } catch (e) {
24166
24608
  return err(e instanceof Error ? e : new Error(String(e)));
@@ -24271,9 +24713,9 @@ var init_harness_catalog = __esm(() => {
24271
24713
  });
24272
24714
 
24273
24715
  // src/core/openspec/openspec-state.ts
24274
- import { createHash as createHash5 } from "node:crypto";
24275
- import { mkdir as mkdir20, readFile as readFile29, rename as rename3, writeFile as writeFile20 } from "node:fs/promises";
24276
- 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";
24277
24719
  function canTransition(from, to) {
24278
24720
  return ALLOWED_TRANSITIONS[from]?.includes(to) ?? false;
24279
24721
  }
@@ -24294,13 +24736,13 @@ function applyBacklogTransition(content, itemId, from, to, progress) {
24294
24736
  }
24295
24737
  async function writeFileAtomic(path, content) {
24296
24738
  const tmp = `${path}.${process.pid}.${Date.now()}.tmp`;
24297
- await writeFile20(tmp, content, "utf-8");
24298
- await rename3(tmp, path);
24739
+ await writeFile21(tmp, content, "utf-8");
24740
+ await rename4(tmp, path);
24299
24741
  }
24300
24742
  async function loadOpenspecState(projectRoot) {
24301
24743
  try {
24302
- const filePath = resolve28(projectRoot, STATE_FILE);
24303
- const content = await readFile29(filePath, "utf-8");
24744
+ const filePath = resolve30(projectRoot, STATE_FILE);
24745
+ const content = await readFile31(filePath, "utf-8");
24304
24746
  const data = JSON.parse(content);
24305
24747
  return ok(OpenspecStateSchema.parse(data));
24306
24748
  } catch (e) {
@@ -24317,10 +24759,10 @@ async function loadOpenspecState(projectRoot) {
24317
24759
  }
24318
24760
  async function writeOpenspecState(projectRoot, state) {
24319
24761
  try {
24320
- const dir = resolve28(projectRoot, ".codeconductor");
24321
- await mkdir20(dir, { recursive: true });
24762
+ const dir = resolve30(projectRoot, ".codeconductor");
24763
+ await mkdir21(dir, { recursive: true });
24322
24764
  const validated = OpenspecStateSchema.parse(state);
24323
- 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));
24324
24766
  return ok(undefined);
24325
24767
  } catch (e) {
24326
24768
  return err(e instanceof Error ? e : new Error(String(e)));
@@ -24342,7 +24784,7 @@ function getNextTaskCard(state) {
24342
24784
  return null;
24343
24785
  }
24344
24786
  function hashContent(content) {
24345
- return createHash5("sha256").update(content).digest("hex").slice(0, 16);
24787
+ return createHash6("sha256").update(content).digest("hex").slice(0, 16);
24346
24788
  }
24347
24789
  function serializeItemSnapshot(item) {
24348
24790
  return JSON.stringify({
@@ -24424,19 +24866,19 @@ var init_openspec_state = __esm(() => {
24424
24866
  });
24425
24867
 
24426
24868
  // src/core/ccep/context-resolver.ts
24427
- import { existsSync as existsSync6 } from "node:fs";
24428
- import { readFile as readFile30 } from "node:fs/promises";
24429
- 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";
24430
24872
  async function loadProductKnowledge(projectRoot) {
24431
24873
  if (isProductGraphDisabled(projectRoot)) {
24432
24874
  return {};
24433
24875
  }
24434
24876
  const graphPath = productGraphPath(projectRoot);
24435
- if (!existsSync6(graphPath)) {
24877
+ if (!existsSync7(graphPath)) {
24436
24878
  return {};
24437
24879
  }
24438
24880
  try {
24439
- const raw = await readFile30(graphPath, "utf-8");
24881
+ const raw = await readFile32(graphPath, "utf-8");
24440
24882
  const graph = ProductGraphSchema.parse(JSON.parse(raw));
24441
24883
  return {
24442
24884
  productName: graph.productName,
@@ -24452,18 +24894,18 @@ async function loadProductKnowledge(projectRoot) {
24452
24894
  }
24453
24895
  async function resolveAstSource(projectRoot) {
24454
24896
  if (isProductGraphDisabled(projectRoot)) {
24455
- const graphifyPath2 = join21(projectRoot, "graphify-out", "graph.json");
24456
- if (existsSync6(graphifyPath2)) {
24897
+ const graphifyPath2 = join22(projectRoot, "graphify-out", "graph.json");
24898
+ if (existsSync7(graphifyPath2)) {
24457
24899
  return { source: "graphify", confidence: "medium" };
24458
24900
  }
24459
24901
  return { source: "manual", confidence: "low" };
24460
24902
  }
24461
24903
  const graphPath = productGraphPath(projectRoot);
24462
- if (existsSync6(graphPath)) {
24904
+ if (existsSync7(graphPath)) {
24463
24905
  return { source: "product-graph", confidence: "high" };
24464
24906
  }
24465
- const graphifyPath = join21(projectRoot, "graphify-out", "graph.json");
24466
- if (existsSync6(graphifyPath)) {
24907
+ const graphifyPath = join22(projectRoot, "graphify-out", "graph.json");
24908
+ if (existsSync7(graphifyPath)) {
24467
24909
  return { source: "graphify", confidence: "medium" };
24468
24910
  }
24469
24911
  try {
@@ -24704,6 +25146,12 @@ function councilConsensus(verdicts, config = DEFAULT_CONFIG2) {
24704
25146
  individualVerdicts: verdicts
24705
25147
  };
24706
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
+ }
24707
25155
  const critical = allFindings.filter((f) => f.severity === "critical");
24708
25156
  if (critical.length > 0 && policy === "reject") {
24709
25157
  return {
@@ -25265,12 +25713,26 @@ async function ccepCommand(options) {
25265
25713
  }
25266
25714
  mergedConfig = { ...mergedConfig, ...parsedConfig.data };
25267
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
+ }
25268
25729
  const verdict = councilConsensus(parsedBallots.verdicts, mergedConfig);
25269
25730
  return {
25270
25731
  code: consensusExitCode(verdict.status),
25271
25732
  data: {
25272
25733
  success: verdict.status === "APPROVED",
25273
25734
  command: "ccep consensus",
25735
+ candidateHash: currentCandidateHash,
25274
25736
  verdict
25275
25737
  }
25276
25738
  };
@@ -25508,8 +25970,8 @@ var init_backlog_validator = __esm(() => {
25508
25970
 
25509
25971
  // src/core/openspec/backlog-scanner.ts
25510
25972
  import { execFileSync as execFileSync2 } from "node:child_process";
25511
- import { readFile as readFile31 } from "node:fs/promises";
25512
- import { resolve as resolve29 } from "node:path";
25973
+ import { readFile as readFile33 } from "node:fs/promises";
25974
+ import { resolve as resolve31 } from "node:path";
25513
25975
  function itemSnapshot(items) {
25514
25976
  const snap = {};
25515
25977
  for (const item of items) {
@@ -25519,8 +25981,8 @@ function itemSnapshot(items) {
25519
25981
  }
25520
25982
  async function scanBacklog(projectRoot, previousSnapshot = {}) {
25521
25983
  try {
25522
- const filePath = resolve29(projectRoot, BACKLOG_FILENAME);
25523
- const content = await readFile31(filePath, "utf-8");
25984
+ const filePath = resolve31(projectRoot, BACKLOG_FILENAME);
25985
+ const content = await readFile33(filePath, "utf-8");
25524
25986
  const hash = hashContent(content);
25525
25987
  let fileChanged = true;
25526
25988
  try {
@@ -25757,8 +26219,8 @@ var init_backlog_planner = __esm(() => {
25757
26219
  });
25758
26220
 
25759
26221
  // src/core/openspec/openspec-generator.ts
25760
- import { mkdir as mkdir21, rename as rename4, writeFile as writeFile21 } from "node:fs/promises";
25761
- import { basename as basename6, 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";
25762
26224
  function pad3(n) {
25763
26225
  return String(n).padStart(3, "0");
25764
26226
  }
@@ -25823,7 +26285,7 @@ The system MUST ${criterion}.
25823
26285
 
25824
26286
  #### Scenario: SC-${n} ${criterion}
25825
26287
 
25826
- - GIVEN the current behavior in ${item.scope}
26288
+ - GIVEN the relevant scoped behavior
25827
26289
  - WHEN this change is applied
25828
26290
  - THEN ${criterion}
25829
26291
  `;
@@ -25837,8 +26299,8 @@ ${blocks.join(`
25837
26299
  `;
25838
26300
  }
25839
26301
  async function writeTasksMarkdown(projectRoot, changePath, cards, options = {}) {
25840
- await mkdir21(resolve30(projectRoot, changePath), { recursive: true });
25841
- 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");
25842
26304
  }
25843
26305
  function tasksContent(cards, options = {}) {
25844
26306
  const criteria = options.acceptanceCriteria ?? [];
@@ -25883,19 +26345,19 @@ function tasksContent(cards, options = {}) {
25883
26345
  }
25884
26346
  async function generateOpenspecChange(projectRoot, item, taskCards, options = {}) {
25885
26347
  const slug = buildChangeSlug(item);
25886
- const changeDir = resolve30(projectRoot, "openspec", "changes", slug);
25887
- await mkdir21(resolve30(changeDir, "specs"), { recursive: true });
26348
+ const changeDir = resolve32(projectRoot, "openspec", "changes", slug);
26349
+ await mkdir22(resolve32(changeDir, "specs"), { recursive: true });
25888
26350
  const taskOpts = {
25889
26351
  tddRequired: options.tddRequired,
25890
26352
  acceptanceCriteria: options.acceptanceCriteria ?? item.acceptanceCriteria
25891
26353
  };
25892
- await writeFile21(resolve30(changeDir, "proposal.md"), proposalContent(item), "utf-8");
25893
- await writeFile21(resolve30(changeDir, "design.md"), designContent(item), "utf-8");
25894
- 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");
25895
26357
  const capability = capabilitySlug(item.title);
25896
- await mkdir21(resolve30(changeDir, "specs", capability), { recursive: true });
25897
- await writeFile21(resolve30(changeDir, "specs", capability, "spec.md"), specDelta(item), "utf-8");
25898
- 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
25899
26361
  backlogId: ${item.id}
25900
26362
  profile: standard
25901
26363
  capabilities:
@@ -25904,25 +26366,25 @@ capabilities:
25904
26366
  return `openspec/changes/${slug}`;
25905
26367
  }
25906
26368
  async function archiveChangeFolder(projectRoot, changePath) {
25907
- const src = resolve30(projectRoot, changePath);
26369
+ const src = resolve32(projectRoot, changePath);
25908
26370
  const slug = basename6(changePath);
25909
- const destDir = resolve30(projectRoot, "openspec", "changes", "archive");
25910
- await mkdir21(destDir, { recursive: true });
25911
- const dest = resolve30(destDir, slug);
25912
- await rename4(src, dest);
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);
25913
26375
  return `openspec/changes/archive/${slug}`;
25914
26376
  }
25915
26377
  async function ensureOpenspecConfig(projectRoot) {
25916
- const configPath = resolve30(projectRoot, "openspec", "config.yaml");
26378
+ const configPath = resolve32(projectRoot, "openspec", "config.yaml");
25917
26379
  try {
25918
26380
  const { access: access7 } = await import("node:fs/promises");
25919
26381
  await access7(configPath);
25920
26382
  } catch {
25921
- await mkdir21(resolve30(projectRoot, "openspec"), { recursive: true });
26383
+ await mkdir22(resolve32(projectRoot, "openspec"), { recursive: true });
25922
26384
  const stub = `# OpenSpec project config (CodeConductor native compatible)
25923
26385
  schema: spec-driven
25924
26386
  `;
25925
- await writeFile21(configPath, stub, "utf-8");
26387
+ await writeFile22(configPath, stub, "utf-8");
25926
26388
  }
25927
26389
  }
25928
26390
  var init_openspec_generator = __esm(() => {
@@ -25930,8 +26392,8 @@ var init_openspec_generator = __esm(() => {
25930
26392
  });
25931
26393
 
25932
26394
  // src/core/openspec/spec-quality.ts
25933
- import { readdir as readdir9, readFile as readFile32 } from "node:fs/promises";
25934
- 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";
25935
26397
  function uniqueIds(matches) {
25936
26398
  return [...new Set(matches ?? [])];
25937
26399
  }
@@ -26048,12 +26510,12 @@ async function walkMarkdown(dir) {
26048
26510
  const out = [];
26049
26511
  let entries;
26050
26512
  try {
26051
- entries = await readdir9(dir, { withFileTypes: true });
26513
+ entries = await readdir11(dir, { withFileTypes: true });
26052
26514
  } catch {
26053
26515
  return out;
26054
26516
  }
26055
26517
  for (const entry of entries) {
26056
- const full = join22(dir, entry.name);
26518
+ const full = join23(dir, entry.name);
26057
26519
  if (entry.isDirectory()) {
26058
26520
  out.push(...await walkMarkdown(full));
26059
26521
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
@@ -26063,8 +26525,8 @@ async function walkMarkdown(dir) {
26063
26525
  return out;
26064
26526
  }
26065
26527
  async function assessChangeFolder(projectRoot, changePath) {
26066
- const root = resolve31(projectRoot);
26067
- const changeRoot = resolve31(root, changePath);
26528
+ const root = resolve33(projectRoot);
26529
+ const changeRoot = resolve33(root, changePath);
26068
26530
  if (!changeRoot.startsWith(root)) {
26069
26531
  return {
26070
26532
  valid: false,
@@ -26082,22 +26544,22 @@ async function assessChangeFolder(projectRoot, changePath) {
26082
26544
  successCriteria: []
26083
26545
  };
26084
26546
  }
26085
- const specDir = join22(changeRoot, "specs");
26547
+ const specDir = join23(changeRoot, "specs");
26086
26548
  const specFiles = await walkMarkdown(specDir);
26087
- const extra = ["proposal.md", "design.md"].map((name) => join22(changeRoot, name));
26549
+ const extra = ["proposal.md", "design.md"].map((name) => join23(changeRoot, name));
26088
26550
  const reports = [];
26089
26551
  for (const file of specFiles) {
26090
- const content = await readFile32(file, "utf-8");
26091
- 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, "/")));
26092
26554
  }
26093
26555
  for (const file of extra) {
26094
26556
  let content;
26095
26557
  try {
26096
- content = await readFile32(file, "utf-8");
26558
+ content = await readFile34(file, "utf-8");
26097
26559
  } catch {
26098
26560
  continue;
26099
26561
  }
26100
- const rel = relative7(root, file).replace(/\\/g, "/");
26562
+ const rel = relative8(root, file).replace(/\\/g, "/");
26101
26563
  if (PLACEHOLDER.test(content)) {
26102
26564
  reports.push({
26103
26565
  valid: false,
@@ -26141,15 +26603,15 @@ var init_spec_quality = __esm(() => {
26141
26603
  FR_ID = /\bFR-\d{3}\b/g;
26142
26604
  SC_ID = /\bSC-\d{3}\b/g;
26143
26605
  US_AC = /\b(?:US|AC)#?\d+\b/g;
26144
- 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;
26145
26607
  NEEDS_CLARIFICATION = /\[NEEDS CLARIFICATION:[^\]]*\]/gi;
26146
26608
  PLACEHOLDER = /\(To be completed/i;
26147
26609
  HOW_LEAK = /\b(TypeScript|PostgreSQL|Django|React|Spring Boot|package\.json|implements class)\b/i;
26148
26610
  });
26149
26611
 
26150
26612
  // src/core/openspec/spec-analyzer.ts
26151
- import { readFile as readFile33, readdir as readdir10 } from "node:fs/promises";
26152
- 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";
26153
26615
  function unique(ids) {
26154
26616
  return [...new Set(ids)];
26155
26617
  }
@@ -26176,17 +26638,17 @@ function testSection(tasksMarkdown) {
26176
26638
  async function readDeltaSpecs(specDir) {
26177
26639
  let entries;
26178
26640
  try {
26179
- entries = await readdir10(specDir, { withFileTypes: true });
26641
+ entries = await readdir12(specDir, { withFileTypes: true });
26180
26642
  } catch {
26181
26643
  return "";
26182
26644
  }
26183
26645
  const contents = [];
26184
26646
  for (const entry of entries) {
26185
- const path = join23(specDir, entry.name);
26647
+ const path = join24(specDir, entry.name);
26186
26648
  if (entry.isDirectory()) {
26187
26649
  contents.push(await readDeltaSpecs(path));
26188
26650
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
26189
- contents.push(await readFile33(path, "utf-8"));
26651
+ contents.push(await readFile35(path, "utf-8"));
26190
26652
  }
26191
26653
  }
26192
26654
  return contents.filter(Boolean).join(`
@@ -26264,17 +26726,17 @@ function analyzeSpecArtifacts(input) {
26264
26726
  };
26265
26727
  }
26266
26728
  async function analyzeChangeFolder(projectRoot, changePath, options) {
26267
- const changeRoot = resolve32(projectRoot, changePath);
26268
- const specMarkdown = await readDeltaSpecs(join23(changeRoot, "specs"));
26729
+ const changeRoot = resolve34(projectRoot, changePath);
26730
+ const specMarkdown = await readDeltaSpecs(join24(changeRoot, "specs"));
26269
26731
  let tasksMarkdown = "";
26270
26732
  try {
26271
- tasksMarkdown = await readFile33(join23(changeRoot, "tasks.md"), "utf-8");
26733
+ tasksMarkdown = await readFile35(join24(changeRoot, "tasks.md"), "utf-8");
26272
26734
  } catch {
26273
26735
  tasksMarkdown = "";
26274
26736
  }
26275
26737
  let designMarkdown;
26276
26738
  try {
26277
- designMarkdown = await readFile33(join23(changeRoot, "design.md"), "utf-8");
26739
+ designMarkdown = await readFile35(join24(changeRoot, "design.md"), "utf-8");
26278
26740
  } catch {
26279
26741
  designMarkdown = undefined;
26280
26742
  }
@@ -26293,18 +26755,18 @@ var init_spec_analyzer = __esm(() => {
26293
26755
  });
26294
26756
 
26295
26757
  // src/core/openspec/spec-sync.ts
26296
- import { mkdir as mkdir22, readFile as readFile34, readdir as readdir11 } from "node:fs/promises";
26297
- 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";
26298
26760
  async function markdownFiles(dir) {
26299
26761
  let entries;
26300
26762
  try {
26301
- entries = await readdir11(dir, { withFileTypes: true });
26763
+ entries = await readdir13(dir, { withFileTypes: true });
26302
26764
  } catch {
26303
26765
  return [];
26304
26766
  }
26305
26767
  const files = [];
26306
26768
  for (const entry of entries) {
26307
- const path = join24(dir, entry.name);
26769
+ const path = join25(dir, entry.name);
26308
26770
  if (entry.isDirectory())
26309
26771
  files.push(...await markdownFiles(path));
26310
26772
  else if (entry.isFile() && entry.name.endsWith(".md"))
@@ -26380,9 +26842,9 @@ ${delta.markdown}`;
26380
26842
  ` };
26381
26843
  }
26382
26844
  async function syncChangeSpecs(projectRoot, changePath) {
26383
- const root = resolve33(projectRoot);
26384
- const changeRoot = resolve33(root, changePath);
26385
- const changeSpecs = join24(changeRoot, "specs");
26845
+ const root = resolve35(projectRoot);
26846
+ const changeRoot = resolve35(root, changePath);
26847
+ const changeSpecs = join25(changeRoot, "specs");
26386
26848
  if (changeRoot !== root && !changeRoot.startsWith(`${root}/`)) {
26387
26849
  return { success: false, syncedPaths: [], errors: ["Change path escapes project root"] };
26388
26850
  }
@@ -26392,34 +26854,34 @@ async function syncChangeSpecs(projectRoot, changePath) {
26392
26854
  }
26393
26855
  const writes = [];
26394
26856
  for (const file of files) {
26395
- const delta = await readFile34(file, "utf-8");
26857
+ const delta = await readFile36(file, "utf-8");
26396
26858
  const requirements = deltaRequirements(delta);
26397
26859
  if (requirements.length === 0) {
26398
26860
  return {
26399
26861
  success: false,
26400
26862
  syncedPaths: [],
26401
- errors: [`${relative8(root, file)}: no delta requirements found`]
26863
+ errors: [`${relative9(root, file)}: no delta requirements found`]
26402
26864
  };
26403
26865
  }
26404
- const relativeSpec = relative8(changeSpecs, file);
26405
- const target = join24(root, "openspec", "specs", relativeSpec);
26866
+ const relativeSpec = relative9(changeSpecs, file);
26867
+ const target = join25(root, "openspec", "specs", relativeSpec);
26406
26868
  let existing = `# ${relativeSpec.replace(/\\/g, "/")}
26407
26869
  `;
26408
26870
  try {
26409
- existing = await readFile34(target, "utf-8");
26871
+ existing = await readFile36(target, "utf-8");
26410
26872
  } catch {}
26411
- const merged = upsertRequirements(existing, requirements, relative8(root, file));
26873
+ const merged = upsertRequirements(existing, requirements, relative9(root, file));
26412
26874
  if (!merged.ok)
26413
26875
  return { success: false, syncedPaths: [], errors: [merged.error] };
26414
26876
  writes.push({ path: target, content: merged.content });
26415
26877
  }
26416
26878
  for (const write of writes) {
26417
- await mkdir22(resolve33(write.path, ".."), { recursive: true });
26879
+ await mkdir23(resolve35(write.path, ".."), { recursive: true });
26418
26880
  await writeFileAtomic(write.path, write.content);
26419
26881
  }
26420
26882
  return {
26421
26883
  success: true,
26422
- syncedPaths: writes.map((write) => relative8(root, write.path).replace(/\\/g, "/")),
26884
+ syncedPaths: writes.map((write) => relative9(root, write.path).replace(/\\/g, "/")),
26423
26885
  errors: []
26424
26886
  };
26425
26887
  }
@@ -26435,8 +26897,8 @@ var exports_openspec_command = {};
26435
26897
  __export(exports_openspec_command, {
26436
26898
  openspecCommand: () => openspecCommand
26437
26899
  });
26438
- import { readFile as readFile35 } from "node:fs/promises";
26439
- import { resolve as resolve34 } from "node:path";
26900
+ import { readFile as readFile37 } from "node:fs/promises";
26901
+ import { resolve as resolve36 } from "node:path";
26440
26902
  async function openspecCommand(options) {
26441
26903
  const { subcommand, itemId, projectRoot, output, reason } = options;
26442
26904
  switch (subcommand) {
@@ -26458,6 +26920,8 @@ async function openspecCommand(options) {
26458
26920
  return handleDone(projectRoot, itemId);
26459
26921
  case "block":
26460
26922
  return handleBlock(projectRoot, itemId, reason);
26923
+ case "unblock":
26924
+ return handleUnblock(projectRoot, itemId);
26461
26925
  case "archive":
26462
26926
  return handleArchive(projectRoot, itemId);
26463
26927
  default:
@@ -26480,7 +26944,7 @@ function fail(command, errors3, extra = {}) {
26480
26944
  };
26481
26945
  }
26482
26946
  async function persistBacklog(projectRoot, content) {
26483
- await writeFileAtomic(resolve34(projectRoot, BACKLOG_FILENAME), content);
26947
+ await writeFileAtomic(resolve36(projectRoot, BACKLOG_FILENAME), content);
26484
26948
  }
26485
26949
  async function persistState(projectRoot, state) {
26486
26950
  const written = await writeOpenspecState(projectRoot, state);
@@ -26490,7 +26954,7 @@ async function persistState(projectRoot, state) {
26490
26954
  return { ok: true };
26491
26955
  }
26492
26956
  async function readBacklogMarkdown(projectRoot) {
26493
- return readFile35(resolve34(projectRoot, BACKLOG_FILENAME), "utf-8");
26957
+ return readFile37(resolve36(projectRoot, BACKLOG_FILENAME), "utf-8");
26494
26958
  }
26495
26959
  async function transitionItem(projectRoot, item, to, progress) {
26496
26960
  const content = await readBacklogMarkdown(projectRoot);
@@ -26688,17 +27152,18 @@ async function handleAnalyze(projectRoot, itemId) {
26688
27152
  const policyParts = [];
26689
27153
  for (const name of ["AGENTS.md", "BACKLOG.md"]) {
26690
27154
  try {
26691
- policyParts.push(await readFile35(resolve34(projectRoot, name), "utf-8"));
27155
+ policyParts.push(await readFile37(resolve36(projectRoot, name), "utf-8"));
26692
27156
  } catch {}
26693
27157
  }
26694
27158
  const cards = itemCards(stateResult.data, targetId);
26695
27159
  const tddCards = cards.filter((c) => c.phase === "test" || c.phase === "implement");
26696
27160
  let hasTddEvidence;
26697
27161
  if (tddCards.length > 0) {
26698
- hasTddEvidence = false;
27162
+ hasTddEvidence = true;
26699
27163
  for (const card of tddCards) {
26700
- if (await hasTddRunnerEvidence(projectRoot, card.id)) {
26701
- hasTddEvidence = true;
27164
+ const expectedPhase = card.phase === "test" ? "red" : "green";
27165
+ if (!await hasTddRunnerEvidence(projectRoot, card.id, expectedPhase)) {
27166
+ hasTddEvidence = false;
26702
27167
  break;
26703
27168
  }
26704
27169
  }
@@ -26883,10 +27348,11 @@ async function handleDone(projectRoot, cardId) {
26883
27348
  const backlog = await loadBacklog(projectRoot);
26884
27349
  const tddRequired = backlog.success ? backlog.data.global.tddRequired : false;
26885
27350
  if (tddRequired && (card.phase === "test" || card.phase === "implement")) {
26886
- const evidenced = await hasTddRunnerEvidence(projectRoot, cardId);
27351
+ const expectedPhase = card.phase === "test" ? "red" : "green";
27352
+ const evidenced = await hasTddRunnerEvidence(projectRoot, cardId, expectedPhase);
26887
27353
  if (!evidenced) {
26888
27354
  return fail(command, [
26889
- `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.`
26890
27356
  ]);
26891
27357
  }
26892
27358
  }
@@ -26961,6 +27427,57 @@ async function handleBlock(projectRoot, cardId, reason) {
26961
27427
  }
26962
27428
  };
26963
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
+ }
26964
27481
  async function handleArchive(projectRoot, itemId) {
26965
27482
  const command = "openspec archive";
26966
27483
  if (!itemId) {
@@ -27037,7 +27554,7 @@ async function handleArchive(projectRoot, itemId) {
27037
27554
  }
27038
27555
  };
27039
27556
  }
27040
- 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";
27041
27558
  var init_openspec_command = __esm(() => {
27042
27559
  init_backlog_parser();
27043
27560
  init_backlog_validator();
@@ -27055,6 +27572,184 @@ var init_openspec_command = __esm(() => {
27055
27572
  init_loop_engine();
27056
27573
  });
27057
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
+
27058
27753
  // src/core/hooks/hook-runner.ts
27059
27754
  function normalizeCommand(raw) {
27060
27755
  return raw.replace(/\s+/g, " ").trim();
@@ -27206,8 +27901,8 @@ __export(exports_hook_command, {
27206
27901
  readStdinText: () => readStdinText
27207
27902
  });
27208
27903
  import { spawnSync } from "node:child_process";
27209
- import { existsSync as existsSync7 } from "node:fs";
27210
- import { resolve as resolve35 } from "node:path";
27904
+ import { existsSync as existsSync8 } from "node:fs";
27905
+ import { resolve as resolve38 } from "node:path";
27211
27906
  function detectFormat(explicit, stdinText) {
27212
27907
  if (explicit)
27213
27908
  return explicit;
@@ -27234,13 +27929,13 @@ function resolvePreToolInput(options, stdinText) {
27234
27929
  };
27235
27930
  }
27236
27931
  async function sessionLines(projectRoot) {
27237
- const backlogPath = resolve35(projectRoot, "BACKLOG.md");
27238
- 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");
27239
27934
  return [
27240
27935
  "[CodeConductor] Session start",
27241
27936
  "Skills: openspec, backlog, evaluation, testing-tdd — invoke via /cc-* then CLI.",
27242
- existsSync7(backlogPath) ? "BACKLOG.md present — run: bun run dev openspec status" : "No BACKLOG.md — author with /cc-backlog if you need an item queue.",
27243
- 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",
27244
27939
  "Hooks: bun run dev hook pre-tool | post-tool | session-start",
27245
27940
  "Eval suites: bun run dev scorecard suite-run --suite workflow-gates"
27246
27941
  ];
@@ -27284,7 +27979,7 @@ async function hookCommand(options) {
27284
27979
  };
27285
27980
  }
27286
27981
  function formatWrittenFile(filePath) {
27287
- if (!filePath || !existsSync7(filePath))
27982
+ if (!filePath || !existsSync8(filePath))
27288
27983
  return;
27289
27984
  const prettier = /\.(ts|tsx|js|jsx|mjs|cjs|json|jsonc|md|mdx|css|scss|html|astro|ya?ml)$/i;
27290
27985
  const eslint = /\.(ts|tsx|js|jsx|mjs|cjs)$/i;
@@ -27702,6 +28397,12 @@ function ccGainToScorecardImpact(result) {
27702
28397
 
27703
28398
  // src/core/evaluation/scorecard-signals.ts
27704
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
+ }
27705
28406
  function collectScorecardSignals(projectRoot, scopeFiles, extra) {
27706
28407
  const findings = [];
27707
28408
  const overrides = {};
@@ -27748,7 +28449,7 @@ function collectScorecardSignals(projectRoot, scopeFiles, extra) {
27748
28449
  changedFiles.add(m[1]);
27749
28450
  }
27750
28451
  if (scopeFiles && scopeFiles.length > 0) {
27751
- 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, ""))));
27752
28453
  if (outOfScope.length > 0) {
27753
28454
  overrides.minimal_diff = {
27754
28455
  score: 0,
@@ -27819,25 +28520,25 @@ var init_scorecard_signals = __esm(() => {
27819
28520
  });
27820
28521
 
27821
28522
  // src/core/evaluation/harness-experiment.ts
27822
- import { existsSync as existsSync8 } from "node:fs";
27823
- import { cp, mkdir as mkdir23, readFile as readFile36, readdir as readdir12, writeFile as writeFile22 } from "node:fs/promises";
27824
- 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";
27825
28526
  function experimentDir(projectRoot, experimentId) {
27826
- return resolve36(projectRoot, EVAL_DIR2, EXPERIMENTS_DIR, experimentId);
28527
+ return resolve39(projectRoot, EVAL_DIR2, EXPERIMENTS_DIR, experimentId);
27827
28528
  }
27828
28529
  function experimentYamlPath(projectRoot, experimentId) {
27829
- return join25(experimentDir(projectRoot, experimentId), "experiment.yml");
28530
+ return join26(experimentDir(projectRoot, experimentId), "experiment.yml");
27830
28531
  }
27831
28532
  async function loadHarnessSuite(projectRoot, suiteId, suitePath) {
27832
28533
  const candidates = suitePath ? [suitePath] : [
27833
- resolve36(projectRoot, "eval", "suites", suiteId, "suite.yml"),
27834
- 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")
27835
28536
  ];
27836
28537
  for (const path of candidates) {
27837
- if (!existsSync8(path))
28538
+ if (!existsSync9(path))
27838
28539
  continue;
27839
28540
  try {
27840
- const suite = HarnessSuiteSchema.parse($parse(await readFile36(path, "utf-8")));
28541
+ const suite = HarnessSuiteSchema.parse($parse(await readFile39(path, "utf-8")));
27841
28542
  return ok({ ...suite, path });
27842
28543
  } catch (e) {
27843
28544
  return err(e instanceof Error ? e : new Error(String(e)));
@@ -27847,7 +28548,7 @@ async function loadHarnessSuite(projectRoot, suiteId, suitePath) {
27847
28548
  }
27848
28549
  async function loadExperiment(projectRoot, experimentId) {
27849
28550
  try {
27850
- const raw = await readFile36(experimentYamlPath(projectRoot, experimentId), "utf-8");
28551
+ const raw = await readFile39(experimentYamlPath(projectRoot, experimentId), "utf-8");
27851
28552
  return ok(HarnessExperimentSchema.parse($parse(raw)));
27852
28553
  } catch (e) {
27853
28554
  if (e.code === "ENOENT") {
@@ -27857,10 +28558,10 @@ async function loadExperiment(projectRoot, experimentId) {
27857
28558
  }
27858
28559
  }
27859
28560
  async function listExperiments(projectRoot) {
27860
- const root = resolve36(projectRoot, EVAL_DIR2, EXPERIMENTS_DIR);
27861
- if (!existsSync8(root))
28561
+ const root = resolve39(projectRoot, EVAL_DIR2, EXPERIMENTS_DIR);
28562
+ if (!existsSync9(root))
27862
28563
  return [];
27863
- const ids = await readdir12(root);
28564
+ const ids = await readdir14(root);
27864
28565
  const experiments = [];
27865
28566
  for (const id of ids) {
27866
28567
  const loaded = await loadExperiment(projectRoot, id);
@@ -27936,9 +28637,9 @@ function generateExperimentId(suiteId, now = new Date) {
27936
28637
  return `abl-${date}-${suiteId}-${rand}`;
27937
28638
  }
27938
28639
  async function copyFixture(suitePath, fixtureDir, dest) {
27939
- const source = fixtureDir ? resolve36(dirname12(suitePath), fixtureDir) : join25(dirname12(suitePath), "fixture");
27940
- await mkdir23(dest, { recursive: true });
27941
- 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)) {
27942
28643
  await cp(source, dest, { recursive: true });
27943
28644
  }
27944
28645
  }
@@ -27959,12 +28660,12 @@ async function startHarnessExperiment(projectRoot, options) {
27959
28660
  suitePath: suite.data.path
27960
28661
  };
27961
28662
  const root = experimentDir(projectRoot, experimentId);
27962
- await mkdir23(root, { recursive: true });
27963
- await writeFile22(experimentYamlPath(projectRoot, experimentId), $stringify(experiment), "utf-8");
27964
- 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");
27965
28666
  for (const task of suite.data.tasks) {
27966
28667
  for (const variantId of variants) {
27967
- const runRoot = join25(root, "runs", task.id, variantDirName(variantId));
28668
+ const runRoot = join26(root, "runs", task.id, variantDirName(variantId));
27968
28669
  await copyFixture(suite.data.path, suite.data.fixtureDir, runRoot);
27969
28670
  await writeConfig(runRoot, structuredClone(DEFAULT_CONFIG), true);
27970
28671
  const disabled = variantId === "baseline" ? [] : options.components.filter((id) => variantIdFor(id) === variantId);
@@ -27976,7 +28677,7 @@ async function startHarnessExperiment(projectRoot, options) {
27976
28677
  });
27977
28678
  if (!overlay.success)
27978
28679
  return overlay;
27979
- 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");
27980
28681
  }
27981
28682
  }
27982
28683
  return ok(experiment);
@@ -28010,8 +28711,8 @@ var init_harness_experiment = __esm(() => {
28010
28711
 
28011
28712
  // src/core/evaluation/suite-run.ts
28012
28713
  import { spawnSync as spawnSync2 } from "node:child_process";
28013
- import { existsSync as existsSync9 } from "node:fs";
28014
- import { resolve as resolve37 } from "node:path";
28714
+ import { existsSync as existsSync10 } from "node:fs";
28715
+ import { resolve as resolve40 } from "node:path";
28015
28716
  async function runHarnessSuiteTasks(projectRoot, suiteId, suitePath) {
28016
28717
  const suite = await loadHarnessSuite(projectRoot, suiteId, suitePath);
28017
28718
  if (!suite.success) {
@@ -28071,7 +28772,7 @@ function runTaskCommand(projectRoot, task) {
28071
28772
  if (parts.length === 0) {
28072
28773
  return { ok: false, detail: "Empty testCommand" };
28073
28774
  }
28074
- 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];
28075
28776
  const args = parts[0] === "bun" ? parts.slice(1) : parts.slice(1);
28076
28777
  const result = spawnSync2(bin, args, {
28077
28778
  cwd: projectRoot,
@@ -28122,11 +28823,11 @@ var init_suite_run = __esm(() => {
28122
28823
  });
28123
28824
 
28124
28825
  // src/core/evaluation/execution-profile.ts
28125
- import { readFile as readFile37 } from "node:fs/promises";
28126
- import { resolve as resolve38 } from "node:path";
28826
+ import { readFile as readFile40 } from "node:fs/promises";
28827
+ import { resolve as resolve41 } from "node:path";
28127
28828
  async function loadExecutionProfile(projectRoot, defaultTarget = "opencode") {
28128
28829
  try {
28129
- const content = await readFile37(resolve38(projectRoot, PROFILE_FILE), "utf-8");
28830
+ const content = await readFile40(resolve41(projectRoot, PROFILE_FILE), "utf-8");
28130
28831
  const data = $parse(content);
28131
28832
  return ExecutionProfileSchema.parse(data);
28132
28833
  } catch {
@@ -28206,14 +28907,14 @@ var init_execution_profile = __esm(() => {
28206
28907
  });
28207
28908
 
28208
28909
  // src/core/evaluation/prompt-diff.ts
28209
- import { readFile as readFile38, readdir as readdir13 } from "node:fs/promises";
28210
- 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";
28211
28912
  function normalizeVersion(v) {
28212
28913
  return v.startsWith("v") ? v : `v${v}`;
28213
28914
  }
28214
28915
  async function listPromptFiles(dir) {
28215
28916
  try {
28216
- const entries = await readdir13(dir, { withFileTypes: true });
28917
+ const entries = await readdir15(dir, { withFileTypes: true });
28217
28918
  return entries.filter((e) => e.isFile() && e.name.endsWith(".md")).map((e) => e.name);
28218
28919
  } catch {
28219
28920
  return [];
@@ -28256,30 +28957,30 @@ async function diffPromptVersions(fromVersion, toVersion, options = {}) {
28256
28957
  const fromV = normalizeVersion(fromVersion);
28257
28958
  const toV = normalizeVersion(toVersion);
28258
28959
  const searchRoots = [
28259
- resolve39(options.projectRoot ?? PACKAGE_ROOT, ".agents", "prompts"),
28260
- join26(ROOT_PRESETS_DIR, target, "prompts"),
28261
- 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")
28262
28963
  ];
28263
28964
  let fromDir = "";
28264
28965
  let toDir = "";
28265
28966
  for (const root of searchRoots) {
28266
- const f = join26(root, fromV);
28267
- const t = join26(root, toV);
28967
+ const f = join27(root, fromV);
28968
+ const t = join27(root, toV);
28268
28969
  try {
28269
- await readFile38(join26(f, "orchestrator.md"), "utf-8");
28970
+ await readFile41(join27(f, "orchestrator.md"), "utf-8");
28270
28971
  fromDir = f;
28271
28972
  toDir = t;
28272
28973
  break;
28273
28974
  } catch {}
28274
28975
  }
28275
28976
  if (!fromDir) {
28276
- fromDir = join26(ROOT_PRESETS_DIR, "opencode", "prompts", fromV);
28277
- 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);
28278
28979
  } else {
28279
28980
  try {
28280
- await readFile38(join26(toDir, "orchestrator.md"), "utf-8");
28981
+ await readFile41(join27(toDir, "orchestrator.md"), "utf-8");
28281
28982
  } catch {
28282
- toDir = join26(ROOT_PRESETS_DIR, "opencode", "prompts", toV);
28983
+ toDir = join27(ROOT_PRESETS_DIR, "opencode", "prompts", toV);
28283
28984
  }
28284
28985
  }
28285
28986
  const fromFiles = await listPromptFiles(fromDir);
@@ -28297,12 +28998,12 @@ async function diffPromptVersions(fromVersion, toVersion, options = {}) {
28297
28998
  let oldText = "";
28298
28999
  let newText = "";
28299
29000
  try {
28300
- oldText = await readFile38(join26(fromDir, name), "utf-8");
29001
+ oldText = await readFile41(join27(fromDir, name), "utf-8");
28301
29002
  } catch {
28302
29003
  oldText = "";
28303
29004
  }
28304
29005
  try {
28305
- newText = await readFile38(join26(toDir, name), "utf-8");
29006
+ newText = await readFile41(join27(toDir, name), "utf-8");
28306
29007
  } catch {
28307
29008
  newText = "";
28308
29009
  }
@@ -28342,12 +29043,12 @@ var init_prompt_diff = __esm(() => {
28342
29043
 
28343
29044
  // src/core/evaluation/regression-checklist.ts
28344
29045
  import { execFileSync as execFileSync4 } from "node:child_process";
28345
- import { mkdir as mkdir24, readFile as readFile39, writeFile as writeFile23 } from "node:fs/promises";
28346
- 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";
28347
29048
  async function loadRegressionChecklist() {
28348
29049
  try {
28349
- const path = resolve40(ROOT_PRESETS_DIR, "templates", "regression-checklist.yml");
28350
- 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");
28351
29052
  const data = $parse(content);
28352
29053
  return data.checks ?? [];
28353
29054
  } catch {
@@ -28402,9 +29103,9 @@ async function runRegressionChecklist(projectRoot, options = {}) {
28402
29103
  checks,
28403
29104
  timestamp: new Date().toISOString()
28404
29105
  };
28405
- const outPath = resolve40(projectRoot, ".codeconductor/evaluation/regression-last.json");
28406
- await mkdir24(dirname13(outPath), { recursive: true });
28407
- 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");
28408
29109
  return ok(report);
28409
29110
  } catch (e) {
28410
29111
  return err(e instanceof Error ? e : new Error(String(e)));
@@ -28446,8 +29147,8 @@ var init_model_comparison = __esm(() => {
28446
29147
  });
28447
29148
 
28448
29149
  // src/core/evaluation/cost-quality-matrix.ts
28449
- import { writeFile as writeFile24 } from "node:fs/promises";
28450
- import { resolve as resolve41 } from "node:path";
29150
+ import { writeFile as writeFile26 } from "node:fs/promises";
29151
+ import { resolve as resolve44 } from "node:path";
28451
29152
  async function buildCostQualityMatrix(projectRoot, outcomes) {
28452
29153
  const agg = aggregateOutcomes(outcomes);
28453
29154
  const rows = Object.entries(agg.byModel).map(([model, entry]) => {
@@ -28467,7 +29168,7 @@ async function buildCostQualityMatrix(projectRoot, outcomes) {
28467
29168
  rows
28468
29169
  };
28469
29170
  const dir = await ensureEvaluationDir(projectRoot);
28470
- await writeFile24(resolve41(dir, "matrix.yml"), $stringify(matrix), "utf-8");
29171
+ await writeFile26(resolve44(dir, "matrix.yml"), $stringify(matrix), "utf-8");
28471
29172
  return matrix;
28472
29173
  }
28473
29174
  function formatMatrixMarkdown(matrix) {
@@ -28491,8 +29192,8 @@ var init_cost_quality_matrix = __esm(() => {
28491
29192
  });
28492
29193
 
28493
29194
  // src/core/evaluation/ablation-report.ts
28494
- import { mkdir as mkdir25, writeFile as writeFile25 } from "node:fs/promises";
28495
- 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";
28496
29197
  function isPass(o) {
28497
29198
  return o.verdict === "PASS" || o.status === "pass";
28498
29199
  }
@@ -28660,10 +29361,10 @@ function formatAblationMarkdown(report) {
28660
29361
  `);
28661
29362
  }
28662
29363
  async function persistAblationReport(projectRoot, markdown) {
28663
- const dir = resolve42(projectRoot, EVAL_DIR2);
28664
- await mkdir25(dir, { recursive: true });
28665
- const path = resolve42(dir, "ablation-last.md");
28666
- 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");
28667
29368
  return path;
28668
29369
  }
28669
29370
  var SCORE_THRESHOLD = 0.1, PASS_RATE_THRESHOLD = 0.05;
@@ -28677,8 +29378,8 @@ var exports_scorecard_command = {};
28677
29378
  __export(exports_scorecard_command, {
28678
29379
  scorecardCommand: () => scorecardCommand
28679
29380
  });
28680
- import { readFile as readFile40 } from "node:fs/promises";
28681
- import { resolve as resolve43 } from "node:path";
29381
+ import { readFile as readFile43 } from "node:fs/promises";
29382
+ import { resolve as resolve46 } from "node:path";
28682
29383
  function contractVersion() {
28683
29384
  return package_default.version;
28684
29385
  }
@@ -28739,7 +29440,7 @@ async function handleCreate(projectRoot, options) {
28739
29440
  if (backlog.success && options.taskId) {
28740
29441
  const item = backlog.data.items.find((i) => i.id === options.taskId);
28741
29442
  if (item) {
28742
- scopeFiles = item.scope.split(/[,;]/).map((s) => s.trim()).filter(Boolean);
29443
+ scopeFiles = parseScopeFiles(item.scope);
28743
29444
  }
28744
29445
  }
28745
29446
  let hints = collectScorecardSignals(projectRoot, scopeFiles);
@@ -28823,7 +29524,7 @@ async function handleRecord(projectRoot, options) {
28823
29524
  const variantId = options.variantId ?? overlay?.variantId;
28824
29525
  const suiteTaskId = options.suiteTaskId;
28825
29526
  const disabled = overlay?.disabledComponents ?? (variantId ? parseVariantId(variantId) : undefined);
28826
- 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;
28827
29528
  const outcome = {
28828
29529
  id: generateEvalId("out"),
28829
29530
  taskId,
@@ -28838,10 +29539,17 @@ async function handleRecord(projectRoot, options) {
28838
29539
  costUsd: options.costUsd,
28839
29540
  tokensIn: options.tokens,
28840
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,
28841
29549
  experimentId,
28842
29550
  variantId,
28843
29551
  suiteTaskId,
28844
- harnessFingerprint: fingerprint,
29552
+ harnessFingerprint: fingerprint2,
28845
29553
  disabledComponents: disabled && disabled.length > 0 ? [...disabled] : disabled ? [] : undefined,
28846
29554
  status: options.verdict === "PASS" ? "pass" : options.verdict === "REJECT" ? "reject" : undefined
28847
29555
  };
@@ -28959,13 +29667,13 @@ async function handleCompareModels(projectRoot, options) {
28959
29667
  outcomes = outcomes.filter((o) => options.modelsFilter.includes(o.model));
28960
29668
  }
28961
29669
  const markdown = generateModelComparisonMarkdown(outcomes, options.modelsFilter);
28962
- const templatePath = resolve43(projectRoot, ".codeconductor/evaluation/model-comparison-last.md");
29670
+ const templatePath = resolve46(projectRoot, ".codeconductor/evaluation/model-comparison-last.md");
28963
29671
  try {
28964
- await readFile40(templatePath);
29672
+ await readFile43(templatePath);
28965
29673
  } catch {}
28966
- const { writeFile: writeFile26, mkdir: mkdir26 } = await import("node:fs/promises");
28967
- await mkdir26(resolve43(projectRoot, ".codeconductor/evaluation"), { recursive: true });
28968
- 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");
28969
29677
  return {
28970
29678
  code: 0,
28971
29679
  data: {
@@ -30434,7 +31142,7 @@ var exports_seo_audit_command = {};
30434
31142
  __export(exports_seo_audit_command, {
30435
31143
  seoAuditCommand: () => seoAuditCommand
30436
31144
  });
30437
- import { join as join27 } from "node:path";
31145
+ import { join as join28 } from "node:path";
30438
31146
  async function seoAuditCommand(options) {
30439
31147
  const { url, sitemap, format, failOn, delay: delay2, output, followRedirects, force } = options;
30440
31148
  if (!url && !sitemap) {
@@ -30447,7 +31155,7 @@ async function seoAuditCommand(options) {
30447
31155
  }
30448
31156
  };
30449
31157
  }
30450
- 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;
30451
31159
  const outputPathToWrite = output ?? defaultMarkdownPath;
30452
31160
  if (outputPathToWrite !== undefined) {
30453
31161
  const preflightError = await preflightContainedOutput(options.projectRoot, outputPathToWrite, { force });
@@ -30832,6 +31540,7 @@ var COMMANDS = [
30832
31540
  { name: "orchestrate", group: "workflow", summary: "Run goal execution orchestration.", usage: ["cc-codeconductor orchestrate <subcommand>"] },
30833
31541
  { name: "impact", group: "workflow", summary: "Analyze change impact.", usage: ["cc-codeconductor impact [--files <paths>]"] },
30834
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"] },
30835
31544
  { name: "seo", group: "tool", summary: "Audit SEO and generate llms.txt.", usage: ["cc-codeconductor seo audit --url <url>"] },
30836
31545
  { name: "debt-harvest", aliases: ["harvest"], group: "tool", summary: "Scan source files for deferred debt.", usage: ["cc-codeconductor debt-harvest"] }
30837
31546
  ];
@@ -31310,6 +32019,24 @@ async function routeCommand(args, projectRoot) {
31310
32019
  allowCompileCheck: options["allow-compile-check"] === true || options["allow-compile-check"] === "true"
31311
32020
  });
31312
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
+ }
31313
32040
  case "ccep": {
31314
32041
  const validSubs = ["parse", "profile", "resolve", "compile", "validate", "evaluate", "consensus", "taskcard"];
31315
32042
  if (subcommand && !validSubs.includes(subcommand)) {
@@ -31348,6 +32075,7 @@ async function routeCommand(args, projectRoot) {
31348
32075
  "start",
31349
32076
  "done",
31350
32077
  "block",
32078
+ "unblock",
31351
32079
  "archive"
31352
32080
  ];
31353
32081
  let openspecSub = "validate";
@@ -31370,6 +32098,19 @@ async function routeCommand(args, projectRoot) {
31370
32098
  output: flags.output
31371
32099
  });
31372
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
+ }
31373
32114
  case "hook": {
31374
32115
  const validHookEvents = ["pre-tool", "post-tool", "session-start"];
31375
32116
  if (subcommand && !validHookEvents.includes(subcommand)) {
@@ -31433,6 +32174,10 @@ async function routeCommand(args, projectRoot) {
31433
32174
  costUsd: options.cost ? parseFloat(String(options.cost)) : undefined,
31434
32175
  tokens: options.tokens ? parseInt(String(options.tokens), 10) : undefined,
31435
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,
31436
32181
  verdict: options.verdict,
31437
32182
  weightedScore: options.score ? parseFloat(String(options.score)) : undefined,
31438
32183
  source: options.source,