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,92 @@
1
+ import { createOperatorAgentHost, invokeProfileTool, } from "./host.js";
2
+ import { createWorkshopAuthorProfile, isTaskProposalIntent, proposeStageFromUserMessage, proposeTaskFromUserMessage, WORKSHOP_AUTHOR_PROFILE_ID, } from "./profiles/workshopAuthor.js";
3
+ /**
4
+ * Deterministic Operator Agent Host for Workshop and tests.
5
+ * Does not call a live provider — scripted turns or auto stage/task mutations.
6
+ */
7
+ export function createFakeOperatorAgentModel(script = [{ type: "propose_stage" }]) {
8
+ let index = 0;
9
+ return {
10
+ async complete({ profile, message, tools }) {
11
+ const turn = script[Math.min(index, script.length - 1)] ?? {
12
+ type: "propose_stage",
13
+ };
14
+ index += 1;
15
+ if (turn.type === "events") {
16
+ return { events: turn.events };
17
+ }
18
+ if (turn.type === "echo") {
19
+ return {
20
+ events: [
21
+ {
22
+ type: "message",
23
+ role: "assistant",
24
+ text: `Got it: ${message}`,
25
+ },
26
+ ],
27
+ };
28
+ }
29
+ if (turn.type === "call_tool") {
30
+ const result = await invokeProfileTool(profile, turn.name, turn.args ?? {}, tools);
31
+ const events = [
32
+ { type: "tool_result", name: turn.name, result },
33
+ ];
34
+ if (turn.message) {
35
+ events.push({
36
+ type: "message",
37
+ role: "assistant",
38
+ text: turn.message,
39
+ });
40
+ }
41
+ else if (!result.ok) {
42
+ events.push({
43
+ type: "message",
44
+ role: "assistant",
45
+ text: `Retrieval unavailable (${result.error ?? "error"}). Continuing with the baked Workshop Author playbook.`,
46
+ });
47
+ }
48
+ return { events };
49
+ }
50
+ if (turn.type === "propose") {
51
+ tools.emitProposal(turn.proposal);
52
+ return {
53
+ events: [
54
+ {
55
+ type: "message",
56
+ role: "assistant",
57
+ text: turn.message ??
58
+ `Applied to draft: ${turn.proposal.summary}. Accept confirms; Reject undoes when the draft is unchanged.`,
59
+ },
60
+ { type: "proposal", proposal: turn.proposal },
61
+ ],
62
+ };
63
+ }
64
+ const proposal = turn.type === "propose_task" || isTaskProposalIntent(message)
65
+ ? proposeTaskFromUserMessage(tools, message)
66
+ : proposeStageFromUserMessage(tools, message);
67
+ return {
68
+ events: [
69
+ {
70
+ type: "message",
71
+ role: "assistant",
72
+ text: `Applied to draft: ${proposal.summary}. Accept confirms; Reject undoes when the draft is unchanged. Nothing was written to disk — Save when you are ready.`,
73
+ },
74
+ { type: "proposal", proposal },
75
+ ],
76
+ };
77
+ },
78
+ };
79
+ }
80
+ export function createWorkshopOperatorHost(scriptOrOptions) {
81
+ const options = Array.isArray(scriptOrOptions)
82
+ ? { script: scriptOrOptions }
83
+ : (scriptOrOptions ?? {});
84
+ const host = createOperatorAgentHost(options.model ?? createFakeOperatorAgentModel(options.script), [
85
+ createWorkshopAuthorProfile({
86
+ retriever: options.retriever,
87
+ projectRoot: options.projectRoot,
88
+ }),
89
+ ]);
90
+ return host;
91
+ }
92
+ export { WORKSHOP_AUTHOR_PROFILE_ID };
@@ -0,0 +1,40 @@
1
+ import type { OperatorAgentHost, OperatorAgentProfile, OperatorAgentSessionEvent, OperatorAgentToolContext, OperatorAgentToolResult, WorkshopToolActivityUpdate } from "./types.js";
2
+ export type OperatorAgentModelTurn = {
3
+ events: OperatorAgentSessionEvent[];
4
+ };
5
+ export type OperatorAgentModelCompleteInput = {
6
+ profile: OperatorAgentProfile;
7
+ message: string;
8
+ contextSnapshot: unknown;
9
+ tools: OperatorAgentToolContext;
10
+ /**
11
+ * Optional mid-turn assistant text callback (Workshop progressive NDJSON).
12
+ * Invoked as Pi `text_delta` (or equivalent) arrives — before complete resolves.
13
+ */
14
+ onDelta?: (text: string) => void;
15
+ /** Mid-turn tool status for the Workshop chat column. */
16
+ onActivity?: (update: WorkshopToolActivityUpdate) => void;
17
+ /** Workshop composer model for this turn. Applied before the prompt. */
18
+ modelId?: string;
19
+ };
20
+ export type OperatorAgentModel = {
21
+ complete(input: OperatorAgentModelCompleteInput): Promise<OperatorAgentModelTurn>;
22
+ /**
23
+ * Optional restart seed (KTD7): inject prior transcript into a new backend
24
+ * session before the first complete for this host session.
25
+ */
26
+ prepareRestart?(input: {
27
+ tools: OperatorAgentToolContext;
28
+ profile: OperatorAgentProfile;
29
+ transcript: readonly {
30
+ role: string;
31
+ text: string;
32
+ }[];
33
+ }): Promise<void>;
34
+ /** Optional: dispose backend resources bound to this tool context. */
35
+ releaseTools?(tools: OperatorAgentToolContext): void | Promise<void>;
36
+ /** Interrupt the in-flight prompt for this tool context. */
37
+ abort?(tools: OperatorAgentToolContext): Promise<void>;
38
+ };
39
+ export declare function createOperatorAgentHost(model: OperatorAgentModel, seedProfiles?: OperatorAgentProfile[]): OperatorAgentHost;
40
+ export declare function invokeProfileTool(profile: OperatorAgentProfile, name: string, args: Record<string, unknown>, ctx: OperatorAgentToolContext): Promise<OperatorAgentToolResult>;
@@ -0,0 +1,179 @@
1
+ import { readDraftFromContext } from "./draftContext.js";
2
+ import { draftFingerprint, enrichProposal, isMutationConflict, UNDO_MUTATION_CONFLICT_NOTICE, } from "./proposals.js";
3
+ import { rejectUnlinkedWorkshopDraftTool } from "../workshop/workshopPin.js";
4
+ function createSession(profile, initialContext, model) {
5
+ let context = initialContext;
6
+ let closed = false;
7
+ const mutations = new Map();
8
+ let lastMutationId = null;
9
+ let lastEmitted = null;
10
+ const toolContext = {
11
+ getContext: () => context,
12
+ setContext: (next) => {
13
+ context = next;
14
+ },
15
+ emitProposal: (proposal) => {
16
+ const enriched = enrichProposal(proposal, context);
17
+ context = profile.contextAdapter.applyProposal(context, enriched);
18
+ const applied = {
19
+ ...enriched,
20
+ appliedFingerprint: draftFingerprint(readDraftFromContext(context)),
21
+ };
22
+ mutations.set(applied.id, applied);
23
+ lastMutationId = applied.id;
24
+ lastEmitted = applied;
25
+ },
26
+ };
27
+ function resolveMutation(mutationId) {
28
+ if (mutations.size === 0)
29
+ return { ok: false, reason: "none" };
30
+ const id = mutationId ?? lastMutationId;
31
+ if (!id)
32
+ return { ok: false, reason: "none" };
33
+ const mutation = mutations.get(id);
34
+ if (!mutation) {
35
+ if (mutationId !== undefined)
36
+ return { ok: false, reason: "id_mismatch" };
37
+ return { ok: false, reason: "none" };
38
+ }
39
+ return { ok: true, mutation };
40
+ }
41
+ function undoMutation(mutationId) {
42
+ const resolved = resolveMutation(mutationId);
43
+ if (!resolved.ok)
44
+ return resolved;
45
+ const { mutation } = resolved;
46
+ if (isMutationConflict(mutation, context)) {
47
+ return {
48
+ ok: false,
49
+ reason: "conflict",
50
+ notice: UNDO_MUTATION_CONFLICT_NOTICE,
51
+ };
52
+ }
53
+ if (mutation.baseContext !== undefined) {
54
+ context = mutation.baseContext;
55
+ }
56
+ mutations.delete(mutation.id);
57
+ if (lastMutationId === mutation.id) {
58
+ lastMutationId = [...mutations.keys()].at(-1) ?? null;
59
+ }
60
+ return { ok: true };
61
+ }
62
+ return {
63
+ profileId: profile.id,
64
+ profileTitle: profile.title,
65
+ getContext: () => context,
66
+ setContext: (next) => {
67
+ context = next;
68
+ },
69
+ getPendingProposal: () => {
70
+ if (!lastMutationId)
71
+ return null;
72
+ return mutations.get(lastMutationId) ?? null;
73
+ },
74
+ getMutation: (mutationId) => mutations.get(mutationId) ?? null,
75
+ async prepareRestart(transcript) {
76
+ if (closed)
77
+ return;
78
+ if (!model.prepareRestart)
79
+ return;
80
+ await model.prepareRestart({
81
+ profile,
82
+ tools: toolContext,
83
+ transcript,
84
+ });
85
+ },
86
+ async send(message, options) {
87
+ if (closed) {
88
+ return [{ type: "error", message: "session is closed" }];
89
+ }
90
+ lastEmitted = null;
91
+ const turn = await model.complete({
92
+ profile,
93
+ message,
94
+ contextSnapshot: profile.contextAdapter.serialize(context),
95
+ tools: toolContext,
96
+ onDelta: options?.onDelta,
97
+ onActivity: options?.onActivity,
98
+ modelId: options?.modelId,
99
+ });
100
+ const events = [];
101
+ let sawProposal = false;
102
+ for (const event of turn.events) {
103
+ if (event.type === "proposal") {
104
+ sawProposal = true;
105
+ events.push({
106
+ type: "proposal",
107
+ proposal: lastEmitted ?? enrichProposal(event.proposal, context),
108
+ });
109
+ }
110
+ else {
111
+ events.push(event);
112
+ }
113
+ }
114
+ if (!sawProposal && lastEmitted) {
115
+ events.push({ type: "proposal", proposal: lastEmitted });
116
+ }
117
+ return events;
118
+ },
119
+ async abort() {
120
+ if (closed)
121
+ return;
122
+ await model.abort?.(toolContext);
123
+ },
124
+ acceptProposal(proposalId) {
125
+ const resolved = resolveMutation(proposalId);
126
+ if (!resolved.ok)
127
+ return resolved;
128
+ mutations.delete(resolved.mutation.id);
129
+ if (lastMutationId === resolved.mutation.id) {
130
+ lastMutationId = [...mutations.keys()].at(-1) ?? null;
131
+ }
132
+ return { ok: true };
133
+ },
134
+ rejectProposal(proposalId) {
135
+ return undoMutation(proposalId);
136
+ },
137
+ undoMutation,
138
+ close() {
139
+ closed = true;
140
+ mutations.clear();
141
+ lastMutationId = null;
142
+ void model.releaseTools?.(toolContext);
143
+ },
144
+ };
145
+ }
146
+ export function createOperatorAgentHost(model, seedProfiles = []) {
147
+ const profiles = new Map();
148
+ for (const profile of seedProfiles) {
149
+ profiles.set(profile.id, profile);
150
+ }
151
+ return {
152
+ registerProfile(profile) {
153
+ profiles.set(profile.id, profile);
154
+ },
155
+ getProfile(id) {
156
+ return profiles.get(id);
157
+ },
158
+ listProfiles() {
159
+ return [...profiles.values()];
160
+ },
161
+ openSession({ profileId, context }) {
162
+ const profile = profiles.get(profileId);
163
+ if (!profile) {
164
+ throw new Error(`Unknown operator agent profile: ${profileId}`);
165
+ }
166
+ return createSession(profile, context, model);
167
+ },
168
+ };
169
+ }
170
+ export async function invokeProfileTool(profile, name, args, ctx) {
171
+ const tool = profile.tools.find((t) => t.name === name);
172
+ if (!tool) {
173
+ return { ok: false, content: null, error: `Unknown tool: ${name}` };
174
+ }
175
+ const blocked = rejectUnlinkedWorkshopDraftTool(ctx.getContext(), name);
176
+ if (blocked)
177
+ return blocked;
178
+ return tool.handler(args, ctx);
179
+ }
@@ -0,0 +1,9 @@
1
+ export type { AcceptProposalResult, OperatorAgentContextAdapter, OperatorAgentHost, OperatorAgentProfile, OperatorAgentProposal, OperatorAgentSession, OperatorAgentSessionEvent, OperatorAgentTool, OperatorAgentToolContext, OperatorAgentToolResult, ProposalArtifactDiff, UndoMutationResult, WorkshopDraftContext, WorkshopToolActivityUpdate, } from "./types.js";
2
+ export { createOperatorAgentHost, invokeProfileTool, type OperatorAgentModel, type OperatorAgentModelTurn, } from "./host.js";
3
+ export { createFakeOperatorAgentModel, createWorkshopOperatorHost, type FakeOperatorTurn, type WorkshopOperatorHostOptions, } from "./fakeHost.js";
4
+ export { createLiveWorkshopOperatorHost, createPiOperatorAgentModel, type LiveWorkshopOperatorHostOptions, type PiOperatorAgentModel, type PiOperatorAgentModelOptions, type PiOperatorOpenSessionInput, type PiOperatorSessionHandle, type WorkshopTranscriptSeedMessage, } from "./piModel.js";
5
+ export { createFailingDocsRetriever, createFilesystemDocsRetriever, createStubDocsRetriever, resolveWorkshopCatalogRoot, type DocsRetrievalHit, type DocsRetrievalResult, type DocsRetriever, } from "./docsRetrieval.js";
6
+ export { createWorkshopDraftContext, draftTrackStages, emptyDraftPackage, isWorkshopDraftContext, readDraftFromContext, withDestination, withDraft, withProjectRoot, workshopDraftContextAdapter, WORKSHOP_AUTHOR_GREETING, } from "./draftContext.js";
7
+ export { affectedStageIds, diffDraftPackages, draftFingerprint, enrichProposal, isMutationConflict, STALE_PROPOSAL_NOTICE, UNDO_MUTATION_CONFLICT_NOTICE, } from "./proposals.js";
8
+ 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";
9
+ export { buildCreatePipelineDraft, buildCreateStageDraft, buildCreateTaskDraft, buildEditPipelineDraft, buildEditStageDraft, buildEditTaskDraft, createSaveTool, createWorkshopAuthorMutatingTools, WORKSHOP_AUTHOR_MUTATING_TOOLS, } from "./profiles/workshopAuthorTools.js";
@@ -0,0 +1,8 @@
1
+ export { createOperatorAgentHost, invokeProfileTool, } from "./host.js";
2
+ export { createFakeOperatorAgentModel, createWorkshopOperatorHost, } from "./fakeHost.js";
3
+ export { createLiveWorkshopOperatorHost, createPiOperatorAgentModel, } from "./piModel.js";
4
+ export { createFailingDocsRetriever, createFilesystemDocsRetriever, createStubDocsRetriever, resolveWorkshopCatalogRoot, } from "./docsRetrieval.js";
5
+ export { createWorkshopDraftContext, draftTrackStages, emptyDraftPackage, isWorkshopDraftContext, readDraftFromContext, withDestination, withDraft, withProjectRoot, workshopDraftContextAdapter, WORKSHOP_AUTHOR_GREETING, } from "./draftContext.js";
6
+ export { affectedStageIds, diffDraftPackages, draftFingerprint, enrichProposal, isMutationConflict, STALE_PROPOSAL_NOTICE, UNDO_MUTATION_CONFLICT_NOTICE, } from "./proposals.js";
7
+ 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";
8
+ export { buildCreatePipelineDraft, buildCreateStageDraft, buildCreateTaskDraft, buildEditPipelineDraft, buildEditStageDraft, buildEditTaskDraft, createSaveTool, createWorkshopAuthorMutatingTools, WORKSHOP_AUTHOR_MUTATING_TOOLS, } from "./profiles/workshopAuthorTools.js";
@@ -0,0 +1,80 @@
1
+ import { type AgentSession, defineTool, SessionManager } from "@earendil-works/pi-coding-agent";
2
+ import "../agent/cursorProvider.js";
3
+ import { type OperatorAgentModel } from "./host.js";
4
+ import { type WorkshopAuthorProfileOptions } from "./profiles/workshopAuthor.js";
5
+ import type { OperatorAgentHost, OperatorAgentProfile, OperatorAgentToolContext, OperatorAgentToolResult, WorkshopToolActivityUpdate } from "./types.js";
6
+ export type WorkshopTranscriptSeedMessage = {
7
+ role: string;
8
+ text: string;
9
+ };
10
+ export type PiOperatorAgentModelOptions = {
11
+ cwd: string;
12
+ /** Sealed Pi agent dir; defaults under `$STAGEFLOW_HOME/workshop/agent`. */
13
+ agentDir?: string;
14
+ /** Override credential auth.json; defaults via resolveCredentialBinding(cwd). */
15
+ authPath?: string;
16
+ /** Model id; defaults via resolveWorkshopModel. */
17
+ model?: string | null;
18
+ settingsDefault?: string | null;
19
+ profileDefault?: string | null;
20
+ /**
21
+ * Optional directory for durable Pi session JSONL (new file each process;
22
+ * restart still uses new Pi + replay — KTD7).
23
+ */
24
+ piSessionDir?: string;
25
+ /** Test seam: inject session construction. */
26
+ openPiSession?: (input: PiOperatorOpenSessionInput) => Promise<PiOperatorSessionHandle>;
27
+ /** Test seam: skip live auth / model resolution. */
28
+ resolveModelId?: () => string;
29
+ };
30
+ export type PiOperatorOpenSessionInput = {
31
+ cwd: string;
32
+ agentDir: string;
33
+ systemPrompt: string;
34
+ toolNames: string[];
35
+ customTools: ReturnType<typeof defineTool>[];
36
+ modelId: string;
37
+ authPath: string;
38
+ piSessionDir?: string;
39
+ };
40
+ export type PiOperatorSessionHandle = {
41
+ session: Pick<AgentSession, "prompt" | "subscribe" | "dispose" | "bindExtensions" | "setModel" | "setThinkingLevel"> & {
42
+ agent?: {
43
+ state: {
44
+ messages: unknown;
45
+ };
46
+ };
47
+ abort?: AgentSession["abort"];
48
+ };
49
+ sessionManager: {
50
+ appendCustomMessageEntry: SessionManager["appendCustomMessageEntry"];
51
+ buildSessionContext: SessionManager["buildSessionContext"];
52
+ getSessionId: SessionManager["getSessionId"];
53
+ };
54
+ restoreProvider?: () => void;
55
+ shutdown: () => Promise<void>;
56
+ piSessionId: string;
57
+ /** Extension paths loaded when this Pi session was opened. Absent on test doubles. */
58
+ extensionPaths?: readonly string[];
59
+ /** Switch the live Pi model before the next prompt. No-op when unchanged. */
60
+ applyModel?: (modelId: string) => Promise<void>;
61
+ };
62
+ export declare function sessionNeedsExtensionReload(loaded: readonly string[] | undefined, needed: readonly string[]): boolean;
63
+ export type PiOperatorAgentModel = OperatorAgentModel & {
64
+ prepareRestart(input: {
65
+ tools: OperatorAgentToolContext;
66
+ profile: OperatorAgentProfile;
67
+ transcript: readonly WorkshopTranscriptSeedMessage[];
68
+ }): Promise<void>;
69
+ releaseTools(tools: OperatorAgentToolContext): Promise<void>;
70
+ dispose(): Promise<void>;
71
+ getPiSessionId(tools: OperatorAgentToolContext): string | undefined;
72
+ };
73
+ export declare function workshopToolLogFields(args: Record<string, unknown>, result?: OperatorAgentToolResult): Record<string, unknown>;
74
+ export declare function workshopToolActivity(id: string, name: string, phase: "start" | "done", args: Record<string, unknown>, result?: OperatorAgentToolResult): WorkshopToolActivityUpdate;
75
+ /**
76
+ * Pi OperatorAgentModel: durable session per host tool-context, Workshop tools only.
77
+ */
78
+ export declare function createPiOperatorAgentModel(options: PiOperatorAgentModelOptions): PiOperatorAgentModel;
79
+ export type LiveWorkshopOperatorHostOptions = WorkshopAuthorProfileOptions & PiOperatorAgentModelOptions;
80
+ export declare function createLiveWorkshopOperatorHost(options: LiveWorkshopOperatorHostOptions): OperatorAgentHost;