codecartographer-pi 0.19.5 → 0.19.6
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/templates/gitignore +55 -0
- package/.codecarto/workflow/scaffold-version.yaml +1 -1
- package/dist/core/amendment.js +28 -23
- package/dist/core/broadside.js +3 -5
- package/dist/core/completion.js +14 -4
- package/dist/core/library.js +111 -106
- package/dist/core/status.d.ts +22 -2
- package/dist/core/status.js +46 -5
- package/dist/core/usage.d.ts +8 -0
- package/dist/core/usage.js +35 -7
- package/dist/core/utils.d.ts +32 -5
- package/dist/core/utils.js +81 -19
- package/dist/core/workspace.d.ts +44 -10
- package/dist/core/workspace.js +161 -30
- package/dist/extensions/codecarto/dashboard-narrator.js +3 -6
- package/dist/extensions/codecarto/dashboard-writer.js +3 -6
- package/dist/extensions/codecarto/index.js +9 -4
- package/dist/extensions/codecarto/phase-compaction.js +7 -7
- package/dist/mcp-server/server.js +4 -1
- package/package.json +1 -1
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
// HTML to `.codecarto/dashboard.html`. Best-effort — failures are swallowed
|
|
3
3
|
// and never escalate to a phase error the user sees, mirroring the
|
|
4
4
|
// recordUsage discipline at extensions/codecarto/index.ts.
|
|
5
|
-
import { readdir, readFile
|
|
5
|
+
import { readdir, readFile } from "node:fs/promises";
|
|
6
6
|
import { join } from "node:path";
|
|
7
|
-
import { DASHBOARD_RELATIVE_PATH, getWorkspaceState, loadUsage, NARRATION_CACHE_RELATIVE_PATH, parseSimpleYaml, pathExists, renderDashboard, } from "../../core/index.js";
|
|
7
|
+
import { atomicWriteFile, DASHBOARD_RELATIVE_PATH, getWorkspaceState, loadUsage, NARRATION_CACHE_RELATIVE_PATH, parseSimpleYaml, pathExists, renderDashboard, } from "../../core/index.js";
|
|
8
8
|
const CLOSEOUT_FILENAME_RE = /^(\d{4}-\d{2}-\d{2})-(.+)\.md$/;
|
|
9
9
|
/**
|
|
10
10
|
* Render and atomically replace `.codecarto/dashboard.html`.
|
|
@@ -36,10 +36,7 @@ export async function writeDashboard(cwd, packageVersion) {
|
|
|
36
36
|
narration,
|
|
37
37
|
};
|
|
38
38
|
const html = renderDashboard(inputs);
|
|
39
|
-
|
|
40
|
-
const tempPath = `${path}.${process.pid}.${Date.now()}.tmp`;
|
|
41
|
-
await writeFile(tempPath, html, "utf8");
|
|
42
|
-
await rename(tempPath, path);
|
|
39
|
+
await atomicWriteFile(join(workspaceDir, DASHBOARD_RELATIVE_PATH), html);
|
|
43
40
|
return true;
|
|
44
41
|
}
|
|
45
42
|
catch {
|
|
@@ -11,7 +11,7 @@ import { parseNextFlags } from "./next-flags.js";
|
|
|
11
11
|
import { buildPiGuideMessage } from "./guide-framing.js";
|
|
12
12
|
import { isCtxLive, notifyCtx } from "./notify.js";
|
|
13
13
|
import { phaseCompactionExtension } from "./phase-compaction.js";
|
|
14
|
-
import { applyAmendment, buildPhasePrompt, buildSkillPrompt, buildValidationSummary, canonicalPath, copyPackagedWorkspace, computePerPhaseTotals, computeTotals, ConfidentialityMismatchError, createEmptyStatus, DEFAULT_PIPELINE_PATH, describeScaffoldStaleness, deriveSlug, discoverLibrary, getNextEligiblePhase, getPipelineLabel, getWorkspaceState,
|
|
14
|
+
import { applyAmendment, buildPhasePrompt, buildSkillPrompt, buildValidationSummary, canonicalPath, copyPackagedWorkspace, computePerPhaseTotals, computeTotals, ConfidentialityMismatchError, createEmptyStatus, DEFAULT_PIPELINE_PATH, describeScaffoldStaleness, deriveSlug, discoverLibrary, getNextEligiblePhase, getPipelineLabel, getWorkspaceState, isWithinPath, resolveExistingPrefix, BROADSIDE_LENS_IDS, BROADSIDE_SKILL_NAME, BroadsideCancelledError, broadsideDirFor, collectResultText, estimateSubmitText, getLens, listAmendmentNames, listBatchModels, listGuideTopics, listScaffoldRefreshFiles, listSkillNames, loadAmendmentFile, loadBroadsideConfig, modelsText, runBroadsideCollect, runBroadsideStatus, runBroadsideSubmit, statusText, loadCodecartoConfig, loadUsage, loadYamlFile, normalizeForComparison, packagedWorkspaceDir, pathExists, PACKAGE_VERSION, readBroadsideSkill, readGuide, refreshScaffold, PhasePreflightError, PIPELINE_ALIASES, publishEntry, resolvePhase, resolvePipelineChoice, resolvePublishSourceRepo, SourceRepoMismatchError, runPhasePreflight, SCAFFOLD_REFRESH_PROTECTED, seedOrchestratorFiles, stringifySimpleYaml, switchPipeline, validatePhaseOutput, writeLibraryConfig, } from "../../core/index.js";
|
|
15
15
|
import { initLibrary } from "../../core/library.js";
|
|
16
16
|
import { resolveUserConfigPath } from "../../core/orchestrator-config.js";
|
|
17
17
|
const STATUS_WIDGET_ID = "codecarto-widget";
|
|
@@ -343,13 +343,17 @@ export default function codeCartographerExtension(pi) {
|
|
|
343
343
|
if (event.toolName === "edit" || event.toolName === "write") {
|
|
344
344
|
const inputPath = typeof event.input.path === "string" ? event.input.path : "";
|
|
345
345
|
const strippedPath = inputPath.startsWith("@") ? inputPath.slice(1) : inputPath;
|
|
346
|
-
|
|
346
|
+
// Resolve through whatever already exists on disk — symlinks included —
|
|
347
|
+
// before appending the unborn tail. `resolve()` would collapse
|
|
348
|
+
// `link/..` lexically and `realpath()` throws on a file that is not
|
|
349
|
+
// there yet, and either gap let a write escape the workspace (#223).
|
|
350
|
+
const targetPath = await resolveExistingPrefix(strippedPath, ctx.cwd);
|
|
347
351
|
const allowedRoots = [await canonicalPath(workspaceDir)];
|
|
348
352
|
const config = await loadCodecartoConfig(workspaceDir);
|
|
349
353
|
if (config.library.path && await discoverLibrary(config.library.path)) {
|
|
350
354
|
allowedRoots.push(await canonicalPath(config.library.path));
|
|
351
355
|
}
|
|
352
|
-
const withinAllowed =
|
|
356
|
+
const withinAllowed = allowedRoots.map((allowedRoot) => isWithinPath(targetPath, allowedRoot));
|
|
353
357
|
if (!withinAllowed.some((result) => result)) {
|
|
354
358
|
notifyCtx(ctx, `Blocked ${event.toolName} outside .codecarto/ or configured library: ${inputPath}`, "warning");
|
|
355
359
|
return { block: true, reason: `CodeCartographer mode only allows ${event.toolName} within .codecarto/ or the configured CodeCartographer library.` };
|
|
@@ -447,7 +451,8 @@ export default function codeCartographerExtension(pi) {
|
|
|
447
451
|
await copyPackagedWorkspace(targetWorkspaceDir);
|
|
448
452
|
}
|
|
449
453
|
const rawStatusPath = join(targetWorkspaceDir, "workflow", "status.yaml");
|
|
450
|
-
|
|
454
|
+
// Absent on a fresh copy: the template ships no status.yaml.
|
|
455
|
+
const rawStatus = (await pathExists(rawStatusPath)) ? ((await loadYamlFile(rawStatusPath)) ?? {}) : {};
|
|
451
456
|
const selectedPipelinePath = pipelineChoice ?? rawStatus.pipeline?.trim() ?? DEFAULT_PIPELINE_PATH;
|
|
452
457
|
const resolvedPipelinePath = join(targetWorkspaceDir, selectedPipelinePath);
|
|
453
458
|
if (!(await pathExists(resolvedPipelinePath))) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { mkdir
|
|
2
|
-
import { join
|
|
1
|
+
import { mkdir } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
3
|
import { compact } from "@earendil-works/pi-coding-agent";
|
|
4
|
-
import { canonicalPath, getWorkspaceState, isWithinPath } from "../../core/index.js";
|
|
4
|
+
import { atomicWriteFile, canonicalPath, getWorkspaceState, isWithinPath, resolveExistingPrefix } from "../../core/index.js";
|
|
5
5
|
const PHASE_SESSION_PREFIX = "CodeCartographer phase: ";
|
|
6
6
|
export function phaseIdFromSessionName(sessionName) {
|
|
7
7
|
if (!sessionName?.startsWith(PHASE_SESSION_PREFIX))
|
|
@@ -29,7 +29,6 @@ export function buildPhaseCompactionInstructions(phaseId, primaryOutput) {
|
|
|
29
29
|
export async function writePhaseCheckpoint(cwd, phaseId, summary, tokensBefore) {
|
|
30
30
|
const dir = join(cwd, ".codecarto", "scratch", "checkpoints");
|
|
31
31
|
const target = join(dir, `${phaseId}.md`);
|
|
32
|
-
const temp = `${target}.${process.pid}.${Date.now()}.tmp`;
|
|
33
32
|
await mkdir(dir, { recursive: true });
|
|
34
33
|
const content = [
|
|
35
34
|
"---",
|
|
@@ -44,8 +43,7 @@ export async function writePhaseCheckpoint(cwd, phaseId, summary, tokensBefore)
|
|
|
44
43
|
summary.trim(),
|
|
45
44
|
"",
|
|
46
45
|
].join("\n");
|
|
47
|
-
await
|
|
48
|
-
await rename(temp, target);
|
|
46
|
+
await atomicWriteFile(target, content);
|
|
49
47
|
return target;
|
|
50
48
|
}
|
|
51
49
|
/**
|
|
@@ -64,7 +62,9 @@ export function phaseCompactionExtension(pi) {
|
|
|
64
62
|
if (event.toolName === "edit" || event.toolName === "write") {
|
|
65
63
|
const inputPath = typeof event.input.path === "string" ? event.input.path : "";
|
|
66
64
|
const strippedPath = inputPath.startsWith("@") ? inputPath.slice(1) : inputPath;
|
|
67
|
-
|
|
65
|
+
// Same containment as the parent extension's hook (#223): follow the
|
|
66
|
+
// existing prefix through symlinks, then append the unborn tail.
|
|
67
|
+
const targetPath = await resolveExistingPrefix(strippedPath, ctx.cwd);
|
|
68
68
|
const allowedRoot = await canonicalPath(join(ctx.cwd, ".codecarto"));
|
|
69
69
|
if (!isWithinPath(targetPath, allowedRoot)) {
|
|
70
70
|
return {
|
|
@@ -125,8 +125,11 @@ export async function handleInit(args) {
|
|
|
125
125
|
// broadside state and results already on disk.
|
|
126
126
|
await copyPackagedWorkspace(targetWorkspaceDir);
|
|
127
127
|
}
|
|
128
|
+
// The template no longer carries a status.yaml (it is this repository's
|
|
129
|
+
// own project state); one is only present when init is re-run over an
|
|
130
|
+
// existing workspace, where its pipeline stays the default.
|
|
128
131
|
const statusPath = join(targetWorkspaceDir, "workflow", "status.yaml");
|
|
129
|
-
const rawStatus = (await loadYamlFile(statusPath)) ?? {};
|
|
132
|
+
const rawStatus = (await pathExists(statusPath)) ? ((await loadYamlFile(statusPath)) ?? {}) : {};
|
|
130
133
|
const selectedPipelinePath = pipelineChoice ?? rawStatus.pipeline?.trim() ?? DEFAULT_PIPELINE_PATH;
|
|
131
134
|
const resolvedPipelinePath = join(targetWorkspaceDir, selectedPipelinePath);
|
|
132
135
|
if (!(await pathExists(resolvedPipelinePath))) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codecartographer-pi",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.6",
|
|
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",
|