pi-note 0.31.0 → 0.32.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.
package/README.md CHANGED
@@ -50,9 +50,10 @@ state routing, tools and UI.
50
50
 
51
51
  Open **`/pinote`** (`/pi-note` is an alias). Select or create a task, preview it,
52
52
  clear the selection, complete it, respond to suggestions, or edit shared settings.
53
- Selection/creation and settings changes require confirmation. Nothing submits a
54
- model prompt automatically; inserting Continue's draft requires confirmation and
55
- preserves an existing draft.
53
+ Selecting an existing task starts it immediately and returns focus to the prompt,
54
+ with no extra confirmation. Creation and settings changes still require confirmation.
55
+ Nothing submits a model prompt automatically; inserting Continue's draft requires
56
+ confirmation and preserves an existing draft.
56
57
 
57
58
  Menus use Pi's native components and configured selection keys. **Escape** goes
58
59
  back; **Ctrl+R** refreshes. Settings with fewer than five choices cycle inline.
@@ -75,9 +76,14 @@ Changing endpoints starts a separate selection namespace. Unsaved Pi sessions
75
76
  cannot guarantee selection persistence.
76
77
 
77
78
  The GTK app's **Start in Kitty…** action (note 0.13.0+) chooses a working directory
78
- and opens a named tab with this task selected, without submitting a prompt. Client
79
- and service both need pi-note 0.31.0+. The one-shot `PINOTE_LAUNCH_TASK` environment
80
- handoff carries only the task ID and displayed revision, never task text or tokens.
79
+ and opens a named tab with this task selected, without submitting a prompt.
80
+ With note 0.15.0+ and pi-note 0.32.0+, successful selection prefills an empty Pi editor
81
+ with `is task clear?`. Configure `gui.kitty_start_prompt` in the
82
+ [GUI config](../docs/gui.md#gui-configuration), or set it to `""` to disable; existing
83
+ drafts are never replaced. The service needs pi-note 0.31.0+.
84
+ The one-shot `PINOTE_LAUNCH_TASK` environment handoff carries the task ID, displayed
85
+ revision and optional editor draft, never task text or tokens. The draft stays
86
+ client-local and is never sent to the service or persisted as launch state.
81
87
  Only a fresh session can consume it. The service must share the GUI's database;
82
88
  missing/stale revisions fail closed. Resume, reload and `/new` never replay the
83
89
  handoff or replace another selection. Pi keeps its normal endpoint/token settings.
@@ -231,7 +231,7 @@ function view(data, scoped = false, secondary = false, features = {}) {
231
231
  ? t.id === state.launch.task_id && t.updated_at === state.launch.updated_at
232
232
  : `${t.text} ${t.tag ?? ''}`.toLowerCase().includes((state.search ?? '').toLowerCase()));
233
233
  for (const candidate of matches.slice(0, 200))
234
- action(`select:${candidate.id}`, `${candidate.tag ? `[${candidate.tag}] ` : ''}${candidate.text.split('\n')[0]}`, { description: `#${candidate.id} · ${candidate.state}`, confirm: 'Select and start this task for this conversation?' });
234
+ action(`select:${candidate.id}`, `${candidate.tag ? `[${candidate.tag}] ` : ''}${candidate.text.split('\n')[0]}`, { description: `#${candidate.id} · ${candidate.state} · Select and start this task` });
235
235
  if (matches.length > 200)
236
236
  body += '\nShowing the first 200 matches; use Filter tasks to narrow the list.';
237
237
  }
package/mcp/core.ts CHANGED
@@ -200,7 +200,7 @@ function view(data: Snapshot, scoped = false, secondary = false, features: { foo
200
200
  const matches = tasks.filter((t) => state.launch
201
201
  ? t.id === state.launch.task_id && t.updated_at === state.launch.updated_at
202
202
  : `${t.text} ${t.tag ?? ''}`.toLowerCase().includes((state.search ?? '').toLowerCase()));
203
- for (const candidate of matches.slice(0, 200)) action(`select:${candidate.id}`, `${candidate.tag ? `[${candidate.tag}] ` : ''}${candidate.text.split('\n')[0]}`, { description: `#${candidate.id} · ${candidate.state}`, confirm: 'Select and start this task for this conversation?' });
203
+ for (const candidate of matches.slice(0, 200)) action(`select:${candidate.id}`, `${candidate.tag ? `[${candidate.tag}] ` : ''}${candidate.text.split('\n')[0]}`, { description: `#${candidate.id} · ${candidate.state} · Select and start this task` });
204
204
  if (matches.length > 200) body += '\nShowing the first 200 matches; use Filter tasks to narrow the list.';
205
205
  }
206
206
  const footer: { text: string; openApp?: true; url?: string; action?: string; secondaryAction?: string; doubleAction?: string; style?: { italic: boolean; color: 'accent' }; width?: number }[] = features.footerNativeActions
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-note",
3
- "version": "0.31.0",
3
+ "version": "0.32.0",
4
4
  "description": "Persistent pinote tasks, Markdown handoffs, and task status for Pi",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/remote/ui.ts CHANGED
@@ -172,7 +172,7 @@ export class RemoteUI {
172
172
  ctx.ui.notify('Value does not match the field type.', 'warning'); continue;
173
173
  }
174
174
  }
175
- if (current()) await this.dispatch(ctx, view, control, value);
175
+ if (current() && await this.dispatch(ctx, view, control, value) && control.id.startsWith('select:')) return;
176
176
  }
177
177
  } catch (error) { if (current()) ctx.ui.notify(error instanceof RemoteFailure ? error.message : 'Pinote unavailable', 'error'); }
178
178
  finally { this.opening = false; }
package/remote.ts CHANGED
@@ -5,6 +5,7 @@ import { ENTRY_TYPE, RemoteSession, type SavedState } from './remote/session.ts'
5
5
  import { registerTools } from './remote/tools.ts';
6
6
  import { registerPreview, RemoteUI } from './remote/ui.ts';
7
7
  import { registerRemoteExit } from './remote/exit.ts';
8
+ import { editorText } from './remote/protocol.ts';
8
9
 
9
10
  // Only an accepted /new (previousSessionFile) may carry this process-local selection.
10
11
  // Reload/resume/fork restore branch entries, never this map or a folder-global store.
@@ -48,12 +49,17 @@ export default function pinoteRemote(pi: ExtensionAPI): void {
48
49
  const branch = ctx.sessionManager.getBranch();
49
50
  let carried = reason === 'new' && previous ? transfers.get(previous) : undefined;
50
51
  let launch: { task_id: number; updated_at: string } | undefined;
52
+ let prompt: string | undefined;
51
53
  if (request) {
52
54
  try {
53
55
  if (reason !== 'startup' || branch.some((entry) => entry.type === 'message' || entry.type === 'custom' && entry.customType === ENTRY_TYPE)) throw new Error('Launch requires a fresh Pi session');
54
56
  const parsed = JSON.parse(request);
55
57
  if (!parsed || !Number.isSafeInteger(parsed.task_id) || parsed.task_id < 1 ||
56
58
  typeof parsed.updated_at !== 'string' || !parsed.updated_at.length || parsed.updated_at.length > 128) throw new Error('Invalid launch request');
59
+ if (parsed.prompt !== undefined) {
60
+ if (typeof parsed.prompt !== 'string' || [...parsed.prompt].length > 4000) throw new Error('Invalid launch prompt');
61
+ prompt = editorText(parsed.prompt);
62
+ }
57
63
  launch = { task_id: parsed.task_id, updated_at: parsed.updated_at };
58
64
  carried = { scope: config.scope, contextId: randomUUID(), state: { launch } };
59
65
  } catch {
@@ -68,6 +74,10 @@ export default function pinoteRemote(pi: ExtensionAPI): void {
68
74
  const control = view.controls.find((item) => item.id === `select:${launch.task_id}`);
69
75
  if (!control) throw new Error('Launch task changed or belongs to another service');
70
76
  await session.action(view, control); // The directory chooser's Start click granted consent.
77
+ if (prompt?.trim() && ctx.mode === 'tui' && ctx.isIdle()) {
78
+ if (ctx.ui.getEditorText().length) ctx.ui.notify('Launch draft not inserted: the editor already contains a draft.', 'warning');
79
+ else ctx.ui.setEditorText(prompt);
80
+ }
71
81
  }
72
82
  if (reason === 'new' && previous) transfers.delete(previous);
73
83
  } catch (error) {