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
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
import { access, mkdtemp, readdir, readFile, rm, stat } from "node:fs/promises";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
5
|
+
import { installProjectSkill, } from "../cli/skillsCommand.js";
|
|
6
|
+
import { runGit } from "../git/exec.js";
|
|
7
|
+
function isPlainObject(value) {
|
|
8
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
9
|
+
}
|
|
10
|
+
function tokenizeCommand(command) {
|
|
11
|
+
return command.trim().split(/\s+/).filter((part) => part.length > 0);
|
|
12
|
+
}
|
|
13
|
+
export function parseSkillsAddCommand(command) {
|
|
14
|
+
const trimmed = command.trim();
|
|
15
|
+
if (trimmed.length === 0) {
|
|
16
|
+
return { ok: false, status: 400, error: "command must be a non-empty string" };
|
|
17
|
+
}
|
|
18
|
+
const tokens = tokenizeCommand(trimmed);
|
|
19
|
+
let rest;
|
|
20
|
+
if (tokens[0] === "npx" && tokens[1] === "skills" && tokens[2] === "add") {
|
|
21
|
+
rest = tokens.slice(3);
|
|
22
|
+
}
|
|
23
|
+
else if (tokens[0] === "skills" && tokens[1] === "add") {
|
|
24
|
+
rest = tokens.slice(2);
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
return {
|
|
28
|
+
ok: false,
|
|
29
|
+
status: 400,
|
|
30
|
+
error: "command must be 'npx skills add <source> [--skill <name>]' or 'skills add …'",
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
let source;
|
|
34
|
+
let skillName;
|
|
35
|
+
for (let i = 0; i < rest.length; i++) {
|
|
36
|
+
const arg = rest[i];
|
|
37
|
+
if (arg === "--skill") {
|
|
38
|
+
const value = rest[++i];
|
|
39
|
+
if (value === undefined || value.length === 0) {
|
|
40
|
+
return { ok: false, status: 400, error: "missing value for --skill" };
|
|
41
|
+
}
|
|
42
|
+
if (value.startsWith("-")) {
|
|
43
|
+
return { ok: false, status: 400, error: "missing value for --skill" };
|
|
44
|
+
}
|
|
45
|
+
skillName = value;
|
|
46
|
+
}
|
|
47
|
+
else if (arg.startsWith("-")) {
|
|
48
|
+
return { ok: false, status: 400, error: `unknown flag: ${arg}` };
|
|
49
|
+
}
|
|
50
|
+
else if (source === undefined) {
|
|
51
|
+
source = arg;
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
return { ok: false, status: 400, error: `unexpected argument: ${arg}` };
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (source === undefined) {
|
|
58
|
+
return { ok: false, status: 400, error: "missing skill source after 'add'" };
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
source,
|
|
62
|
+
...(skillName !== undefined ? { skillName } : {}),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
export function parseInstallSkillBody(body) {
|
|
66
|
+
if (!isPlainObject(body)) {
|
|
67
|
+
return { ok: false, status: 400, error: "Request body must be an object" };
|
|
68
|
+
}
|
|
69
|
+
if (typeof body.command !== "string" || body.command.trim().length === 0) {
|
|
70
|
+
return { ok: false, status: 400, error: "command must be a non-empty string" };
|
|
71
|
+
}
|
|
72
|
+
const parsed = parseSkillsAddCommand(body.command);
|
|
73
|
+
if ("ok" in parsed) {
|
|
74
|
+
return parsed;
|
|
75
|
+
}
|
|
76
|
+
return { command: body.command.trim() };
|
|
77
|
+
}
|
|
78
|
+
async function pathExists(filePath) {
|
|
79
|
+
try {
|
|
80
|
+
await access(filePath);
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
async function readFrontmatterName(skillMdPath) {
|
|
88
|
+
try {
|
|
89
|
+
const raw = await readFile(skillMdPath, "utf8");
|
|
90
|
+
const match = /^---\r?\n([\s\S]*?)\r?\n---/.exec(raw);
|
|
91
|
+
if (!match)
|
|
92
|
+
return undefined;
|
|
93
|
+
const nameLine = /^name:\s*(.+)\s*$/m.exec(match[1] ?? "");
|
|
94
|
+
const value = nameLine?.[1]?.trim();
|
|
95
|
+
if (value === undefined || value.length === 0)
|
|
96
|
+
return undefined;
|
|
97
|
+
return value.replace(/^['"]|['"]$/g, "");
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return undefined;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
export async function locateSkillDirectory(checkoutRoot, skillName) {
|
|
104
|
+
const candidates = [];
|
|
105
|
+
const seen = new Set();
|
|
106
|
+
const pushCandidate = (name, root) => {
|
|
107
|
+
const key = path.resolve(root);
|
|
108
|
+
if (seen.has(key))
|
|
109
|
+
return;
|
|
110
|
+
seen.add(key);
|
|
111
|
+
candidates.push({ name, root: key });
|
|
112
|
+
};
|
|
113
|
+
const rootSkillMd = path.join(checkoutRoot, "SKILL.md");
|
|
114
|
+
if (await pathExists(rootSkillMd)) {
|
|
115
|
+
const name = (await readFrontmatterName(rootSkillMd)) ?? path.basename(path.resolve(checkoutRoot));
|
|
116
|
+
pushCandidate(name, checkoutRoot);
|
|
117
|
+
}
|
|
118
|
+
let entries;
|
|
119
|
+
try {
|
|
120
|
+
entries = await readdir(checkoutRoot, { withFileTypes: true });
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
throw new Error("skill source directory not found");
|
|
124
|
+
}
|
|
125
|
+
for (const entry of entries) {
|
|
126
|
+
if (!entry.isDirectory())
|
|
127
|
+
continue;
|
|
128
|
+
if (entry.name === ".git" || entry.name === "node_modules" || entry.name === "skills") {
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
const skillMd = path.join(checkoutRoot, entry.name, "SKILL.md");
|
|
132
|
+
if (await pathExists(skillMd)) {
|
|
133
|
+
pushCandidate(entry.name, path.join(checkoutRoot, entry.name));
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
const skillsDir = path.join(checkoutRoot, "skills");
|
|
137
|
+
try {
|
|
138
|
+
const skillsStat = await stat(skillsDir);
|
|
139
|
+
if (skillsStat.isDirectory()) {
|
|
140
|
+
const skillEntries = await readdir(skillsDir, { withFileTypes: true });
|
|
141
|
+
for (const entry of skillEntries) {
|
|
142
|
+
if (!entry.isDirectory())
|
|
143
|
+
continue;
|
|
144
|
+
const skillMd = path.join(skillsDir, entry.name, "SKILL.md");
|
|
145
|
+
if (await pathExists(skillMd)) {
|
|
146
|
+
pushCandidate(entry.name, path.join(skillsDir, entry.name));
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
// no skills/ directory
|
|
153
|
+
}
|
|
154
|
+
if (skillName !== undefined) {
|
|
155
|
+
const namedPaths = [
|
|
156
|
+
path.join(checkoutRoot, skillName, "SKILL.md"),
|
|
157
|
+
path.join(checkoutRoot, "skills", skillName, "SKILL.md"),
|
|
158
|
+
];
|
|
159
|
+
for (const skillMd of namedPaths) {
|
|
160
|
+
if (await pathExists(skillMd)) {
|
|
161
|
+
return { name: skillName, root: path.dirname(skillMd) };
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
const match = candidates.find((candidate) => candidate.name === skillName);
|
|
165
|
+
if (match !== undefined) {
|
|
166
|
+
return match;
|
|
167
|
+
}
|
|
168
|
+
throw new Error(`skill "${skillName}" not found in source`);
|
|
169
|
+
}
|
|
170
|
+
if (candidates.length === 1) {
|
|
171
|
+
return candidates[0];
|
|
172
|
+
}
|
|
173
|
+
if (candidates.length === 0) {
|
|
174
|
+
throw new Error("no SKILL.md found in source");
|
|
175
|
+
}
|
|
176
|
+
const names = candidates.map((candidate) => candidate.name).join(", ");
|
|
177
|
+
throw new Error(`multiple skills found (${names}); pass --skill <name>`);
|
|
178
|
+
}
|
|
179
|
+
export function resolveGitCloneUrl(source) {
|
|
180
|
+
const githubHttps = /^https:\/\/github\.com\/([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+?)(?:\.git)?(?:\/|$)/i.exec(source);
|
|
181
|
+
if (githubHttps) {
|
|
182
|
+
return `https://github.com/${githubHttps[1]}/${githubHttps[2]}.git`;
|
|
183
|
+
}
|
|
184
|
+
if (/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(source)) {
|
|
185
|
+
return `https://github.com/${source}.git`;
|
|
186
|
+
}
|
|
187
|
+
throw new Error("source must be a GitHub HTTPS URL, owner/repo slug, or file: URL");
|
|
188
|
+
}
|
|
189
|
+
export async function defaultCloneSkillRepo(cloneUrl, destDir) {
|
|
190
|
+
await runGit({
|
|
191
|
+
args: ["clone", "--depth", "1", "--single-branch", cloneUrl, destDir],
|
|
192
|
+
timeoutMs: 120_000,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
function resolveFileSource(source) {
|
|
196
|
+
if (source.startsWith("file:")) {
|
|
197
|
+
return fileURLToPath(source);
|
|
198
|
+
}
|
|
199
|
+
throw new Error("source must be a GitHub HTTPS URL, owner/repo slug, or file: URL");
|
|
200
|
+
}
|
|
201
|
+
export async function installSkillFromCommand(input) {
|
|
202
|
+
const parsed = parseSkillsAddCommand(input.command);
|
|
203
|
+
if ("ok" in parsed) {
|
|
204
|
+
return { ok: false, error: parsed.error, status: parsed.status };
|
|
205
|
+
}
|
|
206
|
+
let cleanup;
|
|
207
|
+
try {
|
|
208
|
+
let checkoutRoot;
|
|
209
|
+
if (parsed.source.startsWith("file:")) {
|
|
210
|
+
checkoutRoot = resolveFileSource(parsed.source);
|
|
211
|
+
try {
|
|
212
|
+
const sourceStat = await stat(checkoutRoot);
|
|
213
|
+
if (!sourceStat.isDirectory()) {
|
|
214
|
+
return { ok: false, error: "skill source path not found", status: 400 };
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
catch {
|
|
218
|
+
return { ok: false, error: "skill source path not found", status: 400 };
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
let cloneUrl;
|
|
223
|
+
try {
|
|
224
|
+
cloneUrl = resolveGitCloneUrl(parsed.source);
|
|
225
|
+
}
|
|
226
|
+
catch (err) {
|
|
227
|
+
return {
|
|
228
|
+
ok: false,
|
|
229
|
+
error: err instanceof Error ? err.message : String(err),
|
|
230
|
+
status: 400,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
const tempRoot = await mkdtemp(path.join(tmpdir(), "sf-skill-clone-"));
|
|
234
|
+
cleanup = async () => {
|
|
235
|
+
await rm(tempRoot, { recursive: true, force: true });
|
|
236
|
+
};
|
|
237
|
+
const cloneDest = path.join(tempRoot, "repo");
|
|
238
|
+
const cloneRepo = input.cloneRepo ?? defaultCloneSkillRepo;
|
|
239
|
+
await cloneRepo(cloneUrl, cloneDest);
|
|
240
|
+
checkoutRoot = cloneDest;
|
|
241
|
+
}
|
|
242
|
+
const located = await locateSkillDirectory(checkoutRoot, parsed.skillName);
|
|
243
|
+
const result = await installProjectSkill({
|
|
244
|
+
projectRoot: input.projectRoot,
|
|
245
|
+
fromPath: located.root,
|
|
246
|
+
skillName: located.name,
|
|
247
|
+
io: {
|
|
248
|
+
log: () => undefined,
|
|
249
|
+
error: () => undefined,
|
|
250
|
+
},
|
|
251
|
+
});
|
|
252
|
+
if (!result.ok) {
|
|
253
|
+
return {
|
|
254
|
+
ok: false,
|
|
255
|
+
error: result.error,
|
|
256
|
+
...(result.doctorFailed ? { doctorFailed: true, status: 422 } : { status: 400 }),
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
return {
|
|
260
|
+
ok: true,
|
|
261
|
+
skill_name: result.skillName,
|
|
262
|
+
dest_path: result.destPath,
|
|
263
|
+
project_root: input.projectRoot,
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
catch (err) {
|
|
267
|
+
return {
|
|
268
|
+
ok: false,
|
|
269
|
+
error: err instanceof Error ? err.message : String(err),
|
|
270
|
+
status: 400,
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
finally {
|
|
274
|
+
if (cleanup !== undefined) {
|
|
275
|
+
await cleanup();
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
/** Test helper: build a file: command for a local skill tree. */
|
|
280
|
+
export function skillsAddFileCommand(fromPath, skillName) {
|
|
281
|
+
const source = pathToFileURL(path.resolve(fromPath)).href;
|
|
282
|
+
if (skillName === undefined) {
|
|
283
|
+
return `npx skills add ${source}`;
|
|
284
|
+
}
|
|
285
|
+
return `npx skills add ${source} --skill ${skillName}`;
|
|
286
|
+
}
|
|
@@ -1,28 +1,12 @@
|
|
|
1
|
-
import type { StageGateKind } from "../types/stage.js";
|
|
2
1
|
import type { LoadedManifest } from "../types/stageflowManifest.js";
|
|
3
2
|
import { type PipelineListing, type TaskListing } from "./browseCatalog.js";
|
|
4
3
|
import { type StageflowContext } from "../project/resolveStageflowContext.js";
|
|
5
4
|
import { type CatalogContext } from "./resolveCatalogContext.js";
|
|
6
5
|
export type { PipelineListing, PipelineStageListing, TaskListing } from "./browseCatalog.js";
|
|
7
|
-
export type ValidStageListing = {
|
|
8
|
-
path: string;
|
|
9
|
-
id: string;
|
|
10
|
-
used_by_pipeline_ids: string[];
|
|
11
|
-
gate_kinds?: StageGateKind[];
|
|
12
|
-
};
|
|
13
|
-
export type BrokenStageListing = {
|
|
14
|
-
path: string;
|
|
15
|
-
error: string;
|
|
16
|
-
id?: string;
|
|
17
|
-
model?: string;
|
|
18
|
-
gate_kinds?: StageGateKind[];
|
|
19
|
-
};
|
|
20
|
-
export type StageListing = ValidStageListing | BrokenStageListing;
|
|
21
6
|
export type CatalogListOptions = {
|
|
22
7
|
projectRoot: string;
|
|
23
8
|
manifest: LoadedManifest;
|
|
24
9
|
};
|
|
25
10
|
export declare function listTasks(options: CatalogListOptions): Promise<TaskListing[]>;
|
|
26
11
|
export declare function listPipelines(options: CatalogListOptions): Promise<PipelineListing[]>;
|
|
27
|
-
export declare function listStages(_options?: unknown): Promise<StageListing[]>;
|
|
28
12
|
export declare function listModels(cwdOrContext: string | CatalogContext | StageflowContext): Promise<string[]>;
|
|
@@ -17,9 +17,6 @@ export async function listPipelines(options) {
|
|
|
17
17
|
issues: [],
|
|
18
18
|
});
|
|
19
19
|
}
|
|
20
|
-
export async function listStages(_options) {
|
|
21
|
-
return [];
|
|
22
|
-
}
|
|
23
20
|
export async function listModels(cwdOrContext) {
|
|
24
21
|
const ctx = typeof cwdOrContext === "string"
|
|
25
22
|
? catalogContextFromStageflow(await resolveStageflowContext(cwdOrContext))
|
|
@@ -1,32 +1,36 @@
|
|
|
1
1
|
import type { ValidationFindingCode } from "./validateCatalog.js";
|
|
2
2
|
export type TaskLoadCode = "task.invalid_shape" | "task.load_error" | "task.binding_conflict" | "task.repository_ref_required" | "task.ref_without_repository" | "task.repository_invalid";
|
|
3
3
|
export type TriggerLoadCode = "trigger.invalid_shape" | "trigger.load_error" | "trigger.unknown_pipeline" | "trigger.unknown_task";
|
|
4
|
-
|
|
4
|
+
type LoadIssueLocation = {
|
|
5
|
+
line?: number;
|
|
6
|
+
column?: number;
|
|
7
|
+
};
|
|
8
|
+
export type LoadIssue = ({
|
|
5
9
|
code: ValidationFindingCode;
|
|
6
10
|
message: string;
|
|
7
11
|
category: "pipeline";
|
|
8
12
|
pipelineId?: string;
|
|
9
13
|
stageId?: string;
|
|
10
|
-
} | {
|
|
14
|
+
} & LoadIssueLocation) | ({
|
|
11
15
|
code: ValidationFindingCode;
|
|
12
16
|
message: string;
|
|
13
17
|
category: "stage";
|
|
14
18
|
stageId?: string;
|
|
15
|
-
} | {
|
|
19
|
+
} & LoadIssueLocation) | ({
|
|
16
20
|
code: TaskLoadCode;
|
|
17
21
|
message: string;
|
|
18
22
|
category: "task";
|
|
19
23
|
taskId?: string;
|
|
20
|
-
} | {
|
|
24
|
+
} & LoadIssueLocation) | ({
|
|
21
25
|
code: TriggerLoadCode;
|
|
22
26
|
message: string;
|
|
23
27
|
category: "trigger";
|
|
24
28
|
triggerId?: string;
|
|
25
|
-
} | {
|
|
29
|
+
} & LoadIssueLocation) | ({
|
|
26
30
|
code: ValidationFindingCode | string;
|
|
27
31
|
message: string;
|
|
28
32
|
category: "catalog";
|
|
29
|
-
};
|
|
33
|
+
} & LoadIssueLocation);
|
|
30
34
|
export type LoadOutcome<T> = {
|
|
31
35
|
ok: true;
|
|
32
36
|
value: T;
|
|
@@ -37,3 +41,4 @@ export type LoadOutcome<T> = {
|
|
|
37
41
|
};
|
|
38
42
|
export declare function loadFailure<T>(issues: LoadIssue[]): LoadOutcome<T>;
|
|
39
43
|
export declare function loadSuccess<T>(value: T, issues?: LoadIssue[]): LoadOutcome<T>;
|
|
44
|
+
export {};
|
|
@@ -262,7 +262,6 @@ async function buildLoadedPipelineFromMerge(merge, options) {
|
|
|
262
262
|
const stage = {
|
|
263
263
|
...stageOutcome.value,
|
|
264
264
|
...(browser !== undefined ? { browser } : {}),
|
|
265
|
-
...(entry.skill !== undefined ? { skill: entry.skill } : {}),
|
|
266
265
|
...(entry.mcp !== undefined ? { mcp: entry.mcp } : {}),
|
|
267
266
|
...(entry.secrets !== undefined ? { secrets: entry.secrets } : {}),
|
|
268
267
|
...(stageRequires !== undefined ? { requires: stageRequires } : {}),
|
package/dist/config/loadStage.js
CHANGED
|
@@ -7,6 +7,7 @@ import { parseModelField } from "./modelField.js";
|
|
|
7
7
|
import { allowLegacyYamlAuthoring, dialectWarningForDocument, legacyAuthoringRejected, presentLegacyKeys, } from "./legacyYaml.js";
|
|
8
8
|
import { parsePreEmitChecks } from "./parsePreEmitChecks.js";
|
|
9
9
|
import { readYamlObject } from "./readYamlObject.js";
|
|
10
|
+
import { yamlParsePosition } from "./yamlParsePosition.js";
|
|
10
11
|
import { z } from "zod";
|
|
11
12
|
import { parseStageSecrets } from "../runtime/stageSecretDecl.js";
|
|
12
13
|
import { parseToolRequires } from "./toolRequires.js";
|
|
@@ -436,6 +437,7 @@ export async function loadStageOutcome(filePath, options = {}) {
|
|
|
436
437
|
code: "stage.load_error",
|
|
437
438
|
message,
|
|
438
439
|
category: "stage",
|
|
440
|
+
...yamlParsePosition(err),
|
|
439
441
|
},
|
|
440
442
|
]);
|
|
441
443
|
}
|
|
@@ -3,6 +3,7 @@ import path from "node:path";
|
|
|
3
3
|
import { parse as parseYaml } from "yaml";
|
|
4
4
|
import { parseAgentField } from "../agent/agentBackend.js";
|
|
5
5
|
import { loadFailure, loadSuccess } from "./loadOutcome.js";
|
|
6
|
+
import { yamlParsePosition } from "./yamlParsePosition.js";
|
|
6
7
|
import { parseModelField } from "./modelField.js";
|
|
7
8
|
const DEFAULT_PIPELINE_PATTERN = "*.pipeline.yaml";
|
|
8
9
|
const DEFAULT_TASK_PATTERN = "*.task.yaml";
|
|
@@ -87,7 +88,9 @@ export function parseStageflowManifestOutcome(yamlText, manifestPath, projectRoo
|
|
|
87
88
|
}
|
|
88
89
|
catch (err) {
|
|
89
90
|
const message = err instanceof Error ? err.message : String(err);
|
|
90
|
-
return loadFailure([
|
|
91
|
+
return loadFailure([
|
|
92
|
+
{ ...catalogIssue("catalog.manifest_load_error", message), ...yamlParsePosition(err) },
|
|
93
|
+
]);
|
|
91
94
|
}
|
|
92
95
|
const issues = [];
|
|
93
96
|
const record = raw;
|
package/dist/config/loadTask.js
CHANGED
|
@@ -2,6 +2,7 @@ import { readFile } from "node:fs/promises";
|
|
|
2
2
|
import { parse as parseYaml } from "yaml";
|
|
3
3
|
import { resolveWorkspaceBinding } from "../runtime/workspaceBinding.js";
|
|
4
4
|
import { loadFailure, loadSuccess } from "./loadOutcome.js";
|
|
5
|
+
import { yamlParsePosition } from "./yamlParsePosition.js";
|
|
5
6
|
function isPlainObject(value) {
|
|
6
7
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7
8
|
}
|
|
@@ -86,6 +87,7 @@ export function loadTaskFromYamlOutcome(yamlText, source = "task yaml") {
|
|
|
86
87
|
code: "task.load_error",
|
|
87
88
|
message,
|
|
88
89
|
category: "task",
|
|
90
|
+
...yamlParsePosition(err),
|
|
89
91
|
},
|
|
90
92
|
]);
|
|
91
93
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { readFile } from "node:fs/promises";
|
|
2
2
|
import { parse as parseYaml } from "yaml";
|
|
3
3
|
import { loadFailure, loadSuccess } from "./loadOutcome.js";
|
|
4
|
+
import { yamlParsePosition } from "./yamlParsePosition.js";
|
|
4
5
|
function isPlainObject(value) {
|
|
5
6
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6
7
|
}
|
|
@@ -84,6 +85,7 @@ export function loadTriggerFromYamlOutcome(yamlText, source = "trigger yaml") {
|
|
|
84
85
|
code: "trigger.load_error",
|
|
85
86
|
message,
|
|
86
87
|
category: "trigger",
|
|
88
|
+
...yamlParsePosition(err),
|
|
87
89
|
},
|
|
88
90
|
]);
|
|
89
91
|
}
|
|
@@ -4,6 +4,7 @@ import { loadFailure, loadSuccess } from "./loadOutcome.js";
|
|
|
4
4
|
import { allowLegacyYamlAuthoring, dialectWarningForDocument, legacyAuthoringRejected, presentLegacyKeys, } from "./legacyYaml.js";
|
|
5
5
|
import { parseModelField } from "./modelField.js";
|
|
6
6
|
import { readYamlObject } from "./readYamlObject.js";
|
|
7
|
+
import { yamlParsePosition } from "./yamlParsePosition.js";
|
|
7
8
|
import { parseToolRequires } from "./toolRequires.js";
|
|
8
9
|
import { classifyYamlDocument, collectDocumentKeys, mixedDialectIssue, } from "./yamlDialect.js";
|
|
9
10
|
function isPlainObject(value) {
|
|
@@ -39,6 +40,7 @@ async function visitPipelineFile(filePath, stack, idLocations, entries, warnings
|
|
|
39
40
|
code: "pipeline.load_error",
|
|
40
41
|
message,
|
|
41
42
|
category: "pipeline",
|
|
43
|
+
...yamlParsePosition(err),
|
|
42
44
|
},
|
|
43
45
|
]);
|
|
44
46
|
}
|
|
@@ -128,6 +130,7 @@ export async function mergePipelineStages(rootPath) {
|
|
|
128
130
|
code: "pipeline.load_error",
|
|
129
131
|
message,
|
|
130
132
|
category: "pipeline",
|
|
133
|
+
...yamlParsePosition(err),
|
|
131
134
|
},
|
|
132
135
|
]);
|
|
133
136
|
}
|
|
@@ -43,7 +43,6 @@ function extractBodyRaw(raw) {
|
|
|
43
43
|
}
|
|
44
44
|
function hasBodyKey(raw) {
|
|
45
45
|
return Object.keys(raw).some((key) => BODY_KEYS.has(key) &&
|
|
46
|
-
key !== "skill" &&
|
|
47
46
|
key !== "mcp" &&
|
|
48
47
|
key !== "secrets" &&
|
|
49
48
|
key !== "requires" &&
|
|
@@ -116,6 +115,16 @@ export function normalizePipelineStageEntries(rawEntries, ctx) {
|
|
|
116
115
|
return skillOutcome;
|
|
117
116
|
}
|
|
118
117
|
const skill = skillOutcome?.ok ? skillOutcome.value : undefined;
|
|
118
|
+
if (uses && skill !== undefined) {
|
|
119
|
+
return loadFailure([
|
|
120
|
+
{
|
|
121
|
+
code: "pipeline.stage_wrapper_skill_rejected",
|
|
122
|
+
message: `Pipeline ${ctx.pipelineId} (${ctx.path}): stage entry at index ${index} sets skill: on a uses: wrapper; put skill: on the stage file (${uses}) instead`,
|
|
123
|
+
category: "pipeline",
|
|
124
|
+
pipelineId: ctx.pipelineId,
|
|
125
|
+
},
|
|
126
|
+
]);
|
|
127
|
+
}
|
|
119
128
|
const mcpOutcome = parseStageMcp(raw.mcp, `entry at index ${index} in ${declaringPath}`);
|
|
120
129
|
if (!mcpOutcome.ok)
|
|
121
130
|
return mcpOutcome;
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { type CreateDraftPackageInput, type DraftPackageWriteResult } from "./draftPackage.js";
|
|
2
|
+
import type { CatalogRootKind } from "./resolveCatalogRoots.js";
|
|
2
3
|
export type PublishDraftPackageMode = "create" | "overwrite" | "auto";
|
|
4
|
+
export type PublishDraftPackageOptions = {
|
|
5
|
+
catalogRootKind?: CatalogRootKind;
|
|
6
|
+
};
|
|
3
7
|
export type PublishDraftPackageResult = {
|
|
4
8
|
write: DraftPackageWriteResult;
|
|
5
9
|
catalogChanged: boolean;
|
|
6
10
|
};
|
|
7
|
-
export declare function publishDraftPackage(projectRoot: string, input: CreateDraftPackageInput, mode: PublishDraftPackageMode): Promise<PublishDraftPackageResult>;
|
|
11
|
+
export declare function publishDraftPackage(projectRoot: string, input: CreateDraftPackageInput, mode: PublishDraftPackageMode, options?: PublishDraftPackageOptions): Promise<PublishDraftPackageResult>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createDraftPackage, overwriteDraftPackage, } from "./draftPackage.js";
|
|
2
2
|
import { ensureCatalogScanRoot } from "./ensureCatalogScanRoot.js";
|
|
3
|
-
export async function publishDraftPackage(projectRoot, input, mode) {
|
|
3
|
+
export async function publishDraftPackage(projectRoot, input, mode, options = {}) {
|
|
4
4
|
let write;
|
|
5
5
|
if (mode === "create") {
|
|
6
6
|
write = await createDraftPackage(projectRoot, input);
|
|
@@ -20,6 +20,9 @@ export async function publishDraftPackage(projectRoot, input, mode) {
|
|
|
20
20
|
if (!write.ok) {
|
|
21
21
|
return { write, catalogChanged: false };
|
|
22
22
|
}
|
|
23
|
+
if (options.catalogRootKind === "workspace") {
|
|
24
|
+
return { write, catalogChanged: false };
|
|
25
|
+
}
|
|
23
26
|
const catalogChanged = await ensureCatalogScanRoot(projectRoot, input.directory);
|
|
24
27
|
return { write, catalogChanged };
|
|
25
28
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { RunStore } from "../runstore/port.js";
|
|
2
|
-
export type CatalogRootKind = "registered" | "seeded";
|
|
2
|
+
export type CatalogRootKind = "registered" | "seeded" | "workspace";
|
|
3
3
|
export type CatalogRoot = {
|
|
4
4
|
/** Wire id: absolute path for registered; symbolic id for seeded (e.g. "examples"). */
|
|
5
5
|
project_root: string;
|
|
@@ -7,6 +7,9 @@ export type CatalogRoot = {
|
|
|
7
7
|
path: string;
|
|
8
8
|
kind: CatalogRootKind;
|
|
9
9
|
read_only: boolean;
|
|
10
|
+
/** False when workspace provisioning failed at boot. */
|
|
11
|
+
available?: boolean;
|
|
12
|
+
unavailable_reason?: string;
|
|
10
13
|
};
|
|
11
14
|
export type ResolveCatalogRootsOptions = {
|
|
12
15
|
store: RunStore;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { realpathSync, constants } from "node:fs";
|
|
3
3
|
import { access } from "node:fs/promises";
|
|
4
|
+
import { WORKSPACE_CATALOG_ID, lastWorkspaceProvisionResult, workspaceCatalogPath, } from "../project/workspaceCatalog.js";
|
|
4
5
|
function realOrResolve(p) {
|
|
5
6
|
const resolved = path.resolve(p);
|
|
6
7
|
try {
|
|
@@ -19,6 +20,7 @@ export async function resolveCatalogRoots(options) {
|
|
|
19
20
|
const seenPaths = new Set();
|
|
20
21
|
const seededRoots = options.seededRoots ??
|
|
21
22
|
(await import("./seededCatalog.js")).defaultSeededRoots();
|
|
23
|
+
const workspaceAbs = realOrResolve(workspaceCatalogPath());
|
|
22
24
|
let registered = [];
|
|
23
25
|
try {
|
|
24
26
|
registered = await options.store.listRegisteredProjects();
|
|
@@ -28,7 +30,7 @@ export async function resolveCatalogRoots(options) {
|
|
|
28
30
|
}
|
|
29
31
|
for (const root of registered) {
|
|
30
32
|
const abs = realOrResolve(root);
|
|
31
|
-
if (seenPaths.has(abs))
|
|
33
|
+
if (seenPaths.has(abs) || abs === workspaceAbs)
|
|
32
34
|
continue;
|
|
33
35
|
seenPaths.add(abs);
|
|
34
36
|
roots.push({
|
|
@@ -38,6 +40,21 @@ export async function resolveCatalogRoots(options) {
|
|
|
38
40
|
read_only: false,
|
|
39
41
|
});
|
|
40
42
|
}
|
|
43
|
+
if (!seenPaths.has(workspaceAbs)) {
|
|
44
|
+
seenPaths.add(workspaceAbs);
|
|
45
|
+
const provision = lastWorkspaceProvisionResult();
|
|
46
|
+
const available = provision === undefined || provision.ok;
|
|
47
|
+
roots.push({
|
|
48
|
+
project_root: WORKSPACE_CATALOG_ID,
|
|
49
|
+
path: workspaceCatalogPath(),
|
|
50
|
+
kind: "workspace",
|
|
51
|
+
read_only: false,
|
|
52
|
+
available,
|
|
53
|
+
...(provision !== undefined && !provision.ok && provision.reason
|
|
54
|
+
? { unavailable_reason: provision.reason }
|
|
55
|
+
: {}),
|
|
56
|
+
});
|
|
57
|
+
}
|
|
41
58
|
for (const seeded of seededRoots) {
|
|
42
59
|
const abs = realOrResolve(seeded.path);
|
|
43
60
|
if (seenPaths.has(abs))
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { loadPipelineOutcome } from "./loadPipeline.js";
|
|
2
|
+
import { getCatalogScanPaths } from "./browseCatalog.js";
|
|
3
|
+
import { catalogContextFromStageflow } from "./resolveCatalogContext.js";
|
|
4
|
+
import { resolveStageflowContext } from "../project/resolveStageflowContext.js";
|
|
5
|
+
function addUsage(index, skillName, pipelineId, stageId) {
|
|
6
|
+
const entry = index[skillName] ?? { stage_ids: [], pipeline_ids: [] };
|
|
7
|
+
if (!entry.pipeline_ids.includes(pipelineId)) {
|
|
8
|
+
entry.pipeline_ids.push(pipelineId);
|
|
9
|
+
entry.pipeline_ids.sort((a, b) => a.localeCompare(b));
|
|
10
|
+
}
|
|
11
|
+
if (!entry.stage_ids.includes(stageId)) {
|
|
12
|
+
entry.stage_ids.push(stageId);
|
|
13
|
+
entry.stage_ids.sort((a, b) => a.localeCompare(b));
|
|
14
|
+
}
|
|
15
|
+
index[skillName] = entry;
|
|
16
|
+
}
|
|
17
|
+
export async function buildSkillUsageIndex(cwd) {
|
|
18
|
+
const ctx = catalogContextFromStageflow(await resolveStageflowContext(cwd));
|
|
19
|
+
const scanPaths = await getCatalogScanPaths(ctx);
|
|
20
|
+
if (!scanPaths) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
const index = {};
|
|
24
|
+
const loadCwd = ctx.projectRoot ?? cwd;
|
|
25
|
+
for (const pipelinePath of scanPaths.pipelinePaths) {
|
|
26
|
+
const outcome = await loadPipelineOutcome(pipelinePath, { cwd: loadCwd });
|
|
27
|
+
if (!outcome.ok) {
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
const pipelineId = outcome.value.pipeline.id;
|
|
31
|
+
for (const stage of outcome.value.stages) {
|
|
32
|
+
if (stage.skill === undefined) {
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
addUsage(index, stage.skill, pipelineId, stage.id);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return index;
|
|
39
|
+
}
|