@causyne/agent 1.10.13 → 1.10.18

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 (76) hide show
  1. package/docs/ARCHITECTURE.md +118 -17
  2. package/docs/SECURITY_REVIEW.md +13 -1
  3. package/docs/THIRD_PARTY_NOTICES.md +46 -10
  4. package/package.json +10 -4
  5. package/src/agentLoop.js +123 -21
  6. package/src/agentProfiles.js +135 -0
  7. package/src/agentProfiles.ts +143 -0
  8. package/src/approvalGrants.js +17 -35
  9. package/src/approvalGrants.ts +54 -0
  10. package/src/auditLog.d.ts +3 -0
  11. package/src/browser/browserRuntime.js +88 -0
  12. package/src/browser/browserRuntime.ts +107 -0
  13. package/src/browser/causyneBrowser.js +495 -0
  14. package/src/browser/causyneBrowser.ts +594 -0
  15. package/src/browser/searchProviders.js +156 -0
  16. package/src/browser/searchProviders.ts +156 -0
  17. package/src/browser/snapshotWindow.js +28 -0
  18. package/src/browser/snapshotWindow.ts +40 -0
  19. package/src/browser/urlPolicy.js +89 -0
  20. package/src/browser/urlPolicy.ts +89 -0
  21. package/src/checkpoints.js +19 -6
  22. package/src/cliMode.js +13 -1
  23. package/src/commands.js +37 -8
  24. package/src/config.d.ts +2 -0
  25. package/src/decisionPolicy.js +68 -0
  26. package/src/decisionPolicy.ts +106 -0
  27. package/src/hooks.js +121 -107
  28. package/src/hooks.ts +193 -0
  29. package/src/implementationPlan.js +50 -0
  30. package/src/implementationPlan.ts +59 -0
  31. package/src/mcp/mcpClient.js +520 -132
  32. package/src/mcp/mcpClient.ts +584 -0
  33. package/src/mcp/mcpRegistry.js +399 -185
  34. package/src/mcp/mcpRegistry.ts +451 -0
  35. package/src/planCache.js +473 -450
  36. package/src/planCache.ts +840 -0
  37. package/src/plugins/pluginManager.js +40 -5
  38. package/src/plugins/pluginSkills.js +84 -0
  39. package/src/plugins/pluginSkills.ts +106 -0
  40. package/src/provisioning/capabilityProvisioner.d.ts +10 -0
  41. package/src/provisioning/capabilityProvisioner.js +5 -0
  42. package/src/provisioning/capabilityTools.js +2 -1
  43. package/src/sandbox.js +32 -2
  44. package/src/sessionJournal.js +471 -0
  45. package/src/sessionJournal.ts +496 -0
  46. package/src/sessionStore.js +3 -279
  47. package/src/skillsManager.js +18 -0
  48. package/src/subagentJournal.js +215 -0
  49. package/src/subagentJournal.ts +254 -0
  50. package/src/taskShape.js +179 -198
  51. package/src/taskShape.ts +259 -0
  52. package/src/toolPacks.js +7 -5
  53. package/src/tools/browserAutomator.js +45 -241
  54. package/src/tools/browserAutomator.ts +57 -0
  55. package/src/tools/manageLocalAiDependencies.js +1 -1
  56. package/src/tools/registry.js +4 -3
  57. package/src/tools/requestDecision.js +87 -0
  58. package/src/tools/requestDecision.ts +107 -0
  59. package/src/tools/subagentOrchestrator.js +73 -12
  60. package/src/tools/updatePlan.js +37 -84
  61. package/src/tools/updatePlan.ts +48 -0
  62. package/src/tools/webFetch.js +183 -68
  63. package/src/tools/webFetch.ts +185 -0
  64. package/src/tools/webSearch.js +50 -75
  65. package/src/tools/webSearch.ts +56 -0
  66. package/src/tui/ask.js +41 -1
  67. package/src/tui/chatRenderer.js +28 -0
  68. package/src/tui/dialogs.js +91 -0
  69. package/src/tui/prompt.js +32 -3
  70. package/src/tui/toolDisplay.js +0 -1
  71. package/src/types/contracts.js +8 -0
  72. package/src/types/contracts.ts +263 -0
  73. package/src/utils/paths.d.ts +3 -0
  74. package/src/version.d.ts +1 -0
  75. package/src/mcp/jsonRpc.js +0 -165
  76. package/src/tools/todoWrite.js +0 -75
package/src/tui/ask.js CHANGED
@@ -25,7 +25,7 @@
25
25
 
26
26
  import readline from 'readline';
27
27
  import { ChatPrompt, isInteractive } from './prompt.js';
28
- import { SelectLayer, InputLayer, ConfirmLayer } from './dialogs.js';
28
+ import { SelectLayer, InputLayer, ConfirmLayer, DecisionLayer } from './dialogs.js';
29
29
 
30
30
  /**
31
31
  * Run one layer on a temporary prompt host.
@@ -162,3 +162,43 @@ export async function askConfirm(message) {
162
162
  const raw = await fallbackQuestion(`${message} [y/N]`);
163
163
  return /^y(es)?$/i.test(String(raw).trim());
164
164
  }
165
+
166
+ /**
167
+ * Ask for a durable product or architecture choice.
168
+ *
169
+ * This remains separate from permissions: choosing an implementation direction
170
+ * never grants a tool the right to mutate files or execute a command.
171
+ */
172
+ export async function askDecision(request = {}) {
173
+ const options = Array.isArray(request.options) ? request.options : [];
174
+
175
+ if (canAskInPanel()) {
176
+ const answer = await hostOneLayer((resolve) => new DecisionLayer({
177
+ request,
178
+ onAnswer: resolve
179
+ }));
180
+ if (answer !== undefined) return answer;
181
+ }
182
+
183
+ const custom = { id: '__custom__', label: 'Type your own answer', description: '' };
184
+ const selected = await askSelect({
185
+ title: request.header || 'Decision required',
186
+ items: [...options, custom]
187
+ });
188
+ if (!selected) return null;
189
+ if (selected.id === custom.id) {
190
+ const label = await askText({
191
+ title: request.question || 'Describe the direction you want',
192
+ lines: request.reason ? [request.reason] : [],
193
+ validate: (value) => String(value).trim() ? null : 'An answer is required.'
194
+ });
195
+ if (!label) return null;
196
+ return { requestId: request.id, optionId: null, label: String(label).trim(), custom: true };
197
+ }
198
+ return {
199
+ requestId: request.id,
200
+ optionId: selected.id,
201
+ label: selected.label,
202
+ custom: false
203
+ };
204
+ }
@@ -211,6 +211,7 @@ export class ChatRenderer {
211
211
  this.spinnerIndex = 0;
212
212
  this.currentStatus = '';
213
213
  this.pendingApprovals = new Map();
214
+ this.latestPlan = [];
214
215
  this.status = new StatusLine();
215
216
  this.turnStartedAt = null;
216
217
 
@@ -548,9 +549,34 @@ export class ChatRenderer {
548
549
  onAgentPlan(msg) {
549
550
  if (!Array.isArray(msg.plan) || msg.plan.length === 0) return;
550
551
  const plan = msg.plan.slice();
552
+ this.latestPlan = plan;
553
+ if (this.onPlanChange) this.onPlanChange(plan);
551
554
  this.frame('plan', () => this.renderPlan(plan), { items: plan.length });
552
555
  }
553
556
 
557
+ onDecisionRequest(msg) {
558
+ if (this.dialogWillAsk) return;
559
+ const request = msg.request || {};
560
+ this.frame('approval', () => {
561
+ this.write();
562
+ this.write(`${paint('accent', GLYPHS.arrow)} ${bold(safeDisplay(request.header || 'decision required'))}`);
563
+ for (const row of wrapBlock(safeDisplay(request.question || ''), Math.max(20, this.width() - 4))) this.write(` ${row}`);
564
+ this.write();
565
+ }, { kind: request.kind || 'other' });
566
+ }
567
+
568
+ onDecisionResult(msg) {
569
+ const request = msg.request || {};
570
+ const answer = msg.answer;
571
+ this.frame('approval', () => {
572
+ if (!answer) {
573
+ this.write(` ${paint('muted', 'decision dismissed')} ${safeDisplay(request.header || '')}`);
574
+ return;
575
+ }
576
+ this.write(` ${paint('success', GLYPHS.check)} ${bold(safeDisplay(answer.label || ''))}${answer.custom ? dim(' custom choice') : ''}`);
577
+ }, { kind: request.kind || 'other', answered: Boolean(answer) });
578
+ }
579
+
554
580
  renderPlan(plan) {
555
581
  const width = this.width();
556
582
  this.write();
@@ -940,6 +966,8 @@ export class ChatRenderer {
940
966
  case 'step_error': this.onStepError(msg); return true;
941
967
  case 'checkpoint': this.onCheckpoint(msg); return true;
942
968
  case 'approval_request': this.onApprovalRequest(msg); return true;
969
+ case 'decision_request': this.onDecisionRequest(msg); return true;
970
+ case 'decision_result': this.onDecisionResult(msg); return true;
943
971
  case 'error': this.onError(msg); return true;
944
972
  case 'budget_warning': this.onBudgetWarning(msg); return true;
945
973
  case 'notice': this.onNotice(msg); return true;
@@ -489,6 +489,97 @@ export class ApprovalLayer extends Layer {
489
489
  }
490
490
  }
491
491
 
492
+ /** A structured product or architecture choice, separate from permissions. */
493
+ export class DecisionLayer extends Layer {
494
+ constructor(options = {}) {
495
+ super({ width: options.width || 82, height: options.height || 24, ...options });
496
+ this.request = options.request || {};
497
+ this.onAnswer = options.onAnswer || null;
498
+ this.options = Array.isArray(this.request.options) ? this.request.options.slice(0, 4) : [];
499
+ this.selected = 0;
500
+ this.customIndex = this.options.length;
501
+ this.customMode = false;
502
+ this.editor = new LineEditor();
503
+ this.answered = false;
504
+ this.title = safeDisplay(this.request.header || 'decision required');
505
+ this.footer = `↑↓ choose ${GLYPHS.dot} enter select ${GLYPHS.dot} esc cancel`;
506
+ }
507
+
508
+ preferredHeight() {
509
+ const questionRows = wrap(safeDisplay(this.request.question || ''), Math.max(20, this.width - 6)).length;
510
+ const reasonRows = wrap(safeDisplay(this.request.reason || ''), Math.max(20, this.width - 6)).length;
511
+ return Math.min(this.height, questionRows + reasonRows + (this.options.length * 2) + 7);
512
+ }
513
+
514
+ body(width, height) {
515
+ const rows = [];
516
+ rows.push(...wrap(bold(safeDisplay(this.request.question || 'Choose a direction')), width).slice(0, 4));
517
+ if (this.request.reason) rows.push(...wrap(dim(safeDisplay(this.request.reason)), width).slice(0, 3));
518
+ rows.push('');
519
+
520
+ for (const [index, option] of this.options.entries()) {
521
+ const selected = index === this.selected;
522
+ const marker = selected ? paint('accent', GLYPHS.arrow) : paint('muted', GLYPHS.dot);
523
+ rows.push(`${marker} ${selected ? bold(safeDisplay(option.label || '')) : safeDisplay(option.label || '')}`);
524
+ if (option.description) rows.push(` ${dim(truncate(safeDisplay(option.description), Math.max(1, width - 2), GLYPHS.ellipsis))}`);
525
+ }
526
+
527
+ const customSelected = this.selected === this.customIndex;
528
+ rows.push(`${customSelected ? paint('accent', GLYPHS.arrow) : paint('muted', GLYPHS.dot)} ${customSelected ? bold('Type your own answer') : 'Type your own answer'}`);
529
+ if (this.customMode) {
530
+ const value = this.editor.getText();
531
+ rows.push(`${paint('accent', `${GLYPHS.arrow} `)}${value || dim('Describe the direction you want')}`);
532
+ this.cursor = { x: 2 + visibleWidth(value.slice(0, this.editor.col)), y: rows.length - 1 };
533
+ this.footer = `enter submit ${GLYPHS.dot} esc choices`;
534
+ } else {
535
+ this.cursor = null;
536
+ this.footer = `↑↓ choose ${GLYPHS.dot} enter select ${GLYPHS.dot} esc cancel`;
537
+ }
538
+ return rows.slice(0, height);
539
+ }
540
+
541
+ key(event) {
542
+ if (!event) return null;
543
+ if (this.customMode) {
544
+ if (event.name === 'escape') { this.customMode = false; return 'handled'; }
545
+ if (event.name === 'enter' || event.name === 'return') {
546
+ const label = this.editor.getText().replace(/\s+/g, ' ').trim();
547
+ if (!label) return 'handled';
548
+ this.answer({ requestId: this.request.id, optionId: null, label, custom: true });
549
+ return 'close';
550
+ }
551
+ if (event.name === 'backspace') { this.editor.backspace(); return 'handled'; }
552
+ if (event.name === 'delete') { this.editor.deleteForward(); return 'handled'; }
553
+ if (event.name === 'left') { this.editor.moveLeft(); return 'handled'; }
554
+ if (event.name === 'right') { this.editor.moveRight(); return 'handled'; }
555
+ if (event.name === 'home') { this.editor.moveHome(); return 'handled'; }
556
+ if (event.name === 'end') { this.editor.moveEnd(); return 'handled'; }
557
+ if (event.name === 'paste') { this.editor.insert(event.text); return 'handled'; }
558
+ if (event.name === 'char') { this.editor.insert(event.text); return 'handled'; }
559
+ return 'handled';
560
+ }
561
+
562
+ if (event.name === 'escape') { this.answer(null); return 'close'; }
563
+ const count = this.options.length + 1;
564
+ if (event.name === 'up') { this.selected = (this.selected - 1 + count) % count; return 'handled'; }
565
+ if (event.name === 'down') { this.selected = (this.selected + 1) % count; return 'handled'; }
566
+ if (event.name === 'enter' || event.name === 'return') {
567
+ if (this.selected === this.customIndex) { this.customMode = true; return 'handled'; }
568
+ const option = this.options[this.selected];
569
+ if (!option) return 'handled';
570
+ this.answer({ requestId: this.request.id, optionId: option.id, label: option.label, custom: false });
571
+ return 'close';
572
+ }
573
+ return 'handled';
574
+ }
575
+
576
+ answer(value = null) {
577
+ if (this.answered) return;
578
+ this.answered = true;
579
+ if (this.onAnswer) this.onAnswer(value);
580
+ }
581
+ }
582
+
492
583
  /** A yes/no confirm, for destructive commands that are not tool approvals. */
493
584
  export class ConfirmLayer extends Layer {
494
585
  constructor(options = {}) {
package/src/tui/prompt.js CHANGED
@@ -26,7 +26,7 @@ import { barBlock, GUTTER } from './block.js';
26
26
  import { visibleWidth, truncate, wrapBlock, shortenHome, safeDisplay } from './text.js';
27
27
  import { pickExample, fitHints } from './banner.js';
28
28
  import { panelRows } from './overlay.js';
29
- import { commandPalette, skillPicker, ApprovalLayer, ConfirmLayer, HomeLayer, TextLayer } from './dialogs.js';
29
+ import { commandPalette, skillPicker, ApprovalLayer, DecisionLayer, ConfirmLayer, HomeLayer, TextLayer } from './dialogs.js';
30
30
  import { describeTool } from './toolDisplay.js';
31
31
 
32
32
  const CTRL_C_WINDOW_MS = 2000;
@@ -264,6 +264,7 @@ export class ChatPrompt {
264
264
  this.statusMessage = message;
265
265
  this.scheduleDraw();
266
266
  };
267
+ renderer.onPlanChange = () => this.scheduleDraw();
267
268
  }
268
269
 
269
270
  /**
@@ -321,6 +322,26 @@ export class ChatPrompt {
321
322
  return visibleWidth(full) > width ? truncate(full, width, GLYPHS.ellipsis) : full;
322
323
  }
323
324
 
325
+ /** Persistent checklist shown outside the chat transcript. */
326
+ planRows(width) {
327
+ const plan = this.renderer && Array.isArray(this.renderer.latestPlan) ? this.renderer.latestPlan : [];
328
+ if (plan.length === 0) return [];
329
+ const completed = plan.filter(item => item.status === 'completed').length;
330
+ const rows = [`${bold(paint('accent', 'implementation plan'))} ${dim(`${completed}/${plan.length}`)}`];
331
+ const limit = Math.min(plan.length, 5);
332
+ for (const item of plan.slice(0, limit)) {
333
+ const mark = item.status === 'completed'
334
+ ? paint('success', GLYPHS.check)
335
+ : item.status === 'in_progress'
336
+ ? paint('accent', GLYPHS.arrow)
337
+ : paint('muted', GLYPHS.dot);
338
+ rows.push(` ${mark} ${truncate(safeDisplay(item.text || item.step || ''), Math.max(8, width - 5), GLYPHS.ellipsis)}`);
339
+ }
340
+ if (plan.length > limit) rows.push(` ${dim(`${GLYPHS.ellipsis} ${plan.length - limit} more`)}`);
341
+ rows.push('');
342
+ return rows;
343
+ }
344
+
324
345
  startTick() {
325
346
  if (this.tickTimer) return;
326
347
  this.tickTimer = setInterval(() => {
@@ -456,6 +477,13 @@ export class ChatPrompt {
456
477
  });
457
478
  }
458
479
 
480
+ /** Ask for a durable implementation choice, with a free-form option. */
481
+ decide(request = {}) {
482
+ return new Promise((resolve) => {
483
+ this.openLayer(new DecisionLayer({ request, onAnswer: resolve }));
484
+ });
485
+ }
486
+
459
487
  /** A plain yes/no, for the questions that are not tool approvals. */
460
488
  confirm(message, options = {}) {
461
489
  return new Promise((resolve) => {
@@ -1136,12 +1164,13 @@ export class ChatPrompt {
1136
1164
  const status = this.statusRow(width);
1137
1165
  const gap = status.length > 0 ? new Array(FOOTER_GAP).fill('') : [];
1138
1166
 
1167
+ const planRows = this.planRows(width);
1139
1168
  const all = this.clampRows(
1140
- boxRows.concat(pickerRows, noticeRows, gap, status), width
1169
+ planRows.concat(boxRows, pickerRows, noticeRows, gap, status), width
1141
1170
  );
1142
1171
 
1143
1172
  // Park the cursor where the user is typing, not at the end of the picker.
1144
- this.present(all, caretRow + padTop, layout.cursorCol + inset);
1173
+ this.present(all, planRows.length + caretRow + padTop, layout.cursorCol + inset);
1145
1174
  }
1146
1175
 
1147
1176
  /**
@@ -82,7 +82,6 @@ const TOOL_DISPLAY = new Map([
82
82
  ['code_verify_syntax', (a) => ({ verb: 'verify', detail: pathDetail(firstString(a, ['path', 'file_path'])) })],
83
83
 
84
84
  ['memory_write', (a) => ({ verb: 'remember', detail: firstString(a, ['fact', 'key', 'project']) })],
85
- ['TodoWrite', (a) => ({ verb: 'plan', detail: countDetail(a.todos, 'item') })],
86
85
  ['update_plan', (a) => ({ verb: 'plan', detail: countDetail(a.plan, 'step') })],
87
86
  ['tool_search', (a) => ({ verb: 'discover', detail: firstString(a, ['query', 'description']) })],
88
87
  ['fs_read_skill', (a) => ({ verb: 'skill', detail: firstString(a, ['id', 'skillId', 'domain']) })],
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Shared compile-time contracts for the incremental TypeScript migration.
3
+ *
4
+ * This module deliberately exports types only. Runtime data entering from a
5
+ * model, MCP server, plugin, config file, subprocess, or filesystem still has
6
+ * to be validated before it is treated as one of these shapes.
7
+ */
8
+ export {};
@@ -0,0 +1,263 @@
1
+ /**
2
+ * Shared compile-time contracts for the incremental TypeScript migration.
3
+ *
4
+ * This module deliberately exports types only. Runtime data entering from a
5
+ * model, MCP server, plugin, config file, subprocess, or filesystem still has
6
+ * to be validated before it is treated as one of these shapes.
7
+ */
8
+
9
+ export type JsonPrimitive = string | number | boolean | null;
10
+ export type JsonValue = JsonPrimitive | JsonValue[] | { [key: string]: JsonValue };
11
+ export type JsonObject = { [key: string]: JsonValue };
12
+
13
+ export type MessageRole = 'system' | 'user' | 'assistant' | 'tool';
14
+
15
+ export interface TextContentBlock {
16
+ type: 'text';
17
+ text: string;
18
+ }
19
+
20
+ export interface ImageContentBlock {
21
+ type: 'image_url';
22
+ image_url: {
23
+ url: string;
24
+ detail?: 'auto' | 'low' | 'high';
25
+ };
26
+ }
27
+
28
+ export interface AudioContentBlock {
29
+ type: 'input_audio';
30
+ input_audio: {
31
+ data: string;
32
+ format: string;
33
+ };
34
+ }
35
+
36
+ export type MessageContent = string | Array<TextContentBlock | ImageContentBlock | AudioContentBlock | JsonObject>;
37
+
38
+ export interface AgentMessage {
39
+ role: MessageRole;
40
+ content: MessageContent;
41
+ name?: string;
42
+ tool_call_id?: string;
43
+ cacheAnchor?: string;
44
+ spillPath?: string;
45
+ }
46
+
47
+ export interface TokenUsage {
48
+ promptTokens: number;
49
+ completionTokens: number;
50
+ totalTokens?: number;
51
+ }
52
+
53
+ export interface ProviderResponse {
54
+ content: string;
55
+ usage: TokenUsage;
56
+ reasoning?: string;
57
+ toolCalls?: ToolCall[];
58
+ }
59
+
60
+ export interface ProviderChatOptions {
61
+ temperature?: number;
62
+ maxTokens?: number;
63
+ jsonMode?: boolean;
64
+ tools?: ToolSchema[];
65
+ signal?: AbortSignal;
66
+ }
67
+
68
+ export interface JsonSchema {
69
+ type?: string | string[];
70
+ description?: string;
71
+ properties?: Record<string, JsonSchema>;
72
+ required?: string[];
73
+ items?: JsonSchema;
74
+ enum?: JsonPrimitive[];
75
+ additionalProperties?: boolean | JsonSchema;
76
+ }
77
+
78
+ export interface ToolSchema {
79
+ name: string;
80
+ description: string;
81
+ parameters: JsonSchema;
82
+ }
83
+
84
+ export interface ToolCall {
85
+ id?: string;
86
+ name: string;
87
+ arguments: JsonObject;
88
+ }
89
+
90
+ export interface ToolExecutionContext {
91
+ workspace: string;
92
+ signal?: AbortSignal;
93
+ taskId?: string;
94
+ sessionId?: string;
95
+ }
96
+
97
+ export interface ToolSuccess<T extends JsonValue = JsonValue> {
98
+ success: true;
99
+ result: T;
100
+ metadata?: JsonObject;
101
+ }
102
+
103
+ export interface ToolFailure {
104
+ success: false;
105
+ error: string;
106
+ code?: string;
107
+ metadata?: JsonObject;
108
+ }
109
+
110
+ export type ToolResult<T extends JsonValue = JsonValue> = ToolSuccess<T> | ToolFailure;
111
+
112
+ export interface ToolModule<TArguments extends JsonObject = JsonObject, TResult extends JsonValue = JsonValue> {
113
+ schema: ToolSchema;
114
+ execute(arguments_: TArguments, context?: ToolExecutionContext): Promise<ToolResult<TResult>> | ToolResult<TResult>;
115
+ }
116
+
117
+ export type RiskLevel = 'safe' | 'moderate' | 'dangerous' | 'extreme' | 'forbidden';
118
+
119
+ export interface SandboxDecision {
120
+ allowed: boolean;
121
+ risk: RiskLevel;
122
+ reason?: string;
123
+ }
124
+
125
+ export type ApprovalChoice = 'deny' | 'allow_once' | 'allow_always';
126
+
127
+ export interface ApprovalDecision {
128
+ choice: ApprovalChoice;
129
+ toolName: string;
130
+ reason?: string;
131
+ }
132
+
133
+ export type HookEvent = 'PreToolUse' | 'PostToolUse';
134
+
135
+ export interface HookRule {
136
+ event: HookEvent;
137
+ command: string[];
138
+ name?: string;
139
+ tool?: string;
140
+ tools?: string[];
141
+ timeoutMs?: number;
142
+ enabled?: boolean;
143
+ }
144
+
145
+ export interface HookDecision {
146
+ denied: boolean;
147
+ messages: string[];
148
+ reason?: string;
149
+ }
150
+
151
+ export type PlanFailureClass =
152
+ | 'not_found'
153
+ | 'permission'
154
+ | 'timeout'
155
+ | 'network'
156
+ | 'rate_limited'
157
+ | 'invalid_args'
158
+ | 'syntax'
159
+ | 'exit_nonzero'
160
+ | 'failed';
161
+
162
+ export interface PlanStep {
163
+ tool: string;
164
+ note: string;
165
+ ok: boolean;
166
+ why?: PlanFailureClass;
167
+ }
168
+
169
+ export interface PlanTemplate {
170
+ id: string;
171
+ archetype: string;
172
+ keywords: string[];
173
+ steps: PlanStep[];
174
+ uses: number;
175
+ wins: number;
176
+ createdAt: number;
177
+ updatedAt: number;
178
+ }
179
+
180
+ export interface PlanMatch {
181
+ template: PlanTemplate;
182
+ similarity: number;
183
+ matchType: 'exact' | 'fuzzy';
184
+ telemetry: {
185
+ keywordCount: number;
186
+ lookupMs: number;
187
+ };
188
+ }
189
+
190
+ export type PluginCapability = 'workspace:read' | 'workspace:write' | 'network' | 'subprocess';
191
+
192
+ export interface PluginToolManifest {
193
+ name: string;
194
+ description: string;
195
+ parameters: JsonSchema;
196
+ entry: string;
197
+ export?: string;
198
+ capabilities?: PluginCapability[];
199
+ timeoutMs?: number;
200
+ }
201
+
202
+ export interface PluginSkillManifest {
203
+ id: string;
204
+ name?: string;
205
+ description: string;
206
+ file: string;
207
+ }
208
+
209
+ export interface PluginManifest {
210
+ schemaVersion: 1;
211
+ name: string;
212
+ version: string;
213
+ description: string;
214
+ capabilities?: PluginCapability[];
215
+ tools?: PluginToolManifest[];
216
+ skills?: PluginSkillManifest[];
217
+ }
218
+
219
+ export interface AgentProfileManifest {
220
+ schemaVersion: 1;
221
+ name: string;
222
+ description: string;
223
+ instructions: string;
224
+ toolScope: string[];
225
+ maxSteps?: number;
226
+ maxTokens?: number;
227
+ }
228
+
229
+ export interface TaskPhase {
230
+ name: string;
231
+ tools: string[];
232
+ note: string;
233
+ }
234
+
235
+ export interface TaskPackScore {
236
+ name: string;
237
+ score: number;
238
+ }
239
+
240
+ export type TaskConfidence = 'low' | 'medium' | 'high';
241
+
242
+ export interface WorkspaceContext {
243
+ framework?: string;
244
+ projectType?: string;
245
+ designSystem?: string;
246
+ keyFiles?: string[];
247
+ }
248
+
249
+ export interface TaskShape {
250
+ archetype: string;
251
+ archetypeLabel: string;
252
+ packs: TaskPackScore[];
253
+ phases: TaskPhase[];
254
+ confidence: TaskConfidence;
255
+ }
256
+
257
+ export type AgentEvent =
258
+ | { type: 'model.started'; provider: string; model: string }
259
+ | { type: 'model.delta'; text: string }
260
+ | { type: 'tool.requested'; call: ToolCall }
261
+ | { type: 'tool.completed'; callId?: string; result: ToolResult }
262
+ | { type: 'approval.required'; toolName: string; risk: RiskLevel; reason?: string }
263
+ | { type: 'session.notice'; message: string };
@@ -0,0 +1,3 @@
1
+ /** Runtime declarations for the retained JavaScript path boundary. */
2
+ export function resolveUserPath(input: string): string;
3
+ export function causyneHome(): string;
@@ -0,0 +1 @@
1
+ export function getPackageVersion(): string;