@kruntime/komputer 0.1.2 → 0.1.4

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.
@@ -57,7 +57,7 @@ export async function sealUnfinishedToolEvents(runtime) {
57
57
  cursor: row.cursor,
58
58
  });
59
59
  }
60
- if (event.type === 'tool' && (event.status === 'completed' || event.status === 'failed' || event.status === 'denied' || event.status === 'sealed') && typeof event.opId === 'string') {
60
+ if (event.type === 'tool' && (event.status === 'waiting_approval' || event.status === 'completed' || event.status === 'failed' || event.status === 'denied' || event.status === 'sealed') && typeof event.opId === 'string') {
61
61
  results.add(event.opId);
62
62
  }
63
63
  }
@@ -1 +1 @@
1
- {"version":3,"file":"recovery.js","sourceRoot":"","sources":["../../../../../packages/komputer/src/agent/recovery.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"recovery.js","sourceRoot":"","sources":["../../../../../packages/komputer/src/agent/recovery.ts"],"names":[],"mappings":"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"}
@@ -38,6 +38,7 @@ export interface ExecOptions {
38
38
  type ExecShellOptions = ExecOptions & {
39
39
  forceRemote?: boolean;
40
40
  execToolUseId?: string;
41
+ skipCommandAuthority?: boolean;
41
42
  };
42
43
  interface TurnEndPayload {
43
44
  turnId: string;
@@ -152,6 +153,7 @@ export declare class AgentSession {
152
153
  hook(type: string, handler: HookHandler): () => void;
153
154
  hasHooks(type: string): boolean;
154
155
  runHook(type: string, current: Record<string, unknown>): Promise<HookRunResult>;
156
+ private requestAuthorityApproval;
155
157
  hookContext(type: string, current: Record<string, unknown>): HookContext<Record<string, unknown>>;
156
158
  signal(name: string, data?: unknown, options?: {
157
159
  level?: string;
@@ -162,6 +164,7 @@ export declare class AgentSession {
162
164
  }): Promise<Record<string, unknown>>;
163
165
  consumeApproval(approval: ApprovalRecord): Promise<void>;
164
166
  resumeApproval(approval: ApprovalRecord): Promise<unknown>;
167
+ private rejectPausedApprovalTool;
165
168
  resumeFsApproval(current: Record<string, unknown>): Promise<Record<string, unknown>>;
166
169
  close(): Promise<void>;
167
170
  detach(): Promise<void>;
@@ -202,6 +205,7 @@ export declare class AgentSession {
202
205
  recordInput(record: Record<string, unknown>): Promise<void>;
203
206
  private nextQueuedInputId;
204
207
  stats(): AgentSessionStats;
208
+ private isReadonlyCommandName;
205
209
  exec(command: string, options?: ExecOptions): Promise<Record<string, unknown>>;
206
210
  execInternal(command: string, options?: ExecShellOptions): Promise<Record<string, unknown>>;
207
211
  execCommand(command: string | {
@@ -11,13 +11,14 @@ import { id, normalizeBy, now, sleep } from "./utils.js";
11
11
  import { isGovernableShellScript, isSimpleShellCommand, parseShellCommandSegments, rewriteKPathsForRemote } from "./vbash.js";
12
12
  import { decideCommand, decideFs, decideModel, decideNetwork, decideTool, normalizeMode } from "./authority.js";
13
13
  import { K_BUILTINS } from "./shell/builtins/registry.js";
14
- import { builtinErrorText, runBuiltin } from "./shell/builtins/run.js";
14
+ import { builtinCommandSpec, builtinErrorText, runBuiltin } from "./shell/builtins/run.js";
15
15
  import { globMatcher } from "./shell/builtins/path.js";
16
16
  import { commandHelpText, commandResultToShellResult, isShellAssignmentToken, isShellIdentifier, parseShellRedirects, quoteShellWord, recordStringMap, shellArgsToInput, shellExitCode, shellWordToken } from "./shell/runtime.js";
17
17
  import { expandBraceFields, ShellExpander } from "./shell/expansion.js";
18
18
  import { parseShellControlProgram } from "./shell/control.js";
19
19
  import { parseShellFunctionProgram } from "./shell/functions.js";
20
20
  import { hardenShellSandboxRequest, validateShellSandboxRequest } from "./sandbox.js";
21
+ import { isReadonlyRemoteCommand } from "./remote.js";
21
22
  import { SessionMessages } from "./agent/messages.js";
22
23
  import { SessionApprovals, normalizeApprovalDecision } from "./agent/approvals.js";
23
24
  import { sealInterruptedTurns, sealUnfinishedToolEvents, sealUnfinishedTools } from "./agent/recovery.js";
@@ -394,8 +395,20 @@ export class AgentSession {
394
395
  const op = stringField(current, 'op');
395
396
  const path = stringField(current, 'path');
396
397
  const decision = decideFs({ mode: this.modeState, op, path });
397
- if (!decision.ok)
398
- throw new Error(decision.reason);
398
+ if (!decision.ok) {
399
+ if (this.modeState.name === 'plan') {
400
+ const approval = await this.requestAuthorityApproval('fs.before', current, {
401
+ message: `Plan mode requires approval before ${op} ${path}`,
402
+ risk: 'medium',
403
+ preview: { op, path },
404
+ });
405
+ if (approval.status === 'waiting_approval')
406
+ throw new Error(`waiting approval: ${approval.approval.id}`);
407
+ }
408
+ else {
409
+ throw new Error(decision.reason);
410
+ }
411
+ }
399
412
  return current;
400
413
  }
401
414
  async trace(type, data = {}) {
@@ -518,6 +531,20 @@ export class AgentSession {
518
531
  }
519
532
  return { rejected: false, current: value };
520
533
  }
534
+ async requestAuthorityApproval(type, current, request) {
535
+ const remembered = await this.approvalLog.forAction(type, current);
536
+ if (remembered?.status === 'allowed') {
537
+ await this.consumeApproval(remembered);
538
+ return { status: 'allowed' };
539
+ }
540
+ if (remembered?.status === 'pending') {
541
+ await this.emitApprovalRequest(remembered);
542
+ return { status: 'waiting_approval', approval: remembered };
543
+ }
544
+ const approval = await this.approvalLog.create(type, current, request);
545
+ await this.emitApprovalRequest(approval);
546
+ return { status: 'waiting_approval', approval };
547
+ }
521
548
  hookContext(type, current) {
522
549
  return {
523
550
  type,
@@ -537,10 +564,12 @@ export class AgentSession {
537
564
  }
538
565
  async emitApprovalRequest(approval) {
539
566
  const request = approval.request || {};
567
+ const opId = stringField(approval.current || {}, 'execToolUseId');
540
568
  await this.emit({
541
569
  type: 'approval',
542
570
  status: 'requested',
543
571
  approvalId: approval.id,
572
+ opId: opId || undefined,
544
573
  hook: approval.hook,
545
574
  message: typeof request.message === 'string' ? request.message : 'Approval required',
546
575
  risk: request.risk === 'low' || request.risk === 'medium' || request.risk === 'high' ? request.risk : undefined,
@@ -569,10 +598,13 @@ export class AgentSession {
569
598
  approvalId,
570
599
  hook: approval.hook,
571
600
  decision: status === 'allowed' ? 'approved' : 'rejected',
601
+ opId: stringField(approval.current || {}, 'execToolUseId') || undefined,
572
602
  approval,
573
603
  });
574
- if (status === 'rejected')
604
+ if (status === 'rejected') {
605
+ await this.rejectPausedApprovalTool(approval, row);
575
606
  return row;
607
+ }
576
608
  const result = await this.resumeApproval({ ...approval, status });
577
609
  const done = { ...row, result };
578
610
  await this.approvalLog.resumed(approvalId, result);
@@ -594,11 +626,15 @@ export class AgentSession {
594
626
  return this.send(current.content, recordField(current, 'options') || {});
595
627
  }
596
628
  if (hook === 'shell.before' || hook === 'cmd.before') {
597
- const result = await this.execInternal(stringField(current, 'shellScript') || stringField(current, 'script'), {
629
+ const execToolUseId = stringField(current, 'execToolUseId');
630
+ const resumeShell = () => this.execInternal(stringField(current, 'shellScript') || stringField(current, 'script'), {
598
631
  by: stringField(current, 'by') || `approval:${approval.id}`,
599
632
  foreground: typeof current.foreground === 'boolean' ? current.foreground : undefined,
633
+ execToolUseId,
600
634
  });
601
- const execToolUseId = stringField(current, 'execToolUseId');
635
+ const result = this.modeState.name === 'plan'
636
+ ? await this.withTemporaryMode('normal', resumeShell)
637
+ : await resumeShell();
602
638
  if (execToolUseId) {
603
639
  const bounded = this.boundShellResult(result);
604
640
  await this.appendExecToolExchange(execToolUseMessageFromApproval(current, execToolUseId), execToolUseId, bounded, stringField(current, 'by') || `approval:${approval.id}`);
@@ -614,9 +650,12 @@ export class AgentSession {
614
650
  return result;
615
651
  }
616
652
  if (hook === 'tool.before') {
617
- return this.command(stringField(current, 'command'), recordField(current, 'input') || {}, {
653
+ const resumeTool = () => this.command(stringField(current, 'command'), recordField(current, 'input') || {}, {
618
654
  by: stringField(current, 'by') || `approval:${approval.id}`,
619
655
  });
656
+ return this.modeState.name === 'plan'
657
+ ? this.withTemporaryMode('normal', resumeTool)
658
+ : resumeTool();
620
659
  }
621
660
  if (hook === 'tool.after') {
622
661
  await this.trace('tool.ended', { name: current.command, resultType: resultType(current.result), approvedBy: approval.id });
@@ -655,6 +694,30 @@ export class AgentSession {
655
694
  }
656
695
  throw new Error(`approval hook is not resumable: ${hook}`);
657
696
  }
697
+ async rejectPausedApprovalTool(approval, row) {
698
+ const current = approval.current || {};
699
+ const execToolUseId = stringField(current, 'execToolUseId');
700
+ if (!execToolUseId)
701
+ return;
702
+ const by = stringField(row, 'by') || 'approval';
703
+ const result = this.boundShellResult({
704
+ status: 'denied',
705
+ code: 126,
706
+ stdout: '',
707
+ stderr: `Approval rejected: ${approval.id}`,
708
+ approvalId: approval.id,
709
+ });
710
+ await this.appendExecToolExchange(execToolUseMessageFromApproval(current, execToolUseId), execToolUseId, result, by);
711
+ await this.trace('tool.denied', { toolUseId: execToolUseId, approvalId: approval.id, hook: approval.hook });
712
+ await this.emit({
713
+ type: 'tool',
714
+ status: 'denied',
715
+ tool: 'shell',
716
+ result,
717
+ opId: execToolUseId,
718
+ approvalId: approval.id,
719
+ });
720
+ }
658
721
  async resumeFsApproval(current) {
659
722
  const op = stringField(current, 'op');
660
723
  const path = stringField(current, 'path');
@@ -1054,6 +1117,15 @@ export class AgentSession {
1054
1117
  shellFunctions: Object.keys(this.shellFunctions).length,
1055
1118
  };
1056
1119
  }
1120
+ isReadonlyCommandName(cmd, args = [], options = {}) {
1121
+ if (!options.forceRemote && K_BUILTINS.has(cmd))
1122
+ return builtinCommandSpec(cmd)?.readonly === true;
1123
+ const command = !options.forceRemote ? this.runtime.commands.get(cmd) : undefined;
1124
+ if (command)
1125
+ return command.readonly === true;
1126
+ const remote = options.remote ? this.runtime.getRemote(options.remote) : this.runtime.defaultRemote();
1127
+ return isReadonlyRemoteCommand(remote, cmd, args);
1128
+ }
1057
1129
  async exec(command, options = {}) {
1058
1130
  const toolUseId = id('tool');
1059
1131
  const by = normalizeBy(options.by);
@@ -1233,10 +1305,41 @@ export class AgentSession {
1233
1305
  wordTokens: preservesTokens ? concrete.wordTokens : words.map(shellWordToken),
1234
1306
  background: concrete.background,
1235
1307
  };
1236
- const authority = decideCommand({ mode: this.modeState, cmd: currentCmd });
1237
- if (!authority.ok) {
1238
- await this.trace('process.rejected', { cmd: currentCmd, args: currentArgs, reason: authority.reason, mode: this.mode });
1239
- return { status: 'rejected', code: 126, stdout: '', stderr: authority.reason };
1308
+ if (!options.skipCommandAuthority) {
1309
+ const authority = decideCommand({
1310
+ mode: this.modeState,
1311
+ cmd: currentCmd,
1312
+ readonly: this.isReadonlyCommandName(currentCmd, currentArgs, { forceRemote: options.forceRemote, remote: options.remote }),
1313
+ });
1314
+ if (!authority.ok) {
1315
+ if (this.modeState.name === 'plan') {
1316
+ const current = {
1317
+ ...beforeCmd.current,
1318
+ cmd: currentCmd,
1319
+ args: currentArgs,
1320
+ script: currentScript,
1321
+ shellScript: script,
1322
+ cwd: this.hookCwd(),
1323
+ by: normalizeBy(options.by),
1324
+ foreground: foreground && !concrete.background,
1325
+ background: !foreground || concrete.background,
1326
+ execToolUseId: options.execToolUseId,
1327
+ };
1328
+ const approval = await this.requestAuthorityApproval('cmd.before', current, {
1329
+ message: `Plan mode requires approval before command ${currentCmd}`,
1330
+ risk: 'medium',
1331
+ preview: { cmd: currentCmd, args: currentArgs, cwd: this.hookCwd() },
1332
+ });
1333
+ if (approval.status === 'waiting_approval') {
1334
+ await this.trace('process.waiting_approval', { cmd: currentCmd, args: currentArgs, reason: authority.reason, approvalId: approval.approval.id, mode: this.mode });
1335
+ return { status: 'waiting_approval', code: undefined, stdout: '', stderr: '', approval: approval.approval, reason: authority.reason };
1336
+ }
1337
+ }
1338
+ else {
1339
+ await this.trace('process.rejected', { cmd: currentCmd, args: currentArgs, reason: authority.reason, mode: this.mode });
1340
+ return { status: 'rejected', code: 126, stdout: '', stderr: authority.reason };
1341
+ }
1342
+ }
1240
1343
  }
1241
1344
  }
1242
1345
  const cmd = parsed[0]?.cmd || 'bash';
@@ -2659,10 +2762,28 @@ export class AgentSession {
2659
2762
  throw new Error(before.reason || `tool.before rejected ${toolName}`);
2660
2763
  }
2661
2764
  const currentInput = recordField(before.current, 'input') || input;
2662
- const authority = decideTool({ mode: this.modeState, tool: toolName, command: name });
2765
+ const authority = decideTool({
2766
+ mode: this.modeState,
2767
+ tool: toolName,
2768
+ command: name,
2769
+ readonly: command.readonly === true,
2770
+ });
2663
2771
  if (!authority.ok) {
2664
- await this.trace('tool.rejected', { name, input: currentInput, by, reason: authority.reason, mode: this.mode });
2665
- throw new Error(authority.reason);
2772
+ if (this.modeState.name === 'plan') {
2773
+ const approval = await this.requestAuthorityApproval('tool.before', { tool: toolName, command: name, input: currentInput, by }, {
2774
+ message: `Plan mode requires approval before tool ${toolName}`,
2775
+ risk: 'medium',
2776
+ preview: { tool: toolName, input: currentInput },
2777
+ });
2778
+ if (approval.status === 'waiting_approval') {
2779
+ await this.trace('tool.waiting_approval', { name, input: currentInput, by, reason: authority.reason, approvalId: approval.approval.id, mode: this.mode });
2780
+ return { status: 'waiting_approval', approval: approval.approval, reason: authority.reason };
2781
+ }
2782
+ }
2783
+ else {
2784
+ await this.trace('tool.rejected', { name, input: currentInput, by, reason: authority.reason, mode: this.mode });
2785
+ throw new Error(authority.reason);
2786
+ }
2666
2787
  }
2667
2788
  const toolUseId = id('tool');
2668
2789
  const parsed = parseCommandInput(name, command, currentInput);
@@ -2685,7 +2806,7 @@ export class AgentSession {
2685
2806
  : typeof command.mode === 'string'
2686
2807
  ? command.mode
2687
2808
  : undefined;
2688
- const runShell = () => this.withTemporaryShellState({ env: positionalShellEnv(name, argv) }, () => this.execInternal(String(command.script ?? ''), { by: options.by || `command:${name}` }));
2809
+ const runShell = () => this.withTemporaryShellState({ env: positionalShellEnv(name, argv) }, () => this.execInternal(String(command.script ?? ''), { by: options.by || `command:${name}`, skipCommandAuthority: command.readonly === true }));
2689
2810
  result = invocationMode ? await this.withTemporaryMode(invocationMode, runShell) : await runShell();
2690
2811
  }
2691
2812
  else if (command.kind === 'markdown') {
@@ -3037,10 +3158,10 @@ function parseStructuredCommandArgs(name, specs, input, argv) {
3037
3158
  const parsed = {};
3038
3159
  const options = commandOptionSpecs(specs);
3039
3160
  for (const [key, spec] of Object.entries(specs)) {
3040
- if ('default' in spec)
3041
- parsed[key] = spec.default;
3042
- else if ('defaultValue' in spec)
3161
+ if ('defaultValue' in spec)
3043
3162
  parsed[key] = spec.defaultValue;
3163
+ else if ('default' in spec && typeof spec.default !== 'function')
3164
+ parsed[key] = spec.default;
3044
3165
  }
3045
3166
  for (const [key, value] of Object.entries(input)) {
3046
3167
  if (key !== 'argv' && key !== 'stdin' && key !== 'env' && specs[key])