@scotthuang/agent-knock-knock 0.3.2 → 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.
Files changed (69) hide show
  1. package/CHANGELOG.md +9 -571
  2. package/README.md +97 -123
  3. package/dist/src/agent-session-provider.d.ts +1 -2
  4. package/dist/src/approval-policy.d.ts +1 -1
  5. package/dist/src/approval-policy.js +1 -1
  6. package/dist/src/approval-policy.js.map +1 -1
  7. package/dist/src/claude-terminal-agent-adapter.d.ts +2 -17
  8. package/dist/src/claude-terminal-agent-adapter.js +4 -489
  9. package/dist/src/claude-terminal-agent-adapter.js.map +1 -1
  10. package/dist/src/cli.js +1489 -3406
  11. package/dist/src/cli.js.map +1 -1
  12. package/dist/src/codex-local-session-provider.d.ts +1 -2
  13. package/dist/src/codex-local-session-provider.js +1 -9
  14. package/dist/src/codex-local-session-provider.js.map +1 -1
  15. package/dist/src/codex-session-provider.d.ts +1 -8
  16. package/dist/src/codex-session-provider.js +0 -56
  17. package/dist/src/codex-session-provider.js.map +1 -1
  18. package/dist/src/codex-terminal-agent-adapter.d.ts +1 -1
  19. package/dist/src/doctor-capabilities.d.ts +5 -13
  20. package/dist/src/doctor-capabilities.js +15 -60
  21. package/dist/src/doctor-capabilities.js.map +1 -1
  22. package/dist/src/executors.d.ts +5 -51
  23. package/dist/src/executors.js +4 -68
  24. package/dist/src/executors.js.map +1 -1
  25. package/dist/src/openclaw-doctor.d.ts +1 -1
  26. package/dist/src/openclaw-doctor.js +1 -1
  27. package/dist/src/openclaw-doctor.js.map +1 -1
  28. package/dist/src/openclaw-plugin-helpers.d.ts +5 -8
  29. package/dist/src/openclaw-plugin-helpers.js +57 -40
  30. package/dist/src/openclaw-plugin-helpers.js.map +1 -1
  31. package/dist/src/openclaw-plugin.js +138 -248
  32. package/dist/src/openclaw-plugin.js.map +1 -1
  33. package/dist/src/protocol.d.ts +1 -5
  34. package/dist/src/protocol.js +1 -1
  35. package/dist/src/protocol.js.map +1 -1
  36. package/dist/src/session-selector.js +1 -1
  37. package/dist/src/session-selector.js.map +1 -1
  38. package/dist/src/terminal-agent-adapter.d.ts +3 -17
  39. package/dist/src/terminal-agent-adapter.js.map +1 -1
  40. package/dist/src/terminal-agent-bridge.d.ts +3 -3
  41. package/dist/src/terminal-agent-bridge.js +0 -75
  42. package/dist/src/terminal-agent-bridge.js.map +1 -1
  43. package/dist/src/transcript.js +2 -3
  44. package/dist/src/transcript.js.map +1 -1
  45. package/docs/quickstart-tmux.md +7 -7
  46. package/openclaw.plugin.json +4 -83
  47. package/package.json +7 -15
  48. package/templates/openclaw-skills/agent-knock-knock/SKILL.md +94 -147
  49. package/dist/src/acpx-output.d.ts +0 -18
  50. package/dist/src/acpx-output.js +0 -223
  51. package/dist/src/acpx-output.js.map +0 -1
  52. package/dist/src/bootstrap.d.ts +0 -8
  53. package/dist/src/bootstrap.js +0 -45
  54. package/dist/src/bootstrap.js.map +0 -1
  55. package/dist/src/claude-hook-installer.d.ts +0 -65
  56. package/dist/src/claude-hook-installer.js +0 -410
  57. package/dist/src/claude-hook-installer.js.map +0 -1
  58. package/dist/src/claude-hook-protocol.d.ts +0 -89
  59. package/dist/src/claude-hook-protocol.js +0 -243
  60. package/dist/src/claude-hook-protocol.js.map +0 -1
  61. package/dist/src/claude-hook-store.d.ts +0 -247
  62. package/dist/src/claude-hook-store.js +0 -1075
  63. package/dist/src/claude-hook-store.js.map +0 -1
  64. package/dist/src/session-takeover-planner.d.ts +0 -37
  65. package/dist/src/session-takeover-planner.js +0 -57
  66. package/dist/src/session-takeover-planner.js.map +0 -1
  67. package/docs/quickstart-managed-acpx.md +0 -43
  68. package/scripts/smoke-acpx.js +0 -139
  69. package/scripts/smoke-tmux.js +0 -140
@@ -1,4 +1,3 @@
1
- import fs from "node:fs";
2
1
  import { createHash } from "node:crypto";
3
2
  import path from "node:path";
4
3
  import { redactString } from "./runtime-log.js";
@@ -73,33 +72,12 @@ const CLAUDE_EXCERPT_LINES = 80;
73
72
  const CLAUDE_PERMISSION_DETAIL_LENGTH = 600;
74
73
  const CLAUDE_AUTO_APPROVAL_COMMAND_LENGTH = 2000;
75
74
  const CLAUDE_NATIVE_VERSION_PATTERN = /^\d+\.\d+\.\d+$/u;
76
- const TRUSTED_CLAUDE_SHELL_PATHS = new Set([
77
- "/bin/bash",
78
- "/bin/dash",
79
- "/bin/sh",
80
- "/bin/zsh",
81
- "/usr/bin/bash",
82
- "/usr/bin/dash",
83
- "/usr/bin/sh",
84
- "/usr/bin/zsh"
85
- ]);
86
- const TRUSTED_CLAUDE_SHELL_TARGETS = new Set([...TRUSTED_CLAUDE_SHELL_PATHS].flatMap((shell) => {
87
- try {
88
- return [fs.realpathSync(shell)];
89
- }
90
- catch {
91
- return [];
92
- }
93
- }));
94
75
  const ANSI_ESCAPE_PATTERN = /\x1B(?:\[[0-?]*[ -/]*[@-~]|\][^\x07]*(?:\x07|\x1B\\))/gu;
95
76
  export function createClaudeTerminalAgentAdapter(options = {}) {
96
77
  const agentRows = options.agentRows ?? [];
97
- const hookStore = options.hookStore;
98
78
  const transcriptCompletionDetector = options.detectDurableCompletion;
99
79
  const transcriptApprovalDetector = options.detectPendingApproval;
100
- const trustedTokenjuiceLaunchers = options.trustedTokenjuiceLaunchers ?? [];
101
- const durableCompletion = hookStore !== undefined ||
102
- transcriptCompletionDetector !== undefined;
80
+ const durableCompletion = transcriptCompletionDetector !== undefined;
103
81
  return {
104
82
  agent: "claude",
105
83
  displayName: "Claude Code",
@@ -117,23 +95,11 @@ export function createClaudeTerminalAgentAdapter(options = {}) {
117
95
  return classifyClaudeProcess(snapshot, agentRows);
118
96
  },
119
97
  inspectScreen(screenOptions) {
120
- return inspectClaudeScreenWithHooks(screenOptions, hookStore, transcriptApprovalDetector, trustedTokenjuiceLaunchers);
98
+ return transcriptApprovalScreenInspection(inspectClaudeScreen(screenOptions), screenOptions, transcriptApprovalDetector);
121
99
  },
122
- ...(hookStore
123
- ? {
124
- async resolveApproval(request) {
125
- return resolveClaudeHookApproval(hookStore, request);
126
- }
127
- }
128
- : {}),
129
100
  ...(durableCompletion
130
101
  ? {
131
102
  async detectDurableCompletion(request) {
132
- // A configured legacy hook store is authoritative. Falling back when it
133
- // reports pending could bypass its background-task and cron evidence.
134
- if (hookStore) {
135
- return detectClaudeHookCompletion(hookStore, request);
136
- }
137
103
  return transcriptCompletionDetector?.(request);
138
104
  }
139
105
  }
@@ -231,34 +197,6 @@ function hasManagedClaudeApprovalIdentity(runtime) {
231
197
  Boolean(nonEmptyString(runtime?.messageId)) &&
232
198
  Boolean(nonEmptyString(runtime?.terminalTarget));
233
199
  }
234
- function inspectClaudeScreenWithHooks(options, hookStore, transcriptApprovalDetector, trustedTokenjuiceLaunchers) {
235
- const screenInspection = inspectClaudeScreen(options);
236
- if (!hookStore) {
237
- return transcriptApprovalScreenInspection(screenInspection, options, transcriptApprovalDetector);
238
- }
239
- const identity = exactClaudeHookIdentity(options.runtime);
240
- if (!identity) {
241
- return screenInspection.approval.blocked
242
- ? unverifiedHookApproval(screenInspection, "Claude hook permission could not be verified without an exact session id or pid")
243
- : screenInspection;
244
- }
245
- let hookInspection;
246
- try {
247
- hookInspection = hookStore.inspectPermission(identity);
248
- }
249
- catch (error) {
250
- return screenInspection.approval.blocked
251
- ? unverifiedHookApproval(screenInspection, `Claude hook permission identity could not be verified: ${errorMessage(error)}`)
252
- : screenInspection;
253
- }
254
- if (hookInspection.blocked) {
255
- return hookPermissionScreenInspection(screenInspection, hookInspection, trustedTokenjuiceLaunchers);
256
- }
257
- if (screenInspection.approval.blocked) {
258
- return unverifiedHookApproval(screenInspection, `Claude terminal permission is visible but no current structured hook request matched: ${hookInspection.reason}`);
259
- }
260
- return screenInspection;
261
- }
262
200
  function transcriptApprovalScreenInspection(screenInspection, options, detector) {
263
201
  const managedPermissionInspection = (options.managedRequest || hasManagedClaudeApprovalIdentity(options.runtime)) &&
264
202
  screenInspection.approval.blocked &&
@@ -364,105 +302,8 @@ function privacySafeManagedClaudePermissionInspection(screenInspection, screen,
364
302
  screenExcerpt: omitClaudePermissionDetails(screen, undefined, maxExcerptLength)
365
303
  };
366
304
  }
367
- function hookPermissionScreenInspection(screenInspection, hookInspection, trustedTokenjuiceLaunchers) {
368
- if (!hookInspection.approvable) {
369
- return {
370
- ...screenInspection,
371
- activity: {
372
- state: "awaiting_approval",
373
- reason: hookInspection.reason
374
- },
375
- approval: {
376
- blocked: true,
377
- approvable: false,
378
- reason: hookInspection.reason,
379
- promptKind: "claude_permission"
380
- }
381
- };
382
- }
383
- const display = claudePermissionDisplay(hookInspection.toolName, hookInspection.toolInput);
384
- const command = hookInspection.command === undefined
385
- ? undefined
386
- : claudePermissionCommandForApproval(hookInspection.command, trustedTokenjuiceLaunchers);
387
- const requestDetail = command && command.command === undefined
388
- ? [
389
- command.display ? `Command: ${command.display}` : undefined,
390
- display.requestDetail
391
- ].filter((value) => Boolean(value))
392
- .join("; ")
393
- .slice(0, CLAUDE_PERMISSION_DETAIL_LENGTH)
394
- : display.requestDetail;
395
- return {
396
- ...screenInspection,
397
- activity: {
398
- state: "awaiting_approval",
399
- reason: hookInspection.reason
400
- },
401
- approval: {
402
- blocked: true,
403
- approvable: true,
404
- promptKind: hookInspection.promptKind,
405
- cwd: hookInspection.cwd,
406
- toolName: display.toolName,
407
- ...(requestDetail ? { requestDetail } : {}),
408
- ...(command?.command === undefined ? {} : { command: command.command }),
409
- action: {
410
- mode: "structured",
411
- keys: [],
412
- label: "Allow once",
413
- requestId: hookInspection.requestId
414
- }
415
- }
416
- };
417
- }
418
- /**
419
- * Tokenjuice's official Claude PreToolUse hook wraps Bash through a login shell before
420
- * PermissionRequest runs. Recover only that exact, source-tagged shape so policy matching
421
- * sees Claude's original command; every other wrapper remains visible and fails closed.
422
- */
423
- export function normalizeClaudePermissionCommand(command, trustedTokenjuiceLaunchers = []) {
424
- const tokens = tokenizeTrustedWrapperCommand(command);
425
- let normalized = command;
426
- const launcher = tokens?.[0];
427
- const canonicalLauncher = launcher && path.isAbsolute(launcher)
428
- ? realpathOrUndefined(launcher)
429
- : undefined;
430
- const trustedLauncher = launcher
431
- ? trustedTokenjuiceLaunchers.find((candidate) => candidate.configuredPath === launcher)
432
- : undefined;
433
- if (tokens &&
434
- canonicalLauncher &&
435
- trustedLauncher?.canonicalPath === canonicalLauncher &&
436
- tokens[1] === "wrap") {
437
- let index = 2;
438
- if (tokens[index] === "--source" && tokens[index + 1] === "claude-code") {
439
- index += 2;
440
- }
441
- else if (tokens[index] === "--source=claude-code") {
442
- index += 1;
443
- }
444
- else {
445
- return command;
446
- }
447
- const shell = tokens[index + 1];
448
- const canonicalShell = shell && path.isAbsolute(shell)
449
- ? realpathOrUndefined(shell)
450
- : undefined;
451
- if (tokens[index] === "--" &&
452
- shell !== undefined &&
453
- TRUSTED_CLAUDE_SHELL_PATHS.has(shell) &&
454
- canonicalShell !== undefined &&
455
- TRUSTED_CLAUDE_SHELL_TARGETS.has(canonicalShell) &&
456
- tokens[index + 2] === "-lc" &&
457
- tokens.length === index + 4 &&
458
- tokens[index + 3]) {
459
- normalized = tokens[index + 3];
460
- }
461
- }
462
- return normalized;
463
- }
464
- export function claudePermissionCommandForApproval(command, trustedTokenjuiceLaunchers = []) {
465
- const normalized = normalizeClaudePermissionCommand(command, trustedTokenjuiceLaunchers);
305
+ export function claudePermissionCommandForApproval(command) {
306
+ const normalized = command;
466
307
  const redacted = redactString(normalized);
467
308
  const display = singleLineClaudePermissionValue(redacted, CLAUDE_PERMISSION_DETAIL_LENGTH - 20);
468
309
  const policySafe = normalized.length <= CLAUDE_AUTO_APPROVAL_COMMAND_LENGTH && redacted === normalized;
@@ -471,39 +312,6 @@ export function claudePermissionCommandForApproval(command, trustedTokenjuiceLau
471
312
  display
472
313
  };
473
314
  }
474
- function claudePermissionDisplay(toolName, toolInput) {
475
- const safeToolName = singleLineClaudePermissionValue(toolName, 120) || "Unknown Claude tool";
476
- if (!toolInput || typeof toolInput !== "object" || Array.isArray(toolInput)) {
477
- return { toolName: safeToolName };
478
- }
479
- const input = toolInput;
480
- const fields = [
481
- ["file_path", "File"],
482
- ["path", "Path"],
483
- ["notebook_path", "Notebook"],
484
- ["url", "URL"],
485
- ["query", "Query"],
486
- ["pattern", "Pattern"],
487
- ["description", "Description"],
488
- ["domain", "Domain"]
489
- ];
490
- const details = [];
491
- for (const [key, label] of fields) {
492
- const value = input[key];
493
- if (typeof value !== "string") {
494
- continue;
495
- }
496
- const safeValue = singleLineClaudePermissionValue(value, 300);
497
- if (safeValue) {
498
- details.push(`${label}: ${safeValue}`);
499
- }
500
- if (details.length === 3) {
501
- break;
502
- }
503
- }
504
- const requestDetail = details.join("; ").slice(0, CLAUDE_PERMISSION_DETAIL_LENGTH);
505
- return requestDetail ? { toolName: safeToolName, requestDetail } : { toolName: safeToolName };
506
- }
507
315
  function singleLineClaudePermissionValue(value, maxLength) {
508
316
  return redactString(value)
509
317
  .replace(/[\u0000-\u001F\u007F]+/gu, " ")
@@ -511,239 +319,6 @@ function singleLineClaudePermissionValue(value, maxLength) {
511
319
  .trim()
512
320
  .slice(0, maxLength);
513
321
  }
514
- function unverifiedHookApproval(screenInspection, reason) {
515
- return {
516
- ...screenInspection,
517
- activity: {
518
- state: "awaiting_approval",
519
- reason
520
- },
521
- approval: {
522
- blocked: true,
523
- approvable: false,
524
- reason,
525
- promptKind: screenInspection.approval.promptKind ?? "claude_permission",
526
- ...(screenInspection.approval.command === undefined
527
- ? {}
528
- : { command: screenInspection.approval.command })
529
- }
530
- };
531
- }
532
- async function resolveClaudeHookApproval(hookStore, request) {
533
- if (request.expectedFingerprint !== request.actualFingerprint) {
534
- return {
535
- resolved: false,
536
- reason: "Claude approval fingerprint changed before the structured decision"
537
- };
538
- }
539
- if (!request.inspection.approval.approvable ||
540
- request.inspection.approval.action.mode !== "structured" ||
541
- !request.inspection.approval.action.requestId) {
542
- return {
543
- resolved: false,
544
- reason: "Claude approval is not a current structured hook request"
545
- };
546
- }
547
- const runtime = request.runtime;
548
- const identity = exactClaudeHookIdentity(runtime);
549
- if (!identity || !runtime?.conversationId || !runtime.messageId) {
550
- return {
551
- resolved: false,
552
- requestId: request.inspection.approval.action.requestId,
553
- reason: "Claude structured approval requires exact session or pid plus conversation and message identity"
554
- };
555
- }
556
- try {
557
- const current = hookStore.inspectPermission(identity);
558
- if (!current.blocked || !current.approvable) {
559
- return {
560
- resolved: false,
561
- requestId: request.inspection.approval.action.requestId,
562
- reason: current.reason
563
- };
564
- }
565
- if (current.requestId !== request.inspection.approval.action.requestId) {
566
- return {
567
- resolved: false,
568
- requestId: current.requestId,
569
- reason: "Claude permission request changed before the structured decision"
570
- };
571
- }
572
- if (current.conversationId !== runtime.conversationId || current.messageId !== runtime.messageId) {
573
- return {
574
- resolved: false,
575
- requestId: current.requestId,
576
- reason: "Claude permission request belongs to a different conversation message"
577
- };
578
- }
579
- if (runtime.sessionId !== undefined && current.sessionId !== runtime.sessionId) {
580
- return {
581
- resolved: false,
582
- requestId: current.requestId,
583
- reason: "Claude permission request belongs to a different session"
584
- };
585
- }
586
- const lease = hookStore.resolveLease(identity);
587
- if (!lease?.authorizationEligible ||
588
- lease.lease.conversationId !== runtime.conversationId ||
589
- lease.lease.messageId !== runtime.messageId ||
590
- (runtime.terminalTarget !== undefined && lease.lease.terminalTarget !== runtime.terminalTarget)) {
591
- return {
592
- resolved: false,
593
- requestId: current.requestId,
594
- reason: "Claude managed lease no longer matches the terminal conversation"
595
- };
596
- }
597
- hookStore.decidePermission({
598
- sessionId: current.sessionId,
599
- requestId: current.requestId,
600
- fingerprint: current.fingerprint,
601
- conversationId: runtime.conversationId,
602
- messageId: runtime.messageId,
603
- decision: request.decision,
604
- ...(request.decision === "deny" && request.interrupt !== undefined
605
- ? { interrupt: request.interrupt }
606
- : {})
607
- });
608
- return {
609
- resolved: true,
610
- requestId: current.requestId,
611
- reason: request.decision === "allow"
612
- ? "Claude one-time permission was allowed through the structured hook"
613
- : "Claude permission was denied through the structured hook"
614
- };
615
- }
616
- catch (error) {
617
- return {
618
- resolved: false,
619
- requestId: request.inspection.approval.action.requestId,
620
- reason: `Claude structured permission could not be resolved: ${errorMessage(error)}`
621
- };
622
- }
623
- }
624
- async function detectClaudeHookCompletion(hookStore, request) {
625
- if (!request.startedAt) {
626
- return undefined;
627
- }
628
- const runtime = completionRuntime(request.context);
629
- if (!runtime.conversationId || !runtime.messageId) {
630
- return undefined;
631
- }
632
- const identity = {
633
- ...(runtime.sessionId ?? request.sessionId
634
- ? { sessionId: runtime.sessionId ?? request.sessionId }
635
- : {}),
636
- ...(runtime.pid === undefined ? {} : { pid: runtime.pid }),
637
- ...(runtime.cwd ?? request.cwd ? { cwd: runtime.cwd ?? request.cwd } : {}),
638
- requireUnique: true
639
- };
640
- if (!identity.sessionId && identity.pid === undefined && !identity.cwd) {
641
- return undefined;
642
- }
643
- let completion;
644
- try {
645
- completion = hookStore.detectCompletion({
646
- ...identity,
647
- startedAt: request.startedAt,
648
- ...(runtime.promptId === undefined ? {} : { promptId: runtime.promptId }),
649
- conversationId: runtime.conversationId,
650
- messageId: runtime.messageId
651
- });
652
- }
653
- catch {
654
- return undefined;
655
- }
656
- if (completion.status === "done") {
657
- return {
658
- source: "durable",
659
- outcome: "success",
660
- text: completion.text,
661
- timestamp: completion.timestamp,
662
- id: completion.eventId,
663
- confidence: "high",
664
- metadata: {
665
- match: "claude_stop_hook",
666
- session_id: completion.sessionId,
667
- prompt_id: completion.promptId,
668
- cwd: completion.cwd
669
- }
670
- };
671
- }
672
- if (completion.status === "failed") {
673
- return {
674
- source: "durable",
675
- outcome: "failure",
676
- text: claudeFailureText(completion),
677
- timestamp: completion.failure.receivedAt,
678
- id: completion.failure.eventId,
679
- confidence: "high",
680
- metadata: {
681
- match: "claude_stop_failure_hook",
682
- session_id: completion.sessionId,
683
- prompt_id: completion.promptId,
684
- error: completion.failure.code,
685
- ...(completion.failure.details === undefined
686
- ? {}
687
- : { error_details: completion.failure.details })
688
- }
689
- };
690
- }
691
- // Pending background work and unknown/incomplete hook payloads are not completion evidence.
692
- return undefined;
693
- }
694
- function exactClaudeHookIdentity(runtime) {
695
- if (!runtime || (runtime.sessionId === undefined && runtime.pid === undefined)) {
696
- return undefined;
697
- }
698
- return {
699
- ...(runtime.sessionId === undefined ? {} : { sessionId: runtime.sessionId }),
700
- ...(runtime.pid === undefined ? {} : { pid: runtime.pid }),
701
- ...(runtime.cwd === undefined ? {} : { cwd: runtime.cwd }),
702
- requireUnique: true
703
- };
704
- }
705
- function completionRuntime(context) {
706
- const direct = recordValue(context);
707
- const nativeTakeover = recordValue(direct?.nativeTakeover);
708
- const conversation = recordValue(direct?.conversation);
709
- return {
710
- sessionId: nonEmptyString(nativeTakeover?.terminal_agent_session_id) ??
711
- nonEmptyString(direct?.sessionId),
712
- pid: positiveInteger(nativeTakeover?.terminal_agent_pid) ?? positiveInteger(direct?.pid),
713
- cwd: nonEmptyString(nativeTakeover?.source_cwd) ?? nonEmptyString(direct?.cwd),
714
- promptId: nonEmptyString(nativeTakeover?.terminal_agent_prompt_id) ??
715
- nonEmptyString(direct?.promptId) ??
716
- nonEmptyString(direct?.prompt_id),
717
- conversationId: nonEmptyString(direct?.conversationId) ??
718
- nonEmptyString(conversation?.conversation_id),
719
- messageId: nonEmptyString(direct?.messageId) ??
720
- nonEmptyString(nativeTakeover?.terminal_bridge_message_id)
721
- };
722
- }
723
- function claudeFailureText(completion) {
724
- const details = completion.failure.details === undefined
725
- ? undefined
726
- : typeof completion.failure.details === "string"
727
- ? completion.failure.details
728
- : JSON.stringify(completion.failure.details);
729
- return [
730
- `Claude Code turn failed (${completion.failure.code}).`,
731
- completion.failure.message,
732
- details === undefined ? undefined : `Details: ${details}`
733
- ].filter((part) => Boolean(part)).join(" ");
734
- }
735
- function recordValue(value) {
736
- return value !== null && typeof value === "object" && !Array.isArray(value)
737
- ? value
738
- : undefined;
739
- }
740
- function positiveInteger(value) {
741
- const parsed = typeof value === "number" ? value : Number(value);
742
- return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : undefined;
743
- }
744
- function errorMessage(error) {
745
- return error instanceof Error ? error.message : String(error);
746
- }
747
322
  export function detectClaudeApprovalPrompt(screen) {
748
323
  const lines = claudeDetectionTail(screen);
749
324
  const markerIndexes = lines
@@ -1030,66 +605,6 @@ function shortOptionValue(args, option) {
1030
605
  }
1031
606
  return undefined;
1032
607
  }
1033
- function realpathOrUndefined(value) {
1034
- try {
1035
- return fs.realpathSync(value);
1036
- }
1037
- catch {
1038
- return undefined;
1039
- }
1040
- }
1041
- function tokenizeTrustedWrapperCommand(command) {
1042
- const tokens = [];
1043
- let token = "";
1044
- let quote;
1045
- let escaped = false;
1046
- let started = false;
1047
- for (const character of command.trim()) {
1048
- if (escaped) {
1049
- token += character;
1050
- escaped = false;
1051
- started = true;
1052
- continue;
1053
- }
1054
- if (character === "\\" && quote !== "'") {
1055
- escaped = true;
1056
- started = true;
1057
- continue;
1058
- }
1059
- if (quote) {
1060
- if (character === quote) {
1061
- quote = undefined;
1062
- }
1063
- else {
1064
- token += character;
1065
- }
1066
- started = true;
1067
- continue;
1068
- }
1069
- if (character === "'" || character === '"') {
1070
- quote = character;
1071
- started = true;
1072
- continue;
1073
- }
1074
- if (/\s/u.test(character)) {
1075
- if (started) {
1076
- tokens.push(token);
1077
- token = "";
1078
- started = false;
1079
- }
1080
- continue;
1081
- }
1082
- token += character;
1083
- started = true;
1084
- }
1085
- if (escaped || quote) {
1086
- return undefined;
1087
- }
1088
- if (started) {
1089
- tokens.push(token);
1090
- }
1091
- return tokens;
1092
- }
1093
608
  function tokenizeCommand(command) {
1094
609
  const tokens = [];
1095
610
  let token = "";