pi-soly 1.16.1 → 1.16.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/config.ts CHANGED
@@ -272,9 +272,13 @@ function deepMerge(base: SolyConfig, over: RawConfig): SolyConfig {
272
272
  merged.editor.command = over.editor.command;
273
273
  }
274
274
  if (over.plan && typeof over.plan.defaultBranchPrefix === "string") {
275
- // Sanitize: allow only kebab-case words (no slashes, dots, etc.).
276
- // Empty string is allowed and means "no prefix".
277
- const sanitized = over.plan.defaultBranchPrefix.replace(/[^a-z0-9-]/gi, "");
275
+ // Sanitize: lowercase, then allow only kebab-case chars (no
276
+ // slashes/dots/spaces). Empty string is allowed and means
277
+ // "no prefix". We do NOT warn on slash/uppercase — the user
278
+ // probably meant a different prefix shape; silently normalizing
279
+ // keeps configs from being rejected for cosmetic reasons.
280
+ const lowercased = over.plan.defaultBranchPrefix.toLowerCase();
281
+ const sanitized = lowercased.replace(/[^a-z0-9-]/g, "");
278
282
  const collapsed = sanitized.replace(/-+/g, "-").replace(/^-|-$/g, "");
279
283
  merged.plan.defaultBranchPrefix = collapsed;
280
284
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-soly",
3
- "version": "1.16.1",
3
+ "version": "1.16.2",
4
4
  "description": "Project management + workflow framework for pi-coding-agent. Plans, state, MANDATORY rules, self-review, multi-question picker, native footer + welcome chrome — one npm install, zero config. The LLM drives execution and delegates to a worker subagent when available.",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -274,9 +274,12 @@ When the subagent completes, synthesize the result. Do not re-execute its work.
274
274
  };
275
275
  }
276
276
 
277
- // === PLAN MODE (new dual-mode: `<type>/<name>` plans live under .agents/plans/<name>/) ===
277
+ // === PLAN MODE (new dual-mode: `<type>/<name>` plans live under .agents/plans/<prefix>-<name>/) ===
278
278
  if (target.kind === "plan") {
279
- const planDirAbs = `${state.solyDir}/plans/${target.name}`;
279
+ // Plan dir is always flattened: `<prefix>-<name>` if a prefix is
280
+ // present, else just `<name>`.
281
+ const dirSlug = target.prefix ? `${target.prefix}-${target.name}` : target.name;
282
+ const planDirAbs = `${state.solyDir}/plans/${dirSlug}`;
280
283
  const planFile = `${planDirAbs}/PLAN.md`;
281
284
  let planBody: string;
282
285
  try {
@@ -241,7 +241,7 @@ function parseNewTaskFlag(
241
241
  */
242
242
  export type ExecuteTarget =
243
243
  | { kind: "phase"; phase: number; plan: number | null; raw: string }
244
- | { kind: "plan"; name: string; raw: string }
244
+ | { kind: "plan"; name: string; prefix: string | null; raw: string }
245
245
  | { kind: "task"; taskId: string; raw: string }
246
246
  | { kind: "all"; raw: string }
247
247
  | { kind: "feature"; feature: string; raw: string };
@@ -287,7 +287,7 @@ export function describeExecuteTarget(args: string[]): ExecuteTarget | null {
287
287
 
288
288
  const plan = parsePlanName(target);
289
289
  if (!("error" in plan)) {
290
- return { kind: "plan", name: plan.name, raw };
290
+ return { kind: "plan", name: plan.name, prefix: plan.prefix, raw };
291
291
  }
292
292
 
293
293
  const phase = parsePhaseShape(target);
@@ -313,7 +313,7 @@ export function describeExecuteTarget(args: string[]): ExecuteTarget | null {
313
313
  */
314
314
  export type PlanTarget =
315
315
  | { kind: "phase"; phase: number; raw: string }
316
- | { kind: "plan"; name: string; raw: string }
316
+ | { kind: "plan"; name: string; prefix: string | null; raw: string }
317
317
  | { kind: "task"; taskId: string; raw: string }
318
318
  | { kind: "new-task"; slug: string; feature: string; raw: string }
319
319
  | { kind: "feature"; feature: string; raw: string };
@@ -361,7 +361,7 @@ export function describePlanTarget(args: string[]): PlanTarget | null {
361
361
 
362
362
  const plan = parsePlanName(target);
363
363
  if (!("error" in plan)) {
364
- return { kind: "plan", name: plan.name, raw };
364
+ return { kind: "plan", name: plan.name, prefix: plan.prefix, raw };
365
365
  }
366
366
 
367
367
  // Plan target only matches plain N (no .MM — plan is per-phase, executed
@@ -91,9 +91,13 @@ export function buildPlanTransform(cmd: SolyCommand, state: SolyState): Planning
91
91
  };
92
92
  }
93
93
 
94
- // === PLAN MODE (new dual-mode: `<type>/<name>` plans live under .agents/plans/<name>/) ===
94
+ // === PLAN MODE (new dual-mode: `<type>/<name>` plans live under .agents/plans/<prefix>-<name>/) ===
95
95
  if (target.kind === "plan") {
96
- const planDirAbs = `${state.solyDir}/plans/${target.name}`;
96
+ // Plan dir is always flattened: `<prefix>-<name>` if a prefix is
97
+ // present (user typed `<prefix>/<slug>` or the project default
98
+ // applied), else just `<name>`.
99
+ const dirSlug = target.prefix ? `${target.prefix}-${target.name}` : target.name;
100
+ const planDirAbs = `${state.solyDir}/plans/${dirSlug}`;
97
101
  const planFile = `${planDirAbs}/PLAN.md`;
98
102
  let planBody: string;
99
103
  try {
@@ -514,10 +518,11 @@ export function buildDiscussTransform(
514
518
  };
515
519
  }
516
520
 
517
- // Plan mode: `<type>/<name>`
521
+ // Plan mode: `<slug>` or `<prefix>/<slug>`
518
522
  const planParsed = parsePlanName(arg);
519
523
  if (!("error" in planParsed)) {
520
- const planDirAbs = `${state.solyDir}/plans/${planParsed.name}`;
524
+ const dirSlug = planParsed.prefix ? `${planParsed.prefix}-${planParsed.name}` : planParsed.name;
525
+ const planDirAbs = `${state.solyDir}/plans/${dirSlug}`;
521
526
  const planFile = `${planDirAbs}/PLAN.md`;
522
527
  let planBody: string;
523
528
  try {