codecartographer-pi 0.19.4 → 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/auto-runner.js +11 -17
- package/dist/extensions/codecarto/dashboard-narrator.js +3 -6
- package/dist/extensions/codecarto/dashboard-writer.js +3 -6
- package/dist/extensions/codecarto/index.js +101 -135
- package/dist/extensions/codecarto/notify.d.ts +16 -0
- package/dist/extensions/codecarto/notify.js +53 -0
- package/dist/extensions/codecarto/phase-compaction.js +7 -7
- package/dist/mcp-server/server.js +4 -1
- package/package.json +1 -1
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ExtensionCommandContext, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
export type NotifyLevel = "info" | "warning" | "error";
|
|
3
|
+
/** Whether `ctx` still belongs to the live session. See the module comment. */
|
|
4
|
+
export declare function isCtxLive(ctx: ExtensionContext | ExtensionCommandContext): boolean;
|
|
5
|
+
/**
|
|
6
|
+
* Format a notification for a stream. Exported so tests pin the shape a script
|
|
7
|
+
* would parse: one line, prefixed, level visible.
|
|
8
|
+
*/
|
|
9
|
+
export declare function formatStreamNotification(message: string, level: NotifyLevel): string;
|
|
10
|
+
/**
|
|
11
|
+
* Notify through `ctx`: the TUI when there is one, stderr when there is not,
|
|
12
|
+
* nothing when the ctx is stale.
|
|
13
|
+
*/
|
|
14
|
+
export declare function notifyCtx(ctx: ExtensionContext | ExtensionCommandContext, message: string, level: NotifyLevel, stream?: {
|
|
15
|
+
write(chunk: string): unknown;
|
|
16
|
+
}): void;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// User-facing notifications from the orchestrator side of the Pi extension.
|
|
2
|
+
//
|
|
3
|
+
// Two things go wrong with a bare `ctx.ui.notify(...)`, and this module is the
|
|
4
|
+
// one place that handles both.
|
|
5
|
+
//
|
|
6
|
+
// A stale ctx throws. Pi invalidates an extension ctx when the session is
|
|
7
|
+
// replaced, and from then on *every* property access on it throws — `ctx.cwd`
|
|
8
|
+
// and `ctx.hasUI` included. A phase runs as a sub-agent, so by the time
|
|
9
|
+
// post-phase work fires, the ctx captured when the command started may already
|
|
10
|
+
// be dead. That is an ordinary outcome, not an error: the UI it would have
|
|
11
|
+
// refreshed is gone with the session, so the message is dropped.
|
|
12
|
+
//
|
|
13
|
+
// A non-interactive session shows nothing. Under `pi -p`, `ctx.hasUI` is false
|
|
14
|
+
// and `ctx.ui.notify` is a silent no-op. Commands whose only output is a notify
|
|
15
|
+
// — /codecarto-status, /codecarto-usage, /codecarto-list-skills — then exit 0
|
|
16
|
+
// having printed nothing, which is byte-for-byte what a silent refusal looks
|
|
17
|
+
// like (#219). So when there is no UI, the message goes to stderr instead:
|
|
18
|
+
// stderr rather than stdout because `--mode json` owns stdout for its event
|
|
19
|
+
// stream and prose there would corrupt it.
|
|
20
|
+
//
|
|
21
|
+
// This is for the orchestrator's ctx only. Code that runs inside the phase
|
|
22
|
+
// sub-agent (phase-compaction.ts) also sees `hasUI === false`, but there the
|
|
23
|
+
// parent TUI may be on screen, and writing to stderr would put text into a live
|
|
24
|
+
// terminal. That code keeps its own `if (ctx.hasUI)` guards.
|
|
25
|
+
/** Whether `ctx` still belongs to the live session. See the module comment. */
|
|
26
|
+
export function isCtxLive(ctx) {
|
|
27
|
+
try {
|
|
28
|
+
return typeof ctx.cwd === "string";
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Format a notification for a stream. Exported so tests pin the shape a script
|
|
36
|
+
* would parse: one line, prefixed, level visible.
|
|
37
|
+
*/
|
|
38
|
+
export function formatStreamNotification(message, level) {
|
|
39
|
+
return `[codecarto] ${level}: ${message}\n`;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Notify through `ctx`: the TUI when there is one, stderr when there is not,
|
|
43
|
+
* nothing when the ctx is stale.
|
|
44
|
+
*/
|
|
45
|
+
export function notifyCtx(ctx, message, level, stream = process.stderr) {
|
|
46
|
+
if (!isCtxLive(ctx))
|
|
47
|
+
return;
|
|
48
|
+
if (ctx.hasUI) {
|
|
49
|
+
ctx.ui.notify(message, level);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
stream.write(formatStreamNotification(message, level));
|
|
53
|
+
}
|
|
@@ -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",
|