codecartographer-pi 0.17.0 → 0.17.1
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/.codecarto/GUIDE.md +1 -1
- package/.codecarto/findings/architecture/SKILL.md +1 -0
- package/.codecarto/findings/contracts/SKILL.md +1 -0
- package/.codecarto/findings/defect-scan/SKILL.md +15 -1
- package/.codecarto/findings/defect-scan/passes/01-logic-and-correctness.md +1 -1
- package/.codecarto/findings/defect-scan/passes/02-error-handling.md +1 -1
- package/.codecarto/findings/defect-scan/passes/03-concurrency-and-resources.md +1 -1
- package/.codecarto/findings/defect-scan/passes/04-security-and-trust.md +1 -1
- package/.codecarto/findings/defect-scan/passes/05-api-contract-violations.md +2 -1
- package/.codecarto/findings/defect-scan/passes/06-config-and-environment.md +1 -1
- package/.codecarto/findings/defect-scan-mechanical/SKILL.md +3 -2
- package/.codecarto/findings/defect-scan-semantic/SKILL.md +2 -0
- package/.codecarto/findings/porting/SKILL.md +2 -1
- package/.codecarto/findings/protocols/SKILL.md +1 -0
- package/.codecarto/findings/reimplementation-spec/SKILL.md +1 -1
- package/.codecarto/templates/architecture-map.md +1 -1
- package/.codecarto/templates/defect-report.md +23 -0
- package/.codecarto/templates/mechanical-defects.md +22 -0
- package/.codecarto/templates/reverse-engineering-bundle.md +2 -2
- package/.codecarto/templates/semantic-defects.md +26 -0
- package/.codecarto/workflow/VALIDATE.md +1 -1
- package/.codecarto/workflow/pipeline-defect-scan.yaml +2 -0
- package/.codecarto/workflow/pipeline-full-with-audit.yaml +3 -1
- package/.codecarto/workflow/pipeline-full-with-deep-audit.yaml +5 -1
- package/.codecarto/workflow/pipeline-scout-first.yaml +5 -1
- package/.codecarto/workflow/scaffold-version.yaml +1 -1
- package/README.md +4 -4
- package/agent-skill/codecartographer/references/deep-audit-synthesis.md +4 -1
- package/agent-skill/codecartographer/references/library.md +1 -1
- package/agent-skill/codecartographer/references/orchestration.md +1 -1
- package/dist/core/amendment.js +2 -2
- package/dist/core/completion.d.ts +5 -0
- package/dist/core/completion.js +18 -2
- package/dist/core/dashboard.js +5 -3
- package/dist/core/findings.d.ts +59 -0
- package/dist/core/findings.js +145 -0
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.js +1 -0
- package/dist/core/library.d.ts +66 -1
- package/dist/core/library.js +161 -8
- package/dist/core/pipeline.js +15 -0
- package/dist/core/prompts.js +1 -1
- package/dist/core/status.js +14 -6
- package/dist/core/types.d.ts +6 -0
- package/dist/core/utils.d.ts +14 -0
- package/dist/core/utils.js +30 -0
- package/dist/core/workspace.js +11 -18
- package/dist/core/yaml.js +19 -4
- package/dist/extensions/codecarto/auto-runner.d.ts +2 -0
- package/dist/extensions/codecarto/broadside-flags.d.ts +7 -2
- package/dist/extensions/codecarto/broadside-flags.js +22 -9
- package/dist/extensions/codecarto/dashboard-narrator.js +1 -1
- package/dist/extensions/codecarto/index.js +40 -16
- package/dist/extensions/codecarto/phase-compaction.js +4 -0
- package/dist/mcp-server/server.js +65 -7
- package/package.json +2 -2
|
@@ -17,7 +17,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
17
17
|
import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError, } from "@modelcontextprotocol/sdk/types.js";
|
|
18
18
|
import { mkdir, readFile, readdir, rename, writeFile } from "node:fs/promises";
|
|
19
19
|
import { basename, isAbsolute, join } from "node:path";
|
|
20
|
-
import { buildPhasePrompt, buildSkillPrompt, buildValidationSummary, BROADSIDE_DIR, broadsideDirFor, BROADSIDE_LENS_IDS, BROADSIDE_SKILL_NAME, canonicalPath, copyPackagedWorkspace, collectResultText, completeValidatedPhase, computePerPhaseTotals, computeTotals, createEmptyStatus, DEFAULT_PIPELINE_PATH, deriveSlug, discoverLibrary, describeScaffoldStaleness, estimateSubmitText, getLens, getNextEligiblePhase, getPipelineLabel, getWorkspaceState, isValidSlug, isWithinPathResolved, listBatchModels, listEntries, listGuideTopics, loadBroadsideConfig, modelsText, readGuide, listSkillNames, loadCodecartoConfig, loadUsage, loadYamlFile, normalizeForComparison, PACKAGE_VERSION, packagedWorkspaceDir, pathExists, PhasePreflightError, publishEntry, reindex as libraryReindex, refreshScaffold, resolvePhase, resolvePipelineChoice, readBroadsideSkill, runBroadsideCollect, runBroadsideStatus, runBroadsideSubmit, seedOrchestratorFiles, statusText, stringifySimpleYaml, switchPipeline, validatePhaseOutput, writeLibraryConfig, } from "../core/index.js";
|
|
20
|
+
import { buildPhasePrompt, buildSkillPrompt, buildValidationSummary, BROADSIDE_DIR, broadsideDirFor, BROADSIDE_LENS_IDS, BROADSIDE_SKILL_NAME, canonicalPath, copyPackagedWorkspace, collectResultText, completeValidatedPhase, computePerPhaseTotals, computeTotals, createEmptyStatus, DEFAULT_PIPELINE_PATH, deriveSlug, discoverLibrary, describeScaffoldStaleness, detectProvenanceConflicts, estimateSubmitText, getLens, getNextEligiblePhase, getPipelineLabel, getWorkspaceState, isValidSlug, isWithinPathResolved, listBatchModels, listEntries, listGuideTopics, loadBroadsideConfig, modelsText, readGuide, listSkillNames, loadCodecartoConfig, loadUsage, loadYamlFile, normalizeForComparison, PACKAGE_VERSION, packagedWorkspaceDir, pathExists, PhasePreflightError, publishEntry, reindex as libraryReindex, refreshScaffold, resolvePhase, resolvePipelineChoice, readBroadsideSkill, runBroadsideCollect, runBroadsideStatus, runBroadsideSubmit, seedOrchestratorFiles, statusText, stringifySimpleYaml, switchPipeline, validatePhaseOutput, writeLibraryConfig, } from "../core/index.js";
|
|
21
21
|
import { applyAmendment } from "../core/amendment.js";
|
|
22
22
|
import { appendUsageRun } from "../core/usage.js";
|
|
23
23
|
import { initLibrary } from "../core/library.js";
|
|
@@ -262,7 +262,7 @@ export async function handleComplete(args) {
|
|
|
262
262
|
if (validation.overall === "FAIL" || validation.overall === "MISSING") {
|
|
263
263
|
throw new McpError(ErrorCode.InvalidRequest, `Cannot complete ${validation.phaseId}: validation is ${validation.overall}.\n${buildValidationSummary(validation).join("\n")}`);
|
|
264
264
|
}
|
|
265
|
-
const { updatedState, closeoutNotice, orchestratorCheckpoint } = await completeValidatedPhase(cwd, validation, "codecarto_complete").catch((error) => {
|
|
265
|
+
const { updatedState, closeoutNotice, orchestratorCheckpoint, warnings } = await completeValidatedPhase(cwd, validation, "codecarto_complete").catch((error) => {
|
|
266
266
|
throw new McpError(ErrorCode.InvalidParams, error instanceof Error ? error.message : String(error));
|
|
267
267
|
});
|
|
268
268
|
// Record the run in the usage log (issue #100). MCP hosts execute phases in
|
|
@@ -303,6 +303,10 @@ export async function handleComplete(args) {
|
|
|
303
303
|
lines.push(orchestratorCheckpoint);
|
|
304
304
|
if (dashboardPath)
|
|
305
305
|
lines.push(`Dashboard refreshed: ${dashboardPath}`);
|
|
306
|
+
for (const warning of validation.warnings ?? [])
|
|
307
|
+
lines.push(`NOTE: ${warning} Non-gating.`);
|
|
308
|
+
for (const warning of warnings)
|
|
309
|
+
lines.push(`NOTE: ${warning} Non-gating.`);
|
|
306
310
|
return textResult(lines.join("\n"), {
|
|
307
311
|
completedPhase: validation.phaseId,
|
|
308
312
|
validation: validation.overall,
|
|
@@ -310,6 +314,7 @@ export async function handleComplete(args) {
|
|
|
310
314
|
closeoutNotice,
|
|
311
315
|
orchestratorCheckpoint,
|
|
312
316
|
dashboardPath,
|
|
317
|
+
warnings: [...(validation.warnings ?? []), ...warnings],
|
|
313
318
|
});
|
|
314
319
|
}
|
|
315
320
|
export async function handleSkill(args) {
|
|
@@ -472,6 +477,33 @@ async function resolveDefaultsFromWorkspace(cwd, overrides) {
|
|
|
472
477
|
}
|
|
473
478
|
return { pipeline, namespace };
|
|
474
479
|
}
|
|
480
|
+
// ---------- library provenance reporting ----------
|
|
481
|
+
function conflictEntryLabel(conflict) {
|
|
482
|
+
return conflict.namespace ? `${conflict.namespace}/${conflict.slug}` : conflict.slug;
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
485
|
+
* The report block appended to the list and reindex text results when an
|
|
486
|
+
* entry's versions disagree about source_repo (#148). Empty when there is
|
|
487
|
+
* nothing to report, so a healthy library's output does not change. Repair
|
|
488
|
+
* is manual by design: the framework does not rename or renumber versions,
|
|
489
|
+
* because entry paths are ABI.
|
|
490
|
+
*/
|
|
491
|
+
function provenanceConflictLines(conflicts) {
|
|
492
|
+
if (conflicts.length === 0)
|
|
493
|
+
return [];
|
|
494
|
+
const lines = [
|
|
495
|
+
"",
|
|
496
|
+
`Provenance conflicts — ${conflicts.length} ${conflicts.length === 1 ? "entry" : "entries"} whose versions disagree about source_repo:`,
|
|
497
|
+
];
|
|
498
|
+
for (const conflict of conflicts) {
|
|
499
|
+
const others = conflict.disagreeing_versions
|
|
500
|
+
.map((v) => `v${v.version} records ${v.source_repo}`)
|
|
501
|
+
.join("; ");
|
|
502
|
+
lines.push(` ${conflictEntryLabel(conflict)}: the index advertises ${conflict.source_repo} (v${conflict.latest_version}), but ${others}.`);
|
|
503
|
+
}
|
|
504
|
+
lines.push("These entries were merged by a slug collision before publish refused cross-project appends, so each version history spans more than one codebase (a repository that genuinely moved and was re-published with allow_source_repo_change leaves the same shape).", "Repair is manual: split the entry by hand — the framework does not rename or renumber versions, because entry paths are ABI.");
|
|
505
|
+
return lines;
|
|
506
|
+
}
|
|
475
507
|
// ---------- library handlers ----------
|
|
476
508
|
export async function handlePublish(args) {
|
|
477
509
|
const libraryPath = await resolveLibraryPath(args);
|
|
@@ -536,6 +568,7 @@ export async function handlePublish(args) {
|
|
|
536
568
|
}, {
|
|
537
569
|
forceNewVersion: args.force_new_version === true,
|
|
538
570
|
allowSourceRepoChange: args.allow_source_repo_change === true,
|
|
571
|
+
allowConfidentialityMismatch: args.allow_confidentiality_mismatch === true,
|
|
539
572
|
});
|
|
540
573
|
const lines = [
|
|
541
574
|
`Published ${result.namespace ? `${result.namespace}/` : ""}${result.slug} v${result.version} to ${libraryPath}`,
|
|
@@ -567,6 +600,10 @@ export async function handleLibraryList(args) {
|
|
|
567
600
|
if (typeof args.source_repo === "string" && args.source_repo !== "")
|
|
568
601
|
filter.source_repo = args.source_repo;
|
|
569
602
|
const entries = await listEntries(libraryPath, filter);
|
|
603
|
+
// Computed over the listed entries only, read-only: one readdir per entry
|
|
604
|
+
// plus one small metadata read per older version.
|
|
605
|
+
const conflicts = await detectProvenanceConflicts(libraryPath, entries);
|
|
606
|
+
const conflicted = new Set(conflicts.map((c) => `${c.namespace ?? ""}/${c.slug}`));
|
|
570
607
|
const summary = entries.length === 0
|
|
571
608
|
? `No entries match the filter in ${libraryPath}.`
|
|
572
609
|
: [
|
|
@@ -574,8 +611,10 @@ export async function handleLibraryList(args) {
|
|
|
574
611
|
...entries.map((e) => {
|
|
575
612
|
const ns = e.namespace ? `${e.namespace}/` : "";
|
|
576
613
|
const tags = e.tags.length > 0 ? ` [${e.tags.slice(0, 4).join(", ")}${e.tags.length > 4 ? ", ..." : ""}]` : "";
|
|
577
|
-
|
|
614
|
+
const flag = conflicted.has(`${e.namespace ?? ""}/${e.slug}`) ? " — PROVENANCE CONFLICT (see below)" : "";
|
|
615
|
+
return ` ${ns}${e.slug} v${e.latest_version} — ${e.headline}${tags}${flag}`;
|
|
578
616
|
}),
|
|
617
|
+
...provenanceConflictLines(conflicts),
|
|
579
618
|
].join("\n");
|
|
580
619
|
return textResult(summary, {
|
|
581
620
|
libraryPath,
|
|
@@ -583,6 +622,7 @@ export async function handleLibraryList(args) {
|
|
|
583
622
|
namespaced: marker.namespaced,
|
|
584
623
|
count: entries.length,
|
|
585
624
|
entries,
|
|
625
|
+
provenance_conflicts: conflicts,
|
|
586
626
|
});
|
|
587
627
|
}
|
|
588
628
|
export async function handleLibraryReindex(args) {
|
|
@@ -593,17 +633,27 @@ export async function handleLibraryReindex(args) {
|
|
|
593
633
|
}
|
|
594
634
|
const index = await libraryReindex(libraryPath);
|
|
595
635
|
const namespaces = index.namespaces.length > 0 ? index.namespaces.join(", ") : "(none)";
|
|
596
|
-
return textResult(
|
|
636
|
+
return textResult([
|
|
637
|
+
`Reindexed ${libraryPath}: ${index.entry_count} ${index.entry_count === 1 ? "entry" : "entries"} across namespaces [${namespaces}].`,
|
|
638
|
+
...provenanceConflictLines(index.provenance_conflicts),
|
|
639
|
+
].join("\n"), {
|
|
597
640
|
libraryPath,
|
|
598
641
|
libraryName: index.library_name,
|
|
599
642
|
entry_count: index.entry_count,
|
|
600
643
|
namespaces: index.namespaces,
|
|
644
|
+
provenance_conflicts: index.provenance_conflicts,
|
|
601
645
|
});
|
|
602
646
|
}
|
|
603
647
|
export async function handleLibraryInit(args) {
|
|
604
648
|
if (!args.library_path || typeof args.library_path !== "string") {
|
|
605
649
|
throw new McpError(ErrorCode.InvalidParams, "library_path is required.");
|
|
606
650
|
}
|
|
651
|
+
// Same rule as resolveLibraryPath for the other library tools: a relative
|
|
652
|
+
// path would resolve against the MCP server process's cwd and then be
|
|
653
|
+
// persisted verbatim into the user-global config (#134).
|
|
654
|
+
if (!isAbsolute(args.library_path)) {
|
|
655
|
+
throw new McpError(ErrorCode.InvalidParams, `library_path must be absolute, got: ${args.library_path}`);
|
|
656
|
+
}
|
|
607
657
|
const libraryPath = args.library_path;
|
|
608
658
|
const namespaced = !!args.namespace;
|
|
609
659
|
const result = await initLibrary(libraryPath, {
|
|
@@ -1029,7 +1079,11 @@ const TOOLS = [
|
|
|
1029
1079
|
headline: { type: "string" },
|
|
1030
1080
|
tags: { type: "array", items: { type: "string" } },
|
|
1031
1081
|
capabilities: { type: "array", items: { type: "string" } },
|
|
1032
|
-
confidentiality: {
|
|
1082
|
+
confidentiality: {
|
|
1083
|
+
type: "string",
|
|
1084
|
+
enum: ["internal", "shared", "public"],
|
|
1085
|
+
description: "Classification of the entry. Defaults to internal. Ordered internal < shared < public; publish refuses an entry more restricted than the library's visibility unless allow_confidentiality_mismatch is set.",
|
|
1086
|
+
},
|
|
1033
1087
|
model_metadata: {
|
|
1034
1088
|
type: "object",
|
|
1035
1089
|
properties: {
|
|
@@ -1046,13 +1100,17 @@ const TOOLS = [
|
|
|
1046
1100
|
type: "boolean",
|
|
1047
1101
|
description: "Permit publishing when the target entry already records a different source_repo. Off by default, because a mismatch usually means two projects derived the same slug and the spec would land in the wrong version history. Set only when the repository itself moved.",
|
|
1048
1102
|
},
|
|
1103
|
+
allow_confidentiality_mismatch: {
|
|
1104
|
+
type: "boolean",
|
|
1105
|
+
description: "Permit publishing when the entry's confidentiality is more restricted than the library's visibility (internal < shared < public: an internal entry into a shared or public library, a shared entry into a public one). Off by default, because that direction exposes the spec to everyone the library reaches. An omitted confidentiality counts as internal. Set only when the exposure is intended; the recorded confidentiality is not changed.",
|
|
1106
|
+
},
|
|
1049
1107
|
},
|
|
1050
1108
|
required: ["source_repo", "headline"],
|
|
1051
1109
|
},
|
|
1052
1110
|
},
|
|
1053
1111
|
{
|
|
1054
1112
|
name: "codecarto_library_list",
|
|
1055
|
-
description: "List entries in a CodeCartographer library, optionally filtered by namespace, tag, slug, or source_repo. The library is identified by library_path (absolute) or by cwd's config.yaml.",
|
|
1113
|
+
description: "List entries in a CodeCartographer library, optionally filtered by namespace, tag, slug, or source_repo. The library is identified by library_path (absolute) or by cwd's config.yaml. Flags entries whose versions disagree about source_repo (merged by a slug collision before publish refused cross-project appends); repair is manual.",
|
|
1056
1114
|
inputSchema: {
|
|
1057
1115
|
type: "object",
|
|
1058
1116
|
properties: {
|
|
@@ -1067,7 +1125,7 @@ const TOOLS = [
|
|
|
1067
1125
|
},
|
|
1068
1126
|
{
|
|
1069
1127
|
name: "codecarto_library_reindex",
|
|
1070
|
-
description: "Regenerate index.yaml and INDEX.md for a CodeCartographer library from filesystem state. Use after manual edits or to resolve a git merge conflict on index.yaml.",
|
|
1128
|
+
description: "Regenerate index.yaml and INDEX.md for a CodeCartographer library from filesystem state. Use after manual edits or to resolve a git merge conflict on index.yaml. Also reports entries whose versions disagree about source_repo (merged by a slug collision before publish refused cross-project appends); the index files are not changed and repair is manual.",
|
|
1071
1129
|
inputSchema: {
|
|
1072
1130
|
type: "object",
|
|
1073
1131
|
properties: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codecartographer-pi",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.1",
|
|
4
4
|
"mcpName": "io.github.HuginnIndustries/codecartographer",
|
|
5
5
|
"description": "Turn an unfamiliar codebase into a validated reimplementation spec, then synthesize confirmed specs and a product vision into a traceable plan.",
|
|
6
6
|
"type": "module",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"@modelcontextprotocol/sdk": "^1.29.0"
|
|
65
65
|
},
|
|
66
66
|
"peerDependencies": {
|
|
67
|
-
"@earendil-works/pi-coding-agent": "
|
|
67
|
+
"@earendil-works/pi-coding-agent": ">=0.84.0",
|
|
68
68
|
"@sinclair/typebox": "*"
|
|
69
69
|
},
|
|
70
70
|
"pi": {
|