stageflow 0.32.0 → 0.35.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.
- package/README.md +4 -3
- package/dist/agent/adapterSpill.d.ts +14 -0
- package/dist/agent/adapterSpill.js +83 -0
- package/dist/agent/agentBackend.d.ts +2 -2
- package/dist/agent/agentBackend.js +2 -2
- package/dist/agent/claudeAdapter.d.ts +13 -2
- package/dist/agent/claudeAdapter.js +50 -6
- package/dist/agent/cursorProvider.d.ts +3 -0
- package/dist/agent/cursorProvider.js +23 -6
- package/dist/agent/fakeAgent.d.ts +3 -3
- package/dist/agent/fakeAgent.js +0 -6
- package/dist/agent/piAdapter.d.ts +2 -2
- package/dist/agent/piAdapter.js +116 -15
- package/dist/agent/piIsolatedMcp.d.ts +1 -0
- package/dist/agent/piIsolatedMcp.js +19 -1
- package/dist/agent/piIsolatedMcpProbe.d.ts +11 -0
- package/dist/agent/piIsolatedMcpProbe.js +20 -0
- package/dist/agent/port.d.ts +2 -2
- package/dist/agent/providerAuth.d.ts +6 -0
- package/dist/agent/providerAuth.js +86 -17
- package/dist/agent/{resolveAgentPort.d.ts → resolveStagePort.d.ts} +8 -6
- package/dist/agent/{resolveAgentPort.js → resolveStagePort.js} +13 -9
- package/dist/agent/stageTurnDriver.d.ts +33 -0
- package/dist/agent/stageTurnDriver.js +64 -0
- package/dist/agent/toolOutputBudget.d.ts +46 -0
- package/dist/agent/toolOutputBudget.js +97 -0
- package/dist/agent/toolOutputBudgetExtension.d.ts +22 -0
- package/dist/agent/toolOutputBudgetExtension.js +141 -0
- package/dist/agent/toolOutputSpill.d.ts +34 -0
- package/dist/agent/toolOutputSpill.js +85 -0
- package/dist/browser/agentBrowserLiveViewRelay.d.ts +41 -0
- package/dist/browser/agentBrowserLiveViewRelay.js +801 -0
- package/dist/browser/anchor.d.ts +2 -0
- package/dist/browser/anchor.js +2 -1
- package/dist/browser/auditSink.d.ts +8 -0
- package/dist/browser/browserHost.d.ts +29 -0
- package/dist/browser/browserSweep.d.ts +4 -1
- package/dist/browser/browserSweep.js +7 -0
- package/dist/browser/browserTeardown.d.ts +1 -0
- package/dist/browser/browserTeardown.js +32 -2
- package/dist/browser/containerBrowserEndpoint.d.ts +11 -0
- package/dist/browser/containerBrowserEndpoint.js +57 -0
- package/dist/browser/containerBrowserHost.d.ts +24 -0
- package/dist/browser/containerBrowserHost.js +147 -0
- package/dist/browser/dockerSandboxOrchestrator.d.ts +26 -0
- package/dist/browser/dockerSandboxOrchestrator.js +142 -0
- package/dist/browser/fakeLiveViewRelay.d.ts +15 -0
- package/dist/browser/fakeLiveViewRelay.js +94 -0
- package/dist/browser/fakeLiveViewSource.d.ts +6 -0
- package/dist/browser/fakeLiveViewSource.js +16 -0
- package/dist/browser/fakeRemoteBrowserHost.d.ts +2 -1
- package/dist/browser/fakeRemoteBrowserHost.js +2 -1
- package/dist/browser/fakeSandboxOrchestrator.d.ts +9 -0
- package/dist/browser/fakeSandboxOrchestrator.js +44 -0
- package/dist/browser/gateHandoff.d.ts +0 -2
- package/dist/browser/gateHandoff.js +5 -11
- package/dist/browser/hostCapabilities.d.ts +23 -0
- package/dist/browser/hostCapabilities.js +23 -0
- package/dist/browser/humanLogin.d.ts +2 -2
- package/dist/browser/humanLogin.js +11 -2
- package/dist/browser/liveViewPersisted.d.ts +11 -0
- package/dist/browser/liveViewPersisted.js +22 -0
- package/dist/browser/liveViewRelay.d.ts +76 -0
- package/dist/browser/liveViewRelay.js +1 -0
- package/dist/browser/liveViewSessions.d.ts +25 -0
- package/dist/browser/liveViewSessions.js +139 -0
- package/dist/browser/liveViewSource.d.ts +25 -0
- package/dist/browser/liveViewSource.js +7 -0
- package/dist/browser/liveViewTickets.d.ts +46 -0
- package/dist/browser/liveViewTickets.js +122 -0
- package/dist/browser/localBrowserHost.d.ts +10 -0
- package/dist/browser/localBrowserHost.js +53 -7
- package/dist/browser/ownerScope.d.ts +10 -0
- package/dist/browser/ownerScope.js +6 -0
- package/dist/browser/profileStore.d.ts +5 -2
- package/dist/browser/profileStore.js +3 -5
- package/dist/browser/sandboxOrchestrator.d.ts +60 -0
- package/dist/browser/sandboxOrchestrator.js +8 -0
- package/dist/browser/sessionApiSandboxOrchestrator.d.ts +34 -0
- package/dist/browser/sessionApiSandboxOrchestrator.js +108 -0
- package/dist/browser/stageBrowserEnv.d.ts +7 -0
- package/dist/browser/stageBrowserEnv.js +53 -15
- package/dist/browser/stageHandoff.d.ts +47 -0
- package/dist/browser/stageHandoff.js +101 -0
- package/dist/browser/stageProfileLock.d.ts +1 -0
- package/dist/browser/stageProfileLock.js +1 -3
- package/dist/browser/volumeProfileStore.d.ts +7 -0
- package/dist/browser/volumeProfileStore.js +35 -0
- package/dist/cli/browserCommand.d.ts +3 -1
- package/dist/cli/browserCommand.js +25 -20
- package/dist/cli/resolveCliProjectRoot.d.ts +7 -0
- package/dist/cli/resolveCliProjectRoot.js +27 -0
- package/dist/cli/runCommand.d.ts +1 -1
- package/dist/cli/runCommand.js +59 -17
- package/dist/cli/skillsCommand.d.ts +20 -0
- package/dist/cli/skillsCommand.js +74 -31
- package/dist/cli/validateCommand.d.ts +1 -1
- package/dist/cli/validateCommand.js +22 -4
- package/dist/cli.js +4 -4
- package/dist/config/browseCatalog.d.ts +2 -0
- package/dist/config/browseCatalog.js +6 -0
- package/dist/config/catalogRelativePath.d.ts +4 -0
- package/dist/config/catalogRelativePath.js +37 -9
- package/dist/config/createStage.d.ts +1 -0
- package/dist/config/createStage.js +11 -2
- package/dist/config/createTask.d.ts +30 -0
- package/dist/config/createTask.js +161 -0
- package/dist/config/createTrigger.d.ts +15 -0
- package/dist/config/createTrigger.js +32 -25
- package/dist/config/draftPackage.d.ts +41 -0
- package/dist/config/draftPackage.js +216 -23
- package/dist/config/ensureCatalogScanRoot.d.ts +2 -1
- package/dist/config/ensureCatalogScanRoot.js +6 -2
- package/dist/config/findTaskInCatalog.d.ts +33 -0
- package/dist/config/findTaskInCatalog.js +69 -0
- package/dist/config/hostConfig.d.ts +21 -0
- package/dist/config/hostConfig.js +113 -1
- package/dist/config/importTask.d.ts +19 -0
- package/dist/config/importTask.js +133 -0
- package/dist/config/installSkillRequest.d.ts +40 -0
- package/dist/config/installSkillRequest.js +286 -0
- package/dist/config/listConfig.d.ts +0 -16
- package/dist/config/listConfig.js +0 -3
- package/dist/config/loadOutcome.d.ts +11 -6
- package/dist/config/loadPipeline.js +0 -1
- package/dist/config/loadStage.js +2 -0
- package/dist/config/loadStageflowManifest.js +4 -1
- package/dist/config/loadTask.js +2 -0
- package/dist/config/loadTrigger.js +2 -0
- package/dist/config/mergePipelineIncludes.js +3 -0
- package/dist/config/normalizePipelineStageEntry.js +10 -1
- package/dist/config/printTargetYaml.js +0 -1
- package/dist/config/publishDraftPackage.d.ts +5 -1
- package/dist/config/publishDraftPackage.js +4 -1
- package/dist/config/resolveCatalogRoots.d.ts +4 -1
- package/dist/config/resolveCatalogRoots.js +18 -1
- package/dist/config/skillUsageIndex.d.ts +6 -0
- package/dist/config/skillUsageIndex.js +39 -0
- package/dist/config/stageBrowser.js +13 -0
- package/dist/config/triggerAdapterStatus.d.ts +11 -0
- package/dist/config/triggerAdapterStatus.js +90 -0
- package/dist/config/triggerCatalog.d.ts +41 -2
- package/dist/config/triggerCatalog.js +107 -15
- package/dist/config/updateTask.d.ts +30 -0
- package/dist/config/updateTask.js +119 -0
- package/dist/config/updateTrigger.d.ts +38 -0
- package/dist/config/updateTrigger.js +220 -0
- package/dist/config/validateCatalog.d.ts +6 -2
- package/dist/config/validateCatalog.js +48 -7
- package/dist/config/workshopCatalogFilenames.d.ts +37 -0
- package/dist/config/workshopCatalogFilenames.js +125 -0
- package/dist/config/workshopCatalogRepair.d.ts +7 -0
- package/dist/config/workshopCatalogRepair.js +144 -0
- package/dist/config/yamlParsePosition.d.ts +4 -0
- package/dist/config/yamlParsePosition.js +9 -0
- package/dist/hosted/containment.d.ts +3 -0
- package/dist/hosted/containment.js +36 -0
- package/dist/hosted/errors.d.ts +21 -0
- package/dist/hosted/errors.js +30 -0
- package/dist/hosted/packageSkills.d.ts +3 -0
- package/dist/hosted/packageSkills.js +80 -0
- package/dist/hosted/runtime.d.ts +12 -0
- package/dist/hosted/runtime.js +596 -0
- package/dist/hosted/sequencer.d.ts +28 -0
- package/dist/hosted/sequencer.js +129 -0
- package/dist/hosted/translate.d.ts +3 -0
- package/dist/hosted/translate.js +43 -0
- package/dist/hosted/types.d.ts +108 -0
- package/dist/hosted/types.js +10 -0
- package/dist/index.d.ts +9 -1
- package/dist/index.js +6 -0
- package/dist/mcp/getStartedTool.js +15 -6
- package/dist/mcp/triggerTools.js +2 -8
- package/dist/operatorAgent/agentPort.d.ts +11 -0
- package/dist/operatorAgent/agentPort.js +12 -0
- package/dist/operatorAgent/index.d.ts +1 -0
- package/dist/operatorAgent/index.js +1 -0
- package/dist/operatorAgent/piModel.js +26 -6
- package/dist/operatorAgent/profiles/workshopAuthorPlaybook.d.ts +1 -1
- package/dist/operatorAgent/profiles/workshopAuthorPlaybook.js +4 -2
- package/dist/operatorAgent/profiles/workshopAuthorTools.js +103 -16
- package/dist/package-meta.d.ts +1 -1
- package/dist/package-meta.js +1 -1
- package/dist/project/ensureProjectRootsFromEnv.d.ts +3 -0
- package/dist/project/ensureProjectRootsFromEnv.js +22 -0
- package/dist/project/globalHome.d.ts +1 -0
- package/dist/project/globalHome.js +18 -0
- package/dist/project/workspaceCatalog.d.ts +10 -0
- package/dist/project/workspaceCatalog.js +91 -0
- package/dist/projection/projectRun.d.ts +0 -1
- package/dist/projection/projectRun.js +0 -1
- package/dist/runstore/backup.js +14 -4
- package/dist/runstore/port.d.ts +11 -1
- package/dist/runstore/restore.js +5 -2
- package/dist/runstore/sqlite/SqliteRunStore.d.ts +8 -0
- package/dist/runstore/sqlite/SqliteRunStore.js +29 -9
- package/dist/runstore/sqlite/migrations/012-trigger-fires.d.ts +7 -0
- package/dist/runstore/sqlite/migrations/012-trigger-fires.js +18 -0
- package/dist/runstore/sqlite/migrations/index.js +2 -0
- package/dist/runstore/stageSnapshot.d.ts +3 -1
- package/dist/runstore/stageSnapshot.js +19 -0
- package/dist/runstore/workspaceLayout.js +27 -0
- package/dist/runstore/writeContainedArtifact.d.ts +1 -0
- package/dist/runstore/writeContainedArtifact.js +52 -0
- package/dist/runtime/containerLimits.d.ts +0 -3
- package/dist/runtime/containerLimits.js +0 -5
- package/dist/runtime/credentialBinding.d.ts +3 -0
- package/dist/runtime/credentialBinding.js +23 -6
- package/dist/runtime/emailSource.js +20 -28
- package/dist/runtime/githubPollSource.js +20 -28
- package/dist/runtime/pipelineRunner.d.ts +4 -4
- package/dist/runtime/pipelineScheduler.d.ts +2 -2
- package/dist/runtime/pipelineScheduler.js +3 -0
- package/dist/runtime/resumeReconstruct.d.ts +2 -2
- package/dist/runtime/resumeTimedOut.d.ts +2 -2
- package/dist/runtime/runManager.d.ts +18 -2
- package/dist/runtime/runManager.js +95 -30
- package/dist/runtime/runRetentionSweep.d.ts +0 -2
- package/dist/runtime/runRetentionSweep.js +0 -8
- package/dist/runtime/runRetryCoordinator.d.ts +2 -2
- package/dist/runtime/scheduleSource.js +15 -24
- package/dist/runtime/stageAttemptBootstrap.d.ts +2 -2
- package/dist/runtime/stageAttemptBootstrap.js +10 -1
- package/dist/runtime/stageProcessLauncher.js +2 -2
- package/dist/runtime/stageRoots.js +12 -1
- package/dist/runtime/stageRunner.d.ts +2 -2
- package/dist/runtime/stageRunner.js +8 -2
- package/dist/runtime/stageWorker.js +2 -2
- package/dist/runtime/triggerPort.d.ts +5 -3
- package/dist/runtime/triggerRunner.d.ts +1 -0
- package/dist/runtime/triggerRunner.js +27 -20
- package/dist/runtime/webhookAccept.d.ts +25 -0
- package/dist/runtime/webhookAccept.js +56 -0
- package/dist/server/bootstrap.d.ts +7 -2
- package/dist/server/bootstrap.js +15 -1
- package/dist/server/controlToken.d.ts +1 -1
- package/dist/server/controlToken.js +18 -2
- package/dist/server/healthSurfaces.d.ts +12 -0
- package/dist/server/healthSurfaces.js +27 -6
- package/dist/server/http.d.ts +19 -10
- package/dist/server/http.js +605 -85
- package/dist/server/liveViewPath.d.ts +9 -0
- package/dist/server/liveViewPath.js +8 -0
- package/dist/server/liveViewRoutes.d.ts +58 -0
- package/dist/server/liveViewRoutes.js +565 -0
- package/dist/server/mcpHost.d.ts +4 -2
- package/dist/server/mcpHost.js +2 -0
- package/dist/server/readCatalogFile.d.ts +29 -0
- package/dist/server/readCatalogFile.js +215 -0
- package/dist/server/triggerRoutes.d.ts +1 -0
- package/dist/server/triggerRoutes.js +200 -73
- package/dist/tools/readEmail.d.ts +3 -3
- package/dist/tools/writeStageArtifact.d.ts +9 -0
- package/dist/tools/writeStageArtifact.js +2 -47
- package/dist/types/pipeline.d.ts +1 -1
- package/dist/types/stage.d.ts +1 -1
- package/dist/types/stageflowManifest.d.ts +1 -1
- package/dist/ui/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
- package/dist/ui/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
- package/dist/ui/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
- package/dist/ui/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
- package/dist/ui/assets/geist-mono-cyrillic-ext-wght-normal-X_5orZeX.woff2 +0 -0
- package/dist/ui/assets/geist-mono-cyrillic-wght-normal-DiZS0aHC.woff2 +0 -0
- package/dist/ui/assets/geist-mono-latin-ext-wght-normal-Bwz-egvJ.woff2 +0 -0
- package/dist/ui/assets/geist-mono-latin-wght-normal-XN7g48iV.woff2 +0 -0
- package/dist/ui/assets/geist-mono-symbols2-wght-normal-CO5SzqOn.woff2 +0 -0
- package/dist/ui/assets/geist-mono-vietnamese-wght-normal-DadHysG0.woff2 +0 -0
- package/dist/ui/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
- package/dist/ui/assets/index-BoFPkKFg.js +256 -0
- package/dist/ui/assets/{index-Bv4p1aPK.css → index-CIPbbBUi.css} +1 -1
- package/dist/ui/index.html +4 -4
- package/dist/workshop/autosave.d.ts +2 -2
- package/dist/workshop/autosave.js +4 -6
- package/dist/workshop/buildStore.d.ts +2 -0
- package/dist/workshop/chatAttachments.d.ts +27 -0
- package/dist/workshop/chatAttachments.js +98 -0
- package/dist/workshop/chatTurn.d.ts +5 -2
- package/dist/workshop/chatTurn.js +22 -18
- package/dist/workshop/sessionMutations.d.ts +17 -0
- package/dist/workshop/sessionMutations.js +107 -0
- package/dist/workshop/sessionStore.d.ts +10 -0
- package/dist/workshop/sessionStore.js +52 -0
- package/dist/workshop/workshopPin.d.ts +4 -3
- package/dist/workshop/workshopPin.js +26 -6
- package/dist/workshop/workshopTranscriptTurn.d.ts +8 -0
- package/dist/workshop/workshopTranscriptTurn.js +46 -0
- package/examples/README.md +1 -1
- package/examples/archify-on-pr/README.md +1 -1
- package/examples/archify-on-pr/archify-on-pr.pipeline.yaml +0 -1
- package/examples/archify-on-pr/author-diagrams.yaml +1 -0
- package/examples/conditional-fork/branch-a.yaml +1 -1
- package/examples/conditional-fork/decide.yaml +2 -1
- package/examples/feature-loop/{implement.yaml → feature-implement.yaml} +1 -1
- package/examples/feature-loop/feature-loop.pipeline.yaml +10 -10
- package/examples/feature-loop/{plan.yaml → feature-plan.yaml} +1 -1
- package/examples/feature-loop/{review.yaml → feature-review.yaml} +1 -1
- package/examples/feedback-loop/{implement.yaml → feedback-implement.yaml} +1 -1
- package/examples/feedback-loop/feedback-loop-wait-human.pipeline.yaml +9 -9
- package/examples/feedback-loop/feedback-loop.pipeline.yaml +9 -9
- package/examples/feedback-loop/{plan.yaml → feedback-plan.yaml} +1 -1
- package/examples/feedback-loop/{review.yaml → feedback-review.yaml} +1 -1
- package/examples/generic-fan-in/{research.yaml → fan-in-research.yaml} +1 -1
- package/examples/generic-fan-in/generic-fan-in-accepted.pipeline.yaml +3 -3
- package/examples/generic-fan-in/generic-fan-in.pipeline.yaml +3 -3
- package/examples/hello-world/{research.yaml → hello-research.yaml} +1 -1
- package/examples/hello-world/hello.pipeline.yaml +2 -2
- package/examples/mcp-hitl-tour/{review.yaml → mcp-hitl-review.yaml} +1 -1
- package/examples/mcp-hitl-tour/mcp-hitl-tour.pipeline.yaml +3 -3
- package/examples/oss-issue-contribution/oss-explain-fix.yaml +1 -0
- package/examples/oss-issue-contribution/oss-explain-issue.yaml +1 -0
- package/examples/oss-issue-contribution/oss-issue-contribution.pipeline.yaml +0 -2
- package/examples/stageflow.yaml +6 -0
- package/examples/triggers/sample-github-pr.trigger.yaml +12 -0
- package/examples/triggers/sample-inbox-email.trigger.yaml +14 -0
- package/examples/triggers/sample-manual-hello.trigger.yaml +5 -0
- package/examples/triggers/sample-nightly-hello.trigger.yaml +8 -0
- package/examples/triggers/sample-signed-webhook.trigger.yaml +11 -0
- package/examples/triggers-readiness/README.md +48 -0
- package/examples/triggers-readiness/readiness-emit.yaml +18 -0
- package/examples/triggers-readiness/readiness.pipeline.yaml +4 -0
- package/examples/triggers-readiness/readiness.task.yaml +6 -0
- package/examples/triggers-readiness/stageflow.yaml +13 -0
- package/examples/triggers-readiness/triggers/readiness-dynamic-manual.trigger.yaml +4 -0
- package/examples/triggers-readiness/triggers/readiness-email.trigger.yaml +12 -0
- package/examples/triggers-readiness/triggers/readiness-github-pr.trigger.yaml +12 -0
- package/examples/triggers-readiness/triggers/readiness-manual.trigger.yaml +5 -0
- package/examples/triggers-readiness/triggers/readiness-schedule.trigger.yaml +8 -0
- package/examples/triggers-readiness/triggers/readiness-webhook.trigger.yaml +11 -0
- package/package.json +9 -1
- package/skills/stageflow/references/control-surface.md +1 -1
- package/skills/stageflow-author/references/catalog-write-conventions.md +2 -2
- package/skills/stageflow-run/SKILL.md +1 -1
- package/skills/stageflow-run/references/mcp-call.md +1 -1
- package/skills/stageflow-setup/SKILL.md +1 -1
- package/dist/ui/assets/index-59cjF0OA.js +0 -133
package/dist/ui/index.html
CHANGED
|
@@ -5,16 +5,16 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<script>
|
|
7
7
|
try {
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
document.documentElement.setAttribute("data-theme", "dark");
|
|
9
|
+
document.documentElement.setAttribute("data-redesign", "on");
|
|
10
10
|
} catch (e) {}
|
|
11
11
|
</script>
|
|
12
12
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
13
13
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Figtree:wght@400;500;600;700&display=swap" />
|
|
14
14
|
<link rel="icon" type="image/svg+xml" href="/stageflow-icon.svg" />
|
|
15
15
|
<title>Stageflow</title>
|
|
16
|
-
<script type="module" crossorigin src="/assets/index-
|
|
17
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
16
|
+
<script type="module" crossorigin src="/assets/index-BoFPkKFg.js"></script>
|
|
17
|
+
<link rel="stylesheet" crossorigin href="/assets/index-CIPbbBUi.css">
|
|
18
18
|
</head>
|
|
19
19
|
<body>
|
|
20
20
|
<div id="root"></div>
|
|
@@ -22,11 +22,11 @@ export type WorkshopAutosaveRecord = {
|
|
|
22
22
|
savedPath?: string | null;
|
|
23
23
|
savedTaskPath?: string | null;
|
|
24
24
|
diskFingerprints?: Record<string, string>;
|
|
25
|
+
projectRoot?: string | null;
|
|
25
26
|
};
|
|
26
27
|
export declare function workshopAutosaveSlotKey(pipelinePath: string | null | undefined): string;
|
|
27
|
-
export declare function resolveWorkshopAutosaveStoreRoot(
|
|
28
|
+
export declare function resolveWorkshopAutosaveStoreRoot(_options?: {
|
|
28
29
|
projectRoot?: string | null;
|
|
29
|
-
isGitProject?: boolean;
|
|
30
30
|
}): string;
|
|
31
31
|
export declare function workshopAutosaveDir(storeRoot: string): string;
|
|
32
32
|
export declare function workshopAutosaveFilePath(storeRoot: string, key: string): string;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readFileSync, statSync, unlinkSync, writeFileSync, } from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { globalStageflowHome } from "../project/globalHome.js";
|
|
4
|
-
import { storeRootFor } from "../runstore/paths.js";
|
|
5
4
|
export const WORKSHOP_UNTITLED_AUTOSAVE_KEY = "__untitled__";
|
|
6
5
|
export function workshopAutosaveSlotKey(pipelinePath) {
|
|
7
6
|
const trimmed = pipelinePath?.trim();
|
|
@@ -9,11 +8,7 @@ export function workshopAutosaveSlotKey(pipelinePath) {
|
|
|
9
8
|
return WORKSHOP_UNTITLED_AUTOSAVE_KEY;
|
|
10
9
|
return trimmed.replace(/\\/g, "/");
|
|
11
10
|
}
|
|
12
|
-
export function resolveWorkshopAutosaveStoreRoot(
|
|
13
|
-
const root = options.projectRoot?.trim();
|
|
14
|
-
if (root && options.isGitProject !== false) {
|
|
15
|
-
return storeRootFor(path.resolve(root));
|
|
16
|
-
}
|
|
11
|
+
export function resolveWorkshopAutosaveStoreRoot(_options) {
|
|
17
12
|
return globalStageflowHome();
|
|
18
13
|
}
|
|
19
14
|
export function workshopAutosaveDir(storeRoot) {
|
|
@@ -114,6 +109,9 @@ export function parseWorkshopAutosaveRecord(value) {
|
|
|
114
109
|
}
|
|
115
110
|
record.diskFingerprints = fps;
|
|
116
111
|
}
|
|
112
|
+
if (value.projectRoot === null || typeof value.projectRoot === "string") {
|
|
113
|
+
record.projectRoot = value.projectRoot;
|
|
114
|
+
}
|
|
117
115
|
return record;
|
|
118
116
|
}
|
|
119
117
|
export function readWorkshopAutosave(storeRoot, key) {
|
|
@@ -55,6 +55,8 @@ export type WorkshopPickerRow = {
|
|
|
55
55
|
name: string;
|
|
56
56
|
projectRoot: string | null;
|
|
57
57
|
relativePath: string | null;
|
|
58
|
+
/** True when this row's pipeline path appears in the catalog scan (Tasks/Pipelines lists). */
|
|
59
|
+
catalogListed?: boolean;
|
|
58
60
|
};
|
|
59
61
|
export type FocusUnboundWorkshopBuildInput = {
|
|
60
62
|
projectRoot: string;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export declare const WORKSHOP_CHAT_ATTACHMENT_MAX_FILES = 5;
|
|
2
|
+
export declare const WORKSHOP_CHAT_ATTACHMENT_MAX_BYTES: number;
|
|
3
|
+
export declare const WORKSHOP_DOCS_REFERENCE_PATHS: readonly ["docs/yaml-catalog.md", "skills/stageflow-author/references/catalog-mapping.md"];
|
|
4
|
+
export type WorkshopDocsReference = {
|
|
5
|
+
path: string;
|
|
6
|
+
text: string;
|
|
7
|
+
};
|
|
8
|
+
export type WorkshopChatAttachment = {
|
|
9
|
+
name: string;
|
|
10
|
+
mediaType: string;
|
|
11
|
+
size: number;
|
|
12
|
+
content: string;
|
|
13
|
+
};
|
|
14
|
+
export type WorkshopChatContext = {
|
|
15
|
+
docs?: boolean;
|
|
16
|
+
};
|
|
17
|
+
export type ParseWorkshopChatAttachmentsResult = {
|
|
18
|
+
ok: true;
|
|
19
|
+
attachments: WorkshopChatAttachment[];
|
|
20
|
+
} | {
|
|
21
|
+
ok: false;
|
|
22
|
+
error: string;
|
|
23
|
+
};
|
|
24
|
+
export declare function parseWorkshopChatAttachments(value: unknown): ParseWorkshopChatAttachmentsResult;
|
|
25
|
+
export declare function parseWorkshopChatContext(value: unknown): WorkshopChatContext;
|
|
26
|
+
export declare function readWorkshopDocsReference(rootDir?: string): Promise<WorkshopDocsReference | null>;
|
|
27
|
+
export declare function buildWorkshopChatPrompt(message: string, attachments: readonly WorkshopChatAttachment[], docsReference: WorkshopDocsReference | null): string;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { resolveWorkshopCatalogRoot } from "../operatorAgent/docsRetrieval.js";
|
|
4
|
+
export const WORKSHOP_CHAT_ATTACHMENT_MAX_FILES = 5;
|
|
5
|
+
export const WORKSHOP_CHAT_ATTACHMENT_MAX_BYTES = 256 * 1024;
|
|
6
|
+
export const WORKSHOP_DOCS_REFERENCE_PATHS = [
|
|
7
|
+
"docs/yaml-catalog.md",
|
|
8
|
+
"skills/stageflow-author/references/catalog-mapping.md",
|
|
9
|
+
];
|
|
10
|
+
function isPlainObject(value) {
|
|
11
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
12
|
+
}
|
|
13
|
+
export function parseWorkshopChatAttachments(value) {
|
|
14
|
+
if (value === undefined || value === null) {
|
|
15
|
+
return { ok: true, attachments: [] };
|
|
16
|
+
}
|
|
17
|
+
if (!Array.isArray(value)) {
|
|
18
|
+
return { ok: false, error: "attachments must be an array" };
|
|
19
|
+
}
|
|
20
|
+
if (value.length > WORKSHOP_CHAT_ATTACHMENT_MAX_FILES) {
|
|
21
|
+
return {
|
|
22
|
+
ok: false,
|
|
23
|
+
error: `At most ${WORKSHOP_CHAT_ATTACHMENT_MAX_FILES} attachments per message`,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
const attachments = [];
|
|
27
|
+
for (const [index, entry] of value.entries()) {
|
|
28
|
+
if (!isPlainObject(entry)) {
|
|
29
|
+
return { ok: false, error: `attachments[${index}] must be an object` };
|
|
30
|
+
}
|
|
31
|
+
const name = typeof entry.name === "string" ? entry.name.replace(/\s+/g, " ").trim() : "";
|
|
32
|
+
if (!name) {
|
|
33
|
+
return { ok: false, error: `attachments[${index}].name is required` };
|
|
34
|
+
}
|
|
35
|
+
if (typeof entry.content !== "string") {
|
|
36
|
+
return {
|
|
37
|
+
ok: false,
|
|
38
|
+
error: `attachments[${index}].content must be a string (${name})`,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
if (entry.mediaType !== undefined && typeof entry.mediaType !== "string") {
|
|
42
|
+
return {
|
|
43
|
+
ok: false,
|
|
44
|
+
error: `attachments[${index}].mediaType must be a string (${name})`,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
const size = Buffer.byteLength(entry.content, "utf8");
|
|
48
|
+
if (size > WORKSHOP_CHAT_ATTACHMENT_MAX_BYTES) {
|
|
49
|
+
return {
|
|
50
|
+
ok: false,
|
|
51
|
+
error: `Attachment ${name} exceeds ${WORKSHOP_CHAT_ATTACHMENT_MAX_BYTES / 1024} KB`,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
attachments.push({
|
|
55
|
+
name,
|
|
56
|
+
mediaType: entry.mediaType?.trim() || "text/plain",
|
|
57
|
+
size,
|
|
58
|
+
content: entry.content,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
return { ok: true, attachments };
|
|
62
|
+
}
|
|
63
|
+
export function parseWorkshopChatContext(value) {
|
|
64
|
+
return isPlainObject(value) && value.docs === true ? { docs: true } : {};
|
|
65
|
+
}
|
|
66
|
+
function fenceFor(content) {
|
|
67
|
+
const longest = (content.match(/`+/g) ?? []).reduce((max, run) => Math.max(max, run.length), 0);
|
|
68
|
+
return "`".repeat(Math.max(3, longest + 1));
|
|
69
|
+
}
|
|
70
|
+
function fencedBlock(heading, content) {
|
|
71
|
+
const fence = fenceFor(content);
|
|
72
|
+
const body = content.endsWith("\n") ? content : `${content}\n`;
|
|
73
|
+
return `${heading}\n${fence}\n${body}${fence}`;
|
|
74
|
+
}
|
|
75
|
+
export async function readWorkshopDocsReference(rootDir) {
|
|
76
|
+
const root = resolveWorkshopCatalogRoot(rootDir);
|
|
77
|
+
for (const relPath of WORKSHOP_DOCS_REFERENCE_PATHS) {
|
|
78
|
+
try {
|
|
79
|
+
const text = await readFile(path.join(root, relPath), "utf8");
|
|
80
|
+
if (text.trim())
|
|
81
|
+
return { path: relPath, text };
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
export function buildWorkshopChatPrompt(message, attachments, docsReference) {
|
|
90
|
+
const sections = [message];
|
|
91
|
+
for (const attachment of attachments) {
|
|
92
|
+
sections.push(fencedBlock(`Attached file: ${attachment.name}`, attachment.content));
|
|
93
|
+
}
|
|
94
|
+
if (docsReference) {
|
|
95
|
+
sections.push(fencedBlock(`Stageflow YAML authoring reference (${docsReference.path}):`, docsReference.text));
|
|
96
|
+
}
|
|
97
|
+
return sections.join("\n\n");
|
|
98
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { DraftPackage } from "../config/draftPackage.js";
|
|
2
2
|
import { type OperatorAgentHost, type OperatorAgentProposal, type OperatorAgentSession, type OperatorAgentSessionEvent, type ProposalArtifactDiff, type WorkshopToolActivityUpdate } from "../operatorAgent/index.js";
|
|
3
|
+
import { type WorkshopChatAttachment, type WorkshopChatContext } from "./chatAttachments.js";
|
|
3
4
|
import { WorkshopSessionStoreError } from "./sessionStore.js";
|
|
4
5
|
import { type WorkshopPointerChange } from "./workshopPin.js";
|
|
5
6
|
export type { WorkshopPointerChange };
|
|
@@ -51,8 +52,9 @@ export type WorkshopChatTurnInput = {
|
|
|
51
52
|
sessionId: string;
|
|
52
53
|
draft: DraftPackage;
|
|
53
54
|
message: string;
|
|
54
|
-
/** @deprecated Ignored — mutations apply immediately (Accept = soft undo). */
|
|
55
55
|
autoApply?: boolean;
|
|
56
|
+
attachments?: WorkshopChatAttachment[];
|
|
57
|
+
context?: WorkshopChatContext;
|
|
56
58
|
/** Session model override from Workshop chrome. */
|
|
57
59
|
model?: string | null;
|
|
58
60
|
/** Settings default from factory settings /api/settings. */
|
|
@@ -75,6 +77,8 @@ export type WorkshopChatTurnInput = {
|
|
|
75
77
|
onActivity?: (update: WorkshopToolActivityUpdate) => void;
|
|
76
78
|
/** Fired when this turn changes the session pointer. */
|
|
77
79
|
onPointerChange?: (frame: WorkshopPointerChange) => void;
|
|
80
|
+
/** Writable catalog root (absolute path) for agent save; host-resolved. */
|
|
81
|
+
projectRoot?: string;
|
|
78
82
|
};
|
|
79
83
|
export type WorkshopChatTurnResult = {
|
|
80
84
|
sessionId: string;
|
|
@@ -86,7 +90,6 @@ export type WorkshopChatTurnResult = {
|
|
|
86
90
|
* Accept/undo. Name is historical — not a pending gated apply.
|
|
87
91
|
*/
|
|
88
92
|
pending: WorkshopChatProposalPayload | null;
|
|
89
|
-
/** Always false — auto-apply chrome removed; mutations apply immediately. */
|
|
90
93
|
autoApply: boolean;
|
|
91
94
|
model: string;
|
|
92
95
|
/** Build this turn edited. Null when the chat stayed unlinked. */
|
|
@@ -1,17 +1,28 @@
|
|
|
1
|
-
import { createWorkshopDraftContext, createWorkshopOperatorHost, isWorkshopDraftContext, readDraftFromContext, withDraft, WORKSHOP_AUTHOR_PROFILE_ID, } from "../operatorAgent/index.js";
|
|
1
|
+
import { createWorkshopDraftContext, createWorkshopOperatorHost, isWorkshopDraftContext, readDraftFromContext, withDraft, withProjectRoot, WORKSHOP_AUTHOR_PROFILE_ID, } from "../operatorAgent/index.js";
|
|
2
2
|
import { resolveWorkshopModel } from "./modelSettings.js";
|
|
3
3
|
import { getWorkshopBuild, updateWorkshopBuild } from "./buildStore.js";
|
|
4
|
+
import { buildWorkshopChatPrompt, readWorkshopDocsReference, } from "./chatAttachments.js";
|
|
5
|
+
import { transcriptMessagesForTurn } from "./workshopTranscriptTurn.js";
|
|
4
6
|
import { appendWorkshopSessionMessages, getWorkshopSession, resolveWorkshopSessionStoreRoot, WorkshopSessionStoreError, } from "./sessionStore.js";
|
|
5
7
|
import { bindPinnedBuildContext, enqueueSessionWrite, registerLiveWorkshopSession, resetWorkshopPinStateForTests, unregisterLiveWorkshopSession, } from "./workshopPin.js";
|
|
6
|
-
function markUnlinkedChatContext(current, sessionId, draft) {
|
|
8
|
+
function markUnlinkedChatContext(current, sessionId, draft, projectRoot) {
|
|
7
9
|
const base = isWorkshopDraftContext(current)
|
|
8
10
|
? { ...current, draft }
|
|
9
11
|
: { draft };
|
|
10
12
|
delete base.buildId;
|
|
11
13
|
base.chatSessionId = sessionId;
|
|
12
14
|
base.draft = draft;
|
|
15
|
+
if (projectRoot?.trim()) {
|
|
16
|
+
base.projectRoot = projectRoot.trim();
|
|
17
|
+
}
|
|
13
18
|
return base;
|
|
14
19
|
}
|
|
20
|
+
function bindChatProjectRoot(context, projectRoot) {
|
|
21
|
+
const trimmed = projectRoot?.trim();
|
|
22
|
+
if (!trimmed || context.projectRoot)
|
|
23
|
+
return context;
|
|
24
|
+
return withProjectRoot(context, trimmed);
|
|
25
|
+
}
|
|
15
26
|
/**
|
|
16
27
|
* In-memory map of Workshop session id → open OperatorAgentSession.
|
|
17
28
|
* Survives across chat turns until process restart (disk transcript remains).
|
|
@@ -207,17 +218,6 @@ export function toWorkshopChatWireEvent(event, fallbackDraft) {
|
|
|
207
218
|
}
|
|
208
219
|
return { type: "error", message: event.message };
|
|
209
220
|
}
|
|
210
|
-
function transcriptMessagesForTurn(userMessage, events) {
|
|
211
|
-
const messages = [
|
|
212
|
-
{ role: "user", text: userMessage },
|
|
213
|
-
];
|
|
214
|
-
for (const event of events) {
|
|
215
|
-
if (event.type === "message") {
|
|
216
|
-
messages.push({ role: event.role, text: event.text });
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
return messages;
|
|
220
|
-
}
|
|
221
221
|
/**
|
|
222
222
|
* One Workshop Author turn on a durable Operator Agent Host session.
|
|
223
223
|
* Requires an existing session store record (New / POST sessions first).
|
|
@@ -240,6 +240,8 @@ export async function runWorkshopChatTurn(input) {
|
|
|
240
240
|
sessionOverride: input.model,
|
|
241
241
|
settingsDefault: input.settingsDefault,
|
|
242
242
|
});
|
|
243
|
+
const attachments = input.attachments ?? [];
|
|
244
|
+
const prompt = buildWorkshopChatPrompt(message, attachments, input.context?.docs === true ? await readWorkshopDocsReference() : null);
|
|
243
245
|
const registry = input.registry ?? getDefaultRegistry(input.host);
|
|
244
246
|
if (input.host && registry.host !== input.host) {
|
|
245
247
|
throw new Error("host does not match workshop chat session registry");
|
|
@@ -253,10 +255,10 @@ export async function runWorkshopChatTurn(input) {
|
|
|
253
255
|
const draftForOpen = pinnedBuild?.draft ?? input.draft;
|
|
254
256
|
const { session: agentSession, created } = registry.getOrOpen(sessionId, draftForOpen);
|
|
255
257
|
if (pinnedBuild) {
|
|
256
|
-
agentSession.setContext(bindPinnedBuildContext(agentSession.getContext(), pinnedBuild, sessionId));
|
|
258
|
+
agentSession.setContext(bindChatProjectRoot(bindPinnedBuildContext(agentSession.getContext(), pinnedBuild, sessionId), input.projectRoot));
|
|
257
259
|
}
|
|
258
260
|
else {
|
|
259
|
-
agentSession.setContext(markUnlinkedChatContext(agentSession.getContext(), sessionId, draftForOpen));
|
|
261
|
+
agentSession.setContext(bindChatProjectRoot(markUnlinkedChatContext(agentSession.getContext(), sessionId, draftForOpen, input.projectRoot), input.projectRoot));
|
|
260
262
|
}
|
|
261
263
|
registry.bindTurn(sessionId, {
|
|
262
264
|
storeRoot,
|
|
@@ -272,7 +274,7 @@ export async function runWorkshopChatTurn(input) {
|
|
|
272
274
|
typeof agentSession.prepareRestart === "function") {
|
|
273
275
|
await agentSession.prepareRestart(storeRecord.transcript);
|
|
274
276
|
}
|
|
275
|
-
rawEvents = await agentSession.send(
|
|
277
|
+
rawEvents = await agentSession.send(prompt, {
|
|
276
278
|
onDelta: input.onDelta,
|
|
277
279
|
onActivity: (update) => {
|
|
278
280
|
const buildId = registry.getPinnedBuildId(sessionId);
|
|
@@ -302,7 +304,9 @@ export async function runWorkshopChatTurn(input) {
|
|
|
302
304
|
const pendingRaw = agentSession.getPendingProposal();
|
|
303
305
|
const events = rawEvents.map((event) => toWorkshopChatWireEvent(event, draft));
|
|
304
306
|
await enqueueSessionWrite(sessionId, () => {
|
|
305
|
-
appendWorkshopSessionMessages(storeRoot, sessionId, transcriptMessagesForTurn(message, events
|
|
307
|
+
appendWorkshopSessionMessages(storeRoot, sessionId, transcriptMessagesForTurn(message, attachments, events, {
|
|
308
|
+
autoApply: input.autoApply === true,
|
|
309
|
+
}));
|
|
306
310
|
});
|
|
307
311
|
return {
|
|
308
312
|
sessionId,
|
|
@@ -311,7 +315,7 @@ export async function runWorkshopChatTurn(input) {
|
|
|
311
315
|
pending: pendingRaw
|
|
312
316
|
? serializeWorkshopProposal(pendingRaw, draft)
|
|
313
317
|
: null,
|
|
314
|
-
autoApply:
|
|
318
|
+
autoApply: input.autoApply === true,
|
|
315
319
|
model,
|
|
316
320
|
buildId: resultBuildId,
|
|
317
321
|
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ProposalArtifactDiff } from "../operatorAgent/proposals.js";
|
|
2
|
+
import type { WorkshopChatProposalPayload } from "./chatTurn.js";
|
|
3
|
+
type SnapshotDraft = WorkshopChatProposalPayload["baseDraft"];
|
|
4
|
+
export type WorkshopSessionMutationSnapshot = {
|
|
5
|
+
id: string;
|
|
6
|
+
summary: string;
|
|
7
|
+
affectedStageIds: string[];
|
|
8
|
+
artifacts: ProposalArtifactDiff[];
|
|
9
|
+
status: "accepted" | "rejected";
|
|
10
|
+
autoApplied?: boolean;
|
|
11
|
+
baseDraft?: SnapshotDraft;
|
|
12
|
+
nextDraft?: SnapshotDraft;
|
|
13
|
+
baseFingerprint?: string;
|
|
14
|
+
};
|
|
15
|
+
export declare function parseWorkshopSessionMutationSnapshot(value: unknown): WorkshopSessionMutationSnapshot | null;
|
|
16
|
+
export declare function mutationSnapshotsFromProposals(proposals: readonly WorkshopChatProposalPayload[], autoApply: boolean): WorkshopSessionMutationSnapshot[];
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
function isPlainObject(value) {
|
|
2
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
3
|
+
}
|
|
4
|
+
function parseDraft(value) {
|
|
5
|
+
if (!isPlainObject(value))
|
|
6
|
+
return undefined;
|
|
7
|
+
const pipeline = value.pipeline;
|
|
8
|
+
if (!isPlainObject(pipeline))
|
|
9
|
+
return undefined;
|
|
10
|
+
if (typeof pipeline.id !== "string")
|
|
11
|
+
return undefined;
|
|
12
|
+
if (!Array.isArray(pipeline.stages))
|
|
13
|
+
return undefined;
|
|
14
|
+
if (pipeline.stages.some((stage) => !isPlainObject(stage)))
|
|
15
|
+
return undefined;
|
|
16
|
+
if (value.stages !== undefined) {
|
|
17
|
+
if (!Array.isArray(value.stages))
|
|
18
|
+
return undefined;
|
|
19
|
+
for (const entry of value.stages) {
|
|
20
|
+
if (!isPlainObject(entry) ||
|
|
21
|
+
typeof entry.path !== "string" ||
|
|
22
|
+
!isPlainObject(entry.body)) {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (value.task !== undefined) {
|
|
28
|
+
if (!isPlainObject(value.task) ||
|
|
29
|
+
typeof value.task.filename !== "string" ||
|
|
30
|
+
!isPlainObject(value.task.body)) {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return structuredClone(value);
|
|
35
|
+
}
|
|
36
|
+
function parseArtifact(value) {
|
|
37
|
+
if (!isPlainObject(value))
|
|
38
|
+
return null;
|
|
39
|
+
if (typeof value.path !== "string" || !value.path)
|
|
40
|
+
return null;
|
|
41
|
+
if (value.kind !== "added" &&
|
|
42
|
+
value.kind !== "removed" &&
|
|
43
|
+
value.kind !== "modified") {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
const artifact = {
|
|
47
|
+
path: value.path,
|
|
48
|
+
kind: value.kind,
|
|
49
|
+
};
|
|
50
|
+
if (typeof value.before === "string")
|
|
51
|
+
artifact.before = value.before;
|
|
52
|
+
if (typeof value.after === "string")
|
|
53
|
+
artifact.after = value.after;
|
|
54
|
+
return artifact;
|
|
55
|
+
}
|
|
56
|
+
export function parseWorkshopSessionMutationSnapshot(value) {
|
|
57
|
+
if (!isPlainObject(value))
|
|
58
|
+
return null;
|
|
59
|
+
if (typeof value.id !== "string" || !value.id)
|
|
60
|
+
return null;
|
|
61
|
+
if (typeof value.summary !== "string")
|
|
62
|
+
return null;
|
|
63
|
+
if (!Array.isArray(value.affectedStageIds))
|
|
64
|
+
return null;
|
|
65
|
+
const affectedStageIds = value.affectedStageIds.filter((id) => typeof id === "string" && id.length > 0);
|
|
66
|
+
if (!Array.isArray(value.artifacts))
|
|
67
|
+
return null;
|
|
68
|
+
const artifacts = [];
|
|
69
|
+
for (const entry of value.artifacts) {
|
|
70
|
+
const parsed = parseArtifact(entry);
|
|
71
|
+
if (!parsed)
|
|
72
|
+
return null;
|
|
73
|
+
artifacts.push(parsed);
|
|
74
|
+
}
|
|
75
|
+
const status = value.status === "rejected" ? "rejected" : "accepted";
|
|
76
|
+
const baseDraft = parseDraft(value.baseDraft);
|
|
77
|
+
const nextDraft = parseDraft(value.nextDraft);
|
|
78
|
+
const baseFingerprint = typeof value.baseFingerprint === "string" && value.baseFingerprint
|
|
79
|
+
? value.baseFingerprint
|
|
80
|
+
: undefined;
|
|
81
|
+
return {
|
|
82
|
+
id: value.id,
|
|
83
|
+
summary: value.summary,
|
|
84
|
+
affectedStageIds,
|
|
85
|
+
artifacts,
|
|
86
|
+
status,
|
|
87
|
+
...(value.autoApplied === true ? { autoApplied: true } : {}),
|
|
88
|
+
...(baseDraft ? { baseDraft } : {}),
|
|
89
|
+
...(nextDraft ? { nextDraft } : {}),
|
|
90
|
+
...(baseFingerprint ? { baseFingerprint } : {}),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
export function mutationSnapshotsFromProposals(proposals, autoApply) {
|
|
94
|
+
return proposals.map((proposal) => ({
|
|
95
|
+
id: proposal.id,
|
|
96
|
+
summary: proposal.summary,
|
|
97
|
+
affectedStageIds: [...proposal.affectedStageIds],
|
|
98
|
+
artifacts: proposal.artifacts.map((artifact) => ({ ...artifact })),
|
|
99
|
+
status: "accepted",
|
|
100
|
+
baseDraft: structuredClone(proposal.baseDraft),
|
|
101
|
+
nextDraft: structuredClone(proposal.nextDraft),
|
|
102
|
+
...(proposal.baseFingerprint
|
|
103
|
+
? { baseFingerprint: proposal.baseFingerprint }
|
|
104
|
+
: {}),
|
|
105
|
+
...(autoApply ? { autoApplied: true } : {}),
|
|
106
|
+
}));
|
|
107
|
+
}
|
|
@@ -1,10 +1,18 @@
|
|
|
1
|
+
import { type WorkshopSessionMutationSnapshot } from "./sessionMutations.js";
|
|
1
2
|
export declare const WORKSHOP_SESSION_TITLE_MAX_LENGTH = 80;
|
|
2
3
|
export type WorkshopSessionMessageRole = "assistant" | "user" | "system";
|
|
4
|
+
export type WorkshopSessionAttachment = {
|
|
5
|
+
name: string;
|
|
6
|
+
size: number;
|
|
7
|
+
mediaType: string;
|
|
8
|
+
};
|
|
3
9
|
export type WorkshopSessionMessage = {
|
|
4
10
|
id: string;
|
|
5
11
|
role: WorkshopSessionMessageRole;
|
|
6
12
|
text: string;
|
|
7
13
|
createdAt: string;
|
|
14
|
+
attachments?: WorkshopSessionAttachment[];
|
|
15
|
+
mutations?: WorkshopSessionMutationSnapshot[];
|
|
8
16
|
};
|
|
9
17
|
export type WorkshopSessionRecord = {
|
|
10
18
|
version: 1;
|
|
@@ -28,6 +36,8 @@ export type WorkshopSessionAppendMessage = {
|
|
|
28
36
|
role: WorkshopSessionMessageRole;
|
|
29
37
|
text: string;
|
|
30
38
|
createdAt?: string;
|
|
39
|
+
attachments?: WorkshopSessionAttachment[];
|
|
40
|
+
mutations?: WorkshopSessionMutationSnapshot[];
|
|
31
41
|
};
|
|
32
42
|
export type WorkshopSessionStoreErrorCode = "workshop_session_not_found";
|
|
33
43
|
export declare class WorkshopSessionStoreError extends Error {
|
|
@@ -2,6 +2,7 @@ import { randomUUID } from "node:crypto";
|
|
|
2
2
|
import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync, } from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { globalStageflowHome } from "../project/globalHome.js";
|
|
5
|
+
import { parseWorkshopSessionMutationSnapshot, } from "./sessionMutations.js";
|
|
5
6
|
export const WORKSHOP_SESSION_TITLE_MAX_LENGTH = 80;
|
|
6
7
|
export class WorkshopSessionStoreError extends Error {
|
|
7
8
|
code;
|
|
@@ -63,13 +64,46 @@ function parseMessage(value) {
|
|
|
63
64
|
return null;
|
|
64
65
|
if (typeof value.createdAt !== "string" || !value.createdAt)
|
|
65
66
|
return null;
|
|
67
|
+
const attachments = Array.isArray(value.attachments)
|
|
68
|
+
? value.attachments.flatMap((entry) => {
|
|
69
|
+
const parsed = parseAttachment(entry);
|
|
70
|
+
return parsed ? [parsed] : [];
|
|
71
|
+
})
|
|
72
|
+
: [];
|
|
73
|
+
let mutations;
|
|
74
|
+
if (value.mutations !== undefined) {
|
|
75
|
+
if (!Array.isArray(value.mutations))
|
|
76
|
+
return null;
|
|
77
|
+
const parsedMutations = [];
|
|
78
|
+
for (const entry of value.mutations) {
|
|
79
|
+
const parsed = parseWorkshopSessionMutationSnapshot(entry);
|
|
80
|
+
if (!parsed)
|
|
81
|
+
return null;
|
|
82
|
+
parsedMutations.push(parsed);
|
|
83
|
+
}
|
|
84
|
+
if (parsedMutations.length > 0)
|
|
85
|
+
mutations = parsedMutations;
|
|
86
|
+
}
|
|
66
87
|
return {
|
|
67
88
|
id: value.id,
|
|
68
89
|
role: value.role,
|
|
69
90
|
text: value.text,
|
|
70
91
|
createdAt: value.createdAt,
|
|
92
|
+
...(attachments.length > 0 ? { attachments } : {}),
|
|
93
|
+
...(mutations ? { mutations } : {}),
|
|
71
94
|
};
|
|
72
95
|
}
|
|
96
|
+
function parseAttachment(value) {
|
|
97
|
+
if (!isPlainObject(value))
|
|
98
|
+
return null;
|
|
99
|
+
if (typeof value.name !== "string" || !value.name)
|
|
100
|
+
return null;
|
|
101
|
+
if (typeof value.size !== "number" || !Number.isFinite(value.size))
|
|
102
|
+
return null;
|
|
103
|
+
if (typeof value.mediaType !== "string")
|
|
104
|
+
return null;
|
|
105
|
+
return { name: value.name, size: value.size, mediaType: value.mediaType };
|
|
106
|
+
}
|
|
73
107
|
export function parseWorkshopSessionRecord(value) {
|
|
74
108
|
if (!isPlainObject(value))
|
|
75
109
|
return null;
|
|
@@ -211,6 +245,24 @@ export function appendWorkshopSessionMessages(storeRoot, sessionId, messages, op
|
|
|
211
245
|
role: msg.role,
|
|
212
246
|
text: msg.text,
|
|
213
247
|
createdAt: msg.createdAt || now,
|
|
248
|
+
...(msg.attachments && msg.attachments.length > 0
|
|
249
|
+
? {
|
|
250
|
+
attachments: msg.attachments.map(({ name, size, mediaType }) => ({
|
|
251
|
+
name,
|
|
252
|
+
size,
|
|
253
|
+
mediaType,
|
|
254
|
+
})),
|
|
255
|
+
}
|
|
256
|
+
: {}),
|
|
257
|
+
...(msg.mutations && msg.mutations.length > 0
|
|
258
|
+
? {
|
|
259
|
+
mutations: msg.mutations.map((mutation) => ({
|
|
260
|
+
...mutation,
|
|
261
|
+
affectedStageIds: [...mutation.affectedStageIds],
|
|
262
|
+
artifacts: mutation.artifacts.map((artifact) => ({ ...artifact })),
|
|
263
|
+
})),
|
|
264
|
+
}
|
|
265
|
+
: {}),
|
|
214
266
|
};
|
|
215
267
|
appended.push(entry);
|
|
216
268
|
if (!title && entry.role === "user" && entry.text.trim()) {
|
|
@@ -35,17 +35,18 @@ export declare function resolveLiveWorkshopBinding(context: unknown): {
|
|
|
35
35
|
* An unlinked chat turn fails the tool and does not create a build.
|
|
36
36
|
*/
|
|
37
37
|
export declare function rejectUnlinkedWorkshopDraftTool(context: unknown, toolName: string): OperatorAgentToolResult | null;
|
|
38
|
-
/** Tied builds save to the stored path
|
|
39
|
-
export declare function resolvePinnedSaveDestination(context: unknown): {
|
|
38
|
+
/** Tied builds save to the stored path when the write root matches the build tie. */
|
|
39
|
+
export declare function resolvePinnedSaveDestination(context: unknown, writeProjectRoot?: string | null): {
|
|
40
40
|
directory: string;
|
|
41
41
|
pipelineFilename: string;
|
|
42
42
|
} | null;
|
|
43
|
-
/** A successful save
|
|
43
|
+
/** A successful catalog save updates the build tie and in-memory pointer. */
|
|
44
44
|
export declare function recordPinnedWorkshopSave(context: unknown, saved: {
|
|
45
45
|
directory: string;
|
|
46
46
|
pipelineFilename?: string;
|
|
47
47
|
projectRoot: string;
|
|
48
48
|
draft: DraftPackage;
|
|
49
|
+
relativePath?: string;
|
|
49
50
|
}): void;
|
|
50
51
|
/**
|
|
51
52
|
* Create an untitled build and move this turn's pin onto it.
|
|
@@ -117,8 +117,8 @@ export function rejectUnlinkedWorkshopDraftTool(context, toolName) {
|
|
|
117
117
|
error: WORKSHOP_UNLINKED_DRAFT_TOOL_ERROR,
|
|
118
118
|
};
|
|
119
119
|
}
|
|
120
|
-
/** Tied builds save to the stored path
|
|
121
|
-
export function resolvePinnedSaveDestination(context) {
|
|
120
|
+
/** Tied builds save to the stored path when the write root matches the build tie. */
|
|
121
|
+
export function resolvePinnedSaveDestination(context, writeProjectRoot) {
|
|
122
122
|
if (!isWorkshopDraftContext(context) ||
|
|
123
123
|
!context.buildId ||
|
|
124
124
|
!context.chatSessionId) {
|
|
@@ -130,9 +130,21 @@ export function resolvePinnedSaveDestination(context) {
|
|
|
130
130
|
const build = readWorkshopBuild(live.storeRoot, context.buildId);
|
|
131
131
|
if (!build?.projectRoot || !build.relativePath)
|
|
132
132
|
return null;
|
|
133
|
+
if (writeProjectRoot?.trim()) {
|
|
134
|
+
const tieRoot = path.resolve(build.projectRoot);
|
|
135
|
+
const writeRoot = path.resolve(writeProjectRoot.trim());
|
|
136
|
+
if (tieRoot !== writeRoot)
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
133
139
|
return destinationFromRelativePath(build.relativePath);
|
|
134
140
|
}
|
|
135
|
-
|
|
141
|
+
function normalizeSavedRelativePath(value) {
|
|
142
|
+
let trimmed = value.trim().replace(/\\/g, "/");
|
|
143
|
+
while (trimmed.startsWith("./"))
|
|
144
|
+
trimmed = trimmed.slice(2);
|
|
145
|
+
return trimmed;
|
|
146
|
+
}
|
|
147
|
+
/** A successful catalog save updates the build tie and in-memory pointer. */
|
|
136
148
|
export function recordPinnedWorkshopSave(context, saved) {
|
|
137
149
|
if (!isWorkshopDraftContext(context) ||
|
|
138
150
|
!context.buildId ||
|
|
@@ -143,15 +155,23 @@ export function recordPinnedWorkshopSave(context, saved) {
|
|
|
143
155
|
if (!live)
|
|
144
156
|
return;
|
|
145
157
|
const build = readWorkshopBuild(live.storeRoot, context.buildId);
|
|
146
|
-
if (!build
|
|
158
|
+
if (!build)
|
|
147
159
|
return;
|
|
148
160
|
const pipelineFilename = saved.pipelineFilename?.trim() ||
|
|
149
161
|
`${saved.draft.pipeline.id}.pipeline.yaml`;
|
|
150
|
-
|
|
162
|
+
const relativePath = saved.relativePath?.trim()
|
|
163
|
+
? normalizeSavedRelativePath(saved.relativePath)
|
|
164
|
+
: relativePathFromDestination(saved.directory, pipelineFilename);
|
|
165
|
+
const updated = updateWorkshopBuild(live.storeRoot, build.id, {
|
|
151
166
|
draft: saved.draft,
|
|
152
167
|
projectRoot: path.resolve(saved.projectRoot),
|
|
153
|
-
relativePath
|
|
168
|
+
relativePath,
|
|
154
169
|
});
|
|
170
|
+
const session = live.registry.get(context.chatSessionId);
|
|
171
|
+
if (session) {
|
|
172
|
+
session.setContext(bindPinnedBuildContext(session.getContext(), updated, context.chatSessionId));
|
|
173
|
+
}
|
|
174
|
+
emitPointerChange(live.registry, context.chatSessionId, updated);
|
|
155
175
|
}
|
|
156
176
|
/**
|
|
157
177
|
* Create an untitled build and move this turn's pin onto it.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { WorkshopChatAttachment } from "./chatAttachments.js";
|
|
2
|
+
import type { WorkshopChatProposalPayload, WorkshopChatWireEvent } from "./chatTurn.js";
|
|
3
|
+
import type { WorkshopSessionAppendMessage } from "./sessionStore.js";
|
|
4
|
+
export declare function assistantTranscriptTextFromEvents(events: readonly WorkshopChatWireEvent[]): string;
|
|
5
|
+
export declare function proposalPayloadsFromEvents(events: readonly WorkshopChatWireEvent[]): WorkshopChatProposalPayload[];
|
|
6
|
+
export declare function transcriptMessagesForTurn(userMessage: string, attachments: readonly WorkshopChatAttachment[], events: readonly WorkshopChatWireEvent[], options?: {
|
|
7
|
+
autoApply?: boolean;
|
|
8
|
+
}): WorkshopSessionAppendMessage[];
|