codecartographer-pi 0.19.3 → 0.19.4

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.
@@ -3,4 +3,4 @@
3
3
  # workspace's framework-owned files (GUIDE.md, templates/, workflow/ pipelines
4
4
  # and VALIDATE.md) predate the running release. Written at release time and
5
5
  # copied verbatim by init — never edit by hand.
6
- scaffold_version: 0.19.3
6
+ scaffold_version: 0.19.4
package/dist/core/yaml.js CHANGED
@@ -167,6 +167,31 @@ export function parseSimpleYaml(raw) {
167
167
  while (index < lines.length && isBlankOrComment(lines[index] ?? ""))
168
168
  index++;
169
169
  };
170
+ /**
171
+ * Read the body of a block scalar that opened on the line just consumed.
172
+ * Shared by mapping values (`key: >-`) and sequence items (`- >-`): when only
173
+ * the mapping path had it, a handoff whose `decisions:` list used `- >-`
174
+ * still failed with the indentation error that #211 was supposed to end.
175
+ */
176
+ const collectBlockScalarLines = (baseIndent) => {
177
+ const blockLines = [];
178
+ let contentIndent = null;
179
+ while (index < lines.length) {
180
+ const blockLine = lines[index] ?? "";
181
+ if (blockLine.trim() === "") {
182
+ blockLines.push("");
183
+ index++;
184
+ continue;
185
+ }
186
+ const blockIndent = countIndent(blockLine);
187
+ if (blockIndent <= baseIndent)
188
+ break;
189
+ contentIndent ??= blockIndent;
190
+ blockLines.push(blockLine.slice(Math.min(contentIndent, blockIndent)));
191
+ index++;
192
+ }
193
+ return blockLines;
194
+ };
170
195
  const parseBlock = (indent) => {
171
196
  skipBlank();
172
197
  if (index >= lines.length)
@@ -221,23 +246,7 @@ export function parseSimpleYaml(raw) {
221
246
  seen.add(key);
222
247
  const blockHeader = parseBlockScalarHeader(rawValue);
223
248
  if (blockHeader) {
224
- const blockLines = [];
225
- let contentIndent = null;
226
- while (index < lines.length) {
227
- const blockLine = lines[index] ?? "";
228
- if (blockLine.trim() === "") {
229
- blockLines.push("");
230
- index++;
231
- continue;
232
- }
233
- const blockIndent = countIndent(blockLine);
234
- if (blockIndent <= indent)
235
- break;
236
- contentIndent ??= blockIndent;
237
- blockLines.push(blockLine.slice(Math.min(contentIndent, blockIndent)));
238
- index++;
239
- }
240
- assign(key, applyBlockScalar(blockLines, blockHeader));
249
+ assign(key, applyBlockScalar(collectBlockScalarLines(indent), blockHeader));
241
250
  continue;
242
251
  }
243
252
  if (rawValue !== "") {
@@ -285,6 +294,11 @@ export function parseSimpleYaml(raw) {
285
294
  }
286
295
  continue;
287
296
  }
297
+ const itemBlockHeader = parseBlockScalarHeader(rawItem);
298
+ if (itemBlockHeader) {
299
+ result.push(applyBlockScalar(collectBlockScalarLines(indent), itemBlockHeader));
300
+ continue;
301
+ }
288
302
  const separator = findKeySeparator(rawItem);
289
303
  if (separator !== -1) {
290
304
  const key = rawItem.slice(0, separator).trim();
@@ -40,6 +40,27 @@ export const PI_SURFACE_ADDENDUM = [
40
40
  `- **Every tool name maps to a slash command the user runs**, mechanically: \`codecarto_status\` → \`/codecarto-status\`, \`codecarto_next\` → \`/codecarto-next\`, and so on. Two have no Pi equivalent: ${MCP_ONLY_TOOLS.map((name) => `\`${name}\``).join(" and ")}.`,
41
41
  "- **Ignore \"every tool takes an absolute `cwd`\".** Slash commands act on the session's own directory; there is no `cwd` argument to pass.",
42
42
  "- **The drive loop is different.** `/codecarto-next` executes the phase itself, as an isolated sub-agent, and then auto-validates and auto-completes it. The guide's hand-written loop — take the prompt, execute it, write the handoff, then validate and complete yourself — describes the MCP surface. On Pi the user drives and the extension executes; your job is to explain what the framework is doing and answer questions about it, not to reproduce that loop by hand.",
43
+ "",
44
+ "### How to drive a run",
45
+ "",
46
+ "`/codecarto-next` takes flags that change how much runs and how each phase is seeded. They are independent: `--auto` decides *how many phases run*, `--llm-steer` decides *what prompt each one gets*.",
47
+ "",
48
+ "| Invocation | What it does |",
49
+ "| --- | --- |",
50
+ "| `/codecarto-next` | Runs the next eligible phase, once. Good for watching a single phase or retrying one that stopped. |",
51
+ "| `/codecarto-next --auto` | Runs every remaining phase back to back, validating and completing each before starting the next. Stops on a validation failure or a sub-agent error. |",
52
+ "| `/codecarto-next --auto --llm-steer` | The same, with each phase's prompt rewritten from the previous phase's closeout. **This is the usual choice for a full run** — it is what makes phase N+1 aware of what phase N found. |",
53
+ "| `/codecarto-next --auto --strict --llm-steer` | The same, but also stops on `PASS WITH GAPS` instead of advancing through it. Use when gaps should be reviewed rather than carried forward. |",
54
+ "",
55
+ "Notes worth passing on when the user asks:",
56
+ "",
57
+ "- **The first phase is never steered** — there is no previous closeout to steer from, so it reports `LLM rewriter skipped (no previous phase to steer from)` and uses the stock prompt. That message is normal, not a failure.",
58
+ "- **Steering costs an extra model call per phase**, on top of the phase sub-agent itself.",
59
+ "- `--strict` is only valid with `--auto`; on its own it is an error.",
60
+ "- `--no-llm-steer` forces steering off for one invocation when the workspace config has it on (`orchestrator.llm_steer_next_phase`, default off).",
61
+ "- **An auto run that stops says why in its summary block.** If a phase produced its artifact but the pipeline still shows it incomplete, read the `Auto pipeline stopped at …` message rather than assuming the phase failed — the phase usually succeeded and something after it did not.",
62
+ "",
63
+ "If the user has just initialized a workspace and has not said what they want, tell them the run command rather than waiting to be asked: `/codecarto-next --auto --llm-steer` for a full pass, or plain `/codecarto-next` to watch one phase first.",
43
64
  ].join("\n");
44
65
  /**
45
66
  * Assemble the message /codecarto-guide queues. The guide document is embedded
@@ -499,8 +499,14 @@ export default function codeCartographerExtension(pi) {
499
499
  // duties maintain so they exist from the first phase.
500
500
  await seedOrchestratorFiles(targetWorkspaceDir);
501
501
  codecartoModeActive = true;
502
- lastFeedbackLines = [`Initialized workspace with pipeline: ${getPipelineLabel(selectedPipelinePath)}`];
503
- ctx.ui.notify(`Initialized CodeCartographer (${getPipelineLabel(selectedPipelinePath)})`, "info");
502
+ // Name the run command here: init is the moment someone needs it, and
503
+ // the flags that make a full run useful are not guessable from the
504
+ // command name alone.
505
+ lastFeedbackLines = [
506
+ `Initialized workspace with pipeline: ${getPipelineLabel(selectedPipelinePath)}`,
507
+ "Full run: `/codecarto-next --auto --llm-steer` — or `/codecarto-next` to watch one phase first.",
508
+ ];
509
+ ctx.ui.notify(`Initialized CodeCartographer (${getPipelineLabel(selectedPipelinePath)}). Full run: /codecarto-next --auto --llm-steer`, "info");
504
510
  // Render the initial dashboard (empty usage, all phases pending) so
505
511
  // the user sees the file exist immediately after /codecarto-init.
506
512
  void writeDashboard(ctx.cwd, PACKAGE_VERSION);
@@ -573,11 +579,23 @@ export default function codeCartographerExtension(pi) {
573
579
  },
574
580
  });
575
581
  pi.registerCommand("codecarto-next", {
576
- description: "Run the next eligible CodeCartographer phase as a sub-agent. Flags: --llm-steer / --no-llm-steer / --auto [--strict]",
582
+ description: "Run the next phase as a sub-agent. Full run: --auto --llm-steer. Add --strict to stop on PASS WITH GAPS.",
577
583
  getArgumentCompletions: (prefix) => {
578
- const items = ["--llm-steer", "--no-llm-steer", "--auto", "--strict"]
579
- .filter((value) => value.startsWith(prefix))
580
- .map((value) => ({ value, label: value }));
584
+ // Descriptions, not bare flag names: the completion list is the only
585
+ // place most users will ever see what these do, and the useful
586
+ // combination (--auto --llm-steer) is not guessable from the names.
587
+ // --strict is offered only once --auto is present, because on its own
588
+ // it is rejected — suggesting it standalone invites the one error the
589
+ // parser has.
590
+ const autoAlreadyTyped = prefix.includes("--auto");
591
+ const items = [
592
+ { value: "--auto", label: "--auto", description: "run every remaining phase back to back (recommended with --llm-steer)" },
593
+ { value: "--llm-steer", label: "--llm-steer", description: "seed each phase from the previous phase's closeout; no effect on the first phase" },
594
+ { value: "--no-llm-steer", label: "--no-llm-steer", description: "force steering off when the workspace config turns it on" },
595
+ ...(autoAlreadyTyped
596
+ ? [{ value: "--strict", label: "--strict", description: "with --auto: stop on PASS WITH GAPS instead of advancing" }]
597
+ : []),
598
+ ].filter((item) => item.value.startsWith(prefix.split(/\s+/).pop() ?? prefix));
581
599
  return items.length > 0 ? items : null;
582
600
  },
583
601
  handler: async (args, ctx) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codecartographer-pi",
3
- "version": "0.19.3",
3
+ "version": "0.19.4",
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",