praxis-agent 0.36.0 → 0.37.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 (86) hide show
  1. package/README.md +16 -2
  2. package/dist/application/durable-follow-up.d.ts +14 -0
  3. package/dist/application/durable-follow-up.js +52 -0
  4. package/dist/application/native-session-transcript.d.ts +72 -0
  5. package/dist/application/native-session-transcript.js +351 -0
  6. package/dist/application/native-sidechain-transcript.d.ts +34 -0
  7. package/dist/application/native-sidechain-transcript.js +156 -0
  8. package/dist/application/session-service.d.ts +15 -0
  9. package/dist/application/session-service.js +611 -69
  10. package/dist/application/subagent-service.d.ts +5 -1
  11. package/dist/application/subagent-service.js +391 -143
  12. package/dist/application/team-agent-runtime.d.ts +29 -0
  13. package/dist/application/team-agent-runtime.js +169 -0
  14. package/dist/application/team-capability.d.ts +27 -0
  15. package/dist/application/team-capability.js +41 -0
  16. package/dist/application/team-lead-operations.d.ts +38 -0
  17. package/dist/application/team-lead-operations.js +155 -0
  18. package/dist/application/team-mailbox.d.ts +54 -0
  19. package/dist/application/team-mailbox.js +196 -0
  20. package/dist/application/team-manager.d.ts +113 -0
  21. package/dist/application/team-manager.js +681 -0
  22. package/dist/application/team-workspace.d.ts +29 -0
  23. package/dist/application/team-workspace.js +197 -0
  24. package/dist/application/transcript-projection.d.ts +2 -0
  25. package/dist/application/transcript-projection.js +30 -1
  26. package/dist/cli/interactive.d.ts +7 -0
  27. package/dist/cli/interactive.js +387 -136
  28. package/dist/cli/tui/claude-style.d.ts +8 -25
  29. package/dist/cli/tui/claude-style.js +158 -160
  30. package/dist/cli/tui/decision-surface-model.d.ts +71 -0
  31. package/dist/cli/tui/decision-surface-model.js +131 -0
  32. package/dist/cli/tui/decision-surface.d.ts +7 -0
  33. package/dist/cli/tui/decision-surface.js +41 -0
  34. package/dist/cli/tui/help-surface-model.d.ts +68 -0
  35. package/dist/cli/tui/help-surface-model.js +131 -0
  36. package/dist/cli/tui/mcp-panel.js +1 -2
  37. package/dist/cli/tui/permission-surface-model.d.ts +195 -0
  38. package/dist/cli/tui/permission-surface-model.js +360 -0
  39. package/dist/cli/tui/permission-surface.d.ts +7 -0
  40. package/dist/cli/tui/permission-surface.js +69 -0
  41. package/dist/cli/tui/presentation-environment.d.ts +32 -0
  42. package/dist/cli/tui/presentation-environment.js +149 -0
  43. package/dist/cli/tui/tool-permission.js +7 -3
  44. package/dist/cli/tui/transcript-presentation.d.ts +19 -1
  45. package/dist/cli/tui/transcript-presentation.js +26 -6
  46. package/dist/cli/tui/transcript-viewport.d.ts +18 -0
  47. package/dist/cli/tui/transcript-viewport.js +517 -111
  48. package/dist/cli/tui/transcript-window-model.d.ts +108 -0
  49. package/dist/cli/tui/transcript-window-model.js +772 -0
  50. package/dist/cli/tui/tui-screen-model.d.ts +114 -0
  51. package/dist/cli/tui/tui-screen-model.js +210 -0
  52. package/dist/cli/tui/tui-view-model.d.ts +2 -49
  53. package/dist/cli/tui/tui-view-model.js +1 -68
  54. package/dist/cli-runtime.d.ts +2 -0
  55. package/dist/cli-runtime.js +397 -32
  56. package/dist/compatibility/claude/transcript-codec.js +6 -0
  57. package/dist/core/permission-policy.d.ts +4 -0
  58. package/dist/core/permission-policy.js +21 -0
  59. package/dist/core/runtime.d.ts +1 -0
  60. package/dist/core/runtime.js +5 -1
  61. package/dist/core/team-mailbox.d.ts +54 -0
  62. package/dist/core/team-mailbox.js +212 -0
  63. package/dist/core/team-ownership.d.ts +84 -0
  64. package/dist/core/team-ownership.js +505 -0
  65. package/dist/core/tool-execution-scheduler.js +6 -1
  66. package/dist/core/transcript-event.d.ts +5 -1
  67. package/dist/core/transcript-event.js +12 -0
  68. package/dist/persistence/claude-transcript-store.d.ts +2 -1
  69. package/dist/persistence/claude-transcript-store.js +2 -10
  70. package/dist/persistence/native-team-mailbox.d.ts +68 -0
  71. package/dist/persistence/native-team-mailbox.js +542 -0
  72. package/dist/persistence/native-team-store.d.ts +34 -0
  73. package/dist/persistence/native-team-store.js +257 -0
  74. package/dist/persistence/native-transcript-store.d.ts +69 -0
  75. package/dist/persistence/native-transcript-store.js +321 -0
  76. package/dist/persistence/transcript-file-append.d.ts +2 -0
  77. package/dist/persistence/transcript-file-append.js +10 -0
  78. package/dist/tools/claude-capabilities.d.ts +4 -0
  79. package/dist/tools/claude-capabilities.js +18 -2
  80. package/dist/tools/team-lead-tools.d.ts +19 -0
  81. package/dist/tools/team-lead-tools.js +479 -0
  82. package/dist/tools/team-member-tools.d.ts +21 -0
  83. package/dist/tools/team-member-tools.js +259 -0
  84. package/package.json +1 -1
  85. package/dist/cli/tui/fullscreen-renderer.d.ts +0 -14
  86. package/dist/cli/tui/fullscreen-renderer.js +0 -13
@@ -0,0 +1,156 @@
1
+ import { mkdir, open, readFile, rm } from 'node:fs/promises';
2
+ import { basename, isAbsolute, resolve } from 'node:path';
3
+ import { NativeSessionTranscript, } from './native-session-transcript.js';
4
+ import { NativeTranscriptStore } from '../persistence/native-transcript-store.js';
5
+ const permissionModes = new Set([
6
+ 'acceptEdits',
7
+ 'auto',
8
+ 'bypassPermissions',
9
+ 'default',
10
+ 'dontAsk',
11
+ 'plan',
12
+ ]);
13
+ const requiredKeys = [
14
+ 'agentType',
15
+ 'description',
16
+ 'toolUseId',
17
+ 'spawnDepth',
18
+ 'cwd',
19
+ 'promptId',
20
+ ];
21
+ const optionalKeys = [
22
+ 'name',
23
+ 'permissionMode',
24
+ 'isolation',
25
+ 'parentAgentId',
26
+ 'worktreePath',
27
+ ];
28
+ function nonBlank(value) {
29
+ return (typeof value === 'string' &&
30
+ value.trim().length > 0 &&
31
+ !value.includes('\0'));
32
+ }
33
+ function assertPaths(paths) {
34
+ for (const value of [
35
+ paths.sessionId,
36
+ paths.agentId,
37
+ paths.directory,
38
+ paths.transcriptFile,
39
+ paths.metadataFile,
40
+ ]) {
41
+ if (!nonBlank(value))
42
+ throw new Error('native sidechain paths are invalid');
43
+ }
44
+ if (!isAbsolute(paths.directory) ||
45
+ !isAbsolute(paths.transcriptFile) ||
46
+ !isAbsolute(paths.metadataFile))
47
+ throw new Error('native sidechain paths must be absolute');
48
+ const directory = resolve(paths.directory);
49
+ if (resolve(paths.transcriptFile) !==
50
+ resolve(directory, `agent-${paths.agentId}.jsonl`) ||
51
+ resolve(paths.metadataFile) !==
52
+ resolve(directory, `agent-${paths.agentId}.meta.json`) ||
53
+ basename(paths.transcriptFile) !== `agent-${paths.agentId}.jsonl` ||
54
+ basename(paths.metadataFile) !== `agent-${paths.agentId}.meta.json`)
55
+ throw new Error('native sidechain paths do not match agent identity');
56
+ if (paths.lockFile !== undefined &&
57
+ (!nonBlank(paths.lockFile) || !isAbsolute(paths.lockFile)))
58
+ throw new Error('native sidechain lock path is invalid');
59
+ }
60
+ function validateMetadata(value) {
61
+ if (!value || typeof value !== 'object' || Array.isArray(value))
62
+ throw new Error('native sidechain metadata must be an object');
63
+ const record = value;
64
+ if (Object.keys(record).some((key) => !requiredKeys.includes(key) && !optionalKeys.includes(key)))
65
+ throw new Error('native sidechain metadata contains unknown fields');
66
+ if (requiredKeys.some((key) => !(key in record)))
67
+ throw new Error('native sidechain metadata is invalid');
68
+ if (![record.agentType, record.description, record.toolUseId].every(nonBlank))
69
+ throw new Error('native sidechain metadata is invalid');
70
+ if (!Number.isSafeInteger(record.spawnDepth) ||
71
+ Number(record.spawnDepth) <= 0)
72
+ throw new Error('native sidechain metadata is invalid');
73
+ if (!nonBlank(record.cwd) || !isAbsolute(record.cwd))
74
+ throw new Error('native sidechain metadata cwd is invalid');
75
+ if (!nonBlank(record.promptId))
76
+ throw new Error('native sidechain metadata promptId is invalid');
77
+ if (record.name !== undefined && !nonBlank(record.name))
78
+ throw new Error('native sidechain metadata name is invalid');
79
+ if (record.permissionMode !== undefined &&
80
+ (typeof record.permissionMode !== 'string' ||
81
+ !permissionModes.has(record.permissionMode)))
82
+ throw new Error('native sidechain metadata permissionMode is invalid');
83
+ if (record.isolation !== undefined && record.isolation !== 'worktree')
84
+ throw new Error('native sidechain metadata isolation is invalid');
85
+ if (record.parentAgentId !== undefined &&
86
+ (typeof record.parentAgentId !== 'string' ||
87
+ !/^a[0-9a-f]{16}$/u.test(record.parentAgentId)))
88
+ throw new Error('native sidechain metadata parentAgentId is invalid');
89
+ if (record.worktreePath !== undefined &&
90
+ (!nonBlank(record.worktreePath) || !isAbsolute(record.worktreePath)))
91
+ throw new Error('native sidechain metadata worktreePath is invalid');
92
+ return {
93
+ ...record,
94
+ spawnDepth: Number(record.spawnDepth),
95
+ };
96
+ }
97
+ export class NativeSidechainTranscript {
98
+ paths;
99
+ transcript;
100
+ store;
101
+ constructor(paths) {
102
+ this.paths = paths;
103
+ assertPaths(paths);
104
+ this.store = new NativeTranscriptStore({
105
+ transcriptFile: paths.transcriptFile,
106
+ lockFile: paths.lockFile ?? `${paths.transcriptFile}.lock`,
107
+ });
108
+ this.transcript = new NativeSessionTranscript({
109
+ sessionId: paths.sessionId,
110
+ store: this.store,
111
+ });
112
+ }
113
+ async create(prompt, metadata) {
114
+ if (!nonBlank(prompt))
115
+ throw new Error('native sidechain prompt must not be blank');
116
+ const checked = validateMetadata(metadata);
117
+ await mkdir(this.paths.directory, { recursive: true });
118
+ let created = false;
119
+ try {
120
+ const handle = await open(this.paths.metadataFile, 'wx');
121
+ created = true;
122
+ try {
123
+ await handle.writeFile(`${JSON.stringify(checked)}\n`);
124
+ await handle.sync();
125
+ }
126
+ finally {
127
+ await handle.close();
128
+ }
129
+ await this.transcript.withLease({ kind: 'start' }, async (lease) => {
130
+ await lease.appendMessages({
131
+ messages: [{ role: 'user', content: prompt }],
132
+ });
133
+ });
134
+ }
135
+ catch (error) {
136
+ if (created)
137
+ await rm(this.paths.metadataFile, { force: true });
138
+ throw error;
139
+ }
140
+ }
141
+ withLease(operation) {
142
+ return this.transcript.withLease({ kind: 'resume' }, operation);
143
+ }
144
+ async loadReadOnly() {
145
+ const snapshot = await this.store.loadReadOnly();
146
+ if (snapshot.issue)
147
+ throw new Error(`Invalid native sidechain transcript: ${snapshot.issue.message}`);
148
+ if (snapshot.records.some((record) => record.event.sessionId !== this.paths.sessionId))
149
+ throw new Error('native sidechain transcript sessionId does not match paths');
150
+ return snapshot;
151
+ }
152
+ async metadata() {
153
+ return validateMetadata(JSON.parse(await readFile(this.paths.metadataFile, 'utf8')));
154
+ }
155
+ }
156
+ //# sourceMappingURL=native-sidechain-transcript.js.map
@@ -27,10 +27,14 @@ import { type ClaudeToolRole } from '../tools/claude-capabilities.js';
27
27
  import type { ClaudeInteractiveToolManager } from '../tools/claude-interactive-tools.js';
28
28
  import type { ClaudePermissionMode } from '../permissions/claude-permission-resolver.js';
29
29
  import type { ClaudeMcpRuntime, ClaudeMcpServerStatus, ClaudeMcpToolInspection } from '../mcp/claude-mcp-tools.js';
30
+ import type { TeamLeadOperations } from './team-lead-operations.js';
31
+ type TeamLeadToolRegistryFactory = (base: ToolRegistry, operations: TeamLeadOperations, sessionId: string, enabledTools: readonly string[]) => ToolRegistry;
30
32
  export interface ClaudeSessionServiceOptions {
31
33
  configRoot: string;
32
34
  /** `claude` preserves the legacy shared layout; the CLI selects `native` by default. */
33
35
  dataPlane?: DataPlane;
36
+ /** Experimental canonical native transcript writes. */
37
+ experimentalNativeTranscriptWrites?: boolean;
34
38
  cwd: string;
35
39
  claudeVersion: string;
36
40
  provider?: ModelProvider;
@@ -56,6 +60,7 @@ export interface ClaudeSessionServiceOptions {
56
60
  subagentToolNames?: readonly string[];
57
61
  taskToolNames?: readonly string[];
58
62
  scheduledToolNames?: readonly string[];
63
+ teamToolNames?: readonly string[];
59
64
  /** Runtime gates for Claude capability-driven tool exposure. */
60
65
  toolRole?: ClaudeToolRole;
61
66
  toolCapabilityEnvironment?: Readonly<Record<string, string | undefined>>;
@@ -104,6 +109,10 @@ export interface ClaudeSessionServiceOptions {
104
109
  interactiveTools?: ClaudeInteractiveToolManager;
105
110
  mcp?: ClaudeMcpRuntime;
106
111
  costStateStore?: Pick<ClaudeCostStateStore, 'load' | 'save'>;
112
+ /** Shared internal Team lead operations port. */
113
+ teamLeadOperations?: TeamLeadOperations;
114
+ /** Lazily supplied Team tool wrapper, so disabled runs do not load Team code. */
115
+ teamLeadToolRegistryFactory?: TeamLeadToolRegistryFactory;
107
116
  }
108
117
  export interface SessionRunResult {
109
118
  sessionId: string;
@@ -219,6 +228,7 @@ export declare class ClaudeSessionService {
219
228
  private readonly sessionMemoryControllers;
220
229
  private resolvedSessionMemoryProvider;
221
230
  private readonly hookLifecycle;
231
+ private readonly leadOperations;
222
232
  private readonly fileChangeWatcher;
223
233
  private runtimeCwd;
224
234
  constructor(options: ClaudeSessionServiceOptions);
@@ -345,8 +355,11 @@ export declare class ClaudeSessionService {
345
355
  private rememberDurableMetadata;
346
356
  private assertSessionPersistence;
347
357
  private assertWritable;
358
+ private assertTurnWritable;
348
359
  private sessionStatus;
349
360
  private nativeSessionStatus;
361
+ private nativeTranscriptWritesEnabled;
362
+ private assertNativeTranscriptOptions;
350
363
  private claudeSessionSummary;
351
364
  private provider;
352
365
  private assertNativeWriteTargetIsLegacy;
@@ -365,7 +378,9 @@ export declare class ClaudeSessionService {
365
378
  private sessionMemoryProviderFactory;
366
379
  private toolCapabilities;
367
380
  private capabilityToolNames;
381
+ private teamRegistry;
368
382
  private append;
369
383
  private logicalTailUuid;
370
384
  }
385
+ export {};
371
386
  //# sourceMappingURL=session-service.d.ts.map