@pellux/goodvibes-agent 1.1.7 → 1.2.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 (255) hide show
  1. package/CHANGELOG.md +170 -0
  2. package/README.md +46 -30
  3. package/dist/package/{ast-grep-napi.linux-x64-gnu-mkk8xwww.node → ast-grep-napi.linux-x64-gnu-swtppvy9.node} +0 -0
  4. package/dist/package/{ast-grep-napi.linux-x64-musl-ryqtgdv6.node → ast-grep-napi.linux-x64-musl-ttfcdtap.node} +0 -0
  5. package/dist/package/main.js +132577 -91483
  6. package/docs/README.md +14 -7
  7. package/docs/channels-remote-and-api.md +8 -5
  8. package/docs/connected-host.md +14 -12
  9. package/docs/getting-started.md +56 -30
  10. package/docs/knowledge-artifacts-and-multimodal.md +7 -5
  11. package/docs/project-planning.md +2 -2
  12. package/docs/providers-and-routing.md +11 -3
  13. package/docs/tools-and-commands.md +114 -45
  14. package/docs/voice-and-live-tts.md +3 -1
  15. package/package.json +3 -2
  16. package/release/release-notes.md +130 -5
  17. package/release/release-readiness.json +120 -90
  18. package/src/agent/assistant-cockpit.ts +247 -0
  19. package/src/agent/autonomy-schedule-format.ts +96 -0
  20. package/src/agent/autonomy-schedule.ts +514 -0
  21. package/src/agent/channel-delivery-receipts.ts +292 -0
  22. package/src/agent/competitive-feature-inventory.ts +296 -0
  23. package/src/agent/document-registry-types.ts +106 -0
  24. package/src/agent/document-registry.ts +734 -0
  25. package/src/agent/harness-control.ts +2 -2
  26. package/src/agent/memory-prompt.ts +2 -2
  27. package/src/agent/operator-actions.ts +50 -6
  28. package/src/agent/persona-registry.ts +8 -0
  29. package/src/agent/project-context-files.ts +273 -0
  30. package/src/agent/prompt-context-receipts.ts +502 -0
  31. package/src/agent/reminder-schedule-format.ts +16 -2
  32. package/src/agent/research-run-registry.ts +582 -0
  33. package/src/agent/research-source-registry.ts +441 -0
  34. package/src/agent/routine-registry.ts +19 -3
  35. package/src/agent/routine-schedule-format.ts +27 -2
  36. package/src/agent/runtime-profile-starters.ts +7 -0
  37. package/src/agent/runtime-profile.ts +106 -4
  38. package/src/agent/schedule-edit-format.ts +129 -0
  39. package/src/agent/schedule-edit.ts +496 -0
  40. package/src/agent/schedule-next-routes.ts +42 -0
  41. package/src/agent/setup-wizard-checkpoint.ts +140 -0
  42. package/src/agent/setup-wizard.ts +447 -0
  43. package/src/agent/skill-registry-types.ts +102 -0
  44. package/src/agent/skill-registry.ts +81 -107
  45. package/src/agent/vibe-confirmation-routes.ts +62 -0
  46. package/src/agent/vibe-file.ts +285 -0
  47. package/src/cli/agent-knowledge-command.ts +45 -2
  48. package/src/cli/help.ts +3 -0
  49. package/src/cli/profiles-command.ts +25 -11
  50. package/src/config/agent-settings-policy.ts +1 -18
  51. package/src/input/agent-workspace-activation.ts +53 -0
  52. package/src/input/agent-workspace-artifact-browser-editor.ts +494 -0
  53. package/src/input/agent-workspace-artifact-metadata.ts +17 -0
  54. package/src/input/agent-workspace-basic-command-editors.ts +5 -1
  55. package/src/input/agent-workspace-categories.ts +153 -155
  56. package/src/input/agent-workspace-channel-triage.ts +481 -0
  57. package/src/input/agent-workspace-channels.ts +263 -0
  58. package/src/input/agent-workspace-command-editor.ts +152 -0
  59. package/src/input/agent-workspace-context-snapshot.ts +349 -0
  60. package/src/input/agent-workspace-delegation-editor-submission.ts +8 -0
  61. package/src/input/agent-workspace-document-editor.ts +502 -0
  62. package/src/input/agent-workspace-document-ops-editor.ts +523 -0
  63. package/src/input/agent-workspace-host-category.ts +1 -1
  64. package/src/input/agent-workspace-local-library-snapshot.ts +167 -0
  65. package/src/input/agent-workspace-model-compare-editor.ts +376 -0
  66. package/src/input/agent-workspace-model-compare-prompt-submission.ts +552 -0
  67. package/src/input/agent-workspace-model-compare-types.ts +82 -0
  68. package/src/input/agent-workspace-model-compare-utils.ts +35 -0
  69. package/src/input/agent-workspace-onboarding-categories.ts +141 -0
  70. package/src/input/agent-workspace-operations-command-editor-submission.ts +53 -0
  71. package/src/input/agent-workspace-operations-command-editors.ts +22 -0
  72. package/src/input/agent-workspace-research-report-editor.ts +212 -0
  73. package/src/input/agent-workspace-research-run-editor.ts +144 -0
  74. package/src/input/agent-workspace-research-source-editor.ts +167 -0
  75. package/src/input/agent-workspace-review-packet-snapshot.ts +593 -0
  76. package/src/input/agent-workspace-review-packet-utils.ts +265 -0
  77. package/src/input/agent-workspace-settings.ts +262 -30
  78. package/src/input/agent-workspace-setup-checkpoint-action.ts +127 -0
  79. package/src/input/agent-workspace-setup-snapshot.ts +198 -0
  80. package/src/input/agent-workspace-setup.ts +34 -1
  81. package/src/input/agent-workspace-snapshot.ts +162 -147
  82. package/src/input/agent-workspace-types.ts +287 -2
  83. package/src/input/agent-workspace.ts +18 -0
  84. package/src/input/command-registry.ts +9 -2
  85. package/src/input/commands/agent-runtime-profile-runtime.ts +28 -13
  86. package/src/input/commands/channels-runtime.ts +102 -114
  87. package/src/input/commands/delegation-runtime.ts +87 -24
  88. package/src/input/commands/knowledge-browser-flags.ts +12 -0
  89. package/src/input/commands/knowledge.ts +28 -14
  90. package/src/input/commands/operator-actions-runtime.ts +6 -3
  91. package/src/input/commands/schedule-runtime.ts +71 -14
  92. package/src/input/commands/session-content.ts +2 -2
  93. package/src/input/commands/shell-core.ts +2 -0
  94. package/src/input/commands/vibe-runtime.ts +140 -0
  95. package/src/input/commands.ts +2 -0
  96. package/src/input/connected-host-routes.ts +123 -0
  97. package/src/input/settings-modal-types.ts +14 -0
  98. package/src/main.ts +15 -15
  99. package/src/panels/qr-panel.ts +2 -2
  100. package/src/renderer/agent-workspace-context-lines.ts +686 -0
  101. package/src/renderer/agent-workspace.ts +30 -419
  102. package/src/renderer/settings-modal-helpers.ts +12 -0
  103. package/src/renderer/settings-modal.ts +12 -0
  104. package/src/runtime/bootstrap-command-context.ts +11 -1
  105. package/src/runtime/bootstrap-command-parts.ts +14 -3
  106. package/src/runtime/bootstrap-core.ts +39 -1
  107. package/src/runtime/bootstrap-shell.ts +6 -0
  108. package/src/runtime/bootstrap.ts +113 -30
  109. package/src/runtime/connected-host-auth.ts +3 -2
  110. package/src/runtime/execution-ledger.ts +231 -0
  111. package/src/runtime/services.ts +88 -10
  112. package/src/runtime/tool-permission-safety.ts +199 -5
  113. package/src/shell/session-continuity-hints.ts +39 -0
  114. package/src/tools/agent-artifacts-tool.ts +606 -0
  115. package/src/tools/agent-audit-tool.ts +155 -0
  116. package/src/tools/agent-autonomy-schedule-tool.ts +238 -0
  117. package/src/tools/agent-autonomy-tool.ts +140 -0
  118. package/src/tools/agent-channel-send-tool.ts +24 -2
  119. package/src/tools/agent-channels-tool.ts +140 -0
  120. package/src/tools/agent-computer-tool.ts +168 -0
  121. package/src/tools/agent-context-policy.ts +137 -7
  122. package/src/tools/agent-context-tool.ts +143 -0
  123. package/src/tools/agent-delegation-tool.ts +128 -0
  124. package/src/tools/agent-device-tool.ts +240 -0
  125. package/src/tools/agent-documents-tool.ts +684 -0
  126. package/src/tools/agent-execution-tool.ts +230 -0
  127. package/src/tools/agent-harness-agent-orchestration.ts +703 -0
  128. package/src/tools/agent-harness-autonomy-intake.ts +785 -0
  129. package/src/tools/agent-harness-autonomy-live-records.ts +588 -0
  130. package/src/tools/agent-harness-autonomy-queue-types.ts +88 -0
  131. package/src/tools/agent-harness-autonomy-queue.ts +560 -0
  132. package/src/tools/agent-harness-background-processes-types.ts +35 -0
  133. package/src/tools/agent-harness-background-processes.ts +794 -0
  134. package/src/tools/agent-harness-browser-cockpit-route.ts +219 -0
  135. package/src/tools/agent-harness-browser-control.ts +338 -0
  136. package/src/tools/agent-harness-channel-metadata.ts +168 -10
  137. package/src/tools/agent-harness-cli-command-policy.ts +110 -0
  138. package/src/tools/agent-harness-command-catalog.ts +4 -2
  139. package/src/tools/agent-harness-command-runner.ts +42 -0
  140. package/src/tools/agent-harness-connected-host-status.ts +7 -4
  141. package/src/tools/agent-harness-delegation-posture.ts +234 -19
  142. package/src/tools/agent-harness-document-ops-reviewer-readiness.ts +234 -0
  143. package/src/tools/agent-harness-document-ops-types.ts +72 -0
  144. package/src/tools/agent-harness-document-ops.ts +671 -0
  145. package/src/tools/agent-harness-execution-history.ts +489 -0
  146. package/src/tools/agent-harness-execution-posture.ts +382 -0
  147. package/src/tools/agent-harness-file-recovery.ts +135 -0
  148. package/src/tools/agent-harness-keybinding-metadata.ts +16 -12
  149. package/src/tools/agent-harness-learning-curator-common.ts +102 -0
  150. package/src/tools/agent-harness-learning-curator-consolidation.ts +295 -0
  151. package/src/tools/agent-harness-learning-curator-proposals.ts +606 -0
  152. package/src/tools/agent-harness-learning-curator-types.ts +151 -0
  153. package/src/tools/agent-harness-learning-curator.ts +417 -0
  154. package/src/tools/agent-harness-local-model-benchmarks.ts +199 -0
  155. package/src/tools/agent-harness-local-model-cookbook.ts +238 -0
  156. package/src/tools/agent-harness-local-model-endpoints.ts +673 -0
  157. package/src/tools/agent-harness-media-posture.ts +208 -2
  158. package/src/tools/agent-harness-memory-posture.ts +556 -0
  159. package/src/tools/agent-harness-metadata.ts +100 -168
  160. package/src/tools/agent-harness-mode-catalog.ts +84 -33
  161. package/src/tools/agent-harness-model-catalog.ts +162 -0
  162. package/src/tools/agent-harness-model-provider-health.ts +186 -0
  163. package/src/tools/agent-harness-model-readiness.ts +406 -0
  164. package/src/tools/agent-harness-model-routing-types.ts +266 -0
  165. package/src/tools/agent-harness-model-routing-utils.ts +30 -0
  166. package/src/tools/agent-harness-model-routing.ts +137 -190
  167. package/src/tools/agent-harness-operator-methods.ts +115 -133
  168. package/src/tools/agent-harness-pairing-posture.ts +431 -18
  169. package/src/tools/agent-harness-personal-ops-discovery.ts +533 -0
  170. package/src/tools/agent-harness-personal-ops-intake.ts +385 -0
  171. package/src/tools/agent-harness-personal-ops-lanes.ts +204 -0
  172. package/src/tools/agent-harness-personal-ops-records.ts +732 -0
  173. package/src/tools/agent-harness-personal-ops-runner.ts +637 -0
  174. package/src/tools/agent-harness-personal-ops-types.ts +222 -0
  175. package/src/tools/agent-harness-personal-ops.ts +606 -0
  176. package/src/tools/agent-harness-project-context.ts +144 -0
  177. package/src/tools/agent-harness-prompt-context.ts +589 -0
  178. package/src/tools/agent-harness-provider-account-metadata.ts +2 -2
  179. package/src/tools/agent-harness-release-evidence.ts +9 -7
  180. package/src/tools/agent-harness-release-readiness.ts +9 -7
  181. package/src/tools/agent-harness-research-briefing.ts +427 -0
  182. package/src/tools/agent-harness-research-queue.ts +250 -0
  183. package/src/tools/agent-harness-research-runs.ts +295 -0
  184. package/src/tools/agent-harness-research-workflow.ts +322 -0
  185. package/src/tools/agent-harness-security-posture.ts +2 -2
  186. package/src/tools/agent-harness-service-posture.ts +9 -9
  187. package/src/tools/agent-harness-session-metadata.ts +3 -3
  188. package/src/tools/agent-harness-setup-connected-host.ts +501 -0
  189. package/src/tools/agent-harness-setup-describe.ts +557 -0
  190. package/src/tools/agent-harness-setup-handoffs.ts +502 -0
  191. package/src/tools/agent-harness-setup-model-helpers.ts +101 -0
  192. package/src/tools/agent-harness-setup-plan.ts +253 -0
  193. package/src/tools/agent-harness-setup-posture-types.ts +218 -0
  194. package/src/tools/agent-harness-setup-posture-utils.ts +173 -0
  195. package/src/tools/agent-harness-setup-posture.ts +449 -221
  196. package/src/tools/agent-harness-setup-smoke.ts +508 -0
  197. package/src/tools/agent-harness-sudo-posture.ts +114 -0
  198. package/src/tools/agent-harness-tool-schema.ts +120 -7
  199. package/src/tools/agent-harness-tool-types.ts +78 -0
  200. package/src/tools/agent-harness-tool-utils.ts +43 -0
  201. package/src/tools/agent-harness-tool.ts +311 -370
  202. package/src/tools/agent-harness-ui-surface-metadata.ts +76 -69
  203. package/src/tools/agent-harness-ui-surface-types.ts +46 -0
  204. package/src/tools/agent-harness-vibe-health.ts +105 -0
  205. package/src/tools/agent-harness-workspace-action-runner.ts +149 -0
  206. package/src/tools/agent-harness-workspace-actions.ts +114 -8
  207. package/src/tools/agent-harness-workspace-editor-execution.ts +214 -0
  208. package/src/tools/agent-harness-workspace-editor-runner.ts +755 -0
  209. package/src/tools/agent-host-tool.ts +159 -0
  210. package/src/tools/agent-knowledge-ingest-tool.ts +34 -1
  211. package/src/tools/agent-learning-consolidation-core.ts +327 -0
  212. package/src/tools/agent-learning-consolidation-tool.ts +758 -0
  213. package/src/tools/agent-memory-tool.ts +214 -0
  214. package/src/tools/agent-model-compare-export.ts +315 -0
  215. package/src/tools/agent-model-compare-handoff.ts +592 -0
  216. package/src/tools/agent-model-compare-judgment.ts +633 -0
  217. package/src/tools/agent-model-compare-run.ts +722 -0
  218. package/src/tools/agent-model-compare-tool.ts +698 -0
  219. package/src/tools/agent-model-compare-types.ts +191 -0
  220. package/src/tools/agent-model-compare-utils.ts +93 -0
  221. package/src/tools/agent-models-tool.ts +208 -0
  222. package/src/tools/agent-operator-action-tool.ts +1 -1
  223. package/src/tools/agent-operator-method-tool.ts +643 -0
  224. package/src/tools/agent-personal-ops-tool.ts +197 -0
  225. package/src/tools/agent-policy-explanation.ts +415 -0
  226. package/src/tools/agent-research-report-tool.ts +608 -0
  227. package/src/tools/agent-research-runs-tool.ts +434 -0
  228. package/src/tools/agent-research-sources-tool.ts +443 -0
  229. package/src/tools/agent-research-tool.ts +687 -0
  230. package/src/tools/agent-review-packet-presets-core.ts +757 -0
  231. package/src/tools/agent-review-packet-presets-tool.ts +466 -0
  232. package/src/tools/agent-review-packet-share-tool.ts +305 -0
  233. package/src/tools/agent-route-planner-candidates-setup.ts +411 -0
  234. package/src/tools/agent-route-planner-candidates-surfaces.ts +432 -0
  235. package/src/tools/agent-route-planner-candidates-work.ts +251 -0
  236. package/src/tools/agent-route-planner-helpers.ts +667 -0
  237. package/src/tools/agent-route-planner.ts +185 -0
  238. package/src/tools/agent-route-tool.ts +105 -0
  239. package/src/tools/agent-schedule-edit-tool.ts +210 -0
  240. package/src/tools/agent-schedule-tool.ts +282 -0
  241. package/src/tools/agent-security-tool.ts +145 -0
  242. package/src/tools/agent-sessions-tool.ts +122 -0
  243. package/src/tools/agent-settings-import-tool.ts +104 -0
  244. package/src/tools/agent-settings-tool.ts +176 -0
  245. package/src/tools/agent-setup-tool.ts +226 -0
  246. package/src/tools/agent-support-tool.ts +122 -0
  247. package/src/tools/agent-terminal-process-tools.ts +167 -0
  248. package/src/tools/agent-tool-policy-guard-types.ts +77 -0
  249. package/src/tools/agent-tool-policy-guard.ts +106 -85
  250. package/src/tools/agent-vibe-tool.ts +297 -0
  251. package/src/tools/agent-work-plan-tool.ts +265 -6
  252. package/src/tools/agent-workspace-tool.ts +305 -0
  253. package/src/tools/artifact-archive.ts +169 -0
  254. package/src/tools/tool-definition-compaction.ts +36 -0
  255. package/src/version.ts +1 -1
@@ -0,0 +1,231 @@
1
+ import type { RuntimeEventBus, ToolEvent } from '@/runtime/index.ts';
2
+
3
+ export type AgentExecutionStatus = 'running' | 'succeeded' | 'failed' | 'cancelled';
4
+ export type AgentExecutionRouteKind = 'read' | 'write' | 'shell' | 'network' | 'browser' | 'delegation' | 'other';
5
+
6
+ export interface AgentExecutionResultSummary {
7
+ readonly kind: string;
8
+ readonly byteSize: number;
9
+ readonly preview?: string | undefined;
10
+ }
11
+
12
+ export interface AgentExecutionRecord {
13
+ readonly id: string;
14
+ readonly callId: string;
15
+ readonly turnId: string;
16
+ readonly tool: string;
17
+ readonly routeKind: AgentExecutionRouteKind;
18
+ readonly status: AgentExecutionStatus;
19
+ readonly phase: ToolEvent['type'];
20
+ readonly receivedAt: number;
21
+ readonly updatedAt: number;
22
+ readonly completedAt?: number | undefined;
23
+ readonly durationMs?: number | undefined;
24
+ readonly permissionApproved?: boolean | undefined;
25
+ readonly argsPreview: string;
26
+ readonly argsKeys: readonly string[];
27
+ readonly commandPreview?: string | undefined;
28
+ readonly targetPreview?: string | undefined;
29
+ readonly resultSummary?: AgentExecutionResultSummary | undefined;
30
+ readonly error?: string | undefined;
31
+ readonly cancelReason?: string | undefined;
32
+ }
33
+
34
+ interface MutableAgentExecutionRecord {
35
+ id: string;
36
+ callId: string;
37
+ turnId: string;
38
+ tool: string;
39
+ routeKind: AgentExecutionRouteKind;
40
+ status: AgentExecutionStatus;
41
+ phase: ToolEvent['type'];
42
+ receivedAt: number;
43
+ updatedAt: number;
44
+ completedAt?: number | undefined;
45
+ durationMs?: number | undefined;
46
+ permissionApproved?: boolean | undefined;
47
+ argsPreview: string;
48
+ argsKeys: readonly string[];
49
+ commandPreview?: string | undefined;
50
+ targetPreview?: string | undefined;
51
+ resultSummary?: AgentExecutionResultSummary | undefined;
52
+ error?: string | undefined;
53
+ cancelReason?: string | undefined;
54
+ }
55
+
56
+ export interface AgentExecutionLedgerSnapshot {
57
+ readonly records: readonly AgentExecutionRecord[];
58
+ readonly total: number;
59
+ readonly running: number;
60
+ readonly succeeded: number;
61
+ readonly failed: number;
62
+ readonly cancelled: number;
63
+ }
64
+
65
+ const DEFAULT_LIMIT = 500;
66
+ const SECRET_KEY_PATTERN = /(?:api[_-]?key|authorization|bearer|client[_-]?secret|password|secret|token)/i;
67
+
68
+ function truncateText(value: string, max = 220): string {
69
+ const compact = value.replace(/\s+/g, ' ').trim();
70
+ return compact.length > max ? `${compact.slice(0, Math.max(0, max - 1))}...` : compact;
71
+ }
72
+
73
+ function redactValue(value: unknown, depth = 0): unknown {
74
+ if (depth > 3) return '[truncated]';
75
+ if (typeof value === 'string') return truncateText(value);
76
+ if (typeof value === 'number' || typeof value === 'boolean' || value === null) return value;
77
+ if (Array.isArray(value)) return value.slice(0, 8).map((entry) => redactValue(entry, depth + 1));
78
+ if (!value || typeof value !== 'object') return String(value);
79
+ const entries = Object.entries(value as Record<string, unknown>).slice(0, 16).map(([key, entry]) => (
80
+ [key, SECRET_KEY_PATTERN.test(key) ? '[redacted]' : redactValue(entry, depth + 1)] as const
81
+ ));
82
+ return Object.fromEntries(entries);
83
+ }
84
+
85
+ function argsPreview(args: Record<string, unknown>): string {
86
+ try {
87
+ return truncateText(JSON.stringify(redactValue(args)), 360);
88
+ } catch {
89
+ return '[unserializable args]';
90
+ }
91
+ }
92
+
93
+ function stringArg(args: Record<string, unknown>, keys: readonly string[]): string | undefined {
94
+ for (const key of keys) {
95
+ const value = args[key];
96
+ if (typeof value === 'string' && value.trim()) return truncateText(value, 180);
97
+ }
98
+ return undefined;
99
+ }
100
+
101
+ function routeKindForTool(tool: string, args: Record<string, unknown>): AgentExecutionRouteKind {
102
+ const name = tool.toLowerCase();
103
+ if (name.includes('browser') || name.includes('desktop') || name.includes('screenshot')) return 'browser';
104
+ if (name.includes('delegate') || name.includes('agent')) return 'delegation';
105
+ if (name.includes('exec') || name.includes('shell') || name.includes('bash') || typeof args.command === 'string') return 'shell';
106
+ if (name.includes('write') || name.includes('edit') || name.includes('patch') || name.includes('delete')) return 'write';
107
+ if (name.includes('fetch') || name.includes('web') || name.includes('http') || name.includes('url')) return 'network';
108
+ if (name.includes('read') || name.includes('find') || name.includes('inspect') || name.includes('grep') || name.includes('search')) return 'read';
109
+ return 'other';
110
+ }
111
+
112
+ function statusForPhase(phase: ToolEvent['type']): AgentExecutionStatus {
113
+ if (phase === 'TOOL_SUCCEEDED') return 'succeeded';
114
+ if (phase === 'TOOL_FAILED') return 'failed';
115
+ if (phase === 'TOOL_CANCELLED') return 'cancelled';
116
+ return 'running';
117
+ }
118
+
119
+ function resultSummaryFrom(value: Extract<ToolEvent, { type: 'TOOL_SUCCEEDED' | 'TOOL_FAILED' }>['result']): AgentExecutionResultSummary | undefined {
120
+ if (!value) return undefined;
121
+ return {
122
+ kind: value.kind,
123
+ byteSize: value.byteSize,
124
+ ...(typeof value.preview === 'string' && value.preview.trim() ? { preview: truncateText(value.preview, 220) } : {}),
125
+ };
126
+ }
127
+
128
+ function immutable(record: MutableAgentExecutionRecord): AgentExecutionRecord {
129
+ return { ...record };
130
+ }
131
+
132
+ export class AgentExecutionLedger {
133
+ private readonly records = new Map<string, MutableAgentExecutionRecord>();
134
+ private readonly order: string[] = [];
135
+ private readonly subscribers = new Set<() => void>();
136
+ private readonly unsubscribe: () => void;
137
+
138
+ public constructor(
139
+ runtimeBus: RuntimeEventBus,
140
+ private readonly limit: number = DEFAULT_LIMIT,
141
+ ) {
142
+ this.unsubscribe = runtimeBus.onDomain('tools', (envelope) => {
143
+ this.handleToolEvent(envelope.payload as ToolEvent, envelope.ts);
144
+ });
145
+ }
146
+
147
+ public getSnapshot(): AgentExecutionLedgerSnapshot {
148
+ const records = this.order
149
+ .map((id) => this.records.get(id))
150
+ .filter((record): record is MutableAgentExecutionRecord => record !== undefined)
151
+ .map(immutable)
152
+ .reverse();
153
+ return {
154
+ records,
155
+ total: records.length,
156
+ running: records.filter((record) => record.status === 'running').length,
157
+ succeeded: records.filter((record) => record.status === 'succeeded').length,
158
+ failed: records.filter((record) => record.status === 'failed').length,
159
+ cancelled: records.filter((record) => record.status === 'cancelled').length,
160
+ };
161
+ }
162
+
163
+ public subscribe(callback: () => void): () => void {
164
+ this.subscribers.add(callback);
165
+ return () => this.subscribers.delete(callback);
166
+ }
167
+
168
+ public dispose(): void {
169
+ this.unsubscribe();
170
+ this.subscribers.clear();
171
+ }
172
+
173
+ private handleToolEvent(event: ToolEvent, timestamp: number): void {
174
+ if (!('callId' in event)) return;
175
+ if (event.type === 'TOOL_RECEIVED') {
176
+ this.recordReceived(event, timestamp);
177
+ return;
178
+ }
179
+ const existing = this.records.get(event.callId);
180
+ if (!existing) return;
181
+ existing.phase = event.type;
182
+ existing.status = statusForPhase(event.type);
183
+ existing.updatedAt = timestamp;
184
+ if (event.type === 'TOOL_PERMISSIONED') existing.permissionApproved = event.approved;
185
+ if (event.type === 'TOOL_SUCCEEDED') {
186
+ existing.completedAt = timestamp;
187
+ existing.durationMs = event.durationMs;
188
+ existing.resultSummary = resultSummaryFrom(event.result);
189
+ }
190
+ if (event.type === 'TOOL_FAILED') {
191
+ existing.completedAt = timestamp;
192
+ existing.durationMs = event.durationMs;
193
+ existing.error = truncateText(event.error, 220);
194
+ existing.resultSummary = resultSummaryFrom(event.result);
195
+ }
196
+ if (event.type === 'TOOL_CANCELLED') {
197
+ existing.completedAt = timestamp;
198
+ existing.cancelReason = event.reason ? truncateText(event.reason, 220) : undefined;
199
+ }
200
+ this.notify();
201
+ }
202
+
203
+ private recordReceived(event: Extract<ToolEvent, { type: 'TOOL_RECEIVED' }>, timestamp: number): void {
204
+ const record: MutableAgentExecutionRecord = {
205
+ id: event.callId,
206
+ callId: event.callId,
207
+ turnId: event.turnId,
208
+ tool: event.tool,
209
+ routeKind: routeKindForTool(event.tool, event.args),
210
+ status: 'running',
211
+ phase: event.type,
212
+ receivedAt: timestamp,
213
+ updatedAt: timestamp,
214
+ argsPreview: argsPreview(event.args),
215
+ argsKeys: Object.keys(event.args).filter((key) => !SECRET_KEY_PATTERN.test(key)).sort(),
216
+ commandPreview: stringArg(event.args, ['command', 'cmd', 'script']),
217
+ targetPreview: stringArg(event.args, ['path', 'file', 'target', 'url', 'query', 'task']),
218
+ };
219
+ this.records.set(record.id, record);
220
+ this.order.push(record.id);
221
+ while (this.order.length > this.limit) {
222
+ const dropped = this.order.shift();
223
+ if (dropped) this.records.delete(dropped);
224
+ }
225
+ this.notify();
226
+ }
227
+
228
+ private notify(): void {
229
+ for (const callback of this.subscribers) callback();
230
+ }
231
+ }
@@ -9,6 +9,7 @@ import { AutomationDeliveryManager, AutomationManager, AutomationRouteStore } fr
9
9
  import { ChannelPluginRegistry, ChannelPolicyManager, RouteBindingManager, SurfaceRegistry } from '@pellux/goodvibes-sdk/platform/channels';
10
10
  import { ChannelDeliveryRouter } from '@pellux/goodvibes-sdk/platform/channels';
11
11
  import { ApprovalBroker, GatewayMethodCatalog, SharedSessionBroker } from '@pellux/goodvibes-sdk/platform/control-plane';
12
+ import type { SharedSessionRoutingIntent } from '@pellux/goodvibes-sdk/platform/control-plane';
12
13
  import { WatcherRegistry } from '@pellux/goodvibes-sdk/platform/watchers';
13
14
  import { ArtifactStore } from '@pellux/goodvibes-sdk/platform/artifacts';
14
15
  import {
@@ -89,6 +90,7 @@ import {
89
90
  type WorkflowServices,
90
91
  } from '@pellux/goodvibes-sdk/platform/tools';
91
92
  import { WorkPlanStore } from '../work-plans/work-plan-store.ts';
93
+ import { AgentExecutionLedger } from './execution-ledger.ts';
92
94
 
93
95
  type WorktreeRegistry = RuntimeShell.WorktreeRegistry;
94
96
  type SdkRuntimeServices = RuntimeFoundationClientsOptions['runtimeServices'];
@@ -130,6 +132,64 @@ function buildFallbackModelDefinition(provider: string, modelId: string): ModelD
130
132
  };
131
133
  }
132
134
 
135
+ function normalizeSharedSessionModelId(modelId: string | undefined, providerId: string | undefined): string | undefined {
136
+ const trimmedModelId = modelId?.trim();
137
+ if (!trimmedModelId) return undefined;
138
+ const trimmedProviderId = providerId?.trim();
139
+ const separatorIndex = trimmedModelId.indexOf(':');
140
+ if (separatorIndex > 0) return trimmedModelId;
141
+ if (trimmedProviderId) return `${trimmedProviderId}:${trimmedModelId}`;
142
+ return trimmedModelId;
143
+ }
144
+
145
+ function normalizeSharedSessionFallbackModels(models: readonly string[] | undefined): string[] {
146
+ return (models ?? [])
147
+ .filter((model): model is string => typeof model === 'string' && model.trim().length > 0)
148
+ .map((model) => {
149
+ const trimmed = model.trim();
150
+ const separatorIndex = trimmed.indexOf(':');
151
+ if (separatorIndex <= 0 || separatorIndex === trimmed.length - 1) {
152
+ throw new Error(`Shared-session fallback model '${model}' must be provider-qualified.`);
153
+ }
154
+ return trimmed;
155
+ });
156
+ }
157
+
158
+ function buildAgentSpawnRoutingFromSharedSession(
159
+ routing: SharedSessionRoutingIntent | undefined,
160
+ options: { readonly restrictTools?: boolean | undefined } = {},
161
+ ): Partial<Parameters<AgentManager['spawn']>[0]> {
162
+ if (!routing) return options.restrictTools ? { restrictTools: true } : {};
163
+ const provider = routing.providerId?.trim();
164
+ const model = normalizeSharedSessionModelId(routing.modelId, provider);
165
+ if (provider && !model) {
166
+ throw new Error('Shared-session provider routing requires a provider-qualified model when provider is supplied.');
167
+ }
168
+ const fallbackModels = normalizeSharedSessionFallbackModels(routing.fallbackModels);
169
+ const providerFailurePolicy = routing.providerFailurePolicy ?? (
170
+ fallbackModels.length ? 'ordered-fallbacks' : 'fail'
171
+ );
172
+ if (providerFailurePolicy === 'ordered-fallbacks' && fallbackModels.length === 0) {
173
+ throw new Error('Shared-session ordered fallback routing requires at least one provider-qualified fallback model.');
174
+ }
175
+ if (providerFailurePolicy === 'fail' && fallbackModels.length > 0) {
176
+ throw new Error('Shared-session fail routing cannot include fallback models; use ordered-fallbacks to enable model failover.');
177
+ }
178
+ return {
179
+ ...(model ? { model } : {}),
180
+ ...(provider ? { provider } : {}),
181
+ ...(routing.tools?.length ? { tools: [...routing.tools] } : {}),
182
+ ...(options.restrictTools ? { restrictTools: true } : {}),
183
+ routing: {
184
+ providerSelection: routing.providerSelection ?? (provider ? 'concrete' : 'inherit-current'),
185
+ providerFailurePolicy,
186
+ ...(fallbackModels.length ? { fallbackModels } : {}),
187
+ },
188
+ ...(routing.executionIntent ? { executionIntent: routing.executionIntent } : {}),
189
+ ...(routing.reasoningEffort ? { reasoningEffort: routing.reasoningEffort } : {}),
190
+ };
191
+ }
192
+
133
193
  class DisabledAgentWorktreeRegistry extends runtimeShell.WorktreeRegistry {
134
194
  public override async list(): Promise<Awaited<ReturnType<WorktreeRegistry['list']>>> {
135
195
  return [] as Awaited<ReturnType<WorktreeRegistry['list']>>;
@@ -405,6 +465,7 @@ export interface RuntimeServices extends SdkRuntimeServices {
405
465
  readonly processManager: ProcessManager;
406
466
  readonly modeManager: ModeManager;
407
467
  readonly fileUndoManager: FileUndoManager;
468
+ readonly executionLedger: AgentExecutionLedger;
408
469
  readonly integrationHelpers: IntegrationHelperService;
409
470
  /**
410
471
  * Re-root workspace-bound stores to a new working directory.
@@ -516,6 +577,7 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
516
577
  surfaceRoot: GOODVIBES_AGENT_SURFACE_ROOT,
517
578
  createWorktree: createDisabledAgentWrfcWorktreeOps,
518
579
  }]) as WrfcController;
580
+ agentManager.setWrfcController(wrfcController);
519
581
  const hookDispatcher = new HookDispatcher({ toolLLM, projectRoot: workingDirectory }, hookActivityTracker);
520
582
  configManager.attachHookDispatcher(hookDispatcher);
521
583
  const hookWorkbench = createHookWorkbench({
@@ -532,11 +594,13 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
532
594
  messageSender: agentMessageBus,
533
595
  });
534
596
  sessionBroker.setContinuationRunner(async ({ task, input }) => {
535
- throw new Error([
536
- 'GoodVibes Agent does not own shared-session task execution.',
537
- `Received task for session ${input.sessionId}: ${task}`,
538
- 'Delegate explicit build/fix/review work to GoodVibes TUI through the public shared-session/build-delegation contract.',
539
- ].join(' '));
597
+ const record = agentManager.spawn({
598
+ mode: 'spawn',
599
+ task,
600
+ ...buildAgentSpawnRoutingFromSharedSession(input.routing, { restrictTools: true }),
601
+ context: `shared-session:${input.sessionId}`,
602
+ });
603
+ return { agentId: record.id };
540
604
  });
541
605
  const artifactStore = new ArtifactStore({ configManager });
542
606
  const memoryEmbeddingRegistry = new MemoryEmbeddingProviderRegistry({ configManager });
@@ -562,11 +626,23 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
562
626
  runtimeBus: options.runtimeBus,
563
627
  deliveryManager,
564
628
  spawnTask: (input) => {
565
- throw new Error([
566
- 'GoodVibes Agent does not create local automation jobs and does not spawn local automation agents.',
567
- `Received automation prompt: ${input.prompt}`,
568
- 'Use read-only automation observability here; explicit build/fix/review execution belongs to GoodVibes TUI delegation.',
569
- ].join(' '));
629
+ const record = agentManager.spawn({
630
+ mode: 'spawn',
631
+ task: input.prompt,
632
+ ...(input.modelId ? { model: input.modelId } : {}),
633
+ ...(input.modelProvider ? { provider: input.modelProvider } : {}),
634
+ ...(input.fallbackModels ? { fallbackModels: [...input.fallbackModels] } : {}),
635
+ ...(input.routing ? { routing: input.routing } : {}),
636
+ ...(input.executionIntent ? { executionIntent: input.executionIntent } : {}),
637
+ ...(input.template ? { template: input.template } : {}),
638
+ ...(input.reasoningEffort ? { reasoningEffort: input.reasoningEffort } : {}),
639
+ ...(input.toolAllowlist ? { tools: [...input.toolAllowlist], restrictTools: true } : {}),
640
+ context: [
641
+ 'automation-manager:visible-agent',
642
+ input.context,
643
+ ].filter((part): part is string => Boolean(part?.trim())).join('\n\n'),
644
+ });
645
+ return record.id;
570
646
  },
571
647
  });
572
648
  const agentKnowledgeStore = new KnowledgeStore({
@@ -684,6 +760,7 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
684
760
  const processManager = new ProcessManager();
685
761
  const modeManager = new ModeManager();
686
762
  const fileUndoManager = new FileUndoManager();
763
+ const executionLedger = new AgentExecutionLedger(options.runtimeBus);
687
764
  const integrationHelpers = new IntegrationHelperService({
688
765
  workingDirectory,
689
766
  homeDirectory,
@@ -816,6 +893,7 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
816
893
  processManager,
817
894
  modeManager,
818
895
  fileUndoManager,
896
+ executionLedger,
819
897
  integrationHelpers,
820
898
  async rerootStores(newWorkingDir: string): Promise<void> {
821
899
  await projectIndex.reroot(newWorkingDir);
@@ -17,7 +17,25 @@ const READ_TOOL_NAMES = new Set([
17
17
  'inspect',
18
18
  'state',
19
19
  'registry',
20
+ 'route',
20
21
  'goodvibes_context',
22
+ 'autonomy',
23
+ 'channels',
24
+ 'computer',
25
+ 'context',
26
+ 'delegation',
27
+ 'device',
28
+ 'execution',
29
+ 'host',
30
+ 'memory',
31
+ 'models',
32
+ 'personal_ops',
33
+ 'research',
34
+ 'security',
35
+ 'setup',
36
+ 'settings',
37
+ 'vibe',
38
+ 'workspace',
21
39
  'agent_harness',
22
40
  'agent_knowledge',
23
41
  'agent_operator_briefing',
@@ -27,12 +45,36 @@ const WRITE_TOOL_NAMES = new Set([
27
45
  'write',
28
46
  'edit',
29
47
  'goodvibes_settings',
48
+ 'agent_artifacts',
49
+ 'agent_documents',
30
50
  'agent_knowledge_ingest',
51
+ 'agent_learning_consolidation',
31
52
  'agent_local_registry',
53
+ 'agent_research_runs',
54
+ 'agent_research_sources',
55
+ 'agent_research_report',
56
+ 'agent_review_packet_presets',
32
57
  'agent_work_plan',
33
58
  ]);
34
59
 
35
- const EXECUTE_TOOL_NAMES = new Set(['exec', 'repl']);
60
+ const EXECUTE_TOOL_NAMES = new Set(['exec', 'repl', 'terminal', 'process']);
61
+ const READ_ONLY_PROCESS_ACTIONS = new Set(['', 'list', 'status', 'poll', 'log', 'output', 'capabilities', 'doctor', 'parity']);
62
+ const READ_ONLY_SCHEDULE_ACTIONS = new Set(['', 'list', 'status', 'show']);
63
+ const READ_ONLY_SETTINGS_IMPORT_ACTIONS = new Set(['', 'preview', 'inspect', 'show', 'plan']);
64
+ const READ_ONLY_SETTINGS_ACTIONS = new Set(['', 'list', 'status', 'settings', 'catalog', 'search', 'find', 'browse', 'get', 'show', 'inspect', 'read', 'setting', 'get_setting', 'import', 'import_settings', 'settings_import', 'import_goodvibes', 'goodvibes_import', 'preview_import']);
65
+ const READ_ONLY_SETUP_ACTIONS = new Set(['', 'status', 'summary', 'list', 'item', 'show', 'inspect', 'repair', 'fix', 'diagnose_repair', 'host_repair', 'repair_host', 'launch_host', 'checkpoint', 'checkpoint_status']);
66
+ const READ_ONLY_VIBE_ACTIONS = new Set(['', 'status', 'summary', 'list', 'show', 'file', 'source', 'read', 'inspect']);
67
+ const READ_ONLY_PERSONAL_OPS_ACTIONS = new Set(['', 'briefing', 'brief', 'daily', 'daily_brief', 'morning', 'status', 'summary', 'overview', 'map', 'list', 'queue', 'queues', 'review_queue', 'review_queues', 'personal_queue', 'ops_queue', 'intake', 'request', 'route', 'plan', 'triage', 'draft', 'lane', 'inspect', 'show']);
68
+ const READ_ONLY_RESEARCH_ACTIONS = new Set(['', 'briefing', 'brief', 'status', 'dashboard', 'cockpit', 'next', 'plan', 'workflow', 'research', 'runner', 'browser', 'browser_runner', 'browser_backed', 'deep_research', 'runs', 'list_runs', 'run_list', 'run', 'show_run', 'inspect_run', 'sources', 'queue', 'source_queue', 'source', 'show_source', 'inspect_source', 'bundle', 'bundle_sources', 'source_bundle', 'search', 'public_search', 'collect', 'collect_sources', 'source_candidates', 'reports', 'list_reports', 'report_list', 'visual_reports', 'report_artifact', 'show_report', 'inspect_report', 'show_visual_report', 'visual_report_artifact']);
69
+ const READ_ONLY_CHANNELS_ACTIONS = new Set(['', 'status', 'summary', 'list', 'readiness', 'channels', 'channel', 'show', 'inspect', 'setup', 'guide', 'setup_guide', 'channel_setup_guide', 'triage', 'inbox', 'blockers', 'retries', 'channel_triage', 'deliveries', 'delivery', 'receipts', 'history', 'channel_deliveries']);
70
+ const READ_ONLY_MEMORY_ACTIONS = new Set(['', 'status', 'summary', 'posture', 'memory_posture', 'recall', 'providers', 'provider', 'memory_provider', 'embedding', 'external', 'external_provider', 'curator', 'learning', 'learning_curator', 'queue', 'review_queue', 'plan', 'candidate', 'learning_candidate', 'card', 'inspect_candidate', 'list', 'records', 'memories', 'search', 'find', 'lookup', 'get', 'show', 'inspect', 'read']);
71
+ const READ_ONLY_COMPUTER_ACTIONS = new Set(['', 'status', 'summary', 'overview', 'computer', 'computer_use', 'plan', 'route', 'control_plan', 'browser_plan', 'desktop_plan', 'control', 'browser_control', 'desktop', 'desktop_control', 'screenshot', 'screen', 'screen_recording', 'observe', 'browser', 'pwa', 'cockpit', 'browser_cockpit', 'web', 'setup', 'configure', 'browser_desktop_control', 'mcp', 'tools', 'servers', 'mcp_servers']);
72
+ const READ_ONLY_DEVICE_ACTIONS = new Set(['', 'status', 'map', 'capabilities', 'device', 'devices', 'mobile', 'phone', 'pairing', 'capability', 'route', 'pairing_route', 'show', 'inspect', 'browser', 'pwa', 'cockpit', 'browser_cockpit', 'web', 'control', 'browser_control', 'desktop', 'desktop_control', 'computer_use', 'voice', 'media', 'voice_media', 'workflows', 'provider', 'media_provider', 'voice_provider']);
73
+ const READ_ONLY_MODELS_ACTIONS = new Set(['', 'status', 'routing', 'routes', 'models', 'model', 'readiness', 'route_readiness', 'route', 'model_route', 'inspect', 'show', 'candidate', 'endpoint', 'local', 'cookbook', 'local_cookbook', 'recipes', 'recipe', 'ollama', 'llama_cpp', 'llamacpp', 'vllm', 'local_servers', 'providers', 'provider_accounts', 'accounts', 'subscriptions', 'auth', 'logins', 'provider', 'provider_account', 'account', 'subscription', 'auth_status']);
74
+ const READ_ONLY_WORKSPACE_ACTIONS = new Set(['', 'status', 'summary', 'home', 'workspace', 'categories', 'workspace_categories', 'actions', 'list_actions', 'workspace_actions', 'tasks', 'action', 'show', 'inspect', 'workspace_action', 'surfaces', 'ui_surfaces', 'screens', 'views', 'surface', 'ui_surface', 'screen', 'view', 'panels', 'panes', 'panel', 'pane', 'shortcuts', 'shortcut_help', 'help', 'keybindings', 'bindings', 'keys', 'keybinding', 'binding', 'key', 'commands', 'slash_commands', 'command_catalog', 'command', 'slash_command', 'inspect_command', 'cli_commands', 'cli_catalog', 'cli_command', 'inspect_cli_command']);
75
+ const READ_ONLY_AUTONOMY_ACTIONS = new Set(['', 'intake', 'request', 'route', 'plan', 'triage', 'autonomy_intake', 'queue', 'list', 'work', 'ongoing', 'autonomy_queue', 'item', 'card', 'show', 'inspect', 'autonomy_queue_item', 'status', 'summary', 'overview']);
76
+ const READ_ONLY_DELEGATION_ACTIONS = new Set(['', 'status', 'summary', 'overview', 'policy', 'decision', 'decisions', 'delegation_posture', 'routes', 'list', 'catalog', 'posture', 'route', 'item', 'card', 'show', 'inspect', 'delegation_route']);
77
+ const READ_ONLY_EXECUTION_ACTIONS = new Set(['', 'status', 'summary', 'overview', 'routes', 'posture', 'execution_posture', 'route', 'show_route', 'inspect_route', 'execution_route', 'history', 'activity', 'records', 'execution_history', 'record', 'item', 'show', 'inspect', 'execution_history_item', 'processes', 'background', 'backgrounds', 'background_processes', 'capabilities', 'process_capabilities', 'process', 'background_process', 'recovery', 'file_recovery', 'undo_redo']);
36
78
 
37
79
  type MarkedPermissionManager = PermissionManagerLike & { [SAFETY_MARKER]?: true };
38
80
 
@@ -47,9 +89,11 @@ export function installPermissionManagerSafetyGuard(manager: PermissionManagerLi
47
89
 
48
90
  manager.getCategory = (toolName, args = {}) => {
49
91
  try {
50
- return originalGetCategory(toolName, args);
92
+ const category = originalGetCategory(toolName, args);
93
+ const knownCategory = fallbackPermissionCategoryForArgs(toolName, args);
94
+ return category === 'delegate' && knownCategory !== 'delegate' ? knownCategory : category;
51
95
  } catch {
52
- return fallbackPermissionCategory(toolName);
96
+ return fallbackPermissionCategoryForArgs(toolName, args);
53
97
  }
54
98
  };
55
99
 
@@ -57,7 +101,7 @@ export function installPermissionManagerSafetyGuard(manager: PermissionManagerLi
57
101
  try {
58
102
  return await originalCheck(toolName, args);
59
103
  } catch {
60
- return fallbackPermissionCategory(toolName) === 'read';
104
+ return fallbackPermissionCategoryForArgs(toolName, args) === 'read';
61
105
  }
62
106
  };
63
107
 
@@ -66,7 +110,7 @@ export function installPermissionManagerSafetyGuard(manager: PermissionManagerLi
66
110
  try {
67
111
  return await originalCheckDetailed(toolName, args);
68
112
  } catch (error) {
69
- const category = fallbackPermissionCategory(toolName);
113
+ const category = fallbackPermissionCategoryForArgs(toolName, args);
70
114
  const approved = category === 'read';
71
115
  return {
72
116
  approved,
@@ -91,3 +135,153 @@ export function fallbackPermissionCategory(toolName: string): PermissionCategory
91
135
  if (EXECUTE_TOOL_NAMES.has(toolName)) return 'execute';
92
136
  return 'delegate';
93
137
  }
138
+
139
+ export function fallbackPermissionCategoryForArgs(toolName: string, args: Record<string, unknown>): PermissionCategory {
140
+ if (toolName === 'process') {
141
+ const action = typeof args.action === 'string'
142
+ ? args.action.trim().toLowerCase()
143
+ : typeof args.processAction === 'string'
144
+ ? args.processAction.trim().toLowerCase()
145
+ : '';
146
+ return READ_ONLY_PROCESS_ACTIONS.has(action) ? 'read' : 'execute';
147
+ }
148
+ if (toolName === 'schedule') {
149
+ const action = typeof args.action === 'string'
150
+ ? args.action.trim().toLowerCase()
151
+ : typeof args.mode === 'string'
152
+ ? args.mode.trim().toLowerCase()
153
+ : '';
154
+ return READ_ONLY_SCHEDULE_ACTIONS.has(action) ? 'read' : 'execute';
155
+ }
156
+ if (toolName === 'import_goodvibes_settings') {
157
+ const action = typeof args.action === 'string'
158
+ ? args.action.trim().toLowerCase()
159
+ : typeof args.mode === 'string'
160
+ ? args.mode.trim().toLowerCase()
161
+ : '';
162
+ return READ_ONLY_SETTINGS_IMPORT_ACTIONS.has(action) ? 'read' : 'write';
163
+ }
164
+ if (toolName === 'settings') {
165
+ const action = typeof args.action === 'string'
166
+ ? args.action.trim().toLowerCase().replace(/-/g, '_')
167
+ : typeof args.mode === 'string'
168
+ ? args.mode.trim().toLowerCase().replace(/-/g, '_')
169
+ : '';
170
+ const confirmed = args.confirm === true || (typeof args.confirm === 'string' && ['true', 'yes', 'apply', 'run'].includes(args.confirm.trim().toLowerCase()));
171
+ if ((action === 'import' || action === 'import_settings' || action === 'settings_import' || action === 'import_goodvibes' || action === 'goodvibes_import') && confirmed) return 'write';
172
+ return READ_ONLY_SETTINGS_ACTIONS.has(action) ? 'read' : 'write';
173
+ }
174
+ if (toolName === 'setup') {
175
+ const action = typeof args.action === 'string'
176
+ ? args.action.trim().toLowerCase().replace(/-/g, '_')
177
+ : typeof args.mode === 'string'
178
+ ? args.mode.trim().toLowerCase().replace(/-/g, '_')
179
+ : '';
180
+ return READ_ONLY_SETUP_ACTIONS.has(action) ? 'read' : 'write';
181
+ }
182
+ if (toolName === 'vibe') {
183
+ const action = typeof args.action === 'string'
184
+ ? args.action.trim().toLowerCase().replace(/-/g, '_')
185
+ : typeof args.mode === 'string'
186
+ ? args.mode.trim().toLowerCase().replace(/-/g, '_')
187
+ : '';
188
+ return READ_ONLY_VIBE_ACTIONS.has(action) ? 'read' : 'write';
189
+ }
190
+ if (toolName === 'personal_ops') {
191
+ const action = typeof args.action === 'string'
192
+ ? args.action.trim().toLowerCase().replace(/-/g, '_')
193
+ : typeof args.mode === 'string'
194
+ ? args.mode.trim().toLowerCase().replace(/-/g, '_')
195
+ : '';
196
+ return READ_ONLY_PERSONAL_OPS_ACTIONS.has(action) ? 'read' : 'write';
197
+ }
198
+ if (toolName === 'research') {
199
+ const action = typeof args.action === 'string'
200
+ ? args.action.trim().toLowerCase().replace(/-/g, '_')
201
+ : typeof args.mode === 'string'
202
+ ? args.mode.trim().toLowerCase().replace(/-/g, '_')
203
+ : '';
204
+ return READ_ONLY_RESEARCH_ACTIONS.has(action) ? 'read' : 'write';
205
+ }
206
+ if (toolName === 'channels') {
207
+ const action = typeof args.action === 'string'
208
+ ? args.action.trim().toLowerCase().replace(/-/g, '_')
209
+ : typeof args.mode === 'string'
210
+ ? args.mode.trim().toLowerCase().replace(/-/g, '_')
211
+ : '';
212
+ return READ_ONLY_CHANNELS_ACTIONS.has(action) ? 'read' : 'write';
213
+ }
214
+ if (toolName === 'memory') {
215
+ const action = typeof args.action === 'string'
216
+ ? args.action.trim().toLowerCase().replace(/-/g, '_')
217
+ : typeof args.mode === 'string'
218
+ ? args.mode.trim().toLowerCase().replace(/-/g, '_')
219
+ : '';
220
+ return READ_ONLY_MEMORY_ACTIONS.has(action) ? 'read' : 'write';
221
+ }
222
+ if (toolName === 'computer') {
223
+ const action = typeof args.action === 'string'
224
+ ? args.action.trim().toLowerCase().replace(/-/g, '_')
225
+ : typeof args.mode === 'string'
226
+ ? args.mode.trim().toLowerCase().replace(/-/g, '_')
227
+ : '';
228
+ return READ_ONLY_COMPUTER_ACTIONS.has(action) ? 'read' : 'write';
229
+ }
230
+ if (toolName === 'device') {
231
+ const action = typeof args.action === 'string'
232
+ ? args.action.trim().toLowerCase().replace(/-/g, '_')
233
+ : typeof args.mode === 'string'
234
+ ? args.mode.trim().toLowerCase().replace(/-/g, '_')
235
+ : '';
236
+ return READ_ONLY_DEVICE_ACTIONS.has(action) ? 'read' : 'write';
237
+ }
238
+ if (toolName === 'models') {
239
+ const action = typeof args.action === 'string'
240
+ ? args.action.trim().toLowerCase().replace(/-/g, '_')
241
+ : typeof args.mode === 'string'
242
+ ? args.mode.trim().toLowerCase().replace(/-/g, '_')
243
+ : '';
244
+ return READ_ONLY_MODELS_ACTIONS.has(action) ? 'read' : 'write';
245
+ }
246
+ if (toolName === 'workspace') {
247
+ const action = typeof args.action === 'string'
248
+ ? args.action.trim().toLowerCase().replace(/-/g, '_')
249
+ : typeof args.mode === 'string'
250
+ ? args.mode.trim().toLowerCase().replace(/-/g, '_')
251
+ : '';
252
+ return READ_ONLY_WORKSPACE_ACTIONS.has(action) ? 'read' : 'write';
253
+ }
254
+ if (toolName === 'autonomy') {
255
+ const action = typeof args.action === 'string'
256
+ ? args.action.trim().toLowerCase().replace(/-/g, '_')
257
+ : typeof args.mode === 'string'
258
+ ? args.mode.trim().toLowerCase().replace(/-/g, '_')
259
+ : '';
260
+ return READ_ONLY_AUTONOMY_ACTIONS.has(action) ? 'read' : 'write';
261
+ }
262
+ if (toolName === 'delegation') {
263
+ const action = typeof args.action === 'string'
264
+ ? args.action.trim().toLowerCase().replace(/-/g, '_')
265
+ : typeof args.mode === 'string'
266
+ ? args.mode.trim().toLowerCase().replace(/-/g, '_')
267
+ : '';
268
+ return READ_ONLY_DELEGATION_ACTIONS.has(action) ? 'read' : 'write';
269
+ }
270
+ if (toolName === 'execution') {
271
+ const action = typeof args.action === 'string'
272
+ ? args.action.trim().toLowerCase().replace(/-/g, '_')
273
+ : typeof args.mode === 'string'
274
+ ? args.mode.trim().toLowerCase().replace(/-/g, '_')
275
+ : '';
276
+ return READ_ONLY_EXECUTION_ACTIONS.has(action) ? 'read' : 'write';
277
+ }
278
+ if (toolName === 'agent_artifacts') {
279
+ const mode = typeof args.mode === 'string' ? args.mode.trim() : '';
280
+ return mode === 'list' || mode === 'show' ? 'read' : 'write';
281
+ }
282
+ if (toolName === 'agent_review_packet_presets') {
283
+ const mode = typeof args.mode === 'string' ? args.mode.trim() : '';
284
+ return mode === 'list' || mode === 'show' || mode === '' ? 'read' : 'write';
285
+ }
286
+ return fallbackPermissionCategory(toolName);
287
+ }