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