praxis-agent 0.3.0 → 0.4.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
@@ -83,8 +83,9 @@ troubleshooting. Run `praxis --help` for the authoritative command surface.
83
83
  restored active-branch conversation history, streaming and expandable
84
84
  thinking, grouped multi-file reads, globally expandable tool results,
85
85
  command-specific `/add-dir`, `/copy`, `/branch`, `/rename`, `/export`,
86
- provider-backed `/compact`, native `/rewind`, runtime `/cd`, `/config`,
87
- `/usage`, `/mcp`, and live extension-reload controls,
86
+ provider-backed `/compact`, native `/rewind`, runtime `/cd`, transcript-free
87
+ `/btw` side questions with background-Agent handoff, `/config`, `/usage`,
88
+ `/mcp`, and live extension-reload controls,
88
89
  cursor/history composer, per-session model/effort/permission controls,
89
90
  context/status/skill/task dashboards, prompt stash and continuation shortcuts,
90
91
  filterable `@` file and agent references, composer undo, `Ctrl+G` external
@@ -70,6 +70,16 @@ export interface SessionRunResult {
70
70
  costUsd?: number;
71
71
  modelUsage?: Readonly<Record<string, ModelUsage>>;
72
72
  }
73
+ export interface SideQuestionResult {
74
+ sessionId: string;
75
+ text: string;
76
+ usage: ModelUsage;
77
+ costUsd?: number;
78
+ }
79
+ export interface SideQuestionForkResult {
80
+ agentId: string;
81
+ name: string;
82
+ }
73
83
  export interface SessionSummary {
74
84
  sessionId: string;
75
85
  name?: string;
@@ -122,6 +132,8 @@ export declare class ClaudeSessionService {
122
132
  private readonly worktreeManager;
123
133
  private readonly sessionCwds;
124
134
  private readonly hostedSubagents;
135
+ private readonly hostedSubagentsByRegistry;
136
+ private readonly backgroundNotificationWrites;
125
137
  private readonly downloadedFileResourceSessions;
126
138
  private runtimeCwd;
127
139
  constructor(options: ClaudeSessionServiceOptions);
@@ -133,6 +145,8 @@ export declare class ClaudeSessionService {
133
145
  runShell(command: string, signal?: AbortSignal, sessionId?: string, name?: string): Promise<SessionRunResult>;
134
146
  resume(sessionId: string, prompt: string, signal?: AbortSignal, name?: string, images?: readonly ModelImage[], documents?: readonly ModelDocument[], resumeSessionAt?: string): Promise<SessionRunResult>;
135
147
  resumeShell(sessionId: string, command: string, signal?: AbortSignal, name?: string, resumeSessionAt?: string): Promise<SessionRunResult>;
148
+ answerSideQuestion(sessionId: string | undefined, question: string, signal?: AbortSignal, onDelta?: (delta: string) => void, permissionMode?: ClaudePermissionMode): Promise<SideQuestionResult>;
149
+ forkSideQuestion(sessionId: string, question: string, signal?: AbortSignal): Promise<SideQuestionForkResult>;
136
150
  promptSuggestion(sessionId: string, signal?: AbortSignal): Promise<string | null>;
137
151
  sessionNameSuggestion(sessionId: string, signal?: AbortSignal): Promise<string | null>;
138
152
  sessions(): Promise<SessionSummary[]>;
@@ -142,6 +156,7 @@ export declare class ClaudeSessionService {
142
156
  rename(sessionId: string, name: string): Promise<void>;
143
157
  changeCwd(sessionId: string | undefined, requestedCwd: string): Promise<string>;
144
158
  recordCdUsage(sessionId: string): Promise<void>;
159
+ recordBtwUsage(sessionId: string | undefined, permissionMode?: ClaudePermissionMode): Promise<string>;
145
160
  compact(sessionId: string, signal?: AbortSignal, selection?: ManualCompactSelection): Promise<ManualCompactResult>;
146
161
  fork(parentSessionId: string, sessionId?: string, resumeSessionAt?: string): Promise<ForkResult>;
147
162
  rewindFiles(sessionId: string, userMessageId: string): Promise<void>;
@@ -162,7 +177,13 @@ export declare class ClaudeSessionService {
162
177
  private restoreWorktree;
163
178
  private paths;
164
179
  private appendCdCommand;
180
+ private appendSystemLocalCommand;
181
+ private ensureLocalSession;
182
+ private appendInputHistory;
183
+ private appendBackgroundNotification;
184
+ private enqueueBackgroundNotifications;
165
185
  private cdCommandEntries;
186
+ private localCommandEntries;
166
187
  private store;
167
188
  private turnStore;
168
189
  private assertSessionPersistence;
@@ -1 +1 @@
1
- {"version":3,"file":"session-service.d.ts","sourceRoot":"","sources":["../../src/application/session-service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session-service.d.ts","sourceRoot":"","sources":["../../src/application/session-service.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { randomUUID } from 'node:crypto';
2
- import { copyFile, link, lstat, mkdir, readdir, realpath, stat, unlink, } from 'node:fs/promises';
2
+ import { appendFile, copyFile, link, lstat, mkdir, readdir, realpath, stat, unlink, } from 'node:fs/promises';
3
3
  import { homedir } from 'node:os';
4
4
  import { basename, extname, isAbsolute, join, relative } from 'node:path';
5
5
  import { createClaudeCompactEntries, formatClaudeCompactSummary, getCumulativeDroppedTokens, } from '../compatibility/claude/compaction.js';
@@ -91,6 +91,8 @@ export class ClaudeSessionService {
91
91
  worktreeManager;
92
92
  sessionCwds = new Map();
93
93
  hostedSubagents = new Set();
94
+ hostedSubagentsByRegistry = new WeakMap();
95
+ backgroundNotificationWrites = new Map();
94
96
  downloadedFileResourceSessions = new Set();
95
97
  runtimeCwd;
96
98
  constructor(options) {
@@ -127,6 +129,8 @@ export class ClaudeSessionService {
127
129
  async close() {
128
130
  this.scheduledPrompts?.close();
129
131
  await Promise.all([...this.hostedSubagents].map((executor) => executor.close()));
132
+ await Promise.resolve();
133
+ await Promise.all([...this.backgroundNotificationWrites.values()]);
130
134
  this.hostedSubagents.clear();
131
135
  await this.workflowManager?.close();
132
136
  }
@@ -293,7 +297,7 @@ export class ClaudeSessionService {
293
297
  'Monitor',
294
298
  'PushNotification',
295
299
  ];
296
- return {
300
+ const hostedRegistry = {
297
301
  definitions: () => {
298
302
  const definitions = interactiveRegistry.definitions();
299
303
  return [...definitions].sort((left, right) => {
@@ -306,6 +310,10 @@ export class ClaudeSessionService {
306
310
  prepare: (call, context) => interactiveRegistry.prepare(call, context),
307
311
  execute: (call, context) => interactiveRegistry.execute(call, context),
308
312
  };
313
+ if (subagentExecutor) {
314
+ this.hostedSubagentsByRegistry.set(hostedRegistry, subagentExecutor);
315
+ }
316
+ return hostedRegistry;
309
317
  }
310
318
  async run(prompt, signal, sessionId = randomUUID(), name, images, documents) {
311
319
  this.worktreeManager?.bindSession(sessionId);
@@ -323,6 +331,119 @@ export class ClaudeSessionService {
323
331
  this.worktreeManager?.bindSession(sessionId);
324
332
  return this.executeTurn(sessionId, `! ${command}`, true, signal, name, [], [], resumeSessionAt, command);
325
333
  }
334
+ async answerSideQuestion(sessionId, question, signal, onDelta, permissionMode = 'default') {
335
+ const prompt = question.trim();
336
+ if (!prompt)
337
+ throw new Error('Side question must not be empty');
338
+ const activeSessionId = await this.ensureLocalSession(sessionId, permissionMode);
339
+ await this.appendInputHistory(`/btw ${prompt}`, activeSessionId);
340
+ const provider = this.provider();
341
+ let entries = [];
342
+ if (sessionId) {
343
+ const loaded = this.options.sessionPersistence === false
344
+ ? await this.turnStore(activeSessionId).withLease((lease) => lease.load())
345
+ : {
346
+ status: 'completed',
347
+ value: await this.store(activeSessionId).loadReadOnly(),
348
+ };
349
+ if (loaded.status === 'conflict') {
350
+ throw new Error(`Claude side question conflict: ${loaded.reason}`);
351
+ }
352
+ if (loaded.value.entries.length === 0) {
353
+ throw new Error(`Claude session not found: ${activeSessionId}`);
354
+ }
355
+ entries = loaded.value.entries;
356
+ this.restoreWorktree(entries);
357
+ }
358
+ const assembledContext = await this.options.contextAssembler?.assemble({
359
+ cwd: this.activeCwd(),
360
+ });
361
+ const messages = [
362
+ ...(assembledContext?.systemMessages ?? []),
363
+ ...injectFirstUserMessageContext([
364
+ ...projectClaudeModelMessages(entries),
365
+ { role: 'user', content: prompt },
366
+ ], assembledContext?.firstUserMessageContext),
367
+ ];
368
+ const budget = this.contextBudget(provider);
369
+ if (budget)
370
+ budget.assertFits(budget.evaluate(messages));
371
+ let text = '';
372
+ let usage = { inputTokens: 0, outputTokens: 0 };
373
+ for await (const event of provider.complete({
374
+ messages,
375
+ ...(this.options.effort ? { effort: this.options.effort } : {}),
376
+ ...(signal ? { signal } : {}),
377
+ })) {
378
+ if (event.type === 'text-delta') {
379
+ text += event.delta;
380
+ onDelta?.(event.delta);
381
+ }
382
+ else if (event.type === 'usage') {
383
+ usage = event.usage;
384
+ }
385
+ else if (event.type === 'tool-call') {
386
+ throw new Error('Side questions cannot call tools; press f to fork');
387
+ }
388
+ }
389
+ const pricing = this.options.pricing?.resolve(provider.model ?? 'praxis/provider');
390
+ return {
391
+ sessionId: activeSessionId,
392
+ text,
393
+ usage,
394
+ ...(pricing ? { costUsd: usageCostUsd(usage, pricing) } : {}),
395
+ };
396
+ }
397
+ async forkSideQuestion(sessionId, question, signal) {
398
+ const prompt = question.trim();
399
+ if (!prompt)
400
+ throw new Error('Side question must not be empty');
401
+ const name = prompt
402
+ .toLowerCase()
403
+ .replace(/[^a-z0-9]+/gu, '-')
404
+ .replace(/^-+|-+$/gu, '')
405
+ .split('-')
406
+ .filter(Boolean)
407
+ .slice(0, 3)
408
+ .join('-')
409
+ .slice(0, 64) || 'side-question';
410
+ const registry = this.createHostedToolRegistry(sessionId);
411
+ const call = {
412
+ id: randomUUID(),
413
+ name: 'Agent',
414
+ input: {
415
+ description: prompt,
416
+ prompt,
417
+ subagent_type: 'general-purpose',
418
+ run_in_background: true,
419
+ name,
420
+ },
421
+ };
422
+ const context = {
423
+ cwd: this.activeCwd(),
424
+ ...(signal ? { signal } : {}),
425
+ };
426
+ const prepared = await registry.prepare(call, context);
427
+ const result = await registry.execute(prepared, context);
428
+ const agentId = result.nativeToolUseResult?.agentId;
429
+ if (result.isError || typeof agentId !== 'string') {
430
+ throw new Error(result.content || 'Could not fork side question');
431
+ }
432
+ await this.appendSystemLocalCommand(sessionId, 'btw', prompt, `⑂ forked ${name} (${agentId.slice(-4)})`);
433
+ const executor = this.hostedSubagentsByRegistry.get(registry);
434
+ if (executor) {
435
+ void executor
436
+ .notifications(true)
437
+ .then(({ messages }) => this.enqueueBackgroundNotifications(sessionId, messages))
438
+ .catch((error) => this.options.eventSink?.({
439
+ type: 'warning',
440
+ message: error instanceof Error
441
+ ? error.message
442
+ : `Could not persist background notification: ${String(error)}`,
443
+ }));
444
+ }
445
+ return { agentId, name };
446
+ }
326
447
  async promptSuggestion(sessionId, signal) {
327
448
  const provider = this.provider();
328
449
  const loaded = this.options.sessionPersistence === false
@@ -689,6 +810,33 @@ export class ClaudeSessionService {
689
810
  throw new Error(`Claude cd usage conflict: ${result.reason}`);
690
811
  }
691
812
  }
813
+ async recordBtwUsage(sessionId, permissionMode = 'default') {
814
+ const activeSessionId = await this.ensureLocalSession(sessionId, permissionMode);
815
+ await this.appendInputHistory('/btw', activeSessionId);
816
+ while (true) {
817
+ const result = await this.turnStore(activeSessionId).withLease(async (lease) => {
818
+ const snapshot = await lease.load();
819
+ if (snapshot.entries.length === 0) {
820
+ throw new Error(`Claude session not found: ${activeSessionId}`);
821
+ }
822
+ const entries = this.localCommandEntries(activeSessionId, this.activeCwd(), this.logicalTailUuid(snapshot.tail), 'btw', '', 'Usage: /btw <your question>');
823
+ const leafUuid = entries.at(-1)?.uuid;
824
+ if (typeof leafUuid !== 'string') {
825
+ throw new Error('Claude btw local command pair is incomplete');
826
+ }
827
+ const appended = await lease.appendMany(snapshot.tail, [
828
+ ...entries,
829
+ { type: 'last-prompt', leafUuid, sessionId: activeSessionId },
830
+ ]);
831
+ if (appended.status === 'conflict') {
832
+ throw new Error(`Claude local command append conflict: ${appended.reason}`);
833
+ }
834
+ });
835
+ if (result.status === 'completed')
836
+ return activeSessionId;
837
+ await new Promise((resolve) => setTimeout(resolve, 25));
838
+ }
839
+ }
692
840
  async compact(sessionId, signal, selection) {
693
841
  this.assertWritable();
694
842
  const provider = this.provider();
@@ -2183,9 +2331,128 @@ export class ClaudeSessionService {
2183
2331
  throw new Error(`Claude local command conflict: ${result.reason}`);
2184
2332
  }
2185
2333
  }
2334
+ async appendSystemLocalCommand(sessionId, command, args, output) {
2335
+ while (true) {
2336
+ const result = await this.turnStore(sessionId).withLease(async (lease) => {
2337
+ const snapshot = await lease.load();
2338
+ if (snapshot.entries.length === 0) {
2339
+ throw new Error(`Claude session not found: ${sessionId}`);
2340
+ }
2341
+ const appendResult = await lease.appendMany(snapshot.tail, this.localCommandEntries(sessionId, this.activeCwd(), this.logicalTailUuid(snapshot.tail), command, args, output));
2342
+ if (appendResult.status === 'conflict') {
2343
+ throw new Error(`Claude local command append conflict: ${appendResult.reason}`);
2344
+ }
2345
+ });
2346
+ if (result.status === 'completed')
2347
+ return;
2348
+ await new Promise((resolve) => setTimeout(resolve, 25));
2349
+ }
2350
+ }
2351
+ async ensureLocalSession(sessionId, permissionMode) {
2352
+ if (sessionId)
2353
+ return sessionId;
2354
+ this.assertWritable();
2355
+ const createdSessionId = randomUUID();
2356
+ const store = this.turnStore(createdSessionId);
2357
+ const created = await store.create([
2358
+ { type: 'mode', mode: 'normal', sessionId: createdSessionId },
2359
+ {
2360
+ type: 'permission-mode',
2361
+ permissionMode,
2362
+ sessionId: createdSessionId,
2363
+ },
2364
+ ]);
2365
+ if (created.status === 'conflict') {
2366
+ throw new Error(`Session ID ${createdSessionId} is already in use`);
2367
+ }
2368
+ this.sessionCwds.set(createdSessionId, this.activeCwd());
2369
+ this.options.interactiveTools?.restore(createdSessionId, [
2370
+ { type: 'mode', mode: 'normal', sessionId: createdSessionId },
2371
+ {
2372
+ type: 'permission-mode',
2373
+ permissionMode,
2374
+ sessionId: createdSessionId,
2375
+ },
2376
+ ]);
2377
+ return createdSessionId;
2378
+ }
2379
+ async appendInputHistory(display, sessionId) {
2380
+ await mkdir(this.options.configRoot, { recursive: true });
2381
+ await appendFile(join(this.options.configRoot, 'history.jsonl'), `${JSON.stringify({
2382
+ display,
2383
+ pastedContents: {},
2384
+ timestamp: Date.now(),
2385
+ project: this.activeCwd(),
2386
+ sessionId,
2387
+ })}\n`, 'utf8');
2388
+ }
2389
+ async appendBackgroundNotification(sessionId, content) {
2390
+ while (true) {
2391
+ const result = await this.turnStore(sessionId).withLease(async (lease) => {
2392
+ const snapshot = await lease.load();
2393
+ if (snapshot.entries.length === 0) {
2394
+ throw new Error(`Claude session not found: ${sessionId}`);
2395
+ }
2396
+ const timestamp = new Date().toISOString();
2397
+ const entries = [
2398
+ {
2399
+ type: 'queue-operation',
2400
+ operation: 'enqueue',
2401
+ timestamp,
2402
+ sessionId,
2403
+ content,
2404
+ },
2405
+ {
2406
+ type: 'queue-operation',
2407
+ operation: 'dequeue',
2408
+ timestamp,
2409
+ sessionId,
2410
+ },
2411
+ {
2412
+ parentUuid: this.logicalTailUuid(snapshot.tail),
2413
+ isSidechain: false,
2414
+ promptId: randomUUID(),
2415
+ type: 'user',
2416
+ message: { role: 'user', content },
2417
+ uuid: randomUUID(),
2418
+ timestamp,
2419
+ permissionMode: 'default',
2420
+ origin: { kind: 'task-notification' },
2421
+ promptSource: 'system',
2422
+ userType: 'external',
2423
+ entrypoint: 'cli',
2424
+ cwd: this.activeCwd(),
2425
+ sessionId,
2426
+ version: this.options.claudeVersion,
2427
+ gitBranch: null,
2428
+ },
2429
+ ];
2430
+ const appended = await lease.appendMany(snapshot.tail, entries);
2431
+ if (appended.status === 'conflict') {
2432
+ throw new Error(`Claude background notification append conflict: ${appended.reason}`);
2433
+ }
2434
+ });
2435
+ if (result.status === 'completed')
2436
+ return;
2437
+ await new Promise((resolve) => setTimeout(resolve, 25));
2438
+ }
2439
+ }
2440
+ enqueueBackgroundNotifications(sessionId, messages) {
2441
+ const previous = this.backgroundNotificationWrites.get(sessionId);
2442
+ const queued = (previous ?? Promise.resolve()).then(async () => {
2443
+ for (const message of messages) {
2444
+ await this.appendBackgroundNotification(sessionId, message);
2445
+ }
2446
+ });
2447
+ this.backgroundNotificationWrites.set(sessionId, queued);
2448
+ const cleanup = () => {
2449
+ if (this.backgroundNotificationWrites.get(sessionId) === queued)
2450
+ this.backgroundNotificationWrites.delete(sessionId);
2451
+ };
2452
+ void queued.then(cleanup, cleanup);
2453
+ return queued;
2454
+ }
2186
2455
  cdCommandEntries(sessionId, cwd, parentUuid) {
2187
- const firstUuid = randomUUID();
2188
- const secondUuid = randomUUID();
2189
2456
  const timestamp = new Date().toISOString();
2190
2457
  const common = {
2191
2458
  isSidechain: false,
@@ -2197,38 +2464,63 @@ export class ClaudeSessionService {
2197
2464
  version: this.options.claudeVersion,
2198
2465
  gitBranch: null,
2199
2466
  };
2467
+ const localCommands = this.localCommandEntries(sessionId, cwd, parentUuid, 'cd', cwd, `Moved to ${cwd}`, timestamp);
2468
+ const secondUuid = localCommands[1]?.uuid;
2469
+ if (typeof secondUuid !== 'string') {
2470
+ throw new Error('Claude cd local command pair is incomplete');
2471
+ }
2200
2472
  return [
2473
+ ...localCommands,
2201
2474
  {
2202
2475
  ...common,
2476
+ parentUuid: secondUuid,
2477
+ promptId: randomUUID(),
2478
+ type: 'user',
2479
+ message: {
2480
+ role: 'user',
2481
+ content: `<system-reminder>\nThe session's working directory has changed to ${cwd} (via /cd). The environment block at the start of this conversation still names the previous directory — that information is stale. All tool calls and relative paths now resolve from ${cwd}.\n</system-reminder>`,
2482
+ },
2483
+ isMeta: true,
2484
+ uuid: randomUUID(),
2485
+ },
2486
+ ];
2487
+ }
2488
+ localCommandEntries(sessionId, cwd, parentUuid, command, args, output, timestamp = new Date().toISOString()) {
2489
+ const firstUuid = randomUUID();
2490
+ return [
2491
+ {
2492
+ parentUuid,
2493
+ isSidechain: false,
2203
2494
  type: 'system',
2204
2495
  subtype: 'local_command',
2205
- isMeta: false,
2496
+ content: `<command-name>/${command}</command-name>\n <command-message>${command}</command-message>\n <command-args>${args}</command-args>`,
2206
2497
  level: 'info',
2207
- parentUuid,
2498
+ timestamp,
2208
2499
  uuid: firstUuid,
2209
- content: `<command-name>/cd</command-name>\n <command-message>cd</command-message>\n <command-args>${cwd}</command-args>`,
2500
+ isMeta: false,
2501
+ userType: 'external',
2502
+ entrypoint: 'cli',
2503
+ cwd,
2504
+ sessionId,
2505
+ version: this.options.claudeVersion,
2506
+ gitBranch: null,
2210
2507
  },
2211
2508
  {
2212
- ...common,
2509
+ parentUuid: firstUuid,
2510
+ isSidechain: false,
2213
2511
  type: 'system',
2214
2512
  subtype: 'local_command',
2215
- isMeta: false,
2513
+ content: `<local-command-stdout>${output}</local-command-stdout>`,
2216
2514
  level: 'info',
2217
- parentUuid: firstUuid,
2218
- uuid: secondUuid,
2219
- content: `<local-command-stdout>Moved to ${cwd}</local-command-stdout>`,
2220
- },
2221
- {
2222
- ...common,
2223
- parentUuid: secondUuid,
2224
- promptId: randomUUID(),
2225
- type: 'user',
2226
- message: {
2227
- role: 'user',
2228
- content: `<system-reminder>\nThe session's working directory has changed to ${cwd} (via /cd). The environment block at the start of this conversation still names the previous directory — that information is stale. All tool calls and relative paths now resolve from ${cwd}.\n</system-reminder>`,
2229
- },
2230
- isMeta: true,
2515
+ timestamp,
2231
2516
  uuid: randomUUID(),
2517
+ isMeta: false,
2518
+ userType: 'external',
2519
+ entrypoint: 'cli',
2520
+ cwd,
2521
+ sessionId,
2522
+ version: this.options.claudeVersion,
2523
+ gitBranch: null,
2232
2524
  },
2233
2525
  ];
2234
2526
  }