pi-note 0.18.0 → 0.18.1
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/README.md +6 -2
- package/index.ts +23 -13
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -84,7 +84,7 @@ The agent can still read the task separately with `pinote_get_current`.
|
|
|
84
84
|
Click previews work while the agent is running, provided no other Pinote operation
|
|
85
85
|
is open. Each click saves a fresh snapshot in the transcript, above any currently
|
|
86
86
|
streaming response. Later output scrolls it upward; it does not expire. Preview
|
|
87
|
-
reads never lock out the agent's task updates. Settings
|
|
87
|
+
reads never lock out the agent's task updates. Settings also works during a running turn.
|
|
88
88
|
|
|
89
89
|

|
|
90
90
|
|
|
@@ -358,7 +358,11 @@ Pinote no longer polls GitHub, runs `gh`, watches completed tasks, or prompts on
|
|
|
358
358
|
PR merges. No GitHub authentication is required. `PINOTE_PR_POLL_SECONDS` is no
|
|
359
359
|
longer used. Other separately installed Pi PR/Git extensions are unaffected.
|
|
360
360
|
|
|
361
|
-
Tools work without a TUI
|
|
361
|
+
Tools work without a TUI. `/pi-note` works in a TUI while the agent is running:
|
|
362
|
+
you can select/switch tasks, use Continue, preview tasks, respond to suggestions,
|
|
363
|
+
and edit settings without interrupting the turn or submitting input. Completion
|
|
364
|
+
and CLI installation/upgrades still require an idle session. Another pending
|
|
365
|
+
Pinote operation blocks the menu. Open menus do not block agent handoff updates.
|
|
362
366
|
This package does not synchronize databases or paths between machines. Note text
|
|
363
367
|
and fields loaded into Pi are sent to the configured model when used as context;
|
|
364
368
|
avoid secrets. Agent commands do not send desktop notifications.
|
package/index.ts
CHANGED
|
@@ -169,6 +169,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
169
169
|
let epoch = 0;
|
|
170
170
|
let refreshSerial = 0;
|
|
171
171
|
let pending: symbol | undefined;
|
|
172
|
+
let menuPending: symbol | undefined;
|
|
172
173
|
let previewPending = false;
|
|
173
174
|
let setupAbort: AbortController | undefined;
|
|
174
175
|
let activeContext: ExtensionContext | undefined;
|
|
@@ -318,7 +319,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
318
319
|
}
|
|
319
320
|
};
|
|
320
321
|
const preview = async (ctx: ExtensionContext, requestSignal?: AbortSignal): Promise<boolean> => {
|
|
321
|
-
if (!ctx.hasUI || ctx.mode !== "tui" || pending || previewPending || !validId(selectedId)) return false;
|
|
322
|
+
if (!ctx.hasUI || ctx.mode !== "tui" || pending || menuPending || previewPending || !validId(selectedId)) return false;
|
|
322
323
|
const generation = epoch;
|
|
323
324
|
const branch = branchEpoch;
|
|
324
325
|
const id = selectedId;
|
|
@@ -346,7 +347,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
346
347
|
}
|
|
347
348
|
};
|
|
348
349
|
const dispatchCompletion = (ctx: ExtensionContext, displayed: Task, selection: string): Promise<boolean> => {
|
|
349
|
-
if (!ctx.isIdle() || pending || completionDispatch) return Promise.resolve(false);
|
|
350
|
+
if (!ctx.isIdle() || pending || menuPending || completionDispatch) return Promise.resolve(false);
|
|
350
351
|
const token = `${selection}:${randomBytes(8).toString("hex")}`;
|
|
351
352
|
return new Promise((resolve) => {
|
|
352
353
|
const finish = (accepted: boolean) => {
|
|
@@ -367,7 +368,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
367
368
|
const token = args.trim();
|
|
368
369
|
const request = token ? completionDispatch : undefined;
|
|
369
370
|
if (token && (request?.token !== token || request.selection !== `${runtimeToken}:${epoch}:${branchEpoch}:${selectedId}`)) return;
|
|
370
|
-
if (!alive || !ctx.hasUI || ctx.mode !== "tui" || !ctx.isIdle() || pending || setupAbort || !validId(selectedId)) {
|
|
371
|
+
if (!alive || !ctx.hasUI || ctx.mode !== "tui" || !ctx.isIdle() || pending || menuPending || setupAbort || !validId(selectedId)) {
|
|
371
372
|
request?.finish(false);
|
|
372
373
|
if (ctx.hasUI) ctx.ui.notify("Select a task and wait until Pi is idle and the Pinote operation has finished.", "warning");
|
|
373
374
|
return;
|
|
@@ -459,6 +460,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
459
460
|
if (!alive || generation !== epoch) return;
|
|
460
461
|
// Keep the setup lock until its aborted subprocess has actually settled.
|
|
461
462
|
if (!setupAbort) pending = undefined;
|
|
463
|
+
menuPending = undefined;
|
|
462
464
|
await checkCLI(ctx, true);
|
|
463
465
|
if (!alive || generation !== epoch) return;
|
|
464
466
|
if (suggestion) previewBridge?.setSuggestion((choice) => respondToSuggestion(choice, ctx));
|
|
@@ -522,7 +524,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
522
524
|
|
|
523
525
|
const installCLI = async (upgrade: boolean, ctx: ExtensionCommandContext) => {
|
|
524
526
|
if (!ctx.hasUI || ctx.mode !== "tui") return;
|
|
525
|
-
if (pending || !ctx.isIdle()) {
|
|
527
|
+
if (pending || menuPending || !ctx.isIdle()) {
|
|
526
528
|
ctx.ui.notify("Wait until Pi is idle and the pinote operation has finished.", "warning");
|
|
527
529
|
return;
|
|
528
530
|
}
|
|
@@ -563,16 +565,18 @@ export default function (pi: ExtensionAPI) {
|
|
|
563
565
|
return;
|
|
564
566
|
}
|
|
565
567
|
if (token) { ctx.ui.notify("Usage: /pi-note", "warning"); return; }
|
|
566
|
-
if (pending ||
|
|
567
|
-
ctx.ui.notify("Wait until
|
|
568
|
+
if (pending || menuPending) {
|
|
569
|
+
ctx.ui.notify("Wait until the pinote operation has finished.", "warning");
|
|
568
570
|
return;
|
|
569
571
|
}
|
|
570
572
|
const operation = Symbol();
|
|
571
|
-
|
|
573
|
+
menuPending = operation;
|
|
572
574
|
const generation = epoch;
|
|
573
575
|
const branch = branchEpoch;
|
|
574
576
|
const currentSession = () => alive && generation === epoch;
|
|
575
|
-
|
|
577
|
+
// Menus, task selection and preference edits do not interrupt the agent.
|
|
578
|
+
// Completion and CLI setup retain their own idle-only guards.
|
|
579
|
+
const canAct = () => currentSession() && branch === branchEpoch && menuPending === operation;
|
|
576
580
|
try {
|
|
577
581
|
await checkCLI(ctx);
|
|
578
582
|
if (!canAct()) return;
|
|
@@ -633,7 +637,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
633
637
|
if (!canAct() || edited === undefined) return;
|
|
634
638
|
if (edited === "tasks") { settings = false; continue; }
|
|
635
639
|
if (!options.some((option) => option.result === edited)) return;
|
|
636
|
-
if (
|
|
640
|
+
if (menuPending === operation) menuPending = undefined;
|
|
637
641
|
if (edited === "preview") {
|
|
638
642
|
if (!await preview(ctx)) ctx.ui.notify("The task is no longer available for preview.", "warning");
|
|
639
643
|
} else if (edited === "done") await completeSelected("", ctx, current ?? undefined);
|
|
@@ -649,7 +653,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
649
653
|
if (!action || !canAct()) return;
|
|
650
654
|
if (action === "Settings") { settings = true; continue; }
|
|
651
655
|
if (action === "Done" && current) {
|
|
652
|
-
if (
|
|
656
|
+
if (menuPending === operation) menuPending = undefined;
|
|
653
657
|
await completeSelected("", ctx, current);
|
|
654
658
|
return;
|
|
655
659
|
}
|
|
@@ -667,6 +671,11 @@ export default function (pi: ExtensionAPI) {
|
|
|
667
671
|
id = choice;
|
|
668
672
|
} else return;
|
|
669
673
|
const handoff = handoffPrompt();
|
|
674
|
+
if (pending) {
|
|
675
|
+
ctx.ui.notify("Wait until the pinote operation has finished.", "warning");
|
|
676
|
+
return;
|
|
677
|
+
}
|
|
678
|
+
pending = operation;
|
|
670
679
|
refreshSerial++;
|
|
671
680
|
const chosen = await startTask(id, canAct);
|
|
672
681
|
if (!chosen || !canAct()) return;
|
|
@@ -679,6 +688,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
679
688
|
if (currentSession()) ctx.ui.notify(`Pinote: ${clean(error instanceof Error ? error.message : String(error))}`, "error");
|
|
680
689
|
} finally {
|
|
681
690
|
if (pending === operation) pending = undefined;
|
|
691
|
+
if (menuPending === operation) menuPending = undefined;
|
|
682
692
|
if (currentSession()) await refresh(ctx);
|
|
683
693
|
}
|
|
684
694
|
},
|
|
@@ -755,7 +765,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
755
765
|
clearSuggestion(ctx);
|
|
756
766
|
return true;
|
|
757
767
|
}
|
|
758
|
-
if (pending || setupAbort) return false;
|
|
768
|
+
if (pending || menuPending || setupAbort) return false;
|
|
759
769
|
const generation = epoch;
|
|
760
770
|
const branch = branchEpoch;
|
|
761
771
|
const operation = Symbol();
|
|
@@ -804,7 +814,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
804
814
|
const current = await selected(ctx, signal);
|
|
805
815
|
if (!alive || generation !== epoch || branch !== branchEpoch) throw new Error("Pinote operation cancelled: the session changed.");
|
|
806
816
|
if (current || selectedId !== null) throw new Error("A task is already selected; keep it unless the user asks to switch.");
|
|
807
|
-
if (pending || setupAbort) throw new Error("A pinote operation is already open. Retry after it finishes.");
|
|
817
|
+
if (pending || menuPending || setupAbort) throw new Error("A pinote operation is already open. Retry after it finishes.");
|
|
808
818
|
const result = (status: string) => ({ content: [{ type: "text" as const, text: JSON.stringify({ status }) }], details: { status } });
|
|
809
819
|
suggestion = { text: params.text, ...(params.tag === undefined ? {} : { tag: params.tag.trim() }) };
|
|
810
820
|
saveSuggestion();
|
|
@@ -834,7 +844,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
834
844
|
const generation = epoch;
|
|
835
845
|
const branch = branchEpoch;
|
|
836
846
|
if (params.select !== true) return toolResult(await writeTask(ctx, signal, argv, undefined, "0.4.0"));
|
|
837
|
-
if (pending) throw new Error("A pinote operation is already open. Retry after it finishes.");
|
|
847
|
+
if (pending || menuPending) throw new Error("A pinote operation is already open. Retry after it finishes.");
|
|
838
848
|
const operation = Symbol();
|
|
839
849
|
const previousSelection = selectedId;
|
|
840
850
|
pending = operation;
|