pi-note 0.7.1 → 0.8.0

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.
Files changed (3) hide show
  1. package/README.md +23 -4
  2. package/index.ts +23 -2
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -56,10 +56,10 @@ standalone `settings/pi/extensions/pinote.ts` entry if installed; load only one
56
56
 
57
57
  ## Use
58
58
 
59
- `/pi-note` picks a task, marks it in progress, and adds this prompt to the editor:
59
+ `/pi-note` picks a task, marks it in progress, and adds this default prompt to the editor:
60
60
  “Read the current Pinote task. Summarize your understanding, but don’t start work yet.”
61
61
  The agent fetches current task text and saved handoff fields when you submit;
62
- they are not copied into the draft. The prompt asks for a summary, not implementation.
62
+ they are not copied into the draft. The default prompt asks for a summary, not implementation.
63
63
  Existing drafts are preserved; nothing is submitted automatically.
64
64
  With a selected task it offers **Continue**, **Done**, and **Switch task**.
65
65
  Type in the task picker to filter by text, ID, tag, or state (all words must match).
@@ -74,14 +74,33 @@ Resume restores that session's task; a new session starts unselected and does no
74
74
  an older per-folder selection. Pi saves the session after the first submitted message;
75
75
  quitting before that leaves the next launch unselected, while the task stays in progress.
76
76
  Use **Continue**
77
- to insert the same read-and-summarize prompt. Completing, removing, or scheduling a task clears it
77
+ to insert the same configured prompt. Completing, removing, or scheduling a task clears it
78
78
  from sessions that refresh it. Switching does not complete or reset the previous task.
79
79
  Task fields such as `Worktree` and `PR` stay on the task, so sessions can use separate
80
80
  worktrees and pull requests. Task status refreshes at session start, before/after
81
81
  agent activity, and after commands/tools. The CLI's per-directory `agent selected`
82
82
  command is not this session memory.
83
83
 
84
- Agent tools:
84
+ ### Handoff prompt configuration
85
+
86
+ Set `handoffPrompt` in `~/.pi/agent/pi-note.json` (or in the agent directory set
87
+ by `PI_CODING_AGENT_DIR`):
88
+
89
+ ```json
90
+ {
91
+ "handoffPrompt": "Read the current Pinote task. Summarize your understanding and proposed approach, but don’t start work yet."
92
+ }
93
+ ```
94
+
95
+ Both task selection and **Continue** read this file each time; no `/reload` is
96
+ needed after edits. The value is literal text, not a prompt template; use `\n`
97
+ in JSON strings for multiple lines. It must be a nonblank string without control
98
+ characters other than tabs and newlines. A missing file or key uses the default.
99
+ Invalid/unreadable configuration reports an error without starting/switching a
100
+ task or changing the editor. **Done** and agent tools are unaffected. This is
101
+ user-level configuration only; project-local files are not read.
102
+
103
+ ### Agent tools
85
104
 
86
105
  - `pinote_get_current`: read this session's selected task, including its revision.
87
106
  Takes no arguments; returns null when this session has no selected task.
package/index.ts CHANGED
@@ -1,6 +1,7 @@
1
- import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
1
+ import { getAgentDir, type ExtensionAPI, type ExtensionContext } from "@earendil-works/pi-coding-agent";
2
2
  import { truncateToWidth } from "@earendil-works/pi-tui";
3
3
  import { readFileSync } from "node:fs";
4
+ import { join } from "node:path";
4
5
  import { stripVTControlCharacters } from "node:util";
5
6
  import { Type } from "typebox";
6
7
  import { createPRWatcher } from "./pr-watch.ts";
@@ -34,6 +35,26 @@ const clean = (value: string) => stripVTControlCharacters(value).replace(/[\x00-
34
35
  const firstLine = (task: Summary) => clean(task.text.split("\n", 1)[0]).replace(/\s+/gu, " ").trim();
35
36
  const title = (task: Summary) => truncateToWidth(`#${task.id} ${firstLine(task)}`, 60);
36
37
 
38
+ const defaultHandoffPrompt = "Read the current Pinote task. Summarize your understanding, but don’t start work yet.";
39
+ function handoffPrompt(): string {
40
+ const path = join(getAgentDir(), "pi-note.json");
41
+ let raw: string;
42
+ try {
43
+ raw = readFileSync(path, "utf8");
44
+ } catch (error) {
45
+ if ((error as NodeJS.ErrnoException).code === "ENOENT") return defaultHandoffPrompt;
46
+ throw new Error(`Cannot read ${path}. Check the pi-note configuration.`);
47
+ }
48
+ let config: unknown;
49
+ try { config = JSON.parse(raw); } catch { throw new Error(`Invalid JSON in ${path}.`); }
50
+ if (!record(config)) throw new Error(`Expected a JSON object in ${path}.`);
51
+ if (!("handoffPrompt" in config)) return defaultHandoffPrompt;
52
+ if (!text(config.handoffPrompt) || !config.handoffPrompt.trim()) {
53
+ throw new Error(`handoffPrompt in ${path} must be a nonblank string without control characters (except tabs/newlines).`);
54
+ }
55
+ return config.handoffPrompt;
56
+ }
57
+
37
58
  function parse(raw: string): unknown {
38
59
  try { return JSON.parse(raw); } catch { throw new Error(compatible); }
39
60
  }
@@ -333,6 +354,7 @@ export default function (pi: ExtensionAPI) {
333
354
  if (currentSession()) ctx.ui.notify(`Pinote #${current.id} completed.`, "info");
334
355
  return;
335
356
  }
357
+ const handoff = handoffPrompt();
336
358
  let id: number;
337
359
  if (action === "Continue" && current) {
338
360
  id = current.id;
@@ -349,7 +371,6 @@ export default function (pi: ExtensionAPI) {
349
371
  const chosen = await startTask(id, canAct);
350
372
  if (!chosen || !canAct()) return;
351
373
  const draft = ctx.ui.getEditorText();
352
- const handoff = "Read the current Pinote task. Summarize your understanding, but don’t start work yet.";
353
374
  ctx.ui.setEditorText(draft ? `${draft}\n\n${handoff}` : handoff);
354
375
  ctx.ui.notify(`Pinote #${chosen.id} is in progress. Task added to input.`, "info");
355
376
  } catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-note",
3
- "version": "0.7.1",
3
+ "version": "0.8.0",
4
4
  "description": "Persistent pinote tasks, Markdown handoffs, and task status for Pi",
5
5
  "license": "MIT",
6
6
  "type": "module",