actoviq-agent-sdk 0.4.12 → 0.4.13

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 (194) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/src/config/agentDefinitionMigration.d.ts +125 -0
  3. package/dist/src/config/agentDefinitionMigration.d.ts.map +1 -0
  4. package/dist/src/config/agentDefinitionMigration.js +540 -0
  5. package/dist/src/config/agentDefinitionMigration.js.map +1 -0
  6. package/dist/src/config/agentProfiles.d.ts +19 -0
  7. package/dist/src/config/agentProfiles.d.ts.map +1 -1
  8. package/dist/src/config/agentProfiles.js +65 -13
  9. package/dist/src/config/agentProfiles.js.map +1 -1
  10. package/dist/src/config/modelConfigurationCatalog.d.ts +25 -0
  11. package/dist/src/config/modelConfigurationCatalog.d.ts.map +1 -0
  12. package/dist/src/config/modelConfigurationCatalog.js +50 -0
  13. package/dist/src/config/modelConfigurationCatalog.js.map +1 -0
  14. package/dist/src/gui/agentTargetPicker.d.ts +32 -0
  15. package/dist/src/gui/agentTargetPicker.d.ts.map +1 -0
  16. package/dist/src/gui/agentTargetPicker.js +99 -0
  17. package/dist/src/gui/agentTargetPicker.js.map +1 -0
  18. package/dist/src/gui/electronMain.js +1 -0
  19. package/dist/src/gui/electronMain.js.map +1 -1
  20. package/dist/src/gui/hadamardGui.d.ts +23 -0
  21. package/dist/src/gui/hadamardGui.d.ts.map +1 -1
  22. package/dist/src/gui/hadamardGui.js +4120 -931
  23. package/dist/src/gui/hadamardGui.js.map +1 -1
  24. package/dist/src/gui/projectWorkbench.d.ts +6 -2
  25. package/dist/src/gui/projectWorkbench.d.ts.map +1 -1
  26. package/dist/src/gui/projectWorkbench.js +76 -67
  27. package/dist/src/gui/projectWorkbench.js.map +1 -1
  28. package/dist/src/gui/promptTemplates.d.ts +0 -1
  29. package/dist/src/gui/promptTemplates.d.ts.map +1 -1
  30. package/dist/src/gui/promptTemplates.js +0 -3
  31. package/dist/src/gui/promptTemplates.js.map +1 -1
  32. package/dist/src/gui/transcript/clientBundle.d.ts +6 -1
  33. package/dist/src/gui/transcript/clientBundle.d.ts.map +1 -1
  34. package/dist/src/gui/transcript/clientBundle.js +6 -1
  35. package/dist/src/gui/transcript/clientBundle.js.map +1 -1
  36. package/dist/src/help/productCapabilities.d.ts +17 -0
  37. package/dist/src/help/productCapabilities.d.ts.map +1 -0
  38. package/dist/src/help/productCapabilities.js +146 -0
  39. package/dist/src/help/productCapabilities.js.map +1 -0
  40. package/dist/src/index.d.ts +15 -4
  41. package/dist/src/index.d.ts.map +1 -1
  42. package/dist/src/index.js +9 -3
  43. package/dist/src/index.js.map +1 -1
  44. package/dist/src/issues/issueExecution.d.ts.map +1 -1
  45. package/dist/src/issues/issueExecution.js +29 -9
  46. package/dist/src/issues/issueExecution.js.map +1 -1
  47. package/dist/src/manager/assistantGlobalTools.d.ts +44 -0
  48. package/dist/src/manager/assistantGlobalTools.d.ts.map +1 -1
  49. package/dist/src/manager/assistantGlobalTools.js +565 -32
  50. package/dist/src/manager/assistantGlobalTools.js.map +1 -1
  51. package/dist/src/manager/assistantProposals.d.ts +87 -0
  52. package/dist/src/manager/assistantProposals.d.ts.map +1 -0
  53. package/dist/src/manager/assistantProposals.js +207 -0
  54. package/dist/src/manager/assistantProposals.js.map +1 -0
  55. package/dist/src/manager/referenceIndex.d.ts +82 -0
  56. package/dist/src/manager/referenceIndex.d.ts.map +1 -0
  57. package/dist/src/manager/referenceIndex.js +167 -0
  58. package/dist/src/manager/referenceIndex.js.map +1 -0
  59. package/dist/src/manager/referenceOperations.d.ts +108 -0
  60. package/dist/src/manager/referenceOperations.d.ts.map +1 -0
  61. package/dist/src/manager/referenceOperations.js +821 -0
  62. package/dist/src/manager/referenceOperations.js.map +1 -0
  63. package/dist/src/manager/resolveTargetRef.d.ts +67 -0
  64. package/dist/src/manager/resolveTargetRef.d.ts.map +1 -0
  65. package/dist/src/manager/resolveTargetRef.js +81 -0
  66. package/dist/src/manager/resolveTargetRef.js.map +1 -0
  67. package/dist/src/router/modelRouter.d.ts +22 -2
  68. package/dist/src/router/modelRouter.d.ts.map +1 -1
  69. package/dist/src/router/modelRouter.js +76 -9
  70. package/dist/src/router/modelRouter.js.map +1 -1
  71. package/dist/src/runtime/agentClient.d.ts +18 -0
  72. package/dist/src/runtime/agentClient.d.ts.map +1 -1
  73. package/dist/src/runtime/agentClient.js +209 -21
  74. package/dist/src/runtime/agentClient.js.map +1 -1
  75. package/dist/src/runtime/agentSession.d.ts +7 -0
  76. package/dist/src/runtime/agentSession.d.ts.map +1 -1
  77. package/dist/src/runtime/agentSession.js +10 -0
  78. package/dist/src/runtime/agentSession.js.map +1 -1
  79. package/dist/src/runtime/agentTemplates.d.ts +28 -0
  80. package/dist/src/runtime/agentTemplates.d.ts.map +1 -0
  81. package/dist/src/runtime/agentTemplates.js +73 -0
  82. package/dist/src/runtime/agentTemplates.js.map +1 -0
  83. package/dist/src/runtime/conversationEngine.d.ts +2 -0
  84. package/dist/src/runtime/conversationEngine.d.ts.map +1 -1
  85. package/dist/src/runtime/conversationEngine.js +10 -1
  86. package/dist/src/runtime/conversationEngine.js.map +1 -1
  87. package/dist/src/runtime/defaultHadamardAgents.d.ts.map +1 -1
  88. package/dist/src/runtime/defaultHadamardAgents.js +9 -47
  89. package/dist/src/runtime/defaultHadamardAgents.js.map +1 -1
  90. package/dist/src/runtime/effectiveAgentRunOptions.d.ts +49 -0
  91. package/dist/src/runtime/effectiveAgentRunOptions.d.ts.map +1 -0
  92. package/dist/src/runtime/effectiveAgentRunOptions.js +50 -0
  93. package/dist/src/runtime/effectiveAgentRunOptions.js.map +1 -0
  94. package/dist/src/runtime/externalAgentRunner.d.ts +25 -0
  95. package/dist/src/runtime/externalAgentRunner.d.ts.map +1 -0
  96. package/dist/src/runtime/externalAgentRunner.js +57 -0
  97. package/dist/src/runtime/externalAgentRunner.js.map +1 -0
  98. package/dist/src/runtime/hadamardAgentDefinitions.d.ts +15 -0
  99. package/dist/src/runtime/hadamardAgentDefinitions.d.ts.map +1 -1
  100. package/dist/src/runtime/hadamardAgentDefinitions.js +42 -2
  101. package/dist/src/runtime/hadamardAgentDefinitions.js.map +1 -1
  102. package/dist/src/runtime/hadamardAgents.d.ts +6 -0
  103. package/dist/src/runtime/hadamardAgents.d.ts.map +1 -1
  104. package/dist/src/runtime/hadamardAgents.js +52 -1
  105. package/dist/src/runtime/hadamardAgents.js.map +1 -1
  106. package/dist/src/runtime/hadamardPermissions.d.ts +1 -0
  107. package/dist/src/runtime/hadamardPermissions.d.ts.map +1 -1
  108. package/dist/src/runtime/hadamardPermissions.js +6 -0
  109. package/dist/src/runtime/hadamardPermissions.js.map +1 -1
  110. package/dist/src/runtime/tools.d.ts.map +1 -1
  111. package/dist/src/runtime/tools.js +2 -0
  112. package/dist/src/runtime/tools.js.map +1 -1
  113. package/dist/src/team/executorTarget.d.ts +26 -0
  114. package/dist/src/team/executorTarget.d.ts.map +1 -0
  115. package/dist/src/team/executorTarget.js +15 -0
  116. package/dist/src/team/executorTarget.js.map +1 -0
  117. package/dist/src/team/modelTeam.d.ts +5 -1
  118. package/dist/src/team/modelTeam.d.ts.map +1 -1
  119. package/dist/src/team/modelTeam.js +157 -41
  120. package/dist/src/team/modelTeam.js.map +1 -1
  121. package/dist/src/team/teamComposition.d.ts +20 -0
  122. package/dist/src/team/teamComposition.d.ts.map +1 -0
  123. package/dist/src/team/teamComposition.js +78 -0
  124. package/dist/src/team/teamComposition.js.map +1 -0
  125. package/dist/src/team/teamDefinitions.d.ts +10 -1
  126. package/dist/src/team/teamDefinitions.d.ts.map +1 -1
  127. package/dist/src/team/teamDefinitions.js +123 -16
  128. package/dist/src/team/teamDefinitions.js.map +1 -1
  129. package/dist/src/team/teamGraph.d.ts +1 -1
  130. package/dist/src/team/teamGraph.d.ts.map +1 -1
  131. package/dist/src/team/teamGraph.js +1 -1
  132. package/dist/src/team/teamGraph.js.map +1 -1
  133. package/dist/src/team/teamPrompts.d.ts.map +1 -1
  134. package/dist/src/team/teamPrompts.js +0 -4
  135. package/dist/src/team/teamPrompts.js.map +1 -1
  136. package/dist/src/team/teamProposalService.d.ts +9 -1
  137. package/dist/src/team/teamProposalService.d.ts.map +1 -1
  138. package/dist/src/team/teamProposalService.js +66 -6
  139. package/dist/src/team/teamProposalService.js.map +1 -1
  140. package/dist/src/team/teamPropose.d.ts +3 -1
  141. package/dist/src/team/teamPropose.d.ts.map +1 -1
  142. package/dist/src/team/teamPropose.js +16 -10
  143. package/dist/src/team/teamPropose.js.map +1 -1
  144. package/dist/src/team/teamRuntime.d.ts +5 -0
  145. package/dist/src/team/teamRuntime.d.ts.map +1 -1
  146. package/dist/src/team/teamRuntime.js +23 -5
  147. package/dist/src/team/teamRuntime.js.map +1 -1
  148. package/dist/src/team/workflowSquad.d.ts +10 -2
  149. package/dist/src/team/workflowSquad.d.ts.map +1 -1
  150. package/dist/src/team/workflowSquad.js +250 -12
  151. package/dist/src/team/workflowSquad.js.map +1 -1
  152. package/dist/src/tools/enterWorktree.d.ts.map +1 -1
  153. package/dist/src/tools/enterWorktree.js +3 -0
  154. package/dist/src/tools/enterWorktree.js.map +1 -1
  155. package/dist/src/tools/exaSearch.d.ts +2 -2
  156. package/dist/src/tools/exitWorktree.d.ts.map +1 -1
  157. package/dist/src/tools/exitWorktree.js +3 -1
  158. package/dist/src/tools/exitWorktree.js.map +1 -1
  159. package/dist/src/tools/hadamardCoreTools.d.ts +5 -14
  160. package/dist/src/tools/hadamardCoreTools.d.ts.map +1 -1
  161. package/dist/src/tools/hadamardCoreTools.js +31 -0
  162. package/dist/src/tools/hadamardCoreTools.js.map +1 -1
  163. package/dist/src/tools/hadamardFileTools.d.ts.map +1 -1
  164. package/dist/src/tools/hadamardFileTools.js +116 -38
  165. package/dist/src/tools/hadamardFileTools.js.map +1 -1
  166. package/dist/src/tools/planMode/PlanModeTools.js +2 -2
  167. package/dist/src/tools/planMode/PlanModeTools.js.map +1 -1
  168. package/dist/src/tui/hadamardTui.d.ts.map +1 -1
  169. package/dist/src/tui/hadamardTui.js +358 -69
  170. package/dist/src/tui/hadamardTui.js.map +1 -1
  171. package/dist/src/tui/pendingInput.d.ts +17 -0
  172. package/dist/src/tui/pendingInput.d.ts.map +1 -0
  173. package/dist/src/tui/pendingInput.js +23 -0
  174. package/dist/src/tui/pendingInput.js.map +1 -0
  175. package/dist/src/tui/reasoningDisplay.d.ts +13 -0
  176. package/dist/src/tui/reasoningDisplay.d.ts.map +1 -0
  177. package/dist/src/tui/reasoningDisplay.js +45 -0
  178. package/dist/src/tui/reasoningDisplay.js.map +1 -0
  179. package/dist/src/tui/screen.d.ts +11 -1
  180. package/dist/src/tui/screen.d.ts.map +1 -1
  181. package/dist/src/tui/screen.js +64 -34
  182. package/dist/src/tui/screen.js.map +1 -1
  183. package/dist/src/types.d.ts +171 -4
  184. package/dist/src/types.d.ts.map +1 -1
  185. package/dist/src/types.js.map +1 -1
  186. package/dist/src/ui/commandSurface.d.ts +8 -0
  187. package/dist/src/ui/commandSurface.d.ts.map +1 -1
  188. package/dist/src/ui/commandSurface.js +71 -7
  189. package/dist/src/ui/commandSurface.js.map +1 -1
  190. package/package.json +1 -1
  191. package/dist/src/gui/projectSettings.d.ts +0 -2
  192. package/dist/src/gui/projectSettings.d.ts.map +0 -1
  193. package/dist/src/gui/projectSettings.js +0 -2
  194. package/dist/src/gui/projectSettings.js.map +0 -1
@@ -11,11 +11,11 @@ import { access } from 'node:fs/promises';
11
11
  import path from 'node:path';
12
12
  import { z } from 'zod';
13
13
  import { resolveHadamardHome } from '../config/hadamardHome.js';
14
- import { deleteAgentProfile, listAgentProfiles, listSelectableAgents, upsertAgentProfile, } from '../config/agentProfiles.js';
14
+ import { deleteAgentProfile, validateAgentProfile, listAgentProfiles, listSelectableAgents, upsertAgentProfile, } from '../config/agentProfiles.js';
15
15
  import { getHadamardProjectSessionDirectory } from '../config/projectSessionDirectory.js';
16
16
  import { listProjectIssues, isIssueStorageMode, } from '../issues/issueStore.js';
17
17
  import { addMcpServer, readMcpServerConfig, removeMcpServer } from '../mcp/mcpServerConfig.js';
18
- import { addBridgeConfig, findBridgeConfig, readBridgeConfigs, } from '../parity/bridgeConfigs.js';
18
+ import { addBridgeConfig, findBridgeConfig, readBridgeConfigs, removeBridgeConfig, } from '../parity/bridgeConfigs.js';
19
19
  import { deleteRouterProfile, listRouterProfiles, saveRouterProfile, } from '../router/modelRouter.js';
20
20
  import { MANAGED_PLUGIN_IDS, patchManagedPluginSettings, readManagedPluginCatalog, } from '../plugins/managedPluginCatalog.js';
21
21
  import { isRecord } from '../runtime/helpers.js';
@@ -24,8 +24,15 @@ import { listScheduledAutomationTasks, setScheduledAutomationEnabled, upsertSche
24
24
  import { isProjectStatus, readProjectMeta, writeProjectMeta } from '../gui/projectMeta.js';
25
25
  import { readWorkspaceNote, writeWorkspaceNote } from '../gui/workspaceNote.js';
26
26
  import { readWorkspaceRegistry } from '../gui/workspaceRegistry.js';
27
- import { readProgressFile, readProjectPlanFile, } from './projectManager.js';
27
+ import { readManagerConfig, readProgressFile, readProjectPlanFile, } from './projectManager.js';
28
+ import { buildReferenceIndex, findBrokenRefs, findUsages, } from './referenceIndex.js';
29
+ import { renameDefinitionAndReferences, } from './referenceOperations.js';
30
+ import { deleteTeamDefinition, getBuiltInTeamDefinition, listTeamDefinitions, loadTeamDefinition, } from '../team/teamDefinitions.js';
31
+ import { readAllAgentReferenceProfiles, listAgentDefinitionNames, writeAgentDefinitionMarkdown, writeAgentProfileMarkdown, deleteAgentProfileMarkdown, projectAgentDefinitionsDir, } from '../config/agentDefinitionMigration.js';
32
+ import { deleteWorkflow, listWorkflows } from '../workflow/workflowPersistence.js';
28
33
  import { mkdir, readFile, writeFile } from 'node:fs/promises';
34
+ import { loadHadamardAgentDefinitions } from '../runtime/hadamardAgentDefinitions.js';
35
+ import { getProductCapability, productCapabilities, searchProductCapabilities, } from '../help/productCapabilities.js';
29
36
  export function isAssistantScope(value) {
30
37
  return value === 'global' || value === 'project';
31
38
  }
@@ -75,12 +82,19 @@ function redactBridgeConfig(config) {
75
82
  name: config.name,
76
83
  runtime: config.runtime,
77
84
  execution: config.execution ?? 'api',
85
+ authSource: config.authSource ?? (config.execution === 'cli' ? 'native' : 'apiKey'),
86
+ credentialProvider: config.credentialProvider,
87
+ trustProjectResources: config.trustProjectResources === true,
78
88
  provider: config.provider,
79
89
  baseURL: config.baseURL || undefined,
80
90
  model: config.model || undefined,
81
91
  models: (config.models ?? []).map(model => ({
82
92
  name: model.name,
83
93
  context1M: model.context1M === true,
94
+ contextWindowTokens: model.contextWindowTokens,
95
+ maxContextWindowTokens: model.maxContextWindowTokens,
96
+ effectiveContextWindowPercent: model.effectiveContextWindowPercent,
97
+ autoCompactTokenLimit: model.autoCompactTokenLimit,
84
98
  modality: model.modality ?? 'text',
85
99
  })),
86
100
  hasApiKey: Boolean(typeof config.apiKey === 'string' && config.apiKey.trim()),
@@ -100,17 +114,45 @@ function redactRouterProfile(profile) {
100
114
  name: profile.name,
101
115
  description: profile.description,
102
116
  routerModel: redactRouterRef(profile.routerModel),
117
+ routerModelTarget: profile.routerModelTarget,
103
118
  routes: profile.routes.map(route => ({
104
119
  ...redactRouterRef(route),
105
120
  when: route.when,
106
121
  name: route.name,
107
122
  role: route.role,
108
123
  description: route.description,
124
+ effort: route.effort,
125
+ target: route.target,
109
126
  })),
110
127
  fallback: profile.fallback ? redactRouterRef(profile.fallback) : undefined,
128
+ fallbackTarget: profile.fallbackTarget,
111
129
  classificationPrompt: profile.classificationPrompt,
112
130
  };
113
131
  }
132
+ function redactEditorContext(context) {
133
+ if (!context)
134
+ return null;
135
+ const redact = (value) => {
136
+ if (Array.isArray(value))
137
+ return value.map(redact);
138
+ if (!isRecord(value))
139
+ return value;
140
+ const out = {};
141
+ for (const [key, item] of Object.entries(value)) {
142
+ if (/^(apiKey|password|secret|accessToken|refreshToken)$/i.test(key)) {
143
+ out[`${key}Configured`] = Boolean(typeof item === 'string' ? item.trim() : item);
144
+ }
145
+ else {
146
+ out[key] = redact(item);
147
+ }
148
+ }
149
+ return out;
150
+ };
151
+ return {
152
+ ...context,
153
+ ...(context.draft ? { draft: redact(context.draft) } : {}),
154
+ };
155
+ }
114
156
  export async function listAssistantProjectBriefs(homeDir, currentWorkDir) {
115
157
  const current = path.resolve(currentWorkDir);
116
158
  const byPath = new Map();
@@ -176,6 +218,109 @@ async function assertKnownProject(host, projectPath) {
176
218
  }
177
219
  return resolved;
178
220
  }
221
+ /** Reference snapshot used by the P3 reference/delete tools (same edges as /api/references). */
222
+ async function getReferenceSnapshot(host) {
223
+ if (host.getReferenceSnapshot)
224
+ return host.getReferenceSnapshot();
225
+ const bridgeConfigs = readBridgeConfigs(host.homeDir).configs;
226
+ // S3 unified store: profile edges come from the legacy store AND .md
227
+ // definitions in both scopes (incl. bridgeConfig-only definitions).
228
+ const profileByName = new Map(listAgentProfiles(host.homeDir).map(profile => [profile.name, profile]));
229
+ for (const profile of readAllAgentReferenceProfiles(host.homeDir, host.currentWorkDir)) {
230
+ profileByName.set(profile.name, profile);
231
+ }
232
+ const agentProfiles = [...profileByName.values()];
233
+ const routers = listRouterProfiles(host.currentWorkDir, host.homeDir).map(entry => entry.profile);
234
+ const teams = listTeamDefinitions(host.currentWorkDir, host.homeDir).map(entry => entry.definition);
235
+ const automationTasks = await listScheduledAutomationTasks(host.currentWorkDir)
236
+ .catch(() => []);
237
+ const manager = await readManagerConfig(host.currentWorkDir, resolveHadamardHome(host.homeDir))
238
+ .catch(() => undefined);
239
+ const projectMeta = await readProjectMeta(host.currentWorkDir, host.homeDir);
240
+ const issueStorage = isIssueStorageMode(projectMeta.issueStorage)
241
+ ? projectMeta.issueStorage
242
+ : 'home';
243
+ const [issues, assistantConfig] = await Promise.all([
244
+ listProjectIssues(host.currentWorkDir, host.homeDir, issueStorage).catch(() => []),
245
+ readAssistantConfig(host.homeDir),
246
+ ]);
247
+ const workflows = listWorkflows(host.currentWorkDir, host.homeDir);
248
+ const index = buildReferenceIndex({
249
+ bridgeConfigs,
250
+ agentProfiles,
251
+ routers,
252
+ teams,
253
+ automationTasks,
254
+ teamPreferences: host.readTeamPreferences?.() ?? null,
255
+ managerConfigs: manager
256
+ ? [{ name: host.currentWorkDir, bridgeConfig: manager.bridgeConfig }]
257
+ : [],
258
+ issues,
259
+ assistantConfig,
260
+ session: host.getSessionRefState?.() ?? null,
261
+ });
262
+ return {
263
+ index,
264
+ known: {
265
+ configs: bridgeConfigs.map(config => config.name),
266
+ // Selectable agents include ephemeral per-config presets so an active
267
+ // session edge to one of them is not falsely reported as broken; the
268
+ // .md definition names cover unified-store agents in both scopes (S3).
269
+ agents: [
270
+ ...listSelectableAgents(host.homeDir).map(agent => agent.name),
271
+ ...listAgentDefinitionNames(host.homeDir, host.currentWorkDir),
272
+ ],
273
+ teams: teams.map(team => team.name),
274
+ routers: routers.map(router => router.name),
275
+ workflows: workflows.map(workflow => workflow.name),
276
+ },
277
+ };
278
+ }
279
+ async function resolveReferenceOperationContext(host) {
280
+ if (host.referenceOperationContext)
281
+ return host.referenceOperationContext();
282
+ return {
283
+ projectDir: host.currentWorkDir,
284
+ homeDir: host.homeDir,
285
+ managerProjectPath: host.currentWorkDir,
286
+ };
287
+ }
288
+ /**
289
+ * P3 delete discipline: zero-reference deletes proceed immediately; when
290
+ * findUsages reports references the definition is NOT deleted — a proposal
291
+ * card with the reference list and fallback strategies is staged instead, and
292
+ * only Apply (GUI endpoint over AssistantProposalStore) executes the delete.
293
+ */
294
+ async function deleteWithConfirmation(host, kind, name, deleteNow) {
295
+ const { index } = await getReferenceSnapshot(host);
296
+ const usages = findUsages(index, kind, name);
297
+ if (usages.length === 0) {
298
+ await deleteNow();
299
+ return { ok: true, deleted: true, references: [] };
300
+ }
301
+ if (!host.proposals || !host.assistantSessionId) {
302
+ throw new Error(`Refusing to delete ${kind} "${name}": ${usages.length} reference(s) exist and no `
303
+ + 'confirmation channel is available in this host. References: '
304
+ + usages.map(edge => `${edge.from.kind} "${edge.from.name}" (${edge.field})`).join('; '));
305
+ }
306
+ const proposal = host.proposals.stageDelete({
307
+ assistantSessionId: host.assistantSessionId,
308
+ kind,
309
+ name,
310
+ references: usages,
311
+ });
312
+ host.onProposal?.(proposal);
313
+ return {
314
+ ok: true,
315
+ deleted: false,
316
+ staged: true,
317
+ proposalId: proposal.id,
318
+ message: `Found ${usages.length} reference(s) — staged a confirmation card. `
319
+ + `The ${kind} is deleted only after the user applies it.`,
320
+ references: usages,
321
+ strategies: proposal.delete?.strategies ?? [],
322
+ };
323
+ }
179
324
  export function buildAssistantGlobalSystemPrompt(currentWorkDir) {
180
325
  return [
181
326
  'You are the Hadamard desktop Assistant in Global scope.',
@@ -188,6 +333,13 @@ export function buildAssistantGlobalSystemPrompt(currentWorkDir) {
188
333
  '- Start with ListProjects when the user asks about workspaces or status across projects.',
189
334
  '- Use GetProjectOverview / GetProjectDocument / ListProjectIssues for deeper project inspection; always pass an explicit projectPath from ListProjects.',
190
335
  '- Before changing settings, plugins, bridge configs, agents, schedules, or MCP, briefly say what you will change, then call the matching tool.',
336
+ '- Use ListReferences(kind, name) before any rename/delete to show impact, and ListBrokenReferences for proactive health checks.',
337
+ '- Rename tools (RenameBridgeConfig / RenameAgentProfile / RenameRouterProfile / RenameTeam) run one transaction that atomically rewrites every referencing definition.',
338
+ '- Delete-class tools (DeleteBridgeConfig / DeleteAgentProfile / DeleteRouterProfile / DeleteTeam) delete immediately only when nothing references the definition. When references exist they stage a confirmation card with the reference list and fallback strategies; the delete happens only when the user applies that card. Never claim a delete completed while a proposal is pending.',
339
+ '- UpsertTeam and UpsertWorkflow stage proposal cards (Preview/Apply) — they never write to disk directly. DeleteWorkflow removes an unreferenced script workflow directly and refuses while automation tasks still reference it.',
340
+ '- For any question about how to use Hadamard or what a feature does, call SearchProductCapabilities (or List/ReadProductCapability) and ground the answer in its UI location, prerequisites, steps, commands, and limitations. Do not answer product instructions from memory alone.',
341
+ '- Before changing the currently open Agent, Router, Graph, or Workflow, call GetCurrentEditorContext. Preserve its baseDigest when staging a Graph/Workflow proposal so Apply can reject stale drafts.',
342
+ '- ActivateAgent activates a saved profile by default; kind "config" activates a model configuration, kind "router" activates a Router, and kind "team" attaches a Graph or Workflow.',
191
343
  '- Never echo API keys or other secrets. Tool results already redact them.',
192
344
  '- Coding and file edits belong in the main chat, not here. Prefer OpenProject + telling the user to continue in the main conversation when implementation work is needed.',
193
345
  '- Be concise and concrete.',
@@ -201,6 +353,11 @@ export async function createAssistantGlobalTools(host) {
201
353
  apiKey: z.string().optional().describe('$ENV_VAR reference; literal secrets are not persisted'),
202
354
  maxTokens: z.number().int().positive().optional(),
203
355
  });
356
+ const targetRefSchema = z.discriminatedUnion('kind', [
357
+ z.strictObject({ kind: z.literal('model'), config: z.string(), model: z.string() }),
358
+ z.strictObject({ kind: z.literal('agent'), name: z.string() }),
359
+ z.strictObject({ kind: z.literal('team'), name: z.string() }),
360
+ ]);
204
361
  const ListProjects = tool({
205
362
  name: 'ListProjects',
206
363
  description: 'List remembered Hadamard workspaces with brief note, status, and issue counts.',
@@ -302,6 +459,48 @@ export async function createAssistantGlobalTools(host) {
302
459
  homeDir: host.homeDir,
303
460
  ...(host.getAppState ? await host.getAppState() : {}),
304
461
  }));
462
+ const GetCurrentEditorContext = tool({
463
+ name: 'GetCurrentEditorContext',
464
+ description: 'Read the active GUI page/entity and its unsaved Agent, Router, Graph, or Workflow draft with a stable base digest. Use before proposing editor changes.',
465
+ inputSchema: z.strictObject({}),
466
+ isReadOnly: () => true,
467
+ }, async () => ({
468
+ context: redactEditorContext(host.getEditorContext ? await host.getEditorContext() : null),
469
+ }));
470
+ const ListProductCapabilities = tool({
471
+ name: 'ListProductCapabilities',
472
+ description: 'List the machine-readable Hadamard capability catalog. Use this, SearchProductCapabilities, or ReadProductCapability before answering product how-to questions.',
473
+ inputSchema: z.strictObject({}),
474
+ isReadOnly: () => true,
475
+ }, async () => ({
476
+ capabilities: productCapabilities.map(capability => ({
477
+ id: capability.id,
478
+ title: capability.title,
479
+ summary: capability.summary,
480
+ uiLocations: capability.uiLocations,
481
+ commands: capability.commands,
482
+ })),
483
+ }));
484
+ const SearchProductCapabilities = tool({
485
+ name: 'SearchProductCapabilities',
486
+ description: 'Search grounded product instructions by feature, UI label, command, or user goal.',
487
+ inputSchema: z.strictObject({
488
+ query: z.string(),
489
+ limit: z.number().int().min(1).max(50).optional(),
490
+ }),
491
+ isReadOnly: () => true,
492
+ }, async (input) => ({ capabilities: searchProductCapabilities(input.query, input.limit) }));
493
+ const ReadProductCapability = tool({
494
+ name: 'ReadProductCapability',
495
+ description: 'Read complete current instructions for one capability id returned by List/SearchProductCapabilities.',
496
+ inputSchema: z.strictObject({ id: z.string() }),
497
+ isReadOnly: () => true,
498
+ }, async (input) => {
499
+ const capability = getProductCapability(input.id);
500
+ if (!capability)
501
+ throw new Error(`Unknown product capability: ${input.id}`);
502
+ return { capability };
503
+ });
305
504
  const ListBridgeConfigs = tool({
306
505
  name: 'ListBridgeConfigs',
307
506
  description: 'List saved provider/bridge configs (API keys redacted).',
@@ -315,17 +514,43 @@ export async function createAssistantGlobalTools(host) {
315
514
  description: 'List saved agent profiles and selectable auto presets.',
316
515
  inputSchema: z.strictObject({}),
317
516
  isReadOnly: () => true,
318
- }, async () => ({
319
- profiles: listAgentProfiles(host.homeDir),
320
- selectable: listSelectableAgents(host.homeDir).map(agent => ({
321
- name: agent.name,
322
- source: agent.source,
323
- bridgeConfig: agent.bridgeConfig,
324
- model: agent.model,
325
- effort: agent.effort,
326
- ephemeral: agent.ephemeral === true,
327
- })),
328
- }));
517
+ }, async () => {
518
+ const definitions = await loadHadamardAgentDefinitions({
519
+ homeDir: host.homeDir,
520
+ workDir: host.currentWorkDir,
521
+ });
522
+ return {
523
+ profiles: listAgentProfiles(host.homeDir),
524
+ definitions: definitions.map(definition => ({
525
+ name: definition.name,
526
+ description: definition.description,
527
+ source: definition.source,
528
+ sourcePath: definition.sourcePath,
529
+ bridgeConfig: definition.bridgeConfig,
530
+ model: definition.model,
531
+ inheritSessionModel: !definition.bridgeConfig || !definition.model,
532
+ promptMode: definition.promptMode,
533
+ permissionMode: definition.permissionMode,
534
+ effort: definition.effort,
535
+ maxTokens: definition.maxTokens,
536
+ temperature: definition.temperature,
537
+ topP: definition.topP,
538
+ allowedTools: definition.allowedTools,
539
+ workspaceAccess: definition.workspaceAccess,
540
+ maxIterations: definition.maxToolIterations ?? definition.maxTurns,
541
+ timeoutMs: definition.timeoutMs,
542
+ subagent: definition.subagent !== false,
543
+ })),
544
+ selectable: listSelectableAgents(host.homeDir).map(agent => ({
545
+ name: agent.name,
546
+ source: agent.source,
547
+ bridgeConfig: agent.bridgeConfig,
548
+ model: agent.model,
549
+ effort: agent.effort,
550
+ ephemeral: agent.ephemeral === true,
551
+ })),
552
+ };
553
+ });
329
554
  const ListRouterProfilesTool = tool({
330
555
  name: 'ListRouterProfiles',
331
556
  description: 'List project and personal router profiles with API keys redacted.',
@@ -446,6 +671,8 @@ export async function createAssistantGlobalTools(host) {
446
671
  showProviderConfigsInComposer: z.boolean().optional(),
447
672
  showAgentProfilesInComposer: z.boolean().optional(),
448
673
  showRouterProfilesInComposer: z.boolean().optional(),
674
+ useDefaultModelAsFallback: z.boolean().optional(),
675
+ showBuiltInSubagents: z.boolean().optional(),
449
676
  }),
450
677
  }, async (input) => {
451
678
  if (!host.applySettings)
@@ -482,6 +709,9 @@ export async function createAssistantGlobalTools(host) {
482
709
  name: z.string(),
483
710
  runtime: z.enum(['hadamard', 'claude', 'codewhale', 'pi', 'codex', 'reasonix', 'crush']),
484
711
  execution: z.enum(['api', 'cli']).optional(),
712
+ authSource: z.enum(['native', 'apiKey']).optional(),
713
+ credentialProvider: z.string().optional(),
714
+ trustProjectResources: z.boolean().optional(),
485
715
  provider: z.enum(['anthropic', 'openai']).optional(),
486
716
  baseURL: z.string().optional(),
487
717
  apiKey: z.string().optional(),
@@ -489,6 +719,10 @@ export async function createAssistantGlobalTools(host) {
489
719
  models: z.array(z.strictObject({
490
720
  name: z.string(),
491
721
  context1M: z.boolean().optional(),
722
+ contextWindowTokens: z.number().int().positive().optional(),
723
+ maxContextWindowTokens: z.number().int().positive().optional(),
724
+ effectiveContextWindowPercent: z.number().positive().max(100).optional(),
725
+ autoCompactTokenLimit: z.number().int().positive().optional(),
492
726
  modality: z.enum(['text', 'multimodal']).optional(),
493
727
  })).optional(),
494
728
  }),
@@ -498,6 +732,9 @@ export async function createAssistantGlobalTools(host) {
498
732
  name: input.name.trim(),
499
733
  runtime: input.runtime,
500
734
  execution: input.execution ?? existing?.execution ?? 'api',
735
+ authSource: input.authSource ?? existing?.authSource,
736
+ credentialProvider: input.credentialProvider?.trim() || existing?.credentialProvider,
737
+ trustProjectResources: input.trustProjectResources ?? existing?.trustProjectResources,
501
738
  provider: input.provider ?? existing?.provider ?? 'anthropic',
502
739
  baseURL: input.baseURL?.trim() || existing?.baseURL,
503
740
  apiKey: input.apiKey?.trim() || existing?.apiKey,
@@ -509,34 +746,83 @@ export async function createAssistantGlobalTools(host) {
509
746
  });
510
747
  const UpsertAgentProfileTool = tool({
511
748
  name: 'UpsertAgentProfile',
512
- description: 'Create or update a saved agent profile.',
749
+ description: 'Create or update an agent (unified .md store, S3). Omit bridgeConfig+model for an inherit-session-model agent; pass scope "project" to save into <workDir>/.hadamard/agents.',
513
750
  inputSchema: z.strictObject({
514
751
  name: z.string(),
515
- bridgeConfig: z.string(),
516
- model: z.string(),
752
+ bridgeConfig: z.string().optional().describe('Omit (with model) for an inherit-session-model agent'),
753
+ model: z.string().optional(),
517
754
  description: z.string().optional(),
518
755
  permissionMode: z.enum(['default', 'acceptEdits', 'bypassPermissions', 'plan', 'auto']).optional(),
519
756
  effort: z.enum(['auto', 'low', 'medium', 'high', 'max']).optional(),
520
757
  maxTokens: z.number().int().positive().optional(),
521
758
  temperature: z.number().min(0).max(2).optional(),
522
759
  topP: z.number().min(0).max(1).optional(),
760
+ allowedTools: z.array(z.string().min(1)).optional(),
761
+ workspaceAccess: z.enum(['workspace', 'full']).optional(),
762
+ maxIterations: z.number().int().positive().optional(),
763
+ timeoutMs: z.number().int().positive().optional(),
523
764
  systemPromptAppend: z.string().optional(),
765
+ scope: z.enum(['project', 'personal']).optional().describe('Defaults to personal (~/.hadamard/agents)'),
766
+ promptMode: z.enum(['extend', 'replace']).optional(),
767
+ subagent: z.boolean().optional().describe('Default true: the Agent/Task tool may delegate to this agent'),
524
768
  }),
525
769
  }, async (input) => {
770
+ const inheritModel = !input.bridgeConfig?.trim() || !input.model?.trim();
771
+ const extras = {
772
+ ...(input.promptMode ? { promptMode: input.promptMode } : {}),
773
+ ...(typeof input.subagent === 'boolean' ? { subagent: input.subagent } : {}),
774
+ ...(input.permissionMode ? { permissionMode: input.permissionMode } : {}),
775
+ ...(input.effort ? { effort: input.effort } : {}),
776
+ ...(typeof input.maxTokens === 'number' ? { maxTokens: input.maxTokens } : {}),
777
+ ...(typeof input.temperature === 'number' ? { temperature: input.temperature } : {}),
778
+ ...(typeof input.topP === 'number' ? { topP: input.topP } : {}),
779
+ ...(input.allowedTools?.length ? { tools: input.allowedTools } : {}),
780
+ ...(input.workspaceAccess ? { workspaceAccess: input.workspaceAccess } : {}),
781
+ ...(typeof input.maxIterations === 'number' ? { maxIterations: input.maxIterations } : {}),
782
+ ...(typeof input.timeoutMs === 'number' ? { timeoutMs: input.timeoutMs } : {}),
783
+ };
784
+ const scope = input.scope === 'project' ? 'project' : 'personal';
785
+ const unified = inheritModel || scope === 'project' || Object.keys(extras).length > 0;
526
786
  const profile = {
527
787
  name: input.name.trim(),
528
- bridgeConfig: input.bridgeConfig.trim(),
529
- model: input.model.trim(),
788
+ bridgeConfig: input.bridgeConfig?.trim() ?? '',
789
+ model: input.model?.trim() ?? '',
530
790
  ...(input.description ? { description: input.description } : {}),
531
791
  ...(input.permissionMode ? { permissionMode: input.permissionMode } : {}),
532
792
  ...(input.effort ? { effort: input.effort } : {}),
533
793
  ...(typeof input.maxTokens === 'number' ? { maxTokens: input.maxTokens } : {}),
534
794
  ...(typeof input.temperature === 'number' ? { temperature: input.temperature } : {}),
535
795
  ...(typeof input.topP === 'number' ? { topP: input.topP } : {}),
796
+ ...(input.allowedTools?.length ? { allowedTools: input.allowedTools } : {}),
797
+ ...(input.workspaceAccess ? { workspaceAccess: input.workspaceAccess } : {}),
798
+ ...(typeof input.maxIterations === 'number' ? { maxIterations: input.maxIterations } : {}),
799
+ ...(typeof input.timeoutMs === 'number' ? { timeoutMs: input.timeoutMs } : {}),
536
800
  ...(input.systemPromptAppend ? { systemPromptAppend: input.systemPromptAppend } : {}),
801
+ ...(input.promptMode ? { promptMode: input.promptMode } : {}),
802
+ ...(typeof input.subagent === 'boolean' ? { subagent: input.subagent } : {}),
537
803
  };
538
- const saved = upsertAgentProfile(profile, host.homeDir);
539
- return { ok: true, profile: saved.profile, warnings: saved.warnings };
804
+ if (!unified) {
805
+ const saved = upsertAgentProfile(profile, host.homeDir);
806
+ return { ok: true, profile: saved.profile, warnings: saved.warnings };
807
+ }
808
+ if (!/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/.test(profile.name)) {
809
+ throw new Error('Invalid agent name (use letters, digits, . _ -)');
810
+ }
811
+ const directory = scope === 'project' ? projectAgentDefinitionsDir(host.currentWorkDir) : undefined;
812
+ if (inheritModel) {
813
+ const filePath = writeAgentDefinitionMarkdown({
814
+ name: profile.name,
815
+ description: profile.description,
816
+ body: profile.systemPromptAppend,
817
+ extras,
818
+ directory,
819
+ homeDir: host.homeDir,
820
+ });
821
+ return { ok: true, filePath, inheritSessionModel: true };
822
+ }
823
+ const validation = validateAgentProfile(profile, host.homeDir);
824
+ const filePath = writeAgentProfileMarkdown(validation.profile, host.homeDir, { directory, extras });
825
+ return { ok: true, filePath, profile: validation.profile, warnings: validation.warnings };
540
826
  });
541
827
  const UpsertRouterProfileTool = tool({
542
828
  name: 'UpsertRouterProfile',
@@ -546,6 +832,7 @@ export async function createAssistantGlobalTools(host) {
546
832
  scope: z.enum(['project', 'personal']).optional(),
547
833
  description: z.string().optional(),
548
834
  routerModel: routerRefSchema,
835
+ routerModelTarget: targetRefSchema.optional(),
549
836
  routes: z.array(z.strictObject({
550
837
  model: z.string(),
551
838
  provider: z.enum(['anthropic', 'openai']).optional(),
@@ -556,8 +843,11 @@ export async function createAssistantGlobalTools(host) {
556
843
  name: z.string().optional(),
557
844
  role: z.string().optional(),
558
845
  description: z.string().optional(),
846
+ effort: z.enum(['auto', 'low', 'medium', 'high', 'max']).optional(),
847
+ target: targetRefSchema.optional(),
559
848
  })).min(1),
560
849
  fallback: routerRefSchema.optional(),
850
+ fallbackTarget: targetRefSchema.optional(),
561
851
  classificationPrompt: z.string().optional(),
562
852
  }),
563
853
  }, async (input) => {
@@ -565,8 +855,10 @@ export async function createAssistantGlobalTools(host) {
565
855
  name: input.name.trim(),
566
856
  ...(input.description?.trim() ? { description: input.description.trim() } : {}),
567
857
  routerModel: input.routerModel,
858
+ ...(input.routerModelTarget ? { routerModelTarget: input.routerModelTarget } : {}),
568
859
  routes: input.routes,
569
860
  ...(input.fallback ? { fallback: input.fallback } : {}),
861
+ ...(input.fallbackTarget ? { fallbackTarget: input.fallbackTarget } : {}),
570
862
  ...(input.classificationPrompt?.trim()
571
863
  ? { classificationPrompt: input.classificationPrompt.trim() }
572
864
  : {}),
@@ -580,31 +872,110 @@ export async function createAssistantGlobalTools(host) {
580
872
  });
581
873
  const DeleteRouterProfileTool = tool({
582
874
  name: 'DeleteRouterProfile',
583
- description: 'Delete a router profile by name. Optionally constrain deletion to project or personal scope.',
875
+ description: 'Delete a router profile by name. Deletes directly when unreferenced; stages a confirmation card when references exist.',
584
876
  inputSchema: z.strictObject({
585
877
  name: z.string(),
586
878
  scope: z.enum(['project', 'personal']).optional(),
587
879
  }),
588
880
  }, async (input) => {
589
- const deleted = await deleteRouterProfile(input.name.trim(), input.scope === 'personal' ? undefined : host.currentWorkDir, host.homeDir);
590
- return { ok: true, deleted };
881
+ const name = input.name.trim();
882
+ return deleteWithConfirmation(host, 'router', name, async () => {
883
+ const deleted = await deleteRouterProfile(name, input.scope === 'personal' ? undefined : host.currentWorkDir, host.homeDir);
884
+ return { deleted };
885
+ });
591
886
  });
592
887
  const DeleteAgentProfileTool = tool({
593
888
  name: 'DeleteAgentProfile',
594
- description: 'Delete a saved agent profile by name.',
889
+ description: 'Delete an agent by name (profile or pure .md definition, either scope — S3 unified store). Deletes directly when unreferenced; stages a confirmation card when references exist.',
890
+ inputSchema: z.strictObject({ name: z.string() }),
891
+ }, async (input) => {
892
+ const name = input.name.trim();
893
+ return deleteWithConfirmation(host, 'agent', name, () => {
894
+ deleteAgentProfile(name, host.homeDir);
895
+ // Pure .md agents / project scope are not in the legacy store.
896
+ deleteAgentProfileMarkdown(name, host.homeDir, projectAgentDefinitionsDir(host.currentWorkDir));
897
+ return { deleted: true };
898
+ });
899
+ });
900
+ const DeleteBridgeConfigTool = tool({
901
+ name: 'DeleteBridgeConfig',
902
+ description: 'Delete a provider/bridge config by name. Deletes directly when unreferenced; stages a confirmation card when references exist.',
595
903
  inputSchema: z.strictObject({ name: z.string() }),
596
904
  }, async (input) => {
597
- deleteAgentProfile(input.name.trim(), host.homeDir);
598
- return { ok: true };
905
+ const name = input.name.trim();
906
+ if (!findBridgeConfig(name, host.homeDir)) {
907
+ throw new Error(`Bridge config not found: ${name}`);
908
+ }
909
+ return deleteWithConfirmation(host, 'config', name, () => {
910
+ removeBridgeConfig(name, host.homeDir);
911
+ return { deleted: true };
912
+ });
913
+ });
914
+ const DeleteTeamTool = tool({
915
+ name: 'DeleteTeam',
916
+ description: 'Delete a Team definition by name. Built-in Teams cannot be deleted. Deletes directly when unreferenced; stages a confirmation card when references exist.',
917
+ inputSchema: z.strictObject({ name: z.string() }),
918
+ }, async (input) => {
919
+ const name = input.name.trim();
920
+ if (getBuiltInTeamDefinition(name)) {
921
+ throw new Error(`"${name}" is a built-in Team and cannot be deleted. Clone it instead.`);
922
+ }
923
+ const loaded = loadTeamDefinition(name, host.currentWorkDir, host.homeDir);
924
+ if (!loaded)
925
+ throw new Error(`Team not found: ${name}`);
926
+ return deleteWithConfirmation(host, 'team', name, async () => {
927
+ const deleted = await deleteTeamDefinition(name, host.currentWorkDir, host.homeDir);
928
+ if (!deleted)
929
+ throw new Error(`Team not found: ${name}`);
930
+ return { deleted: true };
931
+ });
599
932
  });
600
933
  const ActivateAgentTool = tool({
601
934
  name: 'ActivateAgent',
602
- description: 'Activate a selectable agent / profile in the current chat.',
603
- inputSchema: z.strictObject({ name: z.string() }),
935
+ description: 'Activate a saved Agent/profile, provider config, Router, Graph, or Workflow in the current chat.',
936
+ inputSchema: z.strictObject({
937
+ name: z.string(),
938
+ kind: z.enum(['profile', 'config', 'router', 'team']).optional()
939
+ .describe('Defaults to "profile" (saved agent / selectable preset)'),
940
+ }),
604
941
  }, async (input) => {
605
- if (!host.activateAgent)
606
- throw new Error('ActivateAgent is unavailable in this host.');
607
- return host.activateAgent(input.name.trim());
942
+ const kind = input.kind ?? 'profile';
943
+ if (kind === 'profile') {
944
+ if (!host.activateAgent)
945
+ throw new Error('ActivateAgent is unavailable in this host.');
946
+ return host.activateAgent(input.name.trim());
947
+ }
948
+ if (!host.activateTarget) {
949
+ throw new Error('ActivateAgent router/team activation is unavailable in this host.');
950
+ }
951
+ return host.activateTarget(kind, input.name.trim());
952
+ });
953
+ const UpdateTeamPreferencesTool = tool({
954
+ name: 'UpdateTeamPreferences',
955
+ description: 'Update Agents-page team behavior: automatic invocation, default attached Graph/Workflow, and confirmation before runs.',
956
+ inputSchema: z.strictObject({
957
+ autoInvoke: z.boolean().optional(),
958
+ defaultAttached: z.string().nullable().optional(),
959
+ confirmBeforeRun: z.boolean().optional(),
960
+ }),
961
+ }, async (input) => {
962
+ if (!host.writeTeamPreferences)
963
+ throw new Error('UpdateTeamPreferences is unavailable in this host.');
964
+ const current = host.readTeamPreferences?.() ?? {
965
+ autoInvoke: false,
966
+ defaultAttached: null,
967
+ confirmBeforeRun: true,
968
+ };
969
+ const next = {
970
+ autoInvoke: input.autoInvoke ?? current.autoInvoke,
971
+ defaultAttached: input.defaultAttached === undefined ? current.defaultAttached : input.defaultAttached,
972
+ confirmBeforeRun: input.confirmBeforeRun ?? current.confirmBeforeRun,
973
+ };
974
+ if (next.defaultAttached && !loadTeamDefinition(next.defaultAttached, host.currentWorkDir, host.homeDir)) {
975
+ throw new Error(`Graph/Workflow not found: ${next.defaultAttached}`);
976
+ }
977
+ await host.writeTeamPreferences(next);
978
+ return { ok: true, preferences: next };
608
979
  });
609
980
  const UpdateManagedPlugin = tool({
610
981
  name: 'UpdateManagedPlugin',
@@ -729,12 +1100,162 @@ export async function createAssistantGlobalTools(host) {
729
1100
  removeMcpServer(input.name.trim(), host.homeDir);
730
1101
  return { ok: true, servers: readMcpServerConfig(host.homeDir).servers };
731
1102
  });
1103
+ const ListReferencesTool = tool({
1104
+ name: 'ListReferences',
1105
+ description: 'List every reference to a definition (kind: config|agent|team|router) — impact analysis before rename/delete.',
1106
+ inputSchema: z.strictObject({
1107
+ kind: z.enum(['config', 'agent', 'team', 'router']),
1108
+ name: z.string(),
1109
+ }),
1110
+ isReadOnly: () => true,
1111
+ }, async (input) => {
1112
+ const { index } = await getReferenceSnapshot(host);
1113
+ const references = findUsages(index, input.kind, input.name.trim());
1114
+ return { kind: input.kind, name: input.name.trim(), count: references.length, references };
1115
+ });
1116
+ const ListBrokenReferencesTool = tool({
1117
+ name: 'ListBrokenReferences',
1118
+ description: 'List references whose target no longer exists (proactive health check).',
1119
+ inputSchema: z.strictObject({}),
1120
+ isReadOnly: () => true,
1121
+ }, async () => {
1122
+ const { index, known } = await getReferenceSnapshot(host);
1123
+ const broken = findBrokenRefs(index, known);
1124
+ return { count: broken.length, broken };
1125
+ });
1126
+ const makeRenameTool = (kind, toolName, label) => tool({
1127
+ name: toolName,
1128
+ description: `Rename a ${label} and atomically rewrite every referencing definition (single transaction with rollback).`,
1129
+ inputSchema: z.strictObject({
1130
+ oldName: z.string(),
1131
+ newName: z.string(),
1132
+ }),
1133
+ }, async (input) => {
1134
+ const report = await renameDefinitionAndReferences(kind, input.oldName, input.newName, await resolveReferenceOperationContext(host));
1135
+ return {
1136
+ ok: true,
1137
+ kind,
1138
+ oldName: input.oldName.trim(),
1139
+ newName: input.newName.trim(),
1140
+ rewritten: report.rewritten,
1141
+ };
1142
+ });
1143
+ const RenameBridgeConfigTool = makeRenameTool('config', 'RenameBridgeConfig', 'provider/bridge config');
1144
+ const RenameAgentProfileTool = makeRenameTool('agent', 'RenameAgentProfile', 'agent profile');
1145
+ const RenameRouterProfileTool = makeRenameTool('router', 'RenameRouterProfile', 'router profile');
1146
+ const RenameTeamTool = makeRenameTool('team', 'RenameTeam', 'Team definition');
1147
+ const UpsertTeamTool = tool({
1148
+ name: 'UpsertTeam',
1149
+ description: 'Stage a Team definition create/update as a proposal card (Preview/Apply). Never writes to disk directly; built-in Teams cannot be overwritten.',
1150
+ inputSchema: z.strictObject({
1151
+ projectPath: z.string().optional().describe('Defaults to the current workspace'),
1152
+ definition: z.record(z.string(), z.unknown())
1153
+ .describe('Complete TeamDefinition JSON, preferably graph v3 with stable node ids'),
1154
+ baseDigest: z.string().optional().describe('Digest from GetCurrentEditorContext; required automatically when changing the active unsaved Graph/Workflow draft'),
1155
+ explanation: z.string().optional(),
1156
+ }),
1157
+ }, async (input) => {
1158
+ if (!host.teamProposals || !host.assistantSessionId) {
1159
+ throw new Error('UpsertTeam is unavailable in this host (no Team proposal store).');
1160
+ }
1161
+ const projectPath = input.projectPath?.trim()
1162
+ ? await assertKnownProject(host, input.projectPath)
1163
+ : path.resolve(host.currentWorkDir);
1164
+ const editor = host.getEditorContext ? await host.getEditorContext() : null;
1165
+ const definition = input.definition;
1166
+ const editorMatches = editor
1167
+ && (editor.entityKind === 'graph' || editor.entityKind === 'workflow')
1168
+ && editor.entityName === definition.name
1169
+ && editor.draft
1170
+ && editor.baseDigest;
1171
+ if (editorMatches && input.baseDigest && input.baseDigest !== editor.baseDigest) {
1172
+ throw new Error('The supplied editor base digest is stale. Read GetCurrentEditorContext and propose the change again.');
1173
+ }
1174
+ const proposal = host.teamProposals.stage({
1175
+ assistantSessionId: host.assistantSessionId,
1176
+ projectPath,
1177
+ definition,
1178
+ explanation: input.explanation ?? '',
1179
+ homeDir: host.homeDir,
1180
+ ...(editorMatches ? {
1181
+ baseDefinition: editor.draft,
1182
+ editorBaseDigest: editor.baseDigest,
1183
+ } : {}),
1184
+ });
1185
+ host.onTeamProposal?.(proposal);
1186
+ return {
1187
+ kind: 'team.proposal',
1188
+ proposalId: proposal.id,
1189
+ projectPath: proposal.projectPath,
1190
+ teamName: proposal.teamName,
1191
+ explanation: proposal.explanation,
1192
+ problems: proposal.problems,
1193
+ diff: proposal.diff,
1194
+ status: proposal.status,
1195
+ };
1196
+ });
1197
+ const UpsertWorkflowTool = tool({
1198
+ name: 'UpsertWorkflow',
1199
+ description: 'Stage a script workflow create/update as a confirmation card. Apply writes <name>.js into the project or personal workflows directory.',
1200
+ inputSchema: z.strictObject({
1201
+ name: z.string(),
1202
+ script: z.string().describe('Complete workflow script (export const meta = {...} required)'),
1203
+ scope: z.enum(['project', 'personal']).optional().describe('Defaults to project'),
1204
+ description: z.string().optional(),
1205
+ explanation: z.string().optional(),
1206
+ }),
1207
+ }, async (input) => {
1208
+ if (!host.proposals || !host.assistantSessionId) {
1209
+ throw new Error('UpsertWorkflow is unavailable in this host (no proposal store).');
1210
+ }
1211
+ const proposal = host.proposals.stageWorkflowUpsert({
1212
+ assistantSessionId: host.assistantSessionId,
1213
+ name: input.name,
1214
+ script: input.script,
1215
+ scope: input.scope ?? 'project',
1216
+ projectPath: path.resolve(host.currentWorkDir),
1217
+ description: input.description,
1218
+ explanation: input.explanation,
1219
+ });
1220
+ host.onProposal?.(proposal);
1221
+ return {
1222
+ ok: true,
1223
+ staged: true,
1224
+ proposalId: proposal.id,
1225
+ name: proposal.workflow?.name,
1226
+ problems: proposal.workflow?.problems ?? [],
1227
+ message: 'Staged a confirmation card. The workflow file is written only after the user applies it.',
1228
+ };
1229
+ });
1230
+ const DeleteWorkflowTool = tool({
1231
+ name: 'DeleteWorkflow',
1232
+ description: 'Delete a script workflow by name. Refuses while automation tasks still reference it.',
1233
+ inputSchema: z.strictObject({ name: z.string() }),
1234
+ }, async (input) => {
1235
+ const name = input.name.trim();
1236
+ if (!listWorkflows(host.currentWorkDir, host.homeDir).some(workflow => workflow.name === name)) {
1237
+ throw new Error(`Workflow not found: ${name}`);
1238
+ }
1239
+ const tasks = await listScheduledAutomationTasks(host.currentWorkDir)
1240
+ .catch(() => []);
1241
+ const referencing = tasks.filter(task => task.kind === 'workflow' && task.workflowSource !== 'agent' && task.workflowName === name);
1242
+ if (referencing.length) {
1243
+ throw new Error(`Refusing to delete workflow "${name}": referenced by automation task(s): `
1244
+ + `${referencing.map(task => task.name || task.id).join(', ')}. Delete or re-point those tasks first.`);
1245
+ }
1246
+ const deleted = await deleteWorkflow(name, host.currentWorkDir, host.homeDir);
1247
+ return { ok: true, deleted };
1248
+ });
732
1249
  return [
733
1250
  ListProjects,
734
1251
  GetProjectOverview,
735
1252
  GetProjectDocument,
736
1253
  ListProjectIssues,
737
1254
  GetAppState,
1255
+ GetCurrentEditorContext,
1256
+ ListProductCapabilities,
1257
+ SearchProductCapabilities,
1258
+ ReadProductCapability,
738
1259
  ListBridgeConfigs,
739
1260
  ListAgentProfiles,
740
1261
  ListRouterProfilesTool,
@@ -752,11 +1273,23 @@ export async function createAssistantGlobalTools(host) {
752
1273
  UpsertRouterProfileTool,
753
1274
  DeleteRouterProfileTool,
754
1275
  ActivateAgentTool,
1276
+ UpdateTeamPreferencesTool,
755
1277
  UpdateManagedPlugin,
756
1278
  UpsertScheduledTask,
757
1279
  ToggleScheduledTask,
758
1280
  AddMcpServerTool,
759
1281
  RemoveMcpServerTool,
1282
+ ListReferencesTool,
1283
+ ListBrokenReferencesTool,
1284
+ RenameBridgeConfigTool,
1285
+ RenameAgentProfileTool,
1286
+ RenameRouterProfileTool,
1287
+ RenameTeamTool,
1288
+ DeleteBridgeConfigTool,
1289
+ DeleteTeamTool,
1290
+ UpsertTeamTool,
1291
+ UpsertWorkflowTool,
1292
+ DeleteWorkflowTool,
760
1293
  ];
761
1294
  }
762
1295
  //# sourceMappingURL=assistantGlobalTools.js.map