pi-soly 1.16.1 → 1.16.3
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 +7 -3
- package/nudge.ts +9 -1
- package/package.json +1 -1
- package/workflows/execute.ts +9 -2
- package/workflows/parser.ts +4 -4
- package/workflows/planning.ts +13 -4
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
|
|
276
|
-
// Empty string is allowed and means
|
|
277
|
-
|
|
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/nudge.ts
CHANGED
|
@@ -169,7 +169,15 @@ export function buildNudgeSection(
|
|
|
169
169
|
- \`soly verify\` — self-review loop until clean
|
|
170
170
|
- \`soly status\` — current position + progress (no LLM round-trip)
|
|
171
171
|
|
|
172
|
-
**You may scaffold a new plan yourself** when the user asks for a new piece of work and the scope is clear (or the user just confirmed). Propose the slug AND the full branch name first via ask_pro — offer the default \`${prefix ? prefix + "/" : ""}<slug>\` plus the alternatives \`fix/<slug>\`, \`chore/<slug>\`, or just \`<slug>\` (no prefix). Pick whatever fits the work, then type \`soly new …\` in your next output. Don't ask for trivial one-liners or when the user already said "go". Skip only for a genuine one-off that doesn't deserve a plan branch
|
|
172
|
+
**You may scaffold a new plan yourself** when the user asks for a new piece of work and the scope is clear (or the user just confirmed). Propose the slug AND the full branch name first via ask_pro — offer the default \`${prefix ? prefix + "/" : ""}<slug>\` plus the alternatives \`fix/<slug>\`, \`chore/<slug>\`, or just \`<slug>\` (no prefix). Pick whatever fits the work, then type \`soly new …\` in your next output. Don't ask for trivial one-liners or when the user already said "go". Skip only for a genuine one-off that doesn't deserve a plan branch.
|
|
173
|
+
|
|
174
|
+
**STUDY THE REPO before scaffolding or fleshing out a plan.** Before you write or edit any plan, use the available tools to understand the area you're about to touch:
|
|
175
|
+
- \`soly_snippet(path, offset, limit)\` and \`soly_doc_search(query)\` for bounded reads of the relevant files (don't \`read\` the whole tree — that's why these tools exist).
|
|
176
|
+
- The \`## project layout\` section in this system prompt for a directory overview.
|
|
177
|
+
- \`.agents/docs/\` (intent) for *why* the project is the way it is.
|
|
178
|
+
- \`git log --oneline -20\` for recent context (existing patterns, prior decisions).
|
|
179
|
+
|
|
180
|
+
What to extract: where similar features live, the naming/file-layout conventions, how errors are handled, how tests are written, and any constraints you missed in the prompt. Surface ambiguities as \`ask_pro\` questions BEFORE writing the plan — a plan that knows "the tests go in __tests__/" beats a plan that picks an arbitrary location and rewrites.`
|
|
173
181
|
: "";
|
|
174
182
|
|
|
175
183
|
// Confirm-before-coding gate: for non-trivial implementation, pull the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-soly",
|
|
3
|
-
"version": "1.16.
|
|
3
|
+
"version": "1.16.3",
|
|
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",
|
package/workflows/execute.ts
CHANGED
|
@@ -181,6 +181,8 @@ The worker reads this file first — it contains intent, STATE, ROADMAP (n/a for
|
|
|
181
181
|
|
|
182
182
|
**0-POINT CHECK.** Worker must re-read .agents/docs/ (intent) and .agents/features/${task.feature}/README.md before implementing.
|
|
183
183
|
|
|
184
|
+
**STUDY THE REPO.** The worker MUST use \`soly_snippet(path, offset, limit)\`, \`soly_doc_search(query)\`, and \`## project layout\` from the system prompt to understand the area before changing any file. Read at least: the module being modified, one similar feature for the pattern, and the corresponding test file. Do NOT change code based on assumptions about how the existing code works.
|
|
185
|
+
|
|
184
186
|
Launch a single subagent for this work. Do NOT do the work inline.
|
|
185
187
|
|
|
186
188
|
subagent({
|
|
@@ -274,9 +276,12 @@ When the subagent completes, synthesize the result. Do not re-execute its work.
|
|
|
274
276
|
};
|
|
275
277
|
}
|
|
276
278
|
|
|
277
|
-
// === PLAN MODE (new dual-mode: `<type>/<name>` plans live under .agents/plans/<name>/) ===
|
|
279
|
+
// === PLAN MODE (new dual-mode: `<type>/<name>` plans live under .agents/plans/<prefix>-<name>/) ===
|
|
278
280
|
if (target.kind === "plan") {
|
|
279
|
-
|
|
281
|
+
// Plan dir is always flattened: `<prefix>-<name>` if a prefix is
|
|
282
|
+
// present, else just `<name>`.
|
|
283
|
+
const dirSlug = target.prefix ? `${target.prefix}-${target.name}` : target.name;
|
|
284
|
+
const planDirAbs = `${state.solyDir}/plans/${dirSlug}`;
|
|
280
285
|
const planFile = `${planDirAbs}/PLAN.md`;
|
|
281
286
|
let planBody: string;
|
|
282
287
|
try {
|
|
@@ -323,6 +328,8 @@ ${planBody.slice(0, 4000)}${planBody.length > 4000 ? "\n…(truncated)" : ""}
|
|
|
323
328
|
|
|
324
329
|
**0-POINT CHECK.** Worker must re-read .agents/docs/ (intent) before implementing.
|
|
325
330
|
|
|
331
|
+
**STUDY THE REPO.** Worker MUST use \`soly_snippet(path, offset, limit)\`, \`soly_doc_search(query)\`, and \`## project layout\` from the system prompt to map the area before editing. Read at least: the module(s) the plan touches, one adjacent feature for the convention, and any test files in the same area. Do NOT edit code on assumptions about how existing code is structured.
|
|
332
|
+
|
|
326
333
|
Launch a single subagent to execute the plan. Do NOT do the work inline.
|
|
327
334
|
|
|
328
335
|
subagent({
|
package/workflows/parser.ts
CHANGED
|
@@ -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
|
package/workflows/planning.ts
CHANGED
|
@@ -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
|
-
|
|
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 {
|
|
@@ -114,6 +118,8 @@ ${planBody.slice(0, 4000)}${planBody.length > 4000 ? "\n…(truncated)" : ""}
|
|
|
114
118
|
|
|
115
119
|
**0-POINT CHECK.** Re-read .agents/docs/ (intent) before fleshing out the plan.
|
|
116
120
|
|
|
121
|
+
**STUDY THE REPO.** Before writing PLAN.md, use \`soly_snippet(path, offset, limit)\` and \`soly_doc_search(query)\` to understand the area this plan will touch. Look at how similar features are implemented in this codebase (naming, file layout, error handling, test convention), and check \`## project layout\` from the system prompt for orientation. Extract enough context that the plan names concrete files and conventions, not abstractions. Surface ambiguities as \`ask_pro\` questions BEFORE writing PLAN.md.
|
|
122
|
+
|
|
117
123
|
If ask_pro is available, use it ONCE to gather goal / steps / acceptance criteria (freeText questions, batched). Then write PLAN.md with the answers. If ask_pro is NOT available, write a sensible stub plan and tell the user to refine it via \`soly plan ${target.raw}\` again.
|
|
118
124
|
|
|
119
125
|
Hard rules:
|
|
@@ -514,10 +520,11 @@ export function buildDiscussTransform(
|
|
|
514
520
|
};
|
|
515
521
|
}
|
|
516
522
|
|
|
517
|
-
// Plan mode: `<
|
|
523
|
+
// Plan mode: `<slug>` or `<prefix>/<slug>`
|
|
518
524
|
const planParsed = parsePlanName(arg);
|
|
519
525
|
if (!("error" in planParsed)) {
|
|
520
|
-
const
|
|
526
|
+
const dirSlug = planParsed.prefix ? `${planParsed.prefix}-${planParsed.name}` : planParsed.name;
|
|
527
|
+
const planDirAbs = `${state.solyDir}/plans/${dirSlug}`;
|
|
521
528
|
const planFile = `${planDirAbs}/PLAN.md`;
|
|
522
529
|
let planBody: string;
|
|
523
530
|
try {
|
|
@@ -538,6 +545,8 @@ ${planBody.slice(0, 4000)}${planBody.length > 4000 ? "\n…(truncated)" : ""}
|
|
|
538
545
|
|
|
539
546
|
**0-POINT CHECK.** Re-read .agents/docs/ (intent) before discussing.
|
|
540
547
|
|
|
548
|
+
**STUDY THE REPO.** Use \`soly_snippet(path, offset, limit)\`, \`soly_doc_search(query)\`, and \`## project layout\` from the system prompt to understand the area the plan touches. The discussion should resolve real ambiguities in the existing code, not invent new ones. If the plan body mentions files you haven't read, read them first.
|
|
549
|
+
|
|
541
550
|
Use \`soly_finish_discuss\` to capture the discussion outcome. The flow:
|
|
542
551
|
1. Read the plan above.
|
|
543
552
|
2. Identify ambiguities / open questions / scope clarifications.
|