stageflow 0.35.0 → 0.39.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 (320) hide show
  1. package/README.md +18 -8
  2. package/dist/agent/claudeAdapter.js +12 -0
  3. package/dist/agent/piAdapter.d.ts +9 -1
  4. package/dist/agent/piAdapter.js +30 -2
  5. package/dist/agent/piIsolatedMcp.js +14 -2
  6. package/dist/agent/piIsolatedMcpProbe.d.ts +5 -1
  7. package/dist/agent/piIsolatedMcpProbe.js +16 -30
  8. package/dist/agent/port.d.ts +7 -0
  9. package/dist/agents/agentId.d.ts +8 -0
  10. package/dist/agents/agentId.js +27 -0
  11. package/dist/agents/approvalBroker.d.ts +16 -0
  12. package/dist/agents/approvalBroker.js +45 -0
  13. package/dist/agents/authorChat.d.ts +19 -0
  14. package/dist/agents/authorChat.js +63 -0
  15. package/dist/agents/chatTurn.d.ts +23 -0
  16. package/dist/agents/chatTurn.js +77 -0
  17. package/dist/agents/communications/agentmail.d.ts +19 -0
  18. package/dist/agents/communications/agentmail.js +46 -0
  19. package/dist/agents/communications/agentmailListener.d.ts +59 -0
  20. package/dist/agents/communications/agentmailListener.js +183 -0
  21. package/dist/agents/communications/allowlist.d.ts +10 -0
  22. package/dist/agents/communications/allowlist.js +36 -0
  23. package/dist/agents/communications/channelConnections.d.ts +3 -0
  24. package/dist/agents/communications/channelConnections.js +51 -0
  25. package/dist/agents/communications/delivery.d.ts +53 -0
  26. package/dist/agents/communications/delivery.js +142 -0
  27. package/dist/agents/communications/email.d.ts +26 -0
  28. package/dist/agents/communications/email.js +20 -0
  29. package/dist/agents/communications/identity.d.ts +13 -0
  30. package/dist/agents/communications/identity.js +18 -0
  31. package/dist/agents/communications/imessageListener.d.ts +41 -0
  32. package/dist/agents/communications/imessageListener.js +92 -0
  33. package/dist/agents/communications/inbound.d.ts +63 -0
  34. package/dist/agents/communications/inbound.js +143 -0
  35. package/dist/agents/communications/listener.d.ts +36 -0
  36. package/dist/agents/communications/listener.js +38 -0
  37. package/dist/agents/communications/photon.d.ts +19 -0
  38. package/dist/agents/communications/photon.js +38 -0
  39. package/dist/agents/communications/port.d.ts +27 -0
  40. package/dist/agents/communications/port.js +6 -0
  41. package/dist/agents/communications/slack.d.ts +28 -0
  42. package/dist/agents/communications/slack.js +65 -0
  43. package/dist/agents/communications/supervisor.d.ts +36 -0
  44. package/dist/agents/communications/supervisor.js +96 -0
  45. package/dist/agents/communications/telegram.d.ts +19 -0
  46. package/dist/agents/communications/telegram.js +52 -0
  47. package/dist/agents/definitionSummary.d.ts +13 -0
  48. package/dist/agents/definitionSummary.js +91 -0
  49. package/dist/agents/delegate.d.ts +3 -0
  50. package/dist/agents/delegate.js +8 -0
  51. package/dist/agents/errors.d.ts +10 -0
  52. package/dist/agents/errors.js +32 -0
  53. package/dist/agents/guardrails.d.ts +24 -0
  54. package/dist/agents/guardrails.js +39 -0
  55. package/dist/agents/historyFit.d.ts +10 -0
  56. package/dist/agents/historyFit.js +26 -0
  57. package/dist/agents/hostContext.d.ts +54 -0
  58. package/dist/agents/hostContext.js +156 -0
  59. package/dist/agents/ledgers.d.ts +29 -0
  60. package/dist/agents/ledgers.js +31 -0
  61. package/dist/agents/lineDiff.d.ts +12 -0
  62. package/dist/agents/lineDiff.js +46 -0
  63. package/dist/agents/ndjson.d.ts +9 -0
  64. package/dist/agents/ndjson.js +47 -0
  65. package/dist/agents/otlpExport.d.ts +9 -0
  66. package/dist/agents/otlpExport.js +58 -0
  67. package/dist/agents/otlpSink.d.ts +7 -0
  68. package/dist/agents/otlpSink.js +23 -0
  69. package/dist/agents/policy.d.ts +31 -0
  70. package/dist/agents/policy.js +84 -0
  71. package/dist/agents/projectRoot.d.ts +5 -0
  72. package/dist/agents/projectRoot.js +15 -0
  73. package/dist/agents/runtime/piRuntime.d.ts +52 -0
  74. package/dist/agents/runtime/piRuntime.js +474 -0
  75. package/dist/agents/runtime/types.d.ts +77 -0
  76. package/dist/agents/runtime/types.js +26 -0
  77. package/dist/agents/sandbox.d.ts +17 -0
  78. package/dist/agents/sandbox.js +10 -0
  79. package/dist/agents/scheduleSource.d.ts +32 -0
  80. package/dist/agents/scheduleSource.js +100 -0
  81. package/dist/agents/service.d.ts +298 -0
  82. package/dist/agents/service.js +1105 -0
  83. package/dist/agents/sessions.d.ts +38 -0
  84. package/dist/agents/sessions.js +321 -0
  85. package/dist/agents/store.d.ts +277 -0
  86. package/dist/agents/store.js +643 -0
  87. package/dist/agents/trace.d.ts +27 -0
  88. package/dist/agents/trace.js +29 -0
  89. package/dist/agents/turnLifecycle.d.ts +72 -0
  90. package/dist/agents/turnLifecycle.js +157 -0
  91. package/dist/agents/webChat/publicChat.d.ts +36 -0
  92. package/dist/agents/webChat/publicChat.js +290 -0
  93. package/dist/agents/webChat/rateLimit.d.ts +15 -0
  94. package/dist/agents/webChat/rateLimit.js +33 -0
  95. package/dist/agents/webChat/slug.d.ts +2 -0
  96. package/dist/agents/webChat/slug.js +9 -0
  97. package/dist/channels/config.d.ts +11 -0
  98. package/dist/channels/config.js +95 -0
  99. package/dist/channels/configWriter.d.ts +40 -0
  100. package/dist/channels/configWriter.js +148 -0
  101. package/dist/channels/connectionEdits.d.ts +34 -0
  102. package/dist/channels/connectionEdits.js +53 -0
  103. package/dist/channels/errorInfo.d.ts +18 -0
  104. package/dist/channels/errorInfo.js +71 -0
  105. package/dist/channels/errors.d.ts +12 -0
  106. package/dist/channels/errors.js +13 -0
  107. package/dist/channels/health.d.ts +41 -0
  108. package/dist/channels/health.js +99 -0
  109. package/dist/channels/host.d.ts +55 -0
  110. package/dist/channels/host.js +185 -0
  111. package/dist/channels/http.d.ts +31 -0
  112. package/dist/channels/http.js +79 -0
  113. package/dist/channels/index.d.ts +10 -0
  114. package/dist/channels/index.js +9 -0
  115. package/dist/channels/ledger.d.ts +37 -0
  116. package/dist/channels/ledger.js +95 -0
  117. package/dist/channels/providers/agentmail.d.ts +26 -0
  118. package/dist/channels/providers/agentmail.js +94 -0
  119. package/dist/channels/providers/kit.d.ts +40 -0
  120. package/dist/channels/providers/kit.js +78 -0
  121. package/dist/channels/providers/photonImessage.d.ts +45 -0
  122. package/dist/channels/providers/photonImessage.js +188 -0
  123. package/dist/channels/providers/photonWhatsapp.d.ts +49 -0
  124. package/dist/channels/providers/photonWhatsapp.js +146 -0
  125. package/dist/channels/providers/slack.d.ts +25 -0
  126. package/dist/channels/providers/slack.js +102 -0
  127. package/dist/channels/providers/telegram.d.ts +21 -0
  128. package/dist/channels/providers/telegram.js +101 -0
  129. package/dist/channels/providers.d.ts +5 -0
  130. package/dist/channels/providers.js +22 -0
  131. package/dist/channels/registry.d.ts +54 -0
  132. package/dist/channels/registry.js +186 -0
  133. package/dist/channels/secretStore.d.ts +21 -0
  134. package/dist/channels/secretStore.js +75 -0
  135. package/dist/channels/secrets.d.ts +15 -0
  136. package/dist/channels/secrets.js +50 -0
  137. package/dist/channels/service.d.ts +54 -0
  138. package/dist/channels/service.js +307 -0
  139. package/dist/channels/stageChannels.d.ts +45 -0
  140. package/dist/channels/stageChannels.js +110 -0
  141. package/dist/channels/types.d.ts +169 -0
  142. package/dist/channels/types.js +1 -0
  143. package/dist/cli/agentsCommand.d.ts +14 -0
  144. package/dist/cli/agentsCommand.js +291 -0
  145. package/dist/cli/doctorCommand.js +3 -1
  146. package/dist/cli.js +9 -0
  147. package/dist/config/browseCatalog.js +4 -11
  148. package/dist/config/draftPackage.d.ts +2 -0
  149. package/dist/config/draftPackage.js +8 -0
  150. package/dist/config/hostConfig.js +8 -0
  151. package/dist/config/loadAgent.d.ts +266 -0
  152. package/dist/config/loadAgent.js +374 -0
  153. package/dist/config/loadPipeline.js +31 -4
  154. package/dist/config/loadStage.js +15 -0
  155. package/dist/config/mcpHostCatalog.d.ts +50 -0
  156. package/dist/config/mcpHostCatalog.js +405 -0
  157. package/dist/config/mcpOAuth.d.ts +37 -0
  158. package/dist/config/mcpOAuth.js +263 -0
  159. package/dist/config/mcpRedaction.d.ts +42 -0
  160. package/dist/config/mcpRedaction.js +314 -0
  161. package/dist/config/mcpToolCache.d.ts +20 -0
  162. package/dist/config/mcpToolCache.js +43 -0
  163. package/dist/config/mergePipelineIncludes.d.ts +5 -0
  164. package/dist/config/mergePipelineIncludes.js +52 -0
  165. package/dist/config/pipelineStageKeys.js +1 -0
  166. package/dist/config/resolveStageMcpServers.d.ts +35 -3
  167. package/dist/config/resolveStageMcpServers.js +124 -9
  168. package/dist/config/validateCatalog.d.ts +4 -1
  169. package/dist/config/validateCatalog.js +45 -1
  170. package/dist/errors/codes.d.ts +1 -1
  171. package/dist/errors/codes.js +1 -0
  172. package/dist/mcp/agentTools.d.ts +8 -0
  173. package/dist/mcp/agentTools.js +132 -0
  174. package/dist/mcp/catalogTools.js +7 -9
  175. package/dist/mcp/deps.d.ts +6 -0
  176. package/dist/mcp/pipelineAuthorSupport.d.ts +19 -0
  177. package/dist/mcp/pipelineAuthorSupport.js +10 -0
  178. package/dist/mcp/pipelineAuthorTools.d.ts +8 -0
  179. package/dist/mcp/pipelineAuthorTools.js +109 -0
  180. package/dist/mcp/server.js +5 -0
  181. package/dist/mcp/tools.js +4 -0
  182. package/dist/mcp/triggerTools.js +32 -0
  183. package/dist/memory/access.d.ts +36 -0
  184. package/dist/memory/access.js +116 -0
  185. package/dist/memory/agentIssues.d.ts +3 -0
  186. package/dist/memory/agentIssues.js +23 -0
  187. package/dist/memory/bashDeny.d.ts +6 -0
  188. package/dist/memory/bashDeny.js +35 -0
  189. package/dist/memory/host.d.ts +51 -0
  190. package/dist/memory/host.js +394 -0
  191. package/dist/memory/ids.d.ts +15 -0
  192. package/dist/memory/ids.js +31 -0
  193. package/dist/memory/worker.d.ts +1 -0
  194. package/dist/memory/worker.js +84 -0
  195. package/dist/models/catalog.d.ts +113 -0
  196. package/dist/models/catalog.js +238 -0
  197. package/dist/models/response.d.ts +29 -0
  198. package/dist/models/response.js +25 -0
  199. package/dist/operatorAgent/agentAuthorContext.d.ts +17 -0
  200. package/dist/operatorAgent/agentAuthorContext.js +32 -0
  201. package/dist/operatorAgent/fakeHost.js +2 -0
  202. package/dist/operatorAgent/host.js +6 -3
  203. package/dist/operatorAgent/index.d.ts +4 -0
  204. package/dist/operatorAgent/index.js +4 -0
  205. package/dist/operatorAgent/piModel.js +2 -0
  206. package/dist/operatorAgent/profiles/agentAuthor.d.ts +11 -0
  207. package/dist/operatorAgent/profiles/agentAuthor.js +192 -0
  208. package/dist/operatorAgent/profiles/agentAuthorPlaybook.d.ts +1 -0
  209. package/dist/operatorAgent/profiles/agentAuthorPlaybook.js +29 -0
  210. package/dist/operatorAgent/profiles/workshopAuthor.js +2 -2
  211. package/dist/operatorAgent/profiles/workshopAuthorTools.js +3 -3
  212. package/dist/operatorAgent/proposals.d.ts +1 -0
  213. package/dist/operatorAgent/proposals.js +23 -2
  214. package/dist/package-meta.d.ts +1 -1
  215. package/dist/package-meta.js +1 -1
  216. package/dist/preflight/channelChecks.d.ts +17 -0
  217. package/dist/preflight/channelChecks.js +106 -0
  218. package/dist/preflight/pipelinePreflight.d.ts +9 -2
  219. package/dist/preflight/pipelinePreflight.js +10 -1
  220. package/dist/runstore/createStore.d.ts +2 -0
  221. package/dist/runstore/createStore.js +8 -0
  222. package/dist/runstore/overviewSummary.d.ts +56 -0
  223. package/dist/runstore/overviewSummary.js +134 -0
  224. package/dist/runstore/port.d.ts +3 -0
  225. package/dist/runstore/sqlite/SqliteRunStore.d.ts +2 -0
  226. package/dist/runstore/sqlite/SqliteRunStore.js +18 -0
  227. package/dist/runstore/sqlite/migrations/013-agents.d.ts +12 -0
  228. package/dist/runstore/sqlite/migrations/013-agents.js +156 -0
  229. package/dist/runstore/sqlite/migrations/014-agent-deliveries.d.ts +11 -0
  230. package/dist/runstore/sqlite/migrations/014-agent-deliveries.js +32 -0
  231. package/dist/runstore/sqlite/migrations/index.js +4 -0
  232. package/dist/runtime/pipelineRunner.js +3 -1
  233. package/dist/runtime/repositoryMaterialize.d.ts +1 -1
  234. package/dist/runtime/runManager.js +4 -1
  235. package/dist/runtime/stageAttemptBootstrap.js +31 -1
  236. package/dist/runtime/stageEnvironment.d.ts +2 -0
  237. package/dist/runtime/stageEnvironment.js +6 -1
  238. package/dist/runtime/stageProcessLauncher.js +54 -1
  239. package/dist/runtime/stageSecrets.d.ts +6 -1
  240. package/dist/runtime/stageSecrets.js +34 -1
  241. package/dist/server/agentAuthorRoutes.d.ts +5 -0
  242. package/dist/server/agentAuthorRoutes.js +64 -0
  243. package/dist/server/agentRoutes.d.ts +5 -0
  244. package/dist/server/agentRoutes.js +323 -0
  245. package/dist/server/bootstrap.d.ts +11 -0
  246. package/dist/server/bootstrap.js +40 -10
  247. package/dist/server/channelRoutes.d.ts +9 -0
  248. package/dist/server/channelRoutes.js +88 -0
  249. package/dist/server/controlToken.js +8 -0
  250. package/dist/server/http.d.ts +8 -1
  251. package/dist/server/http.js +183 -20
  252. package/dist/server/mcpHost.js +1 -0
  253. package/dist/server/memoryRoutes.d.ts +5 -0
  254. package/dist/server/memoryRoutes.js +146 -0
  255. package/dist/server/projectMcpRoutes.d.ts +1 -0
  256. package/dist/server/projectMcpRoutes.js +241 -3
  257. package/dist/toolkit/guard.d.ts +27 -0
  258. package/dist/toolkit/guard.js +98 -0
  259. package/dist/toolkit/index.d.ts +48 -0
  260. package/dist/toolkit/index.js +82 -0
  261. package/dist/toolkit/meta.d.ts +36 -0
  262. package/dist/toolkit/meta.js +117 -0
  263. package/dist/toolkit/profiles.d.ts +13 -0
  264. package/dist/toolkit/profiles.js +25 -0
  265. package/dist/toolkit/record.d.ts +15 -0
  266. package/dist/toolkit/record.js +17 -0
  267. package/dist/tools/memoryTools.d.ts +95 -0
  268. package/dist/tools/memoryTools.js +179 -0
  269. package/dist/tools/sendMessage.d.ts +21 -0
  270. package/dist/tools/sendMessage.js +25 -0
  271. package/dist/types/pipeline.d.ts +7 -1
  272. package/dist/types/stage.d.ts +15 -0
  273. package/dist/ui/assets/AssistantRuntimeProvider-CsiPFhCT.js +9 -0
  274. package/dist/ui/assets/MarkdownText-D7tYaIFO.js +29 -0
  275. package/dist/ui/assets/ReadonlyStore-BfXqHykm.js +6 -0
  276. package/dist/ui/assets/Tooltip-DrpoRRNi.js +1 -0
  277. package/dist/ui/assets/chat-BbLukq9W.js +5 -0
  278. package/dist/ui/assets/chat-zIZU_bP1.css +2 -0
  279. package/dist/ui/assets/jsx-runtime-iVoFAvQ_.js +1 -0
  280. package/dist/ui/assets/{index-CIPbbBUi.css → main-BFo79krC.css} +1 -1
  281. package/dist/ui/assets/main-CijYMeM0.js +259 -0
  282. package/dist/ui/chat.html +25 -0
  283. package/dist/ui/index.html +6 -2
  284. package/dist/workshop/modelSettings.d.ts +2 -2
  285. package/dist/workshop/modelSettings.js +5 -11
  286. package/examples/README.md +1 -0
  287. package/examples/channels-smoke/README.md +23 -0
  288. package/examples/channels-smoke/channels-smoke.pipeline.yaml +11 -0
  289. package/examples/channels-smoke/channels-smoke.task.yaml +3 -0
  290. package/examples/channels-smoke/send-email.yaml +32 -0
  291. package/examples/channels-smoke/send-text.yaml +31 -0
  292. package/examples/github-release/README.md +1 -1
  293. package/examples/memory/README.md +99 -0
  294. package/examples/memory/desk-outage.task.yaml +15 -0
  295. package/examples/memory/desk-refund.task.yaml +15 -0
  296. package/examples/memory/desk-revisit-outage.task.yaml +11 -0
  297. package/examples/memory/desk-revisit.pipeline.yaml +123 -0
  298. package/examples/memory/desk.pipeline.yaml +192 -0
  299. package/examples/memory/file-card.pipeline.yaml +39 -0
  300. package/examples/memory/file-ledger.task.yaml +22 -0
  301. package/examples/memory/file-release.task.yaml +24 -0
  302. package/examples/memory/file-rich.pipeline.yaml +40 -0
  303. package/examples/memory/file-ticket.task.yaml +7 -0
  304. package/examples/memory/file-timeline.task.yaml +28 -0
  305. package/examples/memory/find-card.pipeline.yaml +46 -0
  306. package/examples/memory/find-ticket.task.yaml +7 -0
  307. package/examples/memory/missing.pipeline.yaml +16 -0
  308. package/examples/memory/recall.pipeline.yaml +24 -0
  309. package/examples/memory/recall.task.yaml +5 -0
  310. package/examples/memory/remember-ada.task.yaml +6 -0
  311. package/examples/memory/remember-grace.task.yaml +6 -0
  312. package/examples/memory/remember.pipeline.yaml +58 -0
  313. package/examples/memory/stageflow.yaml +12 -0
  314. package/examples/memory/update-card.pipeline.yaml +43 -0
  315. package/examples/memory/update-ledger.task.yaml +23 -0
  316. package/examples/memory/update-rich.pipeline.yaml +44 -0
  317. package/examples/memory/update-ticket.task.yaml +7 -0
  318. package/examples/stage-mcp/README.md +1 -1
  319. package/package.json +9 -3
  320. package/dist/ui/assets/index-BoFPkKFg.js +0 -256
@@ -0,0 +1,113 @@
1
+ /** Last resort when nothing is connected and nothing is configured. Pi resolves unknown OpenRouter ids. */
2
+ export declare const LAST_RESORT_MODEL = "openrouter/nvidia/nemotron-3.5-lightning:free";
3
+ export type CatalogModel = {
4
+ /** `provider/model`, the form Pi resolves and stage, pipeline and agent files store. */
5
+ id: string;
6
+ provider: string;
7
+ name: string;
8
+ free: boolean;
9
+ contextWindow?: number;
10
+ reasoning?: boolean;
11
+ /** The provider runs its own file and shell tools beside Pi's, so agent grants and approvals cannot hold. */
12
+ nativeTools: boolean;
13
+ };
14
+ export type CatalogProvider = {
15
+ id: string;
16
+ name: string;
17
+ models: CatalogModel[];
18
+ /** `live`: Pi's catalog for this provider refreshed; `fallback`: built-in or cached list after an error. */
19
+ source: "live" | "fallback";
20
+ error?: string;
21
+ };
22
+ export type ModelCatalogSnapshot = {
23
+ /** Connected providers only. */
24
+ providers: CatalogProvider[];
25
+ /** Every model id across `providers`, sorted. */
26
+ models: string[];
27
+ fetchedAt: string;
28
+ };
29
+ /** The slice of Pi's ModelRuntime the catalog reads. */
30
+ export type CatalogRuntime = {
31
+ getProviders(): ReadonlyArray<{
32
+ id: string;
33
+ name?: string;
34
+ }>;
35
+ getProviderAuthStatus(providerId: string): {
36
+ configured: boolean;
37
+ };
38
+ listCredentials(): Promise<ReadonlyArray<{
39
+ providerId: string;
40
+ }>>;
41
+ getModels(providerId?: string): ReadonlyArray<{
42
+ id: string;
43
+ name?: string;
44
+ provider: string;
45
+ contextWindow?: number;
46
+ reasoning?: boolean;
47
+ cost?: {
48
+ input?: number;
49
+ output?: number;
50
+ };
51
+ }>;
52
+ refresh(options?: {
53
+ allowNetwork?: boolean;
54
+ providers?: readonly string[];
55
+ force?: boolean;
56
+ signal?: AbortSignal;
57
+ }): Promise<{
58
+ errors: ReadonlyMap<string, Error>;
59
+ } | void>;
60
+ };
61
+ export type CursorModelSource = () => {
62
+ connected: boolean;
63
+ modelIds: string[];
64
+ };
65
+ export type ModelCatalogOptions = {
66
+ cwd: string;
67
+ createRuntime?: (authPath: string) => Promise<CatalogRuntime>;
68
+ cursor?: CursorModelSource;
69
+ now?: () => number;
70
+ /** How long a built snapshot is reused before connections are re-read. */
71
+ ttlMs?: number;
72
+ refreshTimeoutMs?: number;
73
+ };
74
+ /**
75
+ * The one place model lists and the default model come from. Models are those of connected
76
+ * providers, asked of Pi's registry (live where the provider lists models, built-in otherwise).
77
+ */
78
+ export declare class ModelCatalog {
79
+ private readonly options;
80
+ private cached;
81
+ private inflight;
82
+ private lastDefault;
83
+ constructor(options: ModelCatalogOptions);
84
+ private now;
85
+ /** Cached list; rebuilt when older than the TTL or when `refresh` forces Pi to refetch provider catalogs. */
86
+ snapshot(options?: {
87
+ refresh?: boolean;
88
+ }): Promise<ModelCatalogSnapshot>;
89
+ refresh(): Promise<ModelCatalogSnapshot>;
90
+ /** True when the id belongs to a connected provider. Custom ids still run; this only drives warnings. */
91
+ isKnown(id: string): Promise<boolean>;
92
+ /**
93
+ * stageflow.yaml `model`, then the Settings workshop model, then the catalog's pick: the last-resort
94
+ * model when connected, else the first free model, else the first model, else the last resort.
95
+ */
96
+ defaultModel(): Promise<string>;
97
+ /** Synchronous default for call sites that cannot await: the last resolved default, else the last resort. */
98
+ peekDefault(): string;
99
+ private remember;
100
+ private configuredDefault;
101
+ private configuredDefaultSync;
102
+ private pick;
103
+ private build;
104
+ }
105
+ /**
106
+ * The most recently resolved default, for call sites that cannot await. Hosts resolve it at boot,
107
+ * so this is the catalog's answer, not a second source.
108
+ */
109
+ export declare function peekDefaultModel(): string;
110
+ /** The Host's catalog for a working directory, shared by every consumer in the process. */
111
+ export declare function getModelCatalog(cwd: string): ModelCatalog;
112
+ export declare function resetModelCatalogsForTests(): void;
113
+ export declare function setModelCatalogForTests(cwd: string, catalog: ModelCatalog): void;
@@ -0,0 +1,238 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import path from "node:path";
3
+ import { ModelRuntime } from "@earendil-works/pi-coding-agent";
4
+ import { getCursorHostStatus } from "../agent/cursorProvider.js";
5
+ import { globalModelFromManifest } from "../config/resolveModel.js";
6
+ import { resolveStageflowContext } from "../project/resolveStageflowContext.js";
7
+ import { resolveCredentialBinding } from "../runtime/credentialBinding.js";
8
+ import { readFactorySettings } from "../runtime/settingsFile.js";
9
+ /** Last resort when nothing is connected and nothing is configured. Pi resolves unknown OpenRouter ids. */
10
+ export const LAST_RESORT_MODEL = "openrouter/nvidia/nemotron-3.5-lightning:free";
11
+ const DEFAULT_TTL_MS = 30_000;
12
+ const DEFAULT_REFRESH_TIMEOUT_MS = 10_000;
13
+ const NOTHING_CONNECTED = {
14
+ getProviders: () => [],
15
+ getProviderAuthStatus: () => ({ configured: false }),
16
+ listCredentials: async () => [],
17
+ getModels: () => [],
18
+ refresh: async () => undefined,
19
+ };
20
+ // ModelRuntime.create writes auth.json when it is missing; listing models must not, so no file means nothing connected.
21
+ const defaultCreateRuntime = async (authPath) => !existsSync(authPath)
22
+ ? NOTHING_CONNECTED
23
+ : ModelRuntime.create({
24
+ authPath,
25
+ // Same layout as the provider routes: models.json and models-store.json sit beside auth.json.
26
+ modelsPath: path.join(path.dirname(authPath), "models.json"),
27
+ refreshOnCreate: false,
28
+ });
29
+ /** Cursor models come from the extension's cached list; they only count once Cursor is connected. */
30
+ function defaultCursorSource(authPath) {
31
+ return () => {
32
+ const status = getCursorHostStatus();
33
+ const connected = status.cursorApiKeyConfigured && status.cursorSdkReady;
34
+ if (!connected)
35
+ return { connected, modelIds: [] };
36
+ const file = path.join(path.dirname(authPath), "cursor-sdk-model-list.json");
37
+ try {
38
+ if (!existsSync(file))
39
+ return { connected, modelIds: [] };
40
+ const parsed = JSON.parse(readFileSync(file, "utf8"));
41
+ const ids = (parsed.models ?? [])
42
+ .map((entry) => (typeof entry.id === "string" ? entry.id : ""))
43
+ .filter((id) => id.length > 0)
44
+ .map((id) => `cursor/${id === "default" ? "auto" : id}`);
45
+ return { connected, modelIds: ids };
46
+ }
47
+ catch {
48
+ return { connected, modelIds: [] };
49
+ }
50
+ };
51
+ }
52
+ function errorMessage(error) {
53
+ return error instanceof Error ? error.message : String(error);
54
+ }
55
+ function isFree(model) {
56
+ if (model.id.endsWith(":free"))
57
+ return true;
58
+ return model.cost !== undefined && model.cost.input === 0 && model.cost.output === 0;
59
+ }
60
+ /**
61
+ * The one place model lists and the default model come from. Models are those of connected
62
+ * providers, asked of Pi's registry (live where the provider lists models, built-in otherwise).
63
+ */
64
+ export class ModelCatalog {
65
+ options;
66
+ cached;
67
+ inflight;
68
+ lastDefault;
69
+ constructor(options) {
70
+ this.options = options;
71
+ }
72
+ now() {
73
+ return (this.options.now ?? Date.now)();
74
+ }
75
+ /** Cached list; rebuilt when older than the TTL or when `refresh` forces Pi to refetch provider catalogs. */
76
+ async snapshot(options = {}) {
77
+ const ttl = this.options.ttlMs ?? DEFAULT_TTL_MS;
78
+ if (!options.refresh && this.cached && this.now() - this.cached.builtAt < ttl)
79
+ return this.cached.snapshot;
80
+ if (this.inflight && !options.refresh)
81
+ return this.inflight;
82
+ const run = this.build(options.refresh === true)
83
+ .then((snapshot) => {
84
+ this.cached = { snapshot, builtAt: this.now() };
85
+ return snapshot;
86
+ })
87
+ .catch((error) => {
88
+ // Keep serving the last good list when a rebuild fails outright.
89
+ if (this.cached)
90
+ return this.cached.snapshot;
91
+ throw error;
92
+ })
93
+ .finally(() => {
94
+ if (this.inflight === run)
95
+ this.inflight = undefined;
96
+ });
97
+ this.inflight = run;
98
+ return run;
99
+ }
100
+ refresh() {
101
+ return this.snapshot({ refresh: true });
102
+ }
103
+ /** True when the id belongs to a connected provider. Custom ids still run; this only drives warnings. */
104
+ async isKnown(id) {
105
+ const wanted = id.trim();
106
+ if (wanted.length === 0)
107
+ return false;
108
+ return (await this.snapshot()).models.includes(wanted);
109
+ }
110
+ /**
111
+ * stageflow.yaml `model`, then the Settings workshop model, then the catalog's pick: the last-resort
112
+ * model when connected, else the first free model, else the first model, else the last resort.
113
+ */
114
+ async defaultModel() {
115
+ const configured = await this.configuredDefault();
116
+ if (configured)
117
+ return this.remember(configured);
118
+ return this.remember(this.pick(await this.snapshot().catch(() => undefined)));
119
+ }
120
+ /** Synchronous default for call sites that cannot await: the last resolved default, else the last resort. */
121
+ peekDefault() {
122
+ return this.lastDefault ?? this.configuredDefaultSync() ?? this.pick(this.cached?.snapshot);
123
+ }
124
+ remember(id) {
125
+ this.lastDefault = id;
126
+ lastKnownDefault = id;
127
+ return id;
128
+ }
129
+ async configuredDefault() {
130
+ const ctx = await resolveStageflowContext(this.options.cwd);
131
+ const model = globalModelFromManifest(ctx.manifest) ?? readFactorySettings(this.options.cwd).workshopModel;
132
+ const trimmed = model?.trim();
133
+ return trimmed ? trimmed : undefined;
134
+ }
135
+ configuredDefaultSync() {
136
+ const trimmed = readFactorySettings(this.options.cwd).workshopModel?.trim();
137
+ return trimmed ? trimmed : undefined;
138
+ }
139
+ pick(snapshot) {
140
+ const all = snapshot?.providers.flatMap((provider) => provider.models) ?? [];
141
+ if (all.some((model) => model.id === LAST_RESORT_MODEL))
142
+ return LAST_RESORT_MODEL;
143
+ return all.find((model) => model.free && !model.nativeTools)?.id ?? all.find((model) => !model.nativeTools)?.id ?? all[0]?.id ?? LAST_RESORT_MODEL;
144
+ }
145
+ async build(force) {
146
+ const authPath = resolveCredentialBinding(this.options.cwd).authPath;
147
+ const runtime = await (this.options.createRuntime ?? defaultCreateRuntime)(authPath);
148
+ const credentials = new Set((await runtime.listCredentials().catch(() => [])).map((entry) => entry.providerId));
149
+ const connected = runtime
150
+ .getProviders()
151
+ .filter((provider) => credentials.has(provider.id) || runtime.getProviderAuthStatus(provider.id).configured);
152
+ const ids = connected.map((provider) => provider.id);
153
+ // Restore the cached catalogs first, then ask the providers; a failure leaves the cached or built-in list.
154
+ const errors = new Map();
155
+ if (ids.length > 0) {
156
+ await runtime.refresh({ allowNetwork: false, providers: ids }).catch(() => undefined);
157
+ const signal = AbortSignal.timeout(this.options.refreshTimeoutMs ?? DEFAULT_REFRESH_TIMEOUT_MS);
158
+ try {
159
+ const result = await runtime.refresh({ allowNetwork: true, providers: ids, force, signal });
160
+ if (result)
161
+ for (const [id, error] of result.errors)
162
+ errors.set(id, error);
163
+ }
164
+ catch (error) {
165
+ for (const id of ids)
166
+ errors.set(id, error instanceof Error ? error : new Error(errorMessage(error)));
167
+ }
168
+ }
169
+ const providers = connected.map((provider) => {
170
+ const failure = errors.get(provider.id);
171
+ return {
172
+ id: provider.id,
173
+ name: provider.name ?? provider.id,
174
+ source: failure ? "fallback" : "live",
175
+ ...(failure ? { error: errorMessage(failure) } : {}),
176
+ models: runtime
177
+ .getModels(provider.id)
178
+ .map((model) => ({
179
+ id: `${model.provider}/${model.id}`,
180
+ provider: model.provider,
181
+ name: model.name ?? model.id,
182
+ free: isFree(model),
183
+ ...(typeof model.contextWindow === "number" ? { contextWindow: model.contextWindow } : {}),
184
+ ...(typeof model.reasoning === "boolean" ? { reasoning: model.reasoning } : {}),
185
+ nativeTools: false,
186
+ }))
187
+ .sort((a, b) => a.id.localeCompare(b.id)),
188
+ };
189
+ });
190
+ const cursor = (this.options.cursor ?? defaultCursorSource(authPath))();
191
+ if (cursor.connected && cursor.modelIds.length > 0) {
192
+ providers.push({
193
+ id: "cursor",
194
+ name: "Cursor",
195
+ source: "live",
196
+ models: [...new Set(cursor.modelIds)].sort().map((id) => ({
197
+ id,
198
+ provider: "cursor",
199
+ name: id.slice("cursor/".length),
200
+ free: false,
201
+ nativeTools: true,
202
+ })),
203
+ });
204
+ }
205
+ providers.sort((a, b) => a.name.localeCompare(b.name));
206
+ return {
207
+ providers,
208
+ models: providers.flatMap((provider) => provider.models.map((model) => model.id)).sort((a, b) => a.localeCompare(b)),
209
+ fetchedAt: new Date(this.now()).toISOString(),
210
+ };
211
+ }
212
+ }
213
+ const catalogs = new Map();
214
+ let lastKnownDefault;
215
+ /**
216
+ * The most recently resolved default, for call sites that cannot await. Hosts resolve it at boot,
217
+ * so this is the catalog's answer, not a second source.
218
+ */
219
+ export function peekDefaultModel() {
220
+ return lastKnownDefault ?? LAST_RESORT_MODEL;
221
+ }
222
+ /** The Host's catalog for a working directory, shared by every consumer in the process. */
223
+ export function getModelCatalog(cwd) {
224
+ const key = path.resolve(cwd);
225
+ let catalog = catalogs.get(key);
226
+ if (!catalog) {
227
+ catalog = new ModelCatalog({ cwd: key });
228
+ catalogs.set(key, catalog);
229
+ }
230
+ return catalog;
231
+ }
232
+ export function resetModelCatalogsForTests() {
233
+ catalogs.clear();
234
+ lastKnownDefault = undefined;
235
+ }
236
+ export function setModelCatalogForTests(cwd, catalog) {
237
+ catalogs.set(path.resolve(cwd), catalog);
238
+ }
@@ -0,0 +1,29 @@
1
+ import type { RunStore } from "../runstore/port.js";
2
+ import { listModelsMultiProject } from "../config/multiProjectCatalog.js";
3
+ import { type CatalogProvider } from "./catalog.js";
4
+ export type ModelsResponse = {
5
+ /** Catalog ids plus ids pipelines already use, sorted. Back-compatible with the old flat list. */
6
+ models: string[];
7
+ /** Connected providers with their models. */
8
+ providers: CatalogProvider[];
9
+ /** The model a new chat, stage or agent starts on. */
10
+ default: string;
11
+ fetchedAt: string;
12
+ /** Ids pipelines use that no connected provider lists. They still run; pickers warn. */
13
+ unlisted: string[];
14
+ entries: Array<{
15
+ id: string;
16
+ project_root: string;
17
+ }>;
18
+ root_errors: Awaited<ReturnType<typeof listModelsMultiProject>>["root_errors"];
19
+ };
20
+ /** The shared answer for GET /api/models, the MCP `list_models` tool and every picker. */
21
+ export declare function buildModelsResponse(options: {
22
+ store: RunStore;
23
+ cwd: string;
24
+ projectRootFilter?: string | undefined;
25
+ refresh?: boolean;
26
+ }): Promise<{
27
+ response: ModelsResponse;
28
+ used: Awaited<ReturnType<typeof listModelsMultiProject>>;
29
+ }>;
@@ -0,0 +1,25 @@
1
+ import { listModelsMultiProject } from "../config/multiProjectCatalog.js";
2
+ import { getModelCatalog } from "./catalog.js";
3
+ /** The shared answer for GET /api/models, the MCP `list_models` tool and every picker. */
4
+ export async function buildModelsResponse(options) {
5
+ const catalog = getModelCatalog(options.cwd);
6
+ const [snapshot, used, defaultModel] = await Promise.all([
7
+ catalog.snapshot(options.refresh ? { refresh: true } : {}),
8
+ listModelsMultiProject({ store: options.store, bootCwd: options.cwd, projectRootFilter: options.projectRootFilter }),
9
+ catalog.defaultModel(),
10
+ ]);
11
+ const listed = new Set(snapshot.models);
12
+ const unlisted = used.models.filter((id) => !listed.has(id));
13
+ return {
14
+ used,
15
+ response: {
16
+ models: [...new Set([...snapshot.models, ...used.models])].sort((a, b) => a.localeCompare(b)),
17
+ providers: snapshot.providers,
18
+ default: defaultModel,
19
+ fetchedAt: snapshot.fetchedAt,
20
+ unlisted,
21
+ entries: used.items,
22
+ root_errors: used.root_errors,
23
+ },
24
+ };
25
+ }
@@ -0,0 +1,17 @@
1
+ import type { OperatorAgentContextAdapter } from "./types.js";
2
+ /**
3
+ * The unsaved agent definition the author edits: any subset of the v2 agent
4
+ * schema (src/config/loadAgent.ts). It may be incomplete or invalid while the
5
+ * operator is still describing the agent; Save validates it.
6
+ */
7
+ export type AgentAuthorDraft = Record<string, unknown>;
8
+ export type AgentAuthorContext = {
9
+ kind: "agent_author";
10
+ projectRoot?: string;
11
+ draft: AgentAuthorDraft;
12
+ };
13
+ export declare const AGENT_AUTHOR_GREETING = "What should this agent do? Tell me the job, the tools it needs, and anything it must never do without asking.";
14
+ export declare function emptyAgentAuthorDraft(): AgentAuthorDraft;
15
+ export declare function isAgentAuthorContext(value: unknown): value is AgentAuthorContext;
16
+ export declare function readAgentAuthorDraft(context: unknown): AgentAuthorDraft;
17
+ export declare function agentAuthorContextAdapter(): OperatorAgentContextAdapter;
@@ -0,0 +1,32 @@
1
+ export const AGENT_AUTHOR_GREETING = "What should this agent do? Tell me the job, the tools it needs, and anything it must never do without asking.";
2
+ export function emptyAgentAuthorDraft() {
3
+ return {};
4
+ }
5
+ export function isAgentAuthorContext(value) {
6
+ if (value === null || typeof value !== "object")
7
+ return false;
8
+ const record = value;
9
+ return (record.kind === "agent_author" &&
10
+ record.draft !== null &&
11
+ typeof record.draft === "object" &&
12
+ !Array.isArray(record.draft));
13
+ }
14
+ export function readAgentAuthorDraft(context) {
15
+ return isAgentAuthorContext(context) ? structuredClone(context.draft) : emptyAgentAuthorDraft();
16
+ }
17
+ export function agentAuthorContextAdapter() {
18
+ return {
19
+ serialize: (context) => context ?? { kind: "agent_author", draft: emptyAgentAuthorDraft() },
20
+ applyProposal: (context, proposal) => {
21
+ if (!isAgentAuthorContext(proposal.nextContext))
22
+ return context;
23
+ const current = isAgentAuthorContext(context) ? context : undefined;
24
+ const projectRoot = proposal.nextContext.projectRoot ?? current?.projectRoot;
25
+ return {
26
+ kind: "agent_author",
27
+ ...(projectRoot ? { projectRoot } : {}),
28
+ draft: structuredClone(proposal.nextContext.draft),
29
+ };
30
+ },
31
+ };
32
+ }
@@ -1,4 +1,5 @@
1
1
  import { createOperatorAgentHost, invokeProfileTool, } from "./host.js";
2
+ import { createAgentAuthorProfile } from "./profiles/agentAuthor.js";
2
3
  import { createWorkshopAuthorProfile, isTaskProposalIntent, proposeStageFromUserMessage, proposeTaskFromUserMessage, WORKSHOP_AUTHOR_PROFILE_ID, } from "./profiles/workshopAuthor.js";
3
4
  /**
4
5
  * Deterministic Operator Agent Host for Workshop and tests.
@@ -86,6 +87,7 @@ export function createWorkshopOperatorHost(scriptOrOptions) {
86
87
  retriever: options.retriever,
87
88
  projectRoot: options.projectRoot,
88
89
  }),
90
+ createAgentAuthorProfile(),
89
91
  ]);
90
92
  return host;
91
93
  }
@@ -1,5 +1,5 @@
1
- import { readDraftFromContext } from "./draftContext.js";
2
- import { draftFingerprint, enrichProposal, isMutationConflict, UNDO_MUTATION_CONFLICT_NOTICE, } from "./proposals.js";
1
+ import { profileMayUse } from "../toolkit/profiles.js";
2
+ import { enrichProposal, isMutationConflict, operatorContextFingerprint, UNDO_MUTATION_CONFLICT_NOTICE, } from "./proposals.js";
3
3
  import { rejectUnlinkedWorkshopDraftTool } from "../workshop/workshopPin.js";
4
4
  function createSession(profile, initialContext, model) {
5
5
  let context = initialContext;
@@ -17,7 +17,7 @@ function createSession(profile, initialContext, model) {
17
17
  context = profile.contextAdapter.applyProposal(context, enriched);
18
18
  const applied = {
19
19
  ...enriched,
20
- appliedFingerprint: draftFingerprint(readDraftFromContext(context)),
20
+ appliedFingerprint: operatorContextFingerprint(context),
21
21
  };
22
22
  mutations.set(applied.id, applied);
23
23
  lastMutationId = applied.id;
@@ -172,6 +172,9 @@ export async function invokeProfileTool(profile, name, args, ctx) {
172
172
  if (!tool) {
173
173
  return { ok: false, content: null, error: `Unknown tool: ${name}` };
174
174
  }
175
+ if (!profileMayUse(profile.id, name)) {
176
+ return { ok: false, content: null, error: `${profile.id} is not granted ${name}` };
177
+ }
175
178
  const blocked = rejectUnlinkedWorkshopDraftTool(ctx.getContext(), name);
176
179
  if (blocked)
177
180
  return blocked;
@@ -4,6 +4,10 @@ export { createFakeOperatorAgentModel, createWorkshopOperatorHost, type FakeOper
4
4
  export { AGENT_PORT_BACKENDS, createPiAgentPort, resolveAgentPort, type AgentPortBackendId, type AgentPort, type AgentPortOptions, } from "./agentPort.js";
5
5
  export { createLiveWorkshopOperatorHost, createPiOperatorAgentModel, type LiveWorkshopOperatorHostOptions, type PiOperatorAgentModel, type PiOperatorAgentModelOptions, type PiOperatorOpenSessionInput, type PiOperatorSessionHandle, type WorkshopTranscriptSeedMessage, } from "./piModel.js";
6
6
  export { createFailingDocsRetriever, createFilesystemDocsRetriever, createStubDocsRetriever, resolveWorkshopCatalogRoot, type DocsRetrievalHit, type DocsRetrievalResult, type DocsRetriever, } from "./docsRetrieval.js";
7
+ export { agentAuthorContextAdapter, emptyAgentAuthorDraft, isAgentAuthorContext, readAgentAuthorDraft, AGENT_AUTHOR_GREETING, type AgentAuthorContext, type AgentAuthorDraft, } from "./agentAuthorContext.js";
8
+ export { AGENT_AUTHOR_PROFILE_ID, AGENT_AUTHOR_TOOL_NAMES, createAgentAuthorContext, createAgentAuthorProfile, } from "./profiles/agentAuthor.js";
9
+ export { AGENT_AUTHOR_PLAYBOOK } from "./profiles/agentAuthorPlaybook.js";
10
+ export { operatorContextFingerprint } from "./proposals.js";
7
11
  export { createWorkshopDraftContext, draftTrackStages, emptyDraftPackage, isWorkshopDraftContext, readDraftFromContext, withDestination, withDraft, withProjectRoot, workshopDraftContextAdapter, WORKSHOP_AUTHOR_GREETING, } from "./draftContext.js";
8
12
  export { affectedStageIds, diffDraftPackages, draftFingerprint, enrichProposal, isMutationConflict, STALE_PROPOSAL_NOTICE, UNDO_MUTATION_CONFLICT_NOTICE, } from "./proposals.js";
9
13
  export { assertWorkshopAuthorToolsExcludeDiskShell, buildStageAddProposal, buildTaskAddProposal, createWorkshopAuthorProfile, createWorkshopAuthorTools, isTaskProposalIntent, proposeStageFromUserMessage, proposeTaskFromUserMessage, WORKSHOP_AUTHOR_PLAYBOOK, WORKSHOP_AUTHOR_PROFILE_ID, WORKSHOP_AUTHOR_TOOL_NAMES, WORKSHOP_FORBIDDEN_AGENT_TOOLS, workshopAuthorTools, type WorkshopAuthorProfileOptions, } from "./profiles/workshopAuthor.js";
@@ -3,6 +3,10 @@ export { createFakeOperatorAgentModel, createWorkshopOperatorHost, } from "./fak
3
3
  export { AGENT_PORT_BACKENDS, createPiAgentPort, resolveAgentPort, } from "./agentPort.js";
4
4
  export { createLiveWorkshopOperatorHost, createPiOperatorAgentModel, } from "./piModel.js";
5
5
  export { createFailingDocsRetriever, createFilesystemDocsRetriever, createStubDocsRetriever, resolveWorkshopCatalogRoot, } from "./docsRetrieval.js";
6
+ export { agentAuthorContextAdapter, emptyAgentAuthorDraft, isAgentAuthorContext, readAgentAuthorDraft, AGENT_AUTHOR_GREETING, } from "./agentAuthorContext.js";
7
+ export { AGENT_AUTHOR_PROFILE_ID, AGENT_AUTHOR_TOOL_NAMES, createAgentAuthorContext, createAgentAuthorProfile, } from "./profiles/agentAuthor.js";
8
+ export { AGENT_AUTHOR_PLAYBOOK } from "./profiles/agentAuthorPlaybook.js";
9
+ export { operatorContextFingerprint } from "./proposals.js";
6
10
  export { createWorkshopDraftContext, draftTrackStages, emptyDraftPackage, isWorkshopDraftContext, readDraftFromContext, withDestination, withDraft, withProjectRoot, workshopDraftContextAdapter, WORKSHOP_AUTHOR_GREETING, } from "./draftContext.js";
7
11
  export { affectedStageIds, diffDraftPackages, draftFingerprint, enrichProposal, isMutationConflict, STALE_PROPOSAL_NOTICE, UNDO_MUTATION_CONFLICT_NOTICE, } from "./proposals.js";
8
12
  export { assertWorkshopAuthorToolsExcludeDiskShell, buildStageAddProposal, buildTaskAddProposal, createWorkshopAuthorProfile, createWorkshopAuthorTools, isTaskProposalIntent, proposeStageFromUserMessage, proposeTaskFromUserMessage, WORKSHOP_AUTHOR_PLAYBOOK, WORKSHOP_AUTHOR_PROFILE_ID, WORKSHOP_AUTHOR_TOOL_NAMES, WORKSHOP_FORBIDDEN_AGENT_TOOLS, workshopAuthorTools, } from "./profiles/workshopAuthor.js";
@@ -19,6 +19,7 @@ import { globalStageflowHome } from "../project/globalHome.js";
19
19
  import { isUsableAuthFile, resolveCredentialBinding, } from "../runtime/credentialBinding.js";
20
20
  import { resolveWorkshopModel } from "../workshop/modelSettings.js";
21
21
  import { createOperatorAgentHost, invokeProfileTool, } from "./host.js";
22
+ import { createAgentAuthorProfile } from "./profiles/agentAuthor.js";
22
23
  import { createWorkshopAuthorProfile, } from "./profiles/workshopAuthor.js";
23
24
  import { readDraftFromContext } from "./draftContext.js";
24
25
  export function sessionNeedsExtensionReload(loaded, needed) {
@@ -544,5 +545,6 @@ export function createLiveWorkshopOperatorHost(options) {
544
545
  retriever,
545
546
  ...(projectRoot !== undefined ? { projectRoot } : {}),
546
547
  }),
548
+ createAgentAuthorProfile(),
547
549
  ]);
548
550
  }
@@ -0,0 +1,11 @@
1
+ import { type AgentAuthorContext, type AgentAuthorDraft } from "../agentAuthorContext.js";
2
+ import type { OperatorAgentProfile } from "../types.js";
3
+ export declare const AGENT_AUTHOR_PROFILE_ID = "agent-author";
4
+ /** Objects merge key by key; arrays and scalars replace; `null` removes the key. */
5
+ export declare function mergeDraftPatch(draft: AgentAuthorDraft, patch: Record<string, unknown>): AgentAuthorDraft;
6
+ export declare const AGENT_AUTHOR_TOOL_NAMES: readonly ["read_project_file", "list_project_files", "list_mcp_servers", "update_agent_draft"];
7
+ export declare function createAgentAuthorProfile(): OperatorAgentProfile;
8
+ export declare function createAgentAuthorContext(input: {
9
+ projectRoot: string;
10
+ draft?: AgentAuthorDraft;
11
+ }): AgentAuthorContext;