@mjasnikovs/pi-task 0.20.1 → 0.20.2

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.
@@ -115,6 +115,12 @@ interface BridgeCommandDef {
115
115
  /** Register a command with pi AND record it in the bridge so remote slash lines
116
116
  * can invoke it. Use in place of pi.registerCommand for task commands. */
117
117
  export declare function registerBridgeCommand(pi: ExtensionAPI, name: string, def: BridgeCommandDef): void;
118
+ /** Record a command that exists ONLY on the remote bridge — no pi.registerCommand.
119
+ * For browser-side equivalents of things the terminal already handles natively
120
+ * (e.g. /compact, which pi's TUI intercepts before extension dispatch, so a real
121
+ * pi command of that name could never fire and would only duplicate the entry in
122
+ * the terminal's autocomplete). */
123
+ export declare function registerRemoteOnlyCommand(name: string, handler: (args: string, ctx: ExtensionCommandContext) => unknown): void;
118
124
  /** Start a new session in response to a remote `/new`. Reads the freshest
119
125
  * command-capable ctx (currentCtx) at call time. If only a shimmed ctx is
120
126
  * available, the newSession shim throws a clear error. */
@@ -181,6 +181,14 @@ export function registerBridgeCommand(pi, name, def) {
181
181
  b.commands.set(name, wrapped.handler);
182
182
  pi.registerCommand(name, wrapped);
183
183
  }
184
+ /** Record a command that exists ONLY on the remote bridge — no pi.registerCommand.
185
+ * For browser-side equivalents of things the terminal already handles natively
186
+ * (e.g. /compact, which pi's TUI intercepts before extension dispatch, so a real
187
+ * pi command of that name could never fire and would only duplicate the entry in
188
+ * the terminal's autocomplete). */
189
+ export function registerRemoteOnlyCommand(name, handler) {
190
+ getBridge().commands.set(name, handler);
191
+ }
184
192
  export function dispatchRemoteNewSession(rebind) {
185
193
  const b = getBridge();
186
194
  const ctx = b.currentCtx;
@@ -1,5 +1,5 @@
1
1
  import { getConfig } from '../config/config.js';
2
- import { getBridge, dispatchRemoteLine, dispatchRemoteNewSession, makeShimmedCtx, interruptAgent, registerBridgeCommand } from './bridge.js';
2
+ import { getBridge, dispatchRemoteLine, dispatchRemoteNewSession, makeShimmedCtx, interruptAgent, registerBridgeCommand, registerRemoteOnlyCommand, publishNotify } from './bridge.js';
3
3
  import { setupEvents } from './events.js';
4
4
  import { reset, addUserTurn } from './session-state.js';
5
5
  import { html } from './ui.js';
@@ -84,6 +84,18 @@ export function registerRemote(pi) {
84
84
  S.send = null;
85
85
  }
86
86
  });
87
+ // The browser advertises /compact, and pi's TUI intercepts `/compact` before any
88
+ // extension command dispatch — so it can only reach the session through the
89
+ // bridge, via the ctx.compact() action every ExtensionContext carries.
90
+ registerRemoteOnlyCommand('compact', (args, ctx) => {
91
+ const customInstructions = args.trim() || undefined;
92
+ ctx.compact({
93
+ ...(customInstructions ? { customInstructions } : {}),
94
+ onComplete: () => publishNotify('Context compacted', 'info'),
95
+ onError: err => publishNotify(`Compaction failed: ${err.message}`, 'error')
96
+ });
97
+ publishNotify('Compacting context…', 'info');
98
+ });
87
99
  // Bridge-registered (not pi.registerCommand) so `/remote stop` also works when
88
100
  // typed in the browser — the web UI advertises it, and while a /task-auto run
89
101
  // holds the host command loop the browser is the only live input surface.
@@ -147,12 +147,13 @@ export function clientScript(wsUrl) {
147
147
  { name: '/task-auto-resume', desc: 'Resume the active /task-auto run' },
148
148
  { name: '/task-auto-cancel', desc: 'Stop the running /task-auto loop after the current task' },
149
149
  { name: '/new', desc: 'Start a new session' },
150
- { name: '/clear', desc: 'Clear the conversation' },
151
150
  { name: '/compact', desc: 'Compact context to save tokens' },
152
- { name: '/help', desc: 'Show available commands' },
153
- { name: '/fast', desc: 'Toggle fast mode' },
154
151
  { name: '/remote stop', desc: 'Stop the remote server' },
155
152
  ];
153
+ // Every entry above must be dispatchable from the browser — /clear, /help and
154
+ // /fast used to sit here and were not (they are not pi commands at all), so
155
+ // picking one only ever produced "Unknown command". register.test.ts asserts
156
+ // this list stays a subset of what the bridge can actually run.
156
157
  let cmdActive = [];
157
158
  let cmdIndex = -1;
158
159
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mjasnikovs/pi-task",
3
- "version": "0.20.1",
3
+ "version": "0.20.2",
4
4
  "description": "Deterministic task planning and spec-orchestration for local models — crash-safe /task pipelines with verify/enforce gates, a real-time remote web view, and web/docs/fetch/worker subagent tools.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",