stageflow 0.27.0 → 0.30.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 (261) hide show
  1. package/README.md +4 -0
  2. package/builtin-skills/browser/SKILL.md +42 -0
  3. package/dist/agent/claudeAdapter.js +2 -2
  4. package/dist/agent/cursorProvider.d.ts +2 -0
  5. package/dist/agent/cursorProvider.js +30 -5
  6. package/dist/agent/fakeAgent.d.ts +1 -0
  7. package/dist/agent/fakeAgent.js +13 -0
  8. package/dist/agent/piAdapter.d.ts +3 -24
  9. package/dist/agent/piAdapter.js +49 -47
  10. package/dist/agent/piSessionFactory.d.ts +38 -0
  11. package/dist/agent/piSessionFactory.js +60 -0
  12. package/dist/agent/port.d.ts +2 -0
  13. package/dist/agent/streamLogRedact.d.ts +6 -0
  14. package/dist/agent/streamLogRedact.js +23 -1
  15. package/dist/browser/anchor.d.ts +27 -0
  16. package/dist/browser/anchor.js +127 -0
  17. package/dist/browser/auditSink.d.ts +38 -0
  18. package/dist/browser/auditSink.js +34 -0
  19. package/dist/browser/browserHost.d.ts +86 -0
  20. package/dist/browser/browserHost.js +7 -0
  21. package/dist/browser/browserSweep.d.ts +14 -0
  22. package/dist/browser/browserSweep.js +54 -0
  23. package/dist/browser/browserTeardown.d.ts +56 -0
  24. package/dist/browser/browserTeardown.js +235 -0
  25. package/dist/browser/fakeRemoteBrowserHost.d.ts +2 -0
  26. package/dist/browser/fakeRemoteBrowserHost.js +34 -0
  27. package/dist/browser/gateHandoff.d.ts +25 -0
  28. package/dist/browser/gateHandoff.js +83 -0
  29. package/dist/browser/humanLogin.d.ts +18 -0
  30. package/dist/browser/humanLogin.js +34 -0
  31. package/dist/browser/keyProvider.d.ts +10 -0
  32. package/dist/browser/keyProvider.js +39 -0
  33. package/dist/browser/localBrowserHost.d.ts +10 -0
  34. package/dist/browser/localBrowserHost.js +152 -0
  35. package/dist/browser/localProfileLock.d.ts +2 -0
  36. package/dist/browser/localProfileLock.js +218 -0
  37. package/dist/browser/localProfileStore.d.ts +5 -0
  38. package/dist/browser/localProfileStore.js +91 -0
  39. package/dist/browser/loginCheck.d.ts +53 -0
  40. package/dist/browser/loginCheck.js +147 -0
  41. package/dist/browser/memoryProfileLock.d.ts +2 -0
  42. package/dist/browser/memoryProfileLock.js +53 -0
  43. package/dist/browser/memoryProfileStore.d.ts +2 -0
  44. package/dist/browser/memoryProfileStore.js +31 -0
  45. package/dist/browser/navigationAudit.d.ts +16 -0
  46. package/dist/browser/navigationAudit.js +53 -0
  47. package/dist/browser/persistedEnv.d.ts +3 -0
  48. package/dist/browser/persistedEnv.js +15 -0
  49. package/dist/browser/profileLock.d.ts +40 -0
  50. package/dist/browser/profileLock.js +10 -0
  51. package/dist/browser/profileStore.d.ts +23 -0
  52. package/dist/browser/profileStore.js +39 -0
  53. package/dist/browser/runLiveness.d.ts +13 -0
  54. package/dist/browser/runLiveness.js +39 -0
  55. package/dist/browser/sitePolicy.d.ts +10 -0
  56. package/dist/browser/sitePolicy.js +61 -0
  57. package/dist/browser/stageBrowserEnv.d.ts +22 -0
  58. package/dist/browser/stageBrowserEnv.js +147 -0
  59. package/dist/browser/stageProfileLock.d.ts +17 -0
  60. package/dist/browser/stageProfileLock.js +39 -0
  61. package/dist/cli/browserCommand.d.ts +44 -0
  62. package/dist/cli/browserCommand.js +472 -0
  63. package/dist/cli/hostClient.d.ts +20 -0
  64. package/dist/cli/hostClient.js +36 -2
  65. package/dist/cli/initCommand.d.ts +1 -0
  66. package/dist/cli/initCommand.js +23 -7
  67. package/dist/cli/initTemplates.d.ts +5 -2
  68. package/dist/cli/initTemplates.js +25 -2
  69. package/dist/cli/runsCommand.js +6 -2
  70. package/dist/cli/triggerCommand.d.ts +12 -0
  71. package/dist/cli/triggerCommand.js +183 -0
  72. package/dist/cli/validateCommand.d.ts +1 -1
  73. package/dist/cli/validateCommand.js +23 -6
  74. package/dist/cli.js +31 -2
  75. package/dist/config/browseCatalog.d.ts +1 -0
  76. package/dist/config/browseCatalog.js +5 -4
  77. package/dist/config/builtinSkills.d.ts +4 -0
  78. package/dist/config/builtinSkills.js +23 -0
  79. package/dist/config/catalogRelativePath.d.ts +1 -0
  80. package/dist/config/catalogRelativePath.js +10 -2
  81. package/dist/config/createTrigger.d.ts +27 -0
  82. package/dist/config/createTrigger.js +232 -0
  83. package/dist/config/draftPackage.d.ts +117 -0
  84. package/dist/config/draftPackage.js +550 -0
  85. package/dist/config/ensureCatalogScanRoot.d.ts +16 -0
  86. package/dist/config/ensureCatalogScanRoot.js +73 -0
  87. package/dist/config/hostConfig.d.ts +2 -0
  88. package/dist/config/hostConfig.js +27 -0
  89. package/dist/config/listSkills.d.ts +2 -2
  90. package/dist/config/listSkills.js +17 -3
  91. package/dist/config/loadOutcome.d.ts +6 -0
  92. package/dist/config/loadPipeline.js +16 -0
  93. package/dist/config/loadStage.js +7 -0
  94. package/dist/config/loadStageflowManifest.js +25 -0
  95. package/dist/config/loadTrigger.d.ts +9 -0
  96. package/dist/config/loadTrigger.js +120 -0
  97. package/dist/config/multiProjectCatalog.d.ts +2 -0
  98. package/dist/config/multiProjectCatalog.js +26 -18
  99. package/dist/config/normalizePipelineStageEntry.js +8 -1
  100. package/dist/config/parseCompletionContract.js +6 -0
  101. package/dist/config/pipelineStageKeys.js +1 -0
  102. package/dist/config/publishDraftPackage.d.ts +7 -0
  103. package/dist/config/publishDraftPackage.js +25 -0
  104. package/dist/config/resolveCatalogContext.js +1 -1
  105. package/dist/config/resolvePipelineDag.js +1 -1
  106. package/dist/config/scanCatalogPaths.d.ts +1 -1
  107. package/dist/config/scanCatalogPaths.js +6 -2
  108. package/dist/config/stageBrowser.d.ts +12 -0
  109. package/dist/config/stageBrowser.js +118 -0
  110. package/dist/config/triggerCatalog.d.ts +10 -0
  111. package/dist/config/triggerCatalog.js +37 -0
  112. package/dist/config/validateCatalog.d.ts +13 -3
  113. package/dist/config/validateCatalog.js +83 -2
  114. package/dist/config/validateCompletionContract.js +8 -0
  115. package/dist/envelope/preEmitChecks.d.ts +1 -1
  116. package/dist/envelope/preEmitChecks.js +8 -0
  117. package/dist/logging/redact.d.ts +4 -0
  118. package/dist/logging/redact.js +17 -0
  119. package/dist/mcp/catalogTools.js +43 -8
  120. package/dist/mcp/controlTools.js +3 -1
  121. package/dist/mcp/deps.d.ts +2 -0
  122. package/dist/mcp/server.js +1 -0
  123. package/dist/mcp/tools.js +2 -0
  124. package/dist/mcp/triggerTools.d.ts +3 -0
  125. package/dist/mcp/triggerTools.js +176 -0
  126. package/dist/operatorAgent/docsRetrieval.d.ts +40 -0
  127. package/dist/operatorAgent/docsRetrieval.js +269 -0
  128. package/dist/operatorAgent/draftContext.d.ts +16 -0
  129. package/dist/operatorAgent/draftContext.js +68 -0
  130. package/dist/operatorAgent/fakeHost.d.ts +39 -0
  131. package/dist/operatorAgent/fakeHost.js +92 -0
  132. package/dist/operatorAgent/host.d.ts +40 -0
  133. package/dist/operatorAgent/host.js +179 -0
  134. package/dist/operatorAgent/index.d.ts +9 -0
  135. package/dist/operatorAgent/index.js +8 -0
  136. package/dist/operatorAgent/piModel.d.ts +80 -0
  137. package/dist/operatorAgent/piModel.js +528 -0
  138. package/dist/operatorAgent/profiles/workshopAuthor.d.ts +23 -0
  139. package/dist/operatorAgent/profiles/workshopAuthor.js +338 -0
  140. package/dist/operatorAgent/profiles/workshopAuthorPlaybook.d.ts +6 -0
  141. package/dist/operatorAgent/profiles/workshopAuthorPlaybook.js +103 -0
  142. package/dist/operatorAgent/profiles/workshopAuthorTools.d.ts +57 -0
  143. package/dist/operatorAgent/profiles/workshopAuthorTools.js +623 -0
  144. package/dist/operatorAgent/proposals.d.ts +32 -0
  145. package/dist/operatorAgent/proposals.js +144 -0
  146. package/dist/operatorAgent/types.d.ts +128 -0
  147. package/dist/operatorAgent/types.js +1 -0
  148. package/dist/package-meta.d.ts +1 -1
  149. package/dist/package-meta.js +1 -1
  150. package/dist/project/findManifestRoot.d.ts +3 -0
  151. package/dist/project/findManifestRoot.js +35 -0
  152. package/dist/project/resolveStageflowContext.d.ts +7 -0
  153. package/dist/project/resolveStageflowContext.js +44 -28
  154. package/dist/runstore/assertTmpdir.js +6 -2
  155. package/dist/runstore/port.d.ts +28 -0
  156. package/dist/runstore/sqlite/SqliteRunStore.d.ts +8 -1
  157. package/dist/runstore/sqlite/SqliteRunStore.js +90 -0
  158. package/dist/runstore/sqlite/migrations/008-triggers-table.d.ts +7 -0
  159. package/dist/runstore/sqlite/migrations/008-triggers-table.js +19 -0
  160. package/dist/runstore/sqlite/migrations/009-trigger-next-run.d.ts +7 -0
  161. package/dist/runstore/sqlite/migrations/009-trigger-next-run.js +19 -0
  162. package/dist/runstore/sqlite/migrations/010-trigger-adapter-state.d.ts +7 -0
  163. package/dist/runstore/sqlite/migrations/010-trigger-adapter-state.js +17 -0
  164. package/dist/runstore/sqlite/migrations/index.js +6 -0
  165. package/dist/runtime/answerResume.d.ts +1 -0
  166. package/dist/runtime/answerResume.js +3 -1
  167. package/dist/runtime/completionCheckRunner.d.ts +12 -1
  168. package/dist/runtime/completionCheckRunner.js +22 -0
  169. package/dist/runtime/credentialBinding.d.ts +2 -0
  170. package/dist/runtime/credentialBinding.js +3 -0
  171. package/dist/runtime/emailSource.d.ts +72 -0
  172. package/dist/runtime/emailSource.js +304 -0
  173. package/dist/runtime/githubPollSource.d.ts +86 -0
  174. package/dist/runtime/githubPollSource.js +284 -0
  175. package/dist/runtime/pipelineRunner.d.ts +4 -0
  176. package/dist/runtime/pipelineRunner.js +3 -0
  177. package/dist/runtime/pipelineScheduler.d.ts +2 -0
  178. package/dist/runtime/pipelineScheduler.js +85 -1
  179. package/dist/runtime/repositoryMaterialize.d.ts +1 -1
  180. package/dist/runtime/runManager.d.ts +11 -0
  181. package/dist/runtime/runManager.js +149 -1
  182. package/dist/runtime/runRetryCoordinator.d.ts +2 -0
  183. package/dist/runtime/runRetryCoordinator.js +1 -0
  184. package/dist/runtime/scheduleSource.d.ts +38 -0
  185. package/dist/runtime/scheduleSource.js +119 -0
  186. package/dist/runtime/settingsFile.d.ts +5 -0
  187. package/dist/runtime/settingsFile.js +61 -54
  188. package/dist/runtime/stageAttemptBootstrap.js +55 -3
  189. package/dist/runtime/stageEnvironment.js +1 -0
  190. package/dist/runtime/stageHitl.d.ts +1 -0
  191. package/dist/runtime/stageHitl.js +5 -1
  192. package/dist/runtime/stageProcessLauncher.d.ts +2 -0
  193. package/dist/runtime/stageProcessLauncher.js +44 -5
  194. package/dist/runtime/stageRunner.d.ts +5 -0
  195. package/dist/runtime/stageRunner.js +30 -6
  196. package/dist/runtime/stageStreamLog.d.ts +1 -0
  197. package/dist/runtime/stageStreamLog.js +2 -1
  198. package/dist/runtime/triggerCatalog.d.ts +6 -0
  199. package/dist/runtime/triggerCatalog.js +24 -0
  200. package/dist/runtime/triggerEventMatch.d.ts +2 -0
  201. package/dist/runtime/triggerEventMatch.js +6 -0
  202. package/dist/runtime/triggerPort.d.ts +14 -0
  203. package/dist/runtime/triggerPort.js +1 -0
  204. package/dist/runtime/triggerRunner.d.ts +17 -0
  205. package/dist/runtime/triggerRunner.js +89 -0
  206. package/dist/runtime/verifiedStageExecution.d.ts +7 -0
  207. package/dist/runtime/verifiedStageExecution.js +14 -0
  208. package/dist/runtime/webhookSignature.d.ts +1 -0
  209. package/dist/runtime/webhookSignature.js +12 -0
  210. package/dist/server/bootstrap.d.ts +6 -0
  211. package/dist/server/bootstrap.js +64 -0
  212. package/dist/server/controlToken.js +13 -0
  213. package/dist/server/createHttpHost.js +3 -0
  214. package/dist/server/healthSurfaces.js +31 -6
  215. package/dist/server/http.d.ts +15 -0
  216. package/dist/server/http.js +1251 -74
  217. package/dist/server/requestAuthContext.d.ts +1 -1
  218. package/dist/server/triggerRoutes.d.ts +15 -0
  219. package/dist/server/triggerRoutes.js +268 -0
  220. package/dist/tools/askOperator.d.ts +3 -2
  221. package/dist/types/completion.d.ts +3 -0
  222. package/dist/types/pipeline.d.ts +3 -1
  223. package/dist/types/preEmitCheck.d.ts +7 -0
  224. package/dist/types/stage.d.ts +14 -0
  225. package/dist/types/stageflowManifest.d.ts +3 -0
  226. package/dist/types/trigger.d.ts +18 -0
  227. package/dist/types/trigger.js +1 -0
  228. package/dist/ui/assets/{index-CSsDued1.css → index-Bv4p1aPK.css} +1 -1
  229. package/dist/ui/assets/index-CntB4bZR.js +133 -0
  230. package/dist/ui/index.html +2 -2
  231. package/dist/workshop/autosave.d.ts +58 -0
  232. package/dist/workshop/autosave.js +222 -0
  233. package/dist/workshop/buildStore.d.ts +79 -0
  234. package/dist/workshop/buildStore.js +326 -0
  235. package/dist/workshop/chatTurn.d.ts +232 -0
  236. package/dist/workshop/chatTurn.js +475 -0
  237. package/dist/workshop/modelSettings.d.ts +18 -0
  238. package/dist/workshop/modelSettings.js +44 -0
  239. package/dist/workshop/sessionStore.d.ts +61 -0
  240. package/dist/workshop/sessionStore.js +254 -0
  241. package/dist/workshop/workshopPin.d.ts +72 -0
  242. package/dist/workshop/workshopPin.js +193 -0
  243. package/examples/README.md +2 -1
  244. package/examples/browser-session/README.md +77 -0
  245. package/examples/browser-session/browser-session.pipeline.yaml +50 -0
  246. package/examples/browser-session/browser-session.task.yaml +6 -0
  247. package/examples/browser-session/check-login.yaml +22 -0
  248. package/examples/browser-session/fixture-server.mjs +64 -0
  249. package/examples/browser-session/human-login.yaml +31 -0
  250. package/examples/browser-session/merge.yaml +36 -0
  251. package/examples/browser-session/work-a.yaml +41 -0
  252. package/examples/browser-session/work-b.yaml +41 -0
  253. package/examples/stage-mcp/README.md +3 -2
  254. package/examples/stageflow.yaml +51 -0
  255. package/package.json +5 -1
  256. package/skills/stageflow/references/control-surface.md +3 -1
  257. package/skills/stageflow-author/references/stage-prompt-template.md +4 -4
  258. package/skills/stageflow-run/SKILL.md +2 -0
  259. package/skills/stageflow-run/references/task-and-pipeline-selection.md +3 -1
  260. package/skills/stageflow-setup/SKILL.md +11 -0
  261. package/dist/ui/assets/index-B6hlSXXn.js +0 -120
@@ -0,0 +1,528 @@
1
+ /**
2
+ * Live Pi-backed OperatorAgentModel for Workshop Author.
3
+ *
4
+ * Uses the shared Pi session factory (not AgentPort). Workshop tools only —
5
+ * resolveWorkshopToolNames / assertWorkshopToolsExcludeDiskShell. Durable Pi
6
+ * session per host tool-context (R7). Restart: new Pi + transcript replay (KTD7).
7
+ */
8
+ import { mkdir } from "node:fs/promises";
9
+ import path from "node:path";
10
+ import { defineTool, ModelRuntime, resolveCliModel, SessionManager, SettingsManager, } from "@earendil-works/pi-coding-agent";
11
+ import { Type } from "typebox";
12
+ import { createPiAgentSession, createSealedResourceLoader, resolveWorkshopToolNames, } from "../agent/piSessionFactory.js";
13
+ import { cursorBridgePrompt } from "../agent/cursorProvider.js";
14
+ import { findProviderSupport } from "../agent/providerSupport.js";
15
+ import "../agent/cursorProvider.js";
16
+ import { logger as rootLogger } from "../logging/logger.js";
17
+ import { globalStageflowHome } from "../project/globalHome.js";
18
+ import { isUsableAuthFile, resolveCredentialBinding, } from "../runtime/credentialBinding.js";
19
+ import { resolveWorkshopModel } from "../workshop/modelSettings.js";
20
+ import { createOperatorAgentHost, invokeProfileTool, } from "./host.js";
21
+ import { createWorkshopAuthorProfile, } from "./profiles/workshopAuthor.js";
22
+ import { readDraftFromContext } from "./draftContext.js";
23
+ export function sessionNeedsExtensionReload(loaded, needed) {
24
+ if (loaded === undefined)
25
+ return false;
26
+ const have = new Set(loaded);
27
+ return needed.some((extensionPath) => !have.has(extensionPath));
28
+ }
29
+ function extensionPathsForModel(modelId) {
30
+ const provider = findProviderSupport(modelId);
31
+ if (!provider)
32
+ return [];
33
+ const prepared = provider.prepare(modelId);
34
+ if (prepared.error)
35
+ return [];
36
+ return prepared.extensionPaths;
37
+ }
38
+ const FLEX_PARAMS = Type.Object({}, { additionalProperties: true });
39
+ const workshopLog = rootLogger.child({ component: "workshop" });
40
+ export function workshopToolLogFields(args, result) {
41
+ const body = args.body;
42
+ const fields = {
43
+ argKeys: Object.keys(args),
44
+ id: typeof args.id === "string" ? args.id : undefined,
45
+ bodyType: body === undefined ? "missing" : Array.isArray(body) ? "array" : typeof body,
46
+ };
47
+ if (body !== null && typeof body === "object" && !Array.isArray(body)) {
48
+ fields.bodyKeys = Object.keys(body);
49
+ }
50
+ if (typeof body === "string") {
51
+ fields.bodyChars = body.length;
52
+ fields.bodyIgnored = true;
53
+ }
54
+ if (result) {
55
+ fields.ok = result.ok;
56
+ if (result.error)
57
+ fields.error = result.error;
58
+ try {
59
+ fields.resultBytes = JSON.stringify(result).length;
60
+ }
61
+ catch {
62
+ fields.resultBytes = -1;
63
+ }
64
+ }
65
+ return fields;
66
+ }
67
+ export function workshopToolActivity(id, name, phase, args, result) {
68
+ const target = typeof args.id === "string" ? args.id : undefined;
69
+ const base = { id, name, ...(target ? { target } : {}) };
70
+ if (phase === "start")
71
+ return { ...base, status: "running" };
72
+ if (!result?.ok) {
73
+ return {
74
+ ...base,
75
+ status: "error",
76
+ errorMessage: result?.error ?? "unknown error",
77
+ };
78
+ }
79
+ return { ...base, status: "complete" };
80
+ }
81
+ function workshopContextBuildId(context) {
82
+ if (context !== null &&
83
+ typeof context === "object" &&
84
+ "buildId" in context &&
85
+ typeof context.buildId === "string") {
86
+ const buildId = context.buildId.trim();
87
+ return buildId || undefined;
88
+ }
89
+ return undefined;
90
+ }
91
+ function workshopAgentDir() {
92
+ return path.join(globalStageflowHome(), "workshop", "agent");
93
+ }
94
+ function toolResultContent(result) {
95
+ const text = JSON.stringify(result);
96
+ return {
97
+ content: [{ type: "text", text }],
98
+ details: result,
99
+ ...(result.ok ? {} : { isError: true }),
100
+ };
101
+ }
102
+ function buildWorkshopCustomTools(profileTools, getProfile, getTools, onToolResult, reportActivity) {
103
+ return profileTools.map((tool) => defineTool({
104
+ name: tool.name,
105
+ label: tool.name,
106
+ description: tool.description,
107
+ parameters: FLEX_PARAMS,
108
+ execute: async (_toolCallId, params) => {
109
+ const args = params !== null && typeof params === "object" && !Array.isArray(params)
110
+ ? params
111
+ : {};
112
+ workshopLog.info("workshop.tool.start", tool.name, workshopToolLogFields(args));
113
+ const callId = typeof _toolCallId === "string" && _toolCallId
114
+ ? _toolCallId
115
+ : `${tool.name}-${Date.now()}`;
116
+ const pinnedBuildId = workshopContextBuildId(getTools().getContext());
117
+ reportActivity({
118
+ ...workshopToolActivity(callId, tool.name, "start", args),
119
+ ...(pinnedBuildId ? { buildId: pinnedBuildId } : {}),
120
+ });
121
+ const result = await invokeProfileTool(getProfile(), tool.name, args, getTools());
122
+ const fields = workshopToolLogFields(args, result);
123
+ if (result.ok) {
124
+ workshopLog.info("workshop.tool.done", tool.name, fields);
125
+ }
126
+ else {
127
+ workshopLog.warn("workshop.tool.done", tool.name, fields);
128
+ }
129
+ const update = workshopToolActivity(callId, tool.name, "done", args, result);
130
+ const doneBuildId = workshopContextBuildId(getTools().getContext());
131
+ if (result.ok) {
132
+ const draft = readDraftFromContext(getTools().getContext());
133
+ reportActivity({
134
+ ...update,
135
+ draft,
136
+ ...(doneBuildId ? { buildId: doneBuildId } : {}),
137
+ });
138
+ }
139
+ else {
140
+ reportActivity({
141
+ ...update,
142
+ ...(doneBuildId ? { buildId: doneBuildId } : {}),
143
+ });
144
+ }
145
+ onToolResult(tool.name, result);
146
+ return toolResultContent(result);
147
+ },
148
+ }));
149
+ }
150
+ function formatTranscriptReplay(transcript) {
151
+ const lines = transcript
152
+ .filter((m) => typeof m.text === "string" && m.text.trim())
153
+ .map((m) => `${m.role}: ${m.text.trim()}`);
154
+ return [
155
+ "Prior Workshop Author conversation (restored after host restart).",
156
+ "Continue from this context; do not re-ask questions already answered.",
157
+ "",
158
+ ...lines,
159
+ ].join("\n");
160
+ }
161
+ function authNotConfiguredError(authPath) {
162
+ return new Error(`Workshop Author provider auth is not configured (auth file missing or empty: ${authPath}). Configure credentials via \`sf providers\` / the operator console Providers page, then retry.`);
163
+ }
164
+ function syncAgentMessages(session, sessionManager) {
165
+ if (session.agent?.state) {
166
+ session.agent.state.messages = sessionManager.buildSessionContext().messages;
167
+ }
168
+ }
169
+ function extractAssistantText(message) {
170
+ if (message.role !== "assistant")
171
+ return undefined;
172
+ const content = message.content;
173
+ if (typeof content === "string")
174
+ return content;
175
+ if (!Array.isArray(content))
176
+ return undefined;
177
+ const parts = [];
178
+ for (const block of content) {
179
+ if (!block || typeof block !== "object")
180
+ continue;
181
+ const b = block;
182
+ if (b.type === "text" && typeof b.text === "string")
183
+ parts.push(b.text);
184
+ }
185
+ return parts.length > 0 ? parts.join("") : undefined;
186
+ }
187
+ async function openDefaultPiSession(input) {
188
+ if (!isUsableAuthFile(input.authPath)) {
189
+ throw authNotConfiguredError(input.authPath);
190
+ }
191
+ const provider = findProviderSupport(input.modelId);
192
+ const additionalExtensionPaths = [];
193
+ let restoreProvider;
194
+ if (provider) {
195
+ const prepared = provider.prepare(input.modelId);
196
+ if (prepared.error) {
197
+ throw new Error(prepared.error);
198
+ }
199
+ additionalExtensionPaths.push(...prepared.extensionPaths);
200
+ restoreProvider = prepared.restore;
201
+ }
202
+ await mkdir(input.agentDir, { recursive: true });
203
+ if (input.piSessionDir) {
204
+ await mkdir(input.piSessionDir, { recursive: true });
205
+ }
206
+ const modelRuntime = await ModelRuntime.create({
207
+ authPath: input.authPath,
208
+ modelsPath: path.join(path.dirname(input.authPath), "models.json"),
209
+ });
210
+ const settingsManager = SettingsManager.inMemory({
211
+ compaction: { enabled: false },
212
+ });
213
+ const loader = createSealedResourceLoader({
214
+ cwd: input.cwd,
215
+ agentDir: input.agentDir,
216
+ settingsManager,
217
+ systemPrompt: input.systemPrompt,
218
+ ...(additionalExtensionPaths.length > 0
219
+ ? { additionalExtensionPaths }
220
+ : {}),
221
+ });
222
+ await loader.reload();
223
+ const extensionErrors = loader.getExtensions().errors;
224
+ if (extensionErrors.length > 0) {
225
+ restoreProvider?.();
226
+ throw new Error(`Failed to load Pi extension(s): ${extensionErrors
227
+ .map((e) => `${e.path}: ${e.error}`)
228
+ .join("; ")}`);
229
+ }
230
+ const sessionManager = input.piSessionDir
231
+ ? SessionManager.create(input.cwd, input.piSessionDir)
232
+ : SessionManager.inMemory(input.cwd);
233
+ let session;
234
+ try {
235
+ const created = await createPiAgentSession({
236
+ cwd: input.cwd,
237
+ agentDir: input.agentDir,
238
+ modelRuntime,
239
+ sessionManager,
240
+ settingsManager,
241
+ resourceLoader: loader,
242
+ tools: input.toolNames,
243
+ customTools: input.customTools,
244
+ });
245
+ session = created.session;
246
+ await session.bindExtensions({});
247
+ const resolved = resolveCliModel({
248
+ cliModel: input.modelId,
249
+ modelRuntime,
250
+ });
251
+ if (resolved.error || !resolved.model) {
252
+ throw new Error(resolved.error ?? `Model not found: ${input.modelId}`);
253
+ }
254
+ await session.setModel(resolved.model);
255
+ if (resolved.thinkingLevel) {
256
+ session.setThinkingLevel(resolved.thinkingLevel);
257
+ }
258
+ const live = session;
259
+ let currentModelId = input.modelId;
260
+ const applyModel = async (modelId) => {
261
+ if (modelId === currentModelId)
262
+ return;
263
+ const provider = findProviderSupport(modelId);
264
+ if (provider) {
265
+ const prepared = provider.prepare(modelId);
266
+ if (prepared.error) {
267
+ throw new Error(prepared.error);
268
+ }
269
+ }
270
+ const next = resolveCliModel({
271
+ cliModel: modelId,
272
+ modelRuntime,
273
+ });
274
+ if (next.error || !next.model) {
275
+ throw new Error(next.error ?? `Model not found: ${modelId}`);
276
+ }
277
+ await live.setModel(next.model);
278
+ if (next.thinkingLevel) {
279
+ live.setThinkingLevel(next.thinkingLevel);
280
+ }
281
+ currentModelId = modelId;
282
+ };
283
+ return {
284
+ session: live,
285
+ sessionManager,
286
+ restoreProvider,
287
+ piSessionId: sessionManager.getSessionId(),
288
+ extensionPaths: additionalExtensionPaths,
289
+ applyModel,
290
+ shutdown: async () => {
291
+ try {
292
+ live.dispose();
293
+ }
294
+ catch {
295
+ // best-effort
296
+ }
297
+ restoreProvider?.();
298
+ },
299
+ };
300
+ }
301
+ catch (err) {
302
+ try {
303
+ session?.dispose();
304
+ }
305
+ catch {
306
+ // best-effort
307
+ }
308
+ restoreProvider?.();
309
+ throw err;
310
+ }
311
+ }
312
+ /**
313
+ * Pi OperatorAgentModel: durable session per host tool-context, Workshop tools only.
314
+ */
315
+ export function createPiOperatorAgentModel(options) {
316
+ const cwd = options.cwd;
317
+ const agentDir = options.agentDir ?? workshopAgentDir();
318
+ const openPiSession = options.openPiSession ?? openDefaultPiSession;
319
+ const bindings = new WeakMap();
320
+ const activeTools = new Set();
321
+ function resolveAuthPath() {
322
+ if (options.authPath)
323
+ return options.authPath;
324
+ return resolveCredentialBinding(cwd).authPath;
325
+ }
326
+ function resolveModelId() {
327
+ if (options.resolveModelId)
328
+ return options.resolveModelId();
329
+ return resolveWorkshopModel({
330
+ sessionOverride: options.model,
331
+ settingsDefault: options.settingsDefault,
332
+ profileDefault: options.profileDefault,
333
+ });
334
+ }
335
+ async function ensureBound(profile, tools, modelId) {
336
+ const existing = bindings.get(tools);
337
+ if (existing && existing.profileId === profile.id) {
338
+ const reload = modelId !== undefined &&
339
+ sessionNeedsExtensionReload(existing.handle.extensionPaths, extensionPathsForModel(modelId));
340
+ if (!reload) {
341
+ existing.profile = profile;
342
+ existing.tools = tools;
343
+ if (modelId)
344
+ await existing.handle.applyModel?.(modelId);
345
+ return existing;
346
+ }
347
+ }
348
+ if (existing) {
349
+ await existing.handle.shutdown();
350
+ bindings.delete(tools);
351
+ }
352
+ const bindingHolder = { current: null };
353
+ const toolNames = resolveWorkshopToolNames(profile.tools.map((t) => t.name));
354
+ const customTools = buildWorkshopCustomTools(profile.tools, () => {
355
+ if (!bindingHolder.current) {
356
+ throw new Error("Workshop Pi profile not bound");
357
+ }
358
+ return bindingHolder.current.profile;
359
+ }, () => {
360
+ if (!bindingHolder.current) {
361
+ throw new Error("Workshop Pi tool context not bound");
362
+ }
363
+ return bindingHolder.current.tools;
364
+ }, (name, result) => {
365
+ if (!bindingHolder.current)
366
+ return;
367
+ bindingHolder.current.toolEvents.push({
368
+ type: "tool_result",
369
+ name,
370
+ result,
371
+ });
372
+ }, (status) => {
373
+ bindingHolder.current?.reportActivity?.(status);
374
+ });
375
+ const handle = await openPiSession({
376
+ cwd,
377
+ agentDir,
378
+ systemPrompt: profile.playbook,
379
+ toolNames,
380
+ customTools,
381
+ modelId: modelId ?? resolveModelId(),
382
+ authPath: resolveAuthPath(),
383
+ ...(options.piSessionDir ? { piSessionDir: options.piSessionDir } : {}),
384
+ });
385
+ const binding = {
386
+ handle,
387
+ profileId: profile.id,
388
+ profile,
389
+ tools,
390
+ toolEvents: [],
391
+ started: true,
392
+ replayed: false,
393
+ };
394
+ bindingHolder.current = binding;
395
+ bindings.set(tools, binding);
396
+ activeTools.add(tools);
397
+ return binding;
398
+ }
399
+ async function releaseTools(tools) {
400
+ const state = bindings.get(tools);
401
+ if (!state)
402
+ return;
403
+ bindings.delete(tools);
404
+ activeTools.delete(tools);
405
+ await state.handle.shutdown();
406
+ }
407
+ const model = {
408
+ async prepareRestart({ tools, profile, transcript }) {
409
+ const state = await ensureBound(profile, tools);
410
+ if (state.replayed || transcript.length === 0)
411
+ return;
412
+ state.handle.sessionManager.appendCustomMessageEntry("stageflow.workshop_transcript_replay", formatTranscriptReplay(transcript), true, { messageCount: transcript.length });
413
+ syncAgentMessages(state.handle.session, state.handle.sessionManager);
414
+ state.replayed = true;
415
+ },
416
+ async complete({ profile, message, tools, onDelta, onActivity, modelId }) {
417
+ let state;
418
+ try {
419
+ state = await ensureBound(profile, tools, modelId);
420
+ }
421
+ catch (err) {
422
+ const msg = err instanceof Error ? err.message : String(err);
423
+ return {
424
+ events: [{ type: "error", message: msg }],
425
+ };
426
+ }
427
+ state.profile = profile;
428
+ state.tools = tools;
429
+ state.toolEvents = [];
430
+ state.reportActivity = onActivity;
431
+ workshopLog.info("workshop.turn.start", "prompt", {
432
+ modelId,
433
+ chars: message.length,
434
+ });
435
+ const events = [];
436
+ let assistantText = "";
437
+ const unsubscribe = state.handle.session.subscribe((event) => {
438
+ const e = event;
439
+ if (e.type === "message_update") {
440
+ const ame = e.assistantMessageEvent;
441
+ if (ame?.type === "text_delta" && typeof ame.delta === "string") {
442
+ assistantText += ame.delta;
443
+ onDelta?.(ame.delta);
444
+ }
445
+ return;
446
+ }
447
+ if (e.type === "message_end" && e.message) {
448
+ const text = extractAssistantText(e.message);
449
+ if (text && !assistantText) {
450
+ assistantText = text;
451
+ }
452
+ }
453
+ });
454
+ try {
455
+ await state.handle.session.prompt(cursorBridgePrompt(message, modelId, profile.tools.map((tool) => tool.name)));
456
+ }
457
+ catch (err) {
458
+ unsubscribe();
459
+ const msg = err instanceof Error ? err.message : String(err);
460
+ workshopLog.error("workshop.turn.done", msg, { modelId });
461
+ return {
462
+ events: [
463
+ ...state.toolEvents,
464
+ { type: "error", message: msg },
465
+ ],
466
+ };
467
+ }
468
+ unsubscribe();
469
+ workshopLog.info("workshop.turn.done", "prompt", {
470
+ modelId,
471
+ toolCalls: state.toolEvents.length,
472
+ textChars: assistantText.length,
473
+ });
474
+ for (const toolEvent of state.toolEvents) {
475
+ events.push(toolEvent);
476
+ }
477
+ if (assistantText.trim()) {
478
+ events.push({
479
+ type: "message",
480
+ role: "assistant",
481
+ text: assistantText,
482
+ });
483
+ }
484
+ return { events };
485
+ },
486
+ releaseTools,
487
+ async dispose() {
488
+ const pending = [...activeTools];
489
+ activeTools.clear();
490
+ for (const tools of pending) {
491
+ const state = bindings.get(tools);
492
+ bindings.delete(tools);
493
+ if (state)
494
+ await state.handle.shutdown();
495
+ }
496
+ },
497
+ getPiSessionId(tools) {
498
+ return bindings.get(tools)?.handle.piSessionId;
499
+ },
500
+ async abort(tools) {
501
+ const session = bindings.get(tools)?.handle.session;
502
+ if (!session?.abort)
503
+ return;
504
+ workshopLog.info("workshop.turn.abort", "abort");
505
+ await session.abort();
506
+ },
507
+ };
508
+ return model;
509
+ }
510
+ export function createLiveWorkshopOperatorHost(options) {
511
+ const { cwd, agentDir, authPath, model, settingsDefault, profileDefault, piSessionDir, openPiSession, resolveModelId, retriever, projectRoot, } = options;
512
+ return createOperatorAgentHost(createPiOperatorAgentModel({
513
+ cwd,
514
+ ...(agentDir !== undefined ? { agentDir } : {}),
515
+ ...(authPath !== undefined ? { authPath } : {}),
516
+ ...(model !== undefined ? { model } : {}),
517
+ ...(settingsDefault !== undefined ? { settingsDefault } : {}),
518
+ ...(profileDefault !== undefined ? { profileDefault } : {}),
519
+ ...(piSessionDir !== undefined ? { piSessionDir } : {}),
520
+ ...(openPiSession !== undefined ? { openPiSession } : {}),
521
+ ...(resolveModelId !== undefined ? { resolveModelId } : {}),
522
+ }), [
523
+ createWorkshopAuthorProfile({
524
+ retriever,
525
+ projectRoot: projectRoot ?? cwd,
526
+ }),
527
+ ]);
528
+ }
@@ -0,0 +1,23 @@
1
+ import { type DraftPackage } from "../../config/draftPackage.js";
2
+ import { type DocsRetriever } from "../docsRetrieval.js";
3
+ import type { OperatorAgentProfile, OperatorAgentProposal, OperatorAgentTool, OperatorAgentToolContext } from "../types.js";
4
+ import { WORKSHOP_AUTHOR_PLAYBOOK } from "./workshopAuthorPlaybook.js";
5
+ import { type WorkshopAuthorToolOptions } from "./workshopAuthorTools.js";
6
+ export declare const WORKSHOP_AUTHOR_PROFILE_ID = "workshop-author";
7
+ export { WORKSHOP_AUTHOR_PLAYBOOK };
8
+ export { WORKSHOP_AUTHOR_TOOL_NAMES, WORKSHOP_FORBIDDEN_AGENT_TOOLS, buildCreateStageDraft, buildCreateTaskDraft, buildEditStageDraft, buildEditTaskDraft, buildCreatePipelineDraft, buildEditPipelineDraft, createSaveTool, createWorkshopAuthorMutatingTools, } from "./workshopAuthorTools.js";
9
+ export declare function buildStageAddProposal(draft: DraftPackage, userText: string): OperatorAgentProposal;
10
+ export declare function isTaskProposalIntent(message: string): boolean;
11
+ export declare function buildTaskAddProposal(draft: DraftPackage, userText: string): OperatorAgentProposal;
12
+ export type WorkshopAuthorProfileOptions = WorkshopAuthorToolOptions & {
13
+ retriever?: DocsRetriever;
14
+ };
15
+ export declare function createWorkshopAuthorTools(retriever?: DocsRetriever, options?: WorkshopAuthorToolOptions): OperatorAgentTool[];
16
+ /** Default tool list with filesystem docs/examples retrieval. */
17
+ export declare const workshopAuthorTools: OperatorAgentTool[];
18
+ export declare function createWorkshopAuthorProfile(options?: WorkshopAuthorProfileOptions): OperatorAgentProfile;
19
+ export declare function proposeStageFromUserMessage(ctx: OperatorAgentToolContext, message: string): OperatorAgentProposal;
20
+ export declare function proposeTaskFromUserMessage(ctx: OperatorAgentToolContext, message: string): OperatorAgentProposal;
21
+ export declare function assertWorkshopAuthorToolsExcludeDiskShell(tools: readonly {
22
+ name: string;
23
+ }[]): void;