@agent-plan/pi-adapter 0.2.19-next.5 → 0.2.19-next.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/dist/index.d.ts.map +1 -1
- package/dist/index.js +89 -46
- package/package.json +3 -3
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAoB,MAAM,iCAAiC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAoB,MAAM,iCAAiC,CAAC;AAgvBtF,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CAs9F9D"}
|
package/dist/index.js
CHANGED
|
@@ -512,6 +512,9 @@ function statusIcon(status) {
|
|
|
512
512
|
};
|
|
513
513
|
return icons[status] ?? "❓";
|
|
514
514
|
}
|
|
515
|
+
function pad(n) {
|
|
516
|
+
return String(n).padStart(3, "0");
|
|
517
|
+
}
|
|
515
518
|
function applyTaskLifecycleDates(task, nextStatus, now) {
|
|
516
519
|
const previousStatus = task.status;
|
|
517
520
|
if (nextStatus === "in-progress" && !task.startedAt) {
|
|
@@ -1379,7 +1382,7 @@ export default function planPiExtension(pi) {
|
|
|
1379
1382
|
return doc;
|
|
1380
1383
|
});
|
|
1381
1384
|
await st.writeGenerated();
|
|
1382
|
-
ctx.ui.notify(`Feature created: ${feature.
|
|
1385
|
+
ctx.ui.notify(`Feature created: ${formatFeatureRef(feature.number)}${feature.shortId ? ` +MI+ ${feature.shortId}` : ""} +EM+ ${feature.name}`, "info");
|
|
1383
1386
|
return;
|
|
1384
1387
|
}
|
|
1385
1388
|
if (b === "show") {
|
|
@@ -1460,7 +1463,7 @@ export default function planPiExtension(pi) {
|
|
|
1460
1463
|
});
|
|
1461
1464
|
feature = updatedDoc.features.find((entry) => entry.id === featureId) ?? feature;
|
|
1462
1465
|
await st.writeGenerated();
|
|
1463
|
-
ctx.ui.notify(`Feature updated: ${feature.
|
|
1466
|
+
ctx.ui.notify(`Feature updated: ${formatFeatureRef(feature.number)}${feature.shortId ? ` +MI+ ${feature.shortId}` : ""} +EM+ ${feature.name} (${feature.status})`, "info");
|
|
1464
1467
|
return;
|
|
1465
1468
|
}
|
|
1466
1469
|
if (b === "delete") {
|
|
@@ -2823,38 +2826,44 @@ export default function planPiExtension(pi) {
|
|
|
2823
2826
|
pi.registerTool({
|
|
2824
2827
|
name: "feature_list",
|
|
2825
2828
|
label: "Feature List",
|
|
2826
|
-
description: "List
|
|
2827
|
-
parameters: Type.Object({}),
|
|
2828
|
-
async execute(_id,
|
|
2829
|
+
description: "List features (compact: F00x · shortId — name (status; N phases, M tasks)). Use this to discover refs cheaply — do NOT read .planner/ files or plan_get full=true to find entities.",
|
|
2830
|
+
parameters: Type.Object({ featureRef: Type.Optional(Type.String({ description: "Optional: filter to one feature (F00x/shortId/UUID/name)" })) }),
|
|
2831
|
+
async execute(_id, params, _signal, _onUpdate, ctx) {
|
|
2829
2832
|
const st = await requirePlan(ctx);
|
|
2830
2833
|
if (!st)
|
|
2831
2834
|
return { content: [{ type: "text", text: "No .planner/ found." }], details: {} };
|
|
2832
|
-
const
|
|
2835
|
+
const all = (await st.loadFeatures()).features;
|
|
2836
|
+
const ref = params.featureRef?.trim();
|
|
2837
|
+
const matchF = (f) => !ref || formatFeatureRef(f.number) === ref || f.shortId === ref || f.id === ref || f.name.toLowerCase() === ref.toLowerCase();
|
|
2838
|
+
const features = all.filter(matchF);
|
|
2833
2839
|
const phases = await st.loadAllPhases();
|
|
2834
2840
|
const summary = features.map((f) => {
|
|
2835
2841
|
const fp = phases.filter((p) => p.featureId === f.id);
|
|
2836
|
-
return `- ${
|
|
2842
|
+
return `- ${formatFeatureRef(f.number)}${f.shortId ? ` · ${f.shortId}` : ""} — ${f.name} (${f.status}; ${fp.length} phases, ${fp.reduce((t, p) => t + p.tasks.length, 0)} tasks)`;
|
|
2837
2843
|
}).join("\n");
|
|
2838
|
-
return { content: [{ type: "text", text: summary || "No features" }], details: {
|
|
2844
|
+
return { content: [{ type: "text", text: summary || "No features" }], details: {} };
|
|
2839
2845
|
},
|
|
2840
2846
|
});
|
|
2841
2847
|
pi.registerTool({
|
|
2842
2848
|
name: "feature_get",
|
|
2843
2849
|
label: "Feature Get",
|
|
2844
|
-
description: "
|
|
2850
|
+
description: "Show a feature. Compact identity by default (saves tokens); pass full=true to include the description.",
|
|
2845
2851
|
parameters: Type.Object({
|
|
2846
|
-
featureId: Type.String({ description: "Feature
|
|
2852
|
+
featureId: Type.String({ description: "Feature ref: F00x, shortId, UUID, or name" }),
|
|
2853
|
+
full: Type.Optional(Type.Boolean({ description: "If true, include the feature description. Default: compact identity only." })),
|
|
2847
2854
|
}),
|
|
2848
2855
|
async execute(_id, params, _signal, _onUpdate, ctx) {
|
|
2849
2856
|
const st = await requirePlan(ctx);
|
|
2850
2857
|
if (!st)
|
|
2851
2858
|
return { content: [{ type: "text", text: "No .planner/ found." }], details: {} };
|
|
2852
2859
|
const features = (await st.loadFeatures()).features;
|
|
2853
|
-
const
|
|
2860
|
+
const ref = params.featureId.trim();
|
|
2861
|
+
const feature = features.find((f) => formatFeatureRef(f.number) === ref || f.shortId === ref || f.id === ref || f.name.toLowerCase() === ref.toLowerCase());
|
|
2854
2862
|
if (!feature)
|
|
2855
|
-
return { content: [{ type: "text", text: `Feature not found: ${
|
|
2863
|
+
return { content: [{ type: "text", text: `Feature not found: ${ref}` }], details: {} };
|
|
2856
2864
|
const phases = (await st.loadAllPhases()).filter((p) => p.featureId === feature.id);
|
|
2857
|
-
|
|
2865
|
+
const summary = `${feature.name} — ${formatFeatureRef(feature.number)}${feature.shortId ? ` · ${feature.shortId}` : ""} (${feature.status}; ${phases.length} phases)`;
|
|
2866
|
+
return { content: [{ type: "text", text: params.full ? `${summary}\n\n${feature.description || ""}` : summary }], details: {} };
|
|
2858
2867
|
},
|
|
2859
2868
|
});
|
|
2860
2869
|
pi.registerTool({
|
|
@@ -3020,40 +3029,52 @@ export default function planPiExtension(pi) {
|
|
|
3020
3029
|
pi.registerTool({
|
|
3021
3030
|
name: "phase_list",
|
|
3022
3031
|
label: "Phase List",
|
|
3023
|
-
description: "List
|
|
3032
|
+
description: "List phases (compact: F00x/P00x · shortId — title (status; N tasks) [F00x]). Filters: featureRef, status. Cheap discovery — do NOT read .planner/ files or plan_get full=true.",
|
|
3024
3033
|
parameters: Type.Object({
|
|
3025
|
-
|
|
3034
|
+
featureRef: Type.Optional(Type.String({ description: "Optional: filter to one feature (F00x/shortId/UUID/name)" })),
|
|
3035
|
+
status: Type.Optional(Type.String({ description: "Optional: filter by status name" })),
|
|
3026
3036
|
}),
|
|
3027
3037
|
async execute(_id, params, _signal, _onUpdate, ctx) {
|
|
3028
3038
|
const st = await requirePlan(ctx);
|
|
3029
3039
|
if (!st)
|
|
3030
3040
|
return { content: [{ type: "text", text: "No .planner/ found." }], details: {} };
|
|
3041
|
+
const features = (await st.loadFeatures()).features;
|
|
3031
3042
|
let phases = await st.loadAllPhases();
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3043
|
+
const fref = params.featureRef?.trim();
|
|
3044
|
+
if (fref) {
|
|
3045
|
+
const f = features.find((x) => formatFeatureRef(x.number) === fref || x.shortId === fref || x.id === fref || x.name.toLowerCase() === fref.toLowerCase());
|
|
3046
|
+
if (!f)
|
|
3047
|
+
return { content: [{ type: "text", text: `Feature not found: ${fref}` }], details: {} };
|
|
3048
|
+
phases = phases.filter((p) => p.featureId === f.id);
|
|
3049
|
+
}
|
|
3050
|
+
if (params.status)
|
|
3051
|
+
phases = phases.filter((p) => p.status === params.status);
|
|
3052
|
+
const summary = phases.map((p) => {
|
|
3053
|
+
const fNum = featureNumberOfPhase(p, features);
|
|
3054
|
+
const fTag = fNum !== undefined ? ` [F${pad(fNum)}]` : "";
|
|
3055
|
+
return `- ${formatPhaseRef(p.number, fNum)}${p.shortId ? ` · ${p.shortId}` : ""} — ${p.title} (${p.status}; ${p.tasks.length} tasks)${fTag}`;
|
|
3056
|
+
}).join("\n");
|
|
3057
|
+
return { content: [{ type: "text", text: summary || "No phases" }], details: {} };
|
|
3036
3058
|
},
|
|
3037
3059
|
});
|
|
3038
3060
|
pi.registerTool({
|
|
3039
3061
|
name: "phase_get",
|
|
3040
3062
|
label: "Phase Get",
|
|
3041
|
-
description: "
|
|
3063
|
+
description: "Show a phase. Compact identity by default (saves tokens); pass full=true to include the description.",
|
|
3042
3064
|
parameters: Type.Object({
|
|
3043
|
-
phaseId: Type.String({ description: "Phase
|
|
3065
|
+
phaseId: Type.String({ description: "Phase ref: F00x/P00x, bare P00x (global), shortId, UUID, or title" }),
|
|
3066
|
+
full: Type.Optional(Type.Boolean({ description: "If true, include the phase description. Default: compact identity only." })),
|
|
3044
3067
|
}),
|
|
3045
3068
|
async execute(_id, params, _signal, _onUpdate, ctx) {
|
|
3046
3069
|
const st = await requirePlan(ctx);
|
|
3047
3070
|
if (!st)
|
|
3048
3071
|
return { content: [{ type: "text", text: "No .planner/ found." }], details: {} };
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
}
|
|
3053
|
-
catch {
|
|
3072
|
+
const features = (await st.loadFeatures()).features;
|
|
3073
|
+
const phase = findPhaseByRef(await st.loadAllPhases(), features, params.phaseId.trim());
|
|
3074
|
+
if (!phase)
|
|
3054
3075
|
return { content: [{ type: "text", text: `Phase not found: ${params.phaseId}` }], details: {} };
|
|
3055
|
-
}
|
|
3056
|
-
return { content: [{ type: "text", text:
|
|
3076
|
+
const summary = `${phase.title} — ${formatPhaseRef(phase.number, featureNumberOfPhase(phase, features))}${phase.shortId ? ` · ${phase.shortId}` : ""} (${phase.status}; ${phase.tasks.length} tasks)`;
|
|
3077
|
+
return { content: [{ type: "text", text: params.full ? `${summary}\n\n${phase.description || ""}` : summary }], details: {} };
|
|
3057
3078
|
},
|
|
3058
3079
|
});
|
|
3059
3080
|
pi.registerTool({
|
|
@@ -3242,42 +3263,64 @@ export default function planPiExtension(pi) {
|
|
|
3242
3263
|
pi.registerTool({
|
|
3243
3264
|
name: "task_list",
|
|
3244
3265
|
label: "Task List",
|
|
3245
|
-
description: "List tasks
|
|
3266
|
+
description: "List tasks (compact: F00x/P00x/T00x · shortId — title (status)). Filters: featureRef, phaseRef, status. Omit all to list every task. Cheap discovery — do NOT read .planner/ files or plan_get full=true.",
|
|
3246
3267
|
parameters: Type.Object({
|
|
3247
|
-
|
|
3268
|
+
featureRef: Type.Optional(Type.String({})),
|
|
3269
|
+
phaseRef: Type.Optional(Type.String({})),
|
|
3270
|
+
status: Type.Optional(Type.String({ description: "Optional: filter by status name" })),
|
|
3248
3271
|
}),
|
|
3249
3272
|
async execute(_id, params, _signal, _onUpdate, ctx) {
|
|
3250
3273
|
const st = await requirePlan(ctx);
|
|
3251
3274
|
if (!st)
|
|
3252
3275
|
return { content: [{ type: "text", text: "No .planner/ found." }], details: {} };
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3276
|
+
const features = (await st.loadFeatures()).features;
|
|
3277
|
+
let phases = await st.loadAllPhases();
|
|
3278
|
+
const fref = params.featureRef?.trim();
|
|
3279
|
+
if (fref) {
|
|
3280
|
+
const f = features.find((x) => formatFeatureRef(x.number) === fref || x.shortId === fref || x.id === fref || x.name.toLowerCase() === fref.toLowerCase());
|
|
3281
|
+
if (!f)
|
|
3282
|
+
return { content: [{ type: "text", text: `Feature not found: ${fref}` }], details: {} };
|
|
3283
|
+
phases = phases.filter((p) => p.featureId === f.id);
|
|
3284
|
+
}
|
|
3285
|
+
const pref = params.phaseRef?.trim();
|
|
3286
|
+
if (pref) {
|
|
3287
|
+
const p = findPhaseByRef(phases, features, pref);
|
|
3288
|
+
if (!p)
|
|
3289
|
+
return { content: [{ type: "text", text: `Phase not found: ${pref}` }], details: {} };
|
|
3290
|
+
phases = [p];
|
|
3291
|
+
}
|
|
3292
|
+
const out = [];
|
|
3293
|
+
for (const phase of phases) {
|
|
3294
|
+
for (const task of phase.tasks) {
|
|
3295
|
+
if (params.status && task.status !== params.status)
|
|
3296
|
+
continue;
|
|
3297
|
+
out.push(`- ${formatPhaseRef(phase.number, featureNumberOfPhase(phase, features))}/T${pad(task.number)}${task.shortId ? ` · ${task.shortId}` : ""} — ${task.title} (${task.status})`);
|
|
3298
|
+
}
|
|
3299
|
+
}
|
|
3300
|
+
return { content: [{ type: "text", text: out.join("\n") || "No tasks" }], details: {} };
|
|
3262
3301
|
},
|
|
3263
3302
|
});
|
|
3264
3303
|
pi.registerTool({
|
|
3265
3304
|
name: "task_get",
|
|
3266
3305
|
label: "Task Get",
|
|
3267
|
-
description: "
|
|
3306
|
+
description: "Show a task. Compact identity by default (saves tokens); pass full=true to include the description + statusLog.",
|
|
3268
3307
|
parameters: Type.Object({
|
|
3269
3308
|
taskId: Type.String({ description: "Task ref: F00x/P00x/T00x, bare T00x (global), 5-char shortId, UUID, or title" }),
|
|
3309
|
+
full: Type.Optional(Type.Boolean({ description: "If true, include the task description + statusLog. Default: compact identity only." })),
|
|
3270
3310
|
}),
|
|
3271
3311
|
async execute(_id, params, _signal, _onUpdate, ctx) {
|
|
3272
3312
|
const st = await requirePlan(ctx);
|
|
3273
3313
|
if (!st)
|
|
3274
3314
|
return { content: [{ type: "text", text: "No .planner/ found." }], details: {} };
|
|
3275
|
-
const
|
|
3276
|
-
const
|
|
3277
|
-
|
|
3278
|
-
if (!task || !phase)
|
|
3315
|
+
const features = (await st.loadFeatures()).features;
|
|
3316
|
+
const found = findTaskByRef(await st.loadAllPhases(), features, params.taskId.trim());
|
|
3317
|
+
if (!found)
|
|
3279
3318
|
return { content: [{ type: "text", text: `Task not found: ${params.taskId}` }], details: {} };
|
|
3280
|
-
|
|
3319
|
+
const summary = `${found.task.title} — ${formatPhaseRef(found.phase.number, featureNumberOfPhase(found.phase, features))}/T${pad(found.task.number)}${found.task.shortId ? ` · ${found.task.shortId}` : ""} (${found.task.status})`;
|
|
3320
|
+
if (!params.full)
|
|
3321
|
+
return { content: [{ type: "text", text: summary }], details: {} };
|
|
3322
|
+
const log = (found.task.statusLog ?? []).map((e) => ` - ${e.date.slice(0, 10)} ${e.title}`).join("\n");
|
|
3323
|
+
return { content: [{ type: "text", text: `${summary}\n\n${found.task.description || ""}${log ? `\n\nStatus log:\n${log}` : ""}` }], details: {} };
|
|
3281
3324
|
},
|
|
3282
3325
|
});
|
|
3283
3326
|
pi.registerTool({
|
|
@@ -3776,7 +3819,7 @@ export default function planPiExtension(pi) {
|
|
|
3776
3819
|
"3. IMMEDIATE SYNC: Update task status AT THE EXACT MOMENT of transition. Start = task_start NOW. Done = task_complete NOW. Blocked = task_update with motivation NOW. Never batch status updates.",
|
|
3777
3820
|
"4. BLOCKED MOTIVATION: Transitions to blocked/canceled/rejected/deferred/waiting/planned(from non-planned) MUST include a detailed 'motivation' parameter. Write it as if the next person has zero context.",
|
|
3778
3821
|
"5. NO SHORTCUTS: If a tool blocks you, follow the protocol. Bypasses are for emergencies only, not for convenience.",
|
|
3779
|
-
"6. ENTITY REFERENCES
|
|
3822
|
+
"6. ENTITY REFERENCES & FAST LOOKUP: Feature/Phase/Task numbers are GLOBALLY unique (one P003, one T007 in the whole plan) — bare P00x/T00x is a valid unambiguous ref. PREFER the 5-char shortId (e.g. UUXD1) or composite F00x/P00x/T00x in chat; NEVER a raw UUID. To FIND an entity: call feature_list / phase_list / task_list (compact, ~2K tokens for the whole plan) — do NOT read .planner/*.json files or plan_get full=true (~32K tokens) to locate an entity. To ACT: pass the ref directly to the action tool (task_start/complete/update/phase_update accept F00x/P00x/T00x, bare P00x/T00x, shortId, UUID, title). To read a description: call task_get / phase_get / feature_get with full=true for that ONE entity. Tool responses already show shortId + compositeRef; reuse them.",
|
|
3780
3823
|
"═══════════════════════════════════════════════════════════════",
|
|
3781
3824
|
"",
|
|
3782
3825
|
// ── Project details ──
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-plan/pi-adapter",
|
|
3
|
-
"version": "0.2.19-next.
|
|
3
|
+
"version": "0.2.19-next.6",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Pi agent extension for Agent Plan — structured project planning in .planner/",
|
|
6
6
|
"keywords": [
|
|
@@ -28,8 +28,8 @@
|
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"typebox": "^1.1.24",
|
|
30
30
|
"zod": "^3.24.0",
|
|
31
|
-
"@agent-plan/core": "0.2.19-next.
|
|
32
|
-
"@agent-plan/server": "0.2.19-next.
|
|
31
|
+
"@agent-plan/core": "0.2.19-next.6",
|
|
32
|
+
"@agent-plan/server": "0.2.19-next.6"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@earendil-works/pi-coding-agent": "^0.74.0",
|