@smithers-orchestrator/cli 0.17.0 → 0.18.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/dist/CliExitCode-dlFKbqup.d.ts +12 -0
- package/dist/HijackCandidate-FxLeKpcZ.d.ts +13 -0
- package/dist/SemanticToolDefinition-C1UT6pZk.d.ts +71 -0
- package/dist/SupervisorOptions-DtiPbGFx.d.ts +27 -0
- package/dist/agent-commands/agentAddWizard.d.ts +18 -0
- package/dist/agent-commands/regenerateAgentsTsIfPresent.d.ts +15 -0
- package/dist/agent-commands/runAgentAdd.d.ts +83 -0
- package/dist/agent-detection.d.ts +27 -0
- package/dist/ask.d.ts +29 -0
- package/dist/chat.d.ts +96 -0
- package/dist/diff.d.ts +64 -0
- package/dist/event-categories.d.ts +26 -0
- package/dist/find-db.d.ts +47 -0
- package/dist/format.d.ts +35 -0
- package/dist/hijack-session.d.ts +25 -0
- package/dist/hijack.d.ts +54 -0
- package/dist/index.d.ts +1 -0
- package/dist/mcp/semantic-server.d.ts +30 -0
- package/dist/mcp/semantic-tools.d.ts +4 -0
- package/dist/mdx-plugin.d.ts +3 -0
- package/dist/node-detail.d.ts +143 -0
- package/dist/output.d.ts +31 -0
- package/dist/resume-detached.d.ts +17 -0
- package/dist/rewind.d.ts +28 -0
- package/dist/scheduler.d.ts +3 -0
- package/dist/smithersRuntime.d.ts +23 -0
- package/dist/supervisor.d.ts +44 -0
- package/dist/tree.d.ts +51 -0
- package/dist/util/errorMessage.d.ts +40 -0
- package/dist/util/exitCodes.d.ts +19 -0
- package/dist/watch.d.ts +44 -0
- package/dist/why-diagnosis.d.ts +56 -0
- package/dist/workflow-pack.d.ts +38 -0
- package/dist/workflows.d.ts +35 -0
- package/package.json +20 -19
- package/src/workflow-pack.js +652 -19
package/src/workflow-pack.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
2
3
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
4
|
import { dirname, resolve } from "node:path";
|
|
4
5
|
import { fileURLToPath } from "node:url";
|
|
@@ -19,6 +20,9 @@ import { generateAgentsTs } from "./agent-detection.js";
|
|
|
19
20
|
* @typedef {{ path: string; contents: string; preserveExisting?: boolean; }} TemplateFile
|
|
20
21
|
*/
|
|
21
22
|
|
|
23
|
+
const FALLBACK_SMITHERS_SPEC = "latest";
|
|
24
|
+
const require = createRequire(import.meta.url);
|
|
25
|
+
|
|
22
26
|
/**
|
|
23
27
|
* @param {string} path
|
|
24
28
|
*/
|
|
@@ -50,26 +54,33 @@ function readPackageVersion(path, fallback) {
|
|
|
50
54
|
}
|
|
51
55
|
}
|
|
52
56
|
/**
|
|
53
|
-
* Resolve
|
|
54
|
-
* location) and return its `version`. Uses `import.meta.resolve` so it works
|
|
55
|
-
* whether the CLI is running from the monorepo checkout (deps under
|
|
56
|
-
* `apps/cli/node_modules/`) or installed flat under a user's project
|
|
57
|
-
* `node_modules/`. Falls back to the pin bundled at release time when the
|
|
58
|
-
* package isn't installed in the user's project (typical for devDep-only
|
|
59
|
-
* specs like `typescript` and `@types/*`).
|
|
57
|
+
* Resolve an installed dependency version from the current package layout.
|
|
60
58
|
*
|
|
61
|
-
* @param {string}
|
|
59
|
+
* @param {string} specifier
|
|
62
60
|
* @param {string} fallback
|
|
63
61
|
*/
|
|
64
|
-
function
|
|
62
|
+
function resolveInstalledPackageVersion(specifier, fallback) {
|
|
65
63
|
try {
|
|
66
|
-
const
|
|
67
|
-
return readPackageVersion(
|
|
64
|
+
const resolved = require.resolve(`${specifier}/package.json`);
|
|
65
|
+
return readPackageVersion(resolved, fallback);
|
|
68
66
|
}
|
|
69
67
|
catch {
|
|
70
68
|
return fallback;
|
|
71
69
|
}
|
|
72
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* @returns {string | undefined}
|
|
73
|
+
*/
|
|
74
|
+
function readOwnPackageVersion() {
|
|
75
|
+
try {
|
|
76
|
+
const ownPackagePath = fileURLToPath(new URL("../package.json", import.meta.url));
|
|
77
|
+
const version = readJson(ownPackagePath).version;
|
|
78
|
+
return typeof version === "string" && version.length > 0 ? version : undefined;
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
73
84
|
/**
|
|
74
85
|
* Pins shipped with this release for devDep-only specs that won't be in the
|
|
75
86
|
* user's `node_modules` after `bunx smithers-orchestrator@latest init`. Bump
|
|
@@ -88,19 +99,22 @@ const BUNDLED_VERSION_PINS = {
|
|
|
88
99
|
*/
|
|
89
100
|
function readDependencyVersions() {
|
|
90
101
|
return {
|
|
91
|
-
smithersVersion:
|
|
92
|
-
zodVersion:
|
|
93
|
-
typescriptVersion:
|
|
94
|
-
reactTypesVersion:
|
|
95
|
-
reactDomTypesVersion:
|
|
96
|
-
mdxTypesVersion:
|
|
97
|
-
nodeTypesVersion:
|
|
102
|
+
smithersVersion: readOwnPackageVersion(),
|
|
103
|
+
zodVersion: resolveInstalledPackageVersion("zod", BUNDLED_VERSION_PINS.zod),
|
|
104
|
+
typescriptVersion: resolveInstalledPackageVersion("typescript", BUNDLED_VERSION_PINS.typescript),
|
|
105
|
+
reactTypesVersion: resolveInstalledPackageVersion("@types/react", BUNDLED_VERSION_PINS.reactTypes),
|
|
106
|
+
reactDomTypesVersion: resolveInstalledPackageVersion("@types/react-dom", BUNDLED_VERSION_PINS.reactDomTypes),
|
|
107
|
+
mdxTypesVersion: resolveInstalledPackageVersion("@types/mdx", BUNDLED_VERSION_PINS.mdxTypes),
|
|
108
|
+
nodeTypesVersion: resolveInstalledPackageVersion("@types/node", BUNDLED_VERSION_PINS.nodeTypes),
|
|
98
109
|
};
|
|
99
110
|
}
|
|
100
111
|
/**
|
|
101
112
|
* @param {DependencyVersions} versions
|
|
102
113
|
*/
|
|
103
114
|
function renderPackageJson(versions) {
|
|
115
|
+
const smithersSpec = versions.smithersVersion
|
|
116
|
+
? `^${versions.smithersVersion}`
|
|
117
|
+
: FALLBACK_SMITHERS_SPEC;
|
|
104
118
|
return JSON.stringify({
|
|
105
119
|
name: "smithers-workflows",
|
|
106
120
|
private: true,
|
|
@@ -113,7 +127,7 @@ function renderPackageJson(versions) {
|
|
|
113
127
|
},
|
|
114
128
|
dependencies: {
|
|
115
129
|
skills: "github:mattpocock/skills",
|
|
116
|
-
"smithers-orchestrator":
|
|
130
|
+
"smithers-orchestrator": smithersSpec,
|
|
117
131
|
zod: versions.zodVersion,
|
|
118
132
|
},
|
|
119
133
|
devDependencies: {
|
|
@@ -590,6 +604,183 @@ function renderPrompts() {
|
|
|
590
604
|
"",
|
|
591
605
|
].join("\n"),
|
|
592
606
|
},
|
|
607
|
+
{
|
|
608
|
+
path: ".smithers/prompts/mission-plan.mdx",
|
|
609
|
+
contents: [
|
|
610
|
+
"# Mission Plan",
|
|
611
|
+
"",
|
|
612
|
+
"You are the mission orchestrator for a long-running Smithers workflow.",
|
|
613
|
+
"Scope the goal with the user before execution. If critical requirements, constraints, or acceptance criteria are missing, ask one question at a time using the ask-user command from the instructions you were given.",
|
|
614
|
+
"",
|
|
615
|
+
"Design the mission as serial milestones with targeted parallelism inside each milestone.",
|
|
616
|
+
"Each milestone must be a meaningful checkpoint that can be validated before the next milestone begins.",
|
|
617
|
+
"Each feature should be narrow enough for a fresh worker session to execute without needing the full mission history.",
|
|
618
|
+
"Include explicit validation checks for every milestone: tests, lint/typecheck/build commands, integration checks, and UI/browser walkthroughs when the repo has an app surface.",
|
|
619
|
+
"Capture risks, assumptions, out-of-scope items, and anything the user should approve before work starts.",
|
|
620
|
+
"",
|
|
621
|
+
"REQUEST:",
|
|
622
|
+
"{props.prompt}",
|
|
623
|
+
"",
|
|
624
|
+
"LIMITS:",
|
|
625
|
+
"- Max milestones: {props.maxMilestones}",
|
|
626
|
+
"- Max features per milestone: {props.maxFeaturesPerMilestone}",
|
|
627
|
+
"",
|
|
628
|
+
"REQUIRED OUTPUT:",
|
|
629
|
+
"{props.schema}",
|
|
630
|
+
"",
|
|
631
|
+
].join("\n"),
|
|
632
|
+
},
|
|
633
|
+
{
|
|
634
|
+
path: ".smithers/prompts/mission-worker.mdx",
|
|
635
|
+
contents: [
|
|
636
|
+
"# Mission Worker",
|
|
637
|
+
"",
|
|
638
|
+
"You are a focused feature worker in a larger mission. Treat this as a fresh context window: use the mission plan below, execute only your assigned feature, and keep handoff notes precise.",
|
|
639
|
+
"",
|
|
640
|
+
"Rules:",
|
|
641
|
+
"1. Stay within the assigned feature scope unless you must make a small adjacent change to keep the repo working.",
|
|
642
|
+
"2. Prefer existing repo patterns and run the most relevant checks you can.",
|
|
643
|
+
"3. Record files changed, commands run, unresolved issues, and reusable learnings for later workers.",
|
|
644
|
+
"4. If the feature cannot be completed, make the best safe partial progress and explain exactly what blocks it.",
|
|
645
|
+
"",
|
|
646
|
+
"MISSION GOAL:",
|
|
647
|
+
"{props.missionGoal}",
|
|
648
|
+
"",
|
|
649
|
+
"MILESTONE:",
|
|
650
|
+
"```json",
|
|
651
|
+
"{JSON.stringify(props.milestone, null, 2)}",
|
|
652
|
+
"```",
|
|
653
|
+
"",
|
|
654
|
+
"FEATURE:",
|
|
655
|
+
"```json",
|
|
656
|
+
"{JSON.stringify(props.feature, null, 2)}",
|
|
657
|
+
"```",
|
|
658
|
+
"",
|
|
659
|
+
"{props.previousSummary ? `PREVIOUS MILESTONE SUMMARY:\\n${props.previousSummary}` : \"\"}",
|
|
660
|
+
"",
|
|
661
|
+
"REQUIRED OUTPUT:",
|
|
662
|
+
"{props.schema}",
|
|
663
|
+
"",
|
|
664
|
+
].join("\n"),
|
|
665
|
+
},
|
|
666
|
+
{
|
|
667
|
+
path: ".smithers/prompts/mission-integrate.mdx",
|
|
668
|
+
contents: [
|
|
669
|
+
"# Mission Integrate",
|
|
670
|
+
"",
|
|
671
|
+
"You are integrating feature-worker results for one milestone.",
|
|
672
|
+
"",
|
|
673
|
+
"{props.useWorktrees ? \"The feature work may live on per-feature worktree branches. Inspect the branches, merge successful work back into the main workspace, resolve conflicts carefully, and leave conflicted or unsafe branches unmerged with a clear explanation.\" : \"Feature workers ran in the main workspace. Inspect their results and make any small integration fixes needed before validation.\"}",
|
|
674
|
+
"",
|
|
675
|
+
"MISSION GOAL:",
|
|
676
|
+
"{props.missionGoal}",
|
|
677
|
+
"",
|
|
678
|
+
"MILESTONE:",
|
|
679
|
+
"```json",
|
|
680
|
+
"{JSON.stringify(props.milestone, null, 2)}",
|
|
681
|
+
"```",
|
|
682
|
+
"",
|
|
683
|
+
"FEATURE RESULTS:",
|
|
684
|
+
"```json",
|
|
685
|
+
"{JSON.stringify(props.results, null, 2)}",
|
|
686
|
+
"```",
|
|
687
|
+
"",
|
|
688
|
+
"REQUIRED OUTPUT:",
|
|
689
|
+
"{props.schema}",
|
|
690
|
+
"",
|
|
691
|
+
].join("\n"),
|
|
692
|
+
},
|
|
693
|
+
{
|
|
694
|
+
path: ".smithers/prompts/mission-validate.mdx",
|
|
695
|
+
contents: [
|
|
696
|
+
"# Mission Validate",
|
|
697
|
+
"",
|
|
698
|
+
"You are a validation worker for a mission milestone.",
|
|
699
|
+
"Validate accumulated work before the orchestrator moves to the next milestone.",
|
|
700
|
+
"",
|
|
701
|
+
"Run the strongest checks that fit the repo: tests, lint, typecheck, build, smoke tests, and integration checks.",
|
|
702
|
+
"If the repo has a UI, launch it and exercise core flows like a user would. Check render correctness, navigation, state transitions, and obvious layout regressions.",
|
|
703
|
+
"If a check cannot run because the repo lacks commands or setup, report that as a validation limitation instead of inventing results.",
|
|
704
|
+
"",
|
|
705
|
+
"MISSION GOAL:",
|
|
706
|
+
"{props.missionGoal}",
|
|
707
|
+
"",
|
|
708
|
+
"MILESTONE:",
|
|
709
|
+
"```json",
|
|
710
|
+
"{JSON.stringify(props.milestone, null, 2)}",
|
|
711
|
+
"```",
|
|
712
|
+
"",
|
|
713
|
+
"INTEGRATION RESULT:",
|
|
714
|
+
"```json",
|
|
715
|
+
"{JSON.stringify(props.integration, null, 2)}",
|
|
716
|
+
"```",
|
|
717
|
+
"",
|
|
718
|
+
"{props.followUp ? `FOLLOW-UP RESULT:\\n${JSON.stringify(props.followUp, null, 2)}` : \"\"}",
|
|
719
|
+
"",
|
|
720
|
+
"REQUIRED OUTPUT:",
|
|
721
|
+
"{props.schema}",
|
|
722
|
+
"",
|
|
723
|
+
].join("\n"),
|
|
724
|
+
},
|
|
725
|
+
{
|
|
726
|
+
path: ".smithers/prompts/mission-follow-up.mdx",
|
|
727
|
+
contents: [
|
|
728
|
+
"# Mission Follow-Up",
|
|
729
|
+
"",
|
|
730
|
+
"Validation found issues in the current milestone. Fix the concrete regressions and gaps before the mission proceeds.",
|
|
731
|
+
"Keep changes targeted. Do not begin the next milestone.",
|
|
732
|
+
"",
|
|
733
|
+
"MISSION GOAL:",
|
|
734
|
+
"{props.missionGoal}",
|
|
735
|
+
"",
|
|
736
|
+
"MILESTONE:",
|
|
737
|
+
"```json",
|
|
738
|
+
"{JSON.stringify(props.milestone, null, 2)}",
|
|
739
|
+
"```",
|
|
740
|
+
"",
|
|
741
|
+
"VALIDATION RESULT:",
|
|
742
|
+
"```json",
|
|
743
|
+
"{JSON.stringify(props.validation, null, 2)}",
|
|
744
|
+
"```",
|
|
745
|
+
"",
|
|
746
|
+
"REQUIRED OUTPUT:",
|
|
747
|
+
"{props.schema}",
|
|
748
|
+
"",
|
|
749
|
+
].join("\n"),
|
|
750
|
+
},
|
|
751
|
+
{
|
|
752
|
+
path: ".smithers/prompts/mission-final.mdx",
|
|
753
|
+
contents: [
|
|
754
|
+
"# Mission Final Report",
|
|
755
|
+
"",
|
|
756
|
+
"Write the final mission report. Summarize what shipped, what was validated, what remains risky, and the recommended next actions.",
|
|
757
|
+
"Be concrete about files, commands, validation gaps, and any milestone that did not pass validation.",
|
|
758
|
+
"",
|
|
759
|
+
"MISSION PLAN:",
|
|
760
|
+
"```json",
|
|
761
|
+
"{JSON.stringify(props.plan, null, 2)}",
|
|
762
|
+
"```",
|
|
763
|
+
"",
|
|
764
|
+
"FEATURE RESULTS:",
|
|
765
|
+
"```json",
|
|
766
|
+
"{JSON.stringify(props.featureResults, null, 2)}",
|
|
767
|
+
"```",
|
|
768
|
+
"",
|
|
769
|
+
"INTEGRATION RESULTS:",
|
|
770
|
+
"```json",
|
|
771
|
+
"{JSON.stringify(props.integrationResults, null, 2)}",
|
|
772
|
+
"```",
|
|
773
|
+
"",
|
|
774
|
+
"VALIDATION RESULTS:",
|
|
775
|
+
"```json",
|
|
776
|
+
"{JSON.stringify(props.validationResults, null, 2)}",
|
|
777
|
+
"```",
|
|
778
|
+
"",
|
|
779
|
+
"REQUIRED OUTPUT:",
|
|
780
|
+
"{props.schema}",
|
|
781
|
+
"",
|
|
782
|
+
].join("\n"),
|
|
783
|
+
},
|
|
593
784
|
{
|
|
594
785
|
path: ".smithers/prompts/tickets-create.mdx",
|
|
595
786
|
contents: [
|
|
@@ -1974,6 +2165,440 @@ function renderWorkflows() {
|
|
|
1974
2165
|
" </Workflow>",
|
|
1975
2166
|
"));",
|
|
1976
2167
|
]),
|
|
2168
|
+
renderWorkflowFile("mission", "Mission", [
|
|
2169
|
+
...sharedImports,
|
|
2170
|
+
'import AskUserInstructions from "../prompts/ask-user-instructions.mdx";',
|
|
2171
|
+
'import MissionPlanPrompt from "../prompts/mission-plan.mdx";',
|
|
2172
|
+
'import MissionWorkerPrompt from "../prompts/mission-worker.mdx";',
|
|
2173
|
+
'import MissionIntegratePrompt from "../prompts/mission-integrate.mdx";',
|
|
2174
|
+
'import MissionValidatePrompt from "../prompts/mission-validate.mdx";',
|
|
2175
|
+
'import MissionFollowUpPrompt from "../prompts/mission-follow-up.mdx";',
|
|
2176
|
+
'import MissionFinalPrompt from "../prompts/mission-final.mdx";',
|
|
2177
|
+
"",
|
|
2178
|
+
"const missionFeatureSchema = z.looseObject({",
|
|
2179
|
+
' id: z.string().default("feature"),',
|
|
2180
|
+
' title: z.string().default("Feature"),',
|
|
2181
|
+
' instructions: z.string().default("Complete the assigned feature."),',
|
|
2182
|
+
" files: z.array(z.string()).default([]),",
|
|
2183
|
+
" validation: z.array(z.string()).default([]),",
|
|
2184
|
+
' workerType: z.enum(["implementation", "test", "docs", "research"]).default("implementation"),',
|
|
2185
|
+
" canRunInParallel: z.boolean().default(true),",
|
|
2186
|
+
"});",
|
|
2187
|
+
"",
|
|
2188
|
+
"const missionMilestoneSchema = z.looseObject({",
|
|
2189
|
+
' id: z.string().default("milestone"),',
|
|
2190
|
+
' title: z.string().default("Milestone"),',
|
|
2191
|
+
' objective: z.string().default("Complete this milestone."),',
|
|
2192
|
+
" features: z.array(missionFeatureSchema).default([]),",
|
|
2193
|
+
" validationPlan: z.array(z.string()).default([]),",
|
|
2194
|
+
"});",
|
|
2195
|
+
"",
|
|
2196
|
+
"const missionPlanSchema = z.looseObject({",
|
|
2197
|
+
' goal: z.string().default(""),',
|
|
2198
|
+
' summary: z.string().default("Mission plan created."),',
|
|
2199
|
+
" milestones: z.array(missionMilestoneSchema).default([]),",
|
|
2200
|
+
" assumptions: z.array(z.string()).default([]),",
|
|
2201
|
+
" risks: z.array(z.string()).default([]),",
|
|
2202
|
+
" outOfScope: z.array(z.string()).default([]),",
|
|
2203
|
+
' approvalNotes: z.string().nullable().default(null),',
|
|
2204
|
+
"});",
|
|
2205
|
+
"",
|
|
2206
|
+
"const missionApprovalSchema = z.looseObject({",
|
|
2207
|
+
" approved: z.boolean().default(false),",
|
|
2208
|
+
" note: z.string().nullable().default(null),",
|
|
2209
|
+
" decidedBy: z.string().nullable().default(null),",
|
|
2210
|
+
" decidedAt: z.string().nullable().default(null),",
|
|
2211
|
+
"});",
|
|
2212
|
+
"",
|
|
2213
|
+
"const missionFeatureResultSchema = z.looseObject({",
|
|
2214
|
+
' featureId: z.string().default("feature"),',
|
|
2215
|
+
' status: z.enum(["success", "partial", "failed"]).default("partial"),',
|
|
2216
|
+
' summary: z.string().default("Feature worker completed."),',
|
|
2217
|
+
" filesChanged: z.array(z.string()).default([]),",
|
|
2218
|
+
" commandsRun: z.array(z.string()).default([]),",
|
|
2219
|
+
" blockers: z.array(z.string()).default([]),",
|
|
2220
|
+
" reusableLearnings: z.array(z.string()).default([]),",
|
|
2221
|
+
"});",
|
|
2222
|
+
"",
|
|
2223
|
+
"const milestoneIntegrationSchema = z.looseObject({",
|
|
2224
|
+
' milestoneId: z.string().default("milestone"),',
|
|
2225
|
+
' status: z.enum(["integrated", "partial", "blocked"]).default("integrated"),',
|
|
2226
|
+
' summary: z.string().default("Milestone integrated."),',
|
|
2227
|
+
" mergedBranches: z.array(z.string()).default([]),",
|
|
2228
|
+
" conflictedBranches: z.array(z.string()).default([]),",
|
|
2229
|
+
" filesChanged: z.array(z.string()).default([]),",
|
|
2230
|
+
"});",
|
|
2231
|
+
"",
|
|
2232
|
+
"const milestoneValidationSchema = z.looseObject({",
|
|
2233
|
+
' milestoneId: z.string().default("milestone"),',
|
|
2234
|
+
" passed: z.boolean().default(true),",
|
|
2235
|
+
' summary: z.string().default("Validation completed."),',
|
|
2236
|
+
" checks: z.array(z.object({",
|
|
2237
|
+
" name: z.string(),",
|
|
2238
|
+
' status: z.enum(["passed", "failed", "skipped"]),',
|
|
2239
|
+
" details: z.string().nullable().default(null),",
|
|
2240
|
+
" })).default([]),",
|
|
2241
|
+
" regressions: z.array(z.string()).default([]),",
|
|
2242
|
+
" followUps: z.array(z.string()).default([]),",
|
|
2243
|
+
"});",
|
|
2244
|
+
"",
|
|
2245
|
+
"const missionFinalSchema = z.looseObject({",
|
|
2246
|
+
' status: z.enum(["completed", "partial", "cancelled"]).default("completed"),',
|
|
2247
|
+
' summary: z.string().default("Mission complete."),',
|
|
2248
|
+
" completedMilestones: z.number().int().default(0),",
|
|
2249
|
+
" totalMilestones: z.number().int().default(0),",
|
|
2250
|
+
" validationPassed: z.boolean().default(true),",
|
|
2251
|
+
" remainingRisks: z.array(z.string()).default([]),",
|
|
2252
|
+
" nextActions: z.array(z.string()).default([]),",
|
|
2253
|
+
" markdownBody: z.string().default(\"\"),",
|
|
2254
|
+
"});",
|
|
2255
|
+
"",
|
|
2256
|
+
"const inputSchema = z.object({",
|
|
2257
|
+
' prompt: z.string().default("Describe the mission goal."),',
|
|
2258
|
+
" requirePlanApproval: z.boolean().default(true),",
|
|
2259
|
+
" maxMilestones: z.number().int().min(1).max(20).default(6),",
|
|
2260
|
+
" maxFeaturesPerMilestone: z.number().int().min(1).max(20).default(6),",
|
|
2261
|
+
" maxConcurrency: z.number().int().min(1).max(10).default(3),",
|
|
2262
|
+
" useWorktrees: z.boolean().default(false),",
|
|
2263
|
+
' baseBranch: z.string().default("main"),',
|
|
2264
|
+
"});",
|
|
2265
|
+
"",
|
|
2266
|
+
"const { Workflow, Task, Sequence, Parallel, Approval, Worktree, smithers, outputs } = createSmithers({",
|
|
2267
|
+
" input: inputSchema,",
|
|
2268
|
+
" missionPlan: missionPlanSchema,",
|
|
2269
|
+
" missionApproval: missionApprovalSchema,",
|
|
2270
|
+
" missionFeature: missionFeatureResultSchema,",
|
|
2271
|
+
" milestoneIntegration: milestoneIntegrationSchema,",
|
|
2272
|
+
" milestoneValidation: milestoneValidationSchema,",
|
|
2273
|
+
" missionFinal: missionFinalSchema,",
|
|
2274
|
+
"});",
|
|
2275
|
+
"",
|
|
2276
|
+
'const missionMemory = { kind: "workflow", id: "mission" } as const;',
|
|
2277
|
+
"",
|
|
2278
|
+
"function slugify(value: unknown, fallback: string): string {",
|
|
2279
|
+
' const normalized = String(value ?? "")',
|
|
2280
|
+
" .toLowerCase()",
|
|
2281
|
+
' .replace(/[^a-z0-9]+/g, "-")',
|
|
2282
|
+
' .replace(/^-+|-+$/g, "");',
|
|
2283
|
+
" return normalized.length > 0 ? normalized : fallback;",
|
|
2284
|
+
"}",
|
|
2285
|
+
"",
|
|
2286
|
+
"function asStringArray(value: unknown): string[] {",
|
|
2287
|
+
" return Array.isArray(value) ? value.map((entry) => String(entry)).filter(Boolean) : [];",
|
|
2288
|
+
"}",
|
|
2289
|
+
"",
|
|
2290
|
+
"function normalizeFeature(feature: any, index: number): any {",
|
|
2291
|
+
" const title = typeof feature?.title === \"string\" && feature.title.length > 0",
|
|
2292
|
+
" ? feature.title",
|
|
2293
|
+
" : `Feature ${index + 1}`;",
|
|
2294
|
+
" return {",
|
|
2295
|
+
" id: slugify(feature?.id ?? title, `feature-${index + 1}`),",
|
|
2296
|
+
" title,",
|
|
2297
|
+
" instructions: typeof feature?.instructions === \"string\" && feature.instructions.length > 0",
|
|
2298
|
+
" ? feature.instructions",
|
|
2299
|
+
" : `Complete ${title}.`,",
|
|
2300
|
+
" files: asStringArray(feature?.files),",
|
|
2301
|
+
" validation: asStringArray(feature?.validation),",
|
|
2302
|
+
" workerType: [\"implementation\", \"test\", \"docs\", \"research\"].includes(feature?.workerType)",
|
|
2303
|
+
" ? feature.workerType",
|
|
2304
|
+
' : "implementation",',
|
|
2305
|
+
" canRunInParallel: feature?.canRunInParallel !== false,",
|
|
2306
|
+
" };",
|
|
2307
|
+
"}",
|
|
2308
|
+
"",
|
|
2309
|
+
"function normalizeMilestones(plan: any, maxMilestones: number, maxFeaturesPerMilestone: number): any[] {",
|
|
2310
|
+
" return (Array.isArray(plan?.milestones) ? plan.milestones : [])",
|
|
2311
|
+
" .slice(0, maxMilestones)",
|
|
2312
|
+
" .map((milestone: any, index: number) => {",
|
|
2313
|
+
" const title = typeof milestone?.title === \"string\" && milestone.title.length > 0",
|
|
2314
|
+
" ? milestone.title",
|
|
2315
|
+
" : `Milestone ${index + 1}`;",
|
|
2316
|
+
" const features = (Array.isArray(milestone?.features) ? milestone.features : [])",
|
|
2317
|
+
" .slice(0, maxFeaturesPerMilestone)",
|
|
2318
|
+
" .map((feature: any, featureIndex: number) => normalizeFeature(feature, featureIndex));",
|
|
2319
|
+
" return {",
|
|
2320
|
+
" id: slugify(milestone?.id ?? title, `milestone-${index + 1}`),",
|
|
2321
|
+
" title,",
|
|
2322
|
+
" objective: typeof milestone?.objective === \"string\" && milestone.objective.length > 0",
|
|
2323
|
+
" ? milestone.objective",
|
|
2324
|
+
" : title,",
|
|
2325
|
+
" validationPlan: asStringArray(milestone?.validationPlan),",
|
|
2326
|
+
" features: features.length > 0",
|
|
2327
|
+
" ? features",
|
|
2328
|
+
" : [normalizeFeature({ title, instructions: milestone?.objective ?? title }, 0)],",
|
|
2329
|
+
" };",
|
|
2330
|
+
" });",
|
|
2331
|
+
"}",
|
|
2332
|
+
"",
|
|
2333
|
+
"function featureTaskId(milestoneIndex: number, feature: any): string {",
|
|
2334
|
+
" return `mission:milestone:${milestoneIndex + 1}:feature:${feature.id}`;",
|
|
2335
|
+
"}",
|
|
2336
|
+
"",
|
|
2337
|
+
"function milestoneIntegrateId(milestoneIndex: number): string {",
|
|
2338
|
+
" return `mission:milestone:${milestoneIndex + 1}:integrate`;",
|
|
2339
|
+
"}",
|
|
2340
|
+
"",
|
|
2341
|
+
"function milestoneValidationId(milestoneIndex: number): string {",
|
|
2342
|
+
" return `mission:milestone:${milestoneIndex + 1}:validate`;",
|
|
2343
|
+
"}",
|
|
2344
|
+
"",
|
|
2345
|
+
"function milestoneFollowUpId(milestoneIndex: number): string {",
|
|
2346
|
+
" return `mission:milestone:${milestoneIndex + 1}:follow-up`;",
|
|
2347
|
+
"}",
|
|
2348
|
+
"",
|
|
2349
|
+
"function milestoneRevalidationId(milestoneIndex: number): string {",
|
|
2350
|
+
" return `mission:milestone:${milestoneIndex + 1}:revalidate`;",
|
|
2351
|
+
"}",
|
|
2352
|
+
"",
|
|
2353
|
+
"function featureNeeds(milestoneIndex: number, features: any[]): Record<string, string> {",
|
|
2354
|
+
" return Object.fromEntries(features.map((feature, index) => [`feature${index}`, featureTaskId(milestoneIndex, feature)]));",
|
|
2355
|
+
"}",
|
|
2356
|
+
"",
|
|
2357
|
+
"function featureDeps(features: any[]): Record<string, typeof missionFeatureResultSchema> {",
|
|
2358
|
+
" return Object.fromEntries(features.map((_, index) => [`feature${index}`, outputs.missionFeature]));",
|
|
2359
|
+
"}",
|
|
2360
|
+
"",
|
|
2361
|
+
"function workerAgentsFor(feature: any): any {",
|
|
2362
|
+
" if (feature.workerType === \"research\") return agents.smartTool;",
|
|
2363
|
+
" if (feature.workerType === \"docs\") return agents.cheapFast;",
|
|
2364
|
+
" return agents.smart;",
|
|
2365
|
+
"}",
|
|
2366
|
+
"",
|
|
2367
|
+
"function previousMilestoneSummary(ctx: any): string {",
|
|
2368
|
+
" const integrations = ctx.outputs.milestoneIntegration ?? [];",
|
|
2369
|
+
" const validations = ctx.outputs.milestoneValidation ?? [];",
|
|
2370
|
+
" return [",
|
|
2371
|
+
" ...integrations.map((entry: any) => `Integration: ${entry.summary}`),",
|
|
2372
|
+
" ...validations.map((entry: any) => `Validation: ${entry.passed ? \"passed\" : \"failed\"} - ${entry.summary}`),",
|
|
2373
|
+
" ].slice(-8).join(\"\\n\");",
|
|
2374
|
+
"}",
|
|
2375
|
+
"",
|
|
2376
|
+
"function milestoneIsTerminal(ctx: any, milestoneIndex: number): boolean {",
|
|
2377
|
+
" const revalidation = ctx.outputMaybe(\"milestoneValidation\", { nodeId: milestoneRevalidationId(milestoneIndex) });",
|
|
2378
|
+
" if (revalidation) return true;",
|
|
2379
|
+
" const validation = ctx.outputMaybe(\"milestoneValidation\", { nodeId: milestoneValidationId(milestoneIndex) });",
|
|
2380
|
+
" return Boolean(validation && validation.passed !== false);",
|
|
2381
|
+
"}",
|
|
2382
|
+
"",
|
|
2383
|
+
"function activeMilestoneIndex(ctx: any, milestones: any[]): number {",
|
|
2384
|
+
" for (let index = 0; index < milestones.length; index += 1) {",
|
|
2385
|
+
" if (!milestoneIsTerminal(ctx, index)) return index;",
|
|
2386
|
+
" }",
|
|
2387
|
+
" return milestones.length;",
|
|
2388
|
+
"}",
|
|
2389
|
+
"",
|
|
2390
|
+
"function renderFeatureWorker(ctx: any, plan: any, milestone: any, milestoneIndex: number, feature: any) {",
|
|
2391
|
+
" const taskId = featureTaskId(milestoneIndex, feature);",
|
|
2392
|
+
" const workerTask = (",
|
|
2393
|
+
" <Task",
|
|
2394
|
+
" key={taskId}",
|
|
2395
|
+
" id={taskId}",
|
|
2396
|
+
" output={outputs.missionFeature}",
|
|
2397
|
+
" agent={workerAgentsFor(feature)}",
|
|
2398
|
+
" timeoutMs={3_600_000}",
|
|
2399
|
+
" heartbeatTimeoutMs={900_000}",
|
|
2400
|
+
" continueOnFail",
|
|
2401
|
+
" memory={{",
|
|
2402
|
+
" recall: { namespace: missionMemory, query: `${plan.goal} ${milestone.title} ${feature.title}`, topK: 5 },",
|
|
2403
|
+
" remember: { namespace: missionMemory, key: taskId },",
|
|
2404
|
+
" }}",
|
|
2405
|
+
" >",
|
|
2406
|
+
" <MissionWorkerPrompt",
|
|
2407
|
+
" missionGoal={plan.goal || ctx.input.prompt}",
|
|
2408
|
+
" milestone={milestone}",
|
|
2409
|
+
" feature={feature}",
|
|
2410
|
+
" previousSummary={previousMilestoneSummary(ctx)}",
|
|
2411
|
+
" />",
|
|
2412
|
+
" </Task>",
|
|
2413
|
+
" );",
|
|
2414
|
+
"",
|
|
2415
|
+
" if (!(ctx.input.useWorktrees ?? false)) return workerTask;",
|
|
2416
|
+
"",
|
|
2417
|
+
" return (",
|
|
2418
|
+
" <Worktree",
|
|
2419
|
+
" key={taskId}",
|
|
2420
|
+
" id={`mission-worktree-${milestoneIndex + 1}-${feature.id}`}",
|
|
2421
|
+
" path={`.worktrees/mission-${milestoneIndex + 1}-${feature.id}`}",
|
|
2422
|
+
" branch={`mission/${milestoneIndex + 1}/${feature.id}`}",
|
|
2423
|
+
" baseBranch={ctx.input.baseBranch ?? \"main\"}",
|
|
2424
|
+
" >",
|
|
2425
|
+
" {workerTask}",
|
|
2426
|
+
" </Worktree>",
|
|
2427
|
+
" );",
|
|
2428
|
+
"}",
|
|
2429
|
+
"",
|
|
2430
|
+
"function renderMilestone(ctx: any, plan: any, milestone: any, milestoneIndex: number) {",
|
|
2431
|
+
" const features = milestone.features;",
|
|
2432
|
+
" const integrationId = milestoneIntegrateId(milestoneIndex);",
|
|
2433
|
+
" const validationId = milestoneValidationId(milestoneIndex);",
|
|
2434
|
+
" const integration = ctx.outputMaybe(\"milestoneIntegration\", { nodeId: integrationId });",
|
|
2435
|
+
" const validation = ctx.outputMaybe(\"milestoneValidation\", { nodeId: validationId });",
|
|
2436
|
+
" const needsFollowUp = Boolean(validation && validation.passed === false);",
|
|
2437
|
+
"",
|
|
2438
|
+
" return (",
|
|
2439
|
+
" <Sequence>",
|
|
2440
|
+
" <Parallel maxConcurrency={Math.min(ctx.input.maxConcurrency ?? 3, features.length)}>",
|
|
2441
|
+
" {features.map((feature: any) => renderFeatureWorker(ctx, plan, milestone, milestoneIndex, feature))}",
|
|
2442
|
+
" </Parallel>",
|
|
2443
|
+
" <Task",
|
|
2444
|
+
" id={integrationId}",
|
|
2445
|
+
" output={outputs.milestoneIntegration}",
|
|
2446
|
+
" agent={agents.smartTool}",
|
|
2447
|
+
" needs={featureNeeds(milestoneIndex, features)}",
|
|
2448
|
+
" deps={featureDeps(features)}",
|
|
2449
|
+
" timeoutMs={1_800_000}",
|
|
2450
|
+
" memory={{ remember: { namespace: missionMemory, key: integrationId } }}",
|
|
2451
|
+
" >",
|
|
2452
|
+
" {(deps: any) => {",
|
|
2453
|
+
" const results = features.map((_: any, index: number) => deps[`feature${index}`]);",
|
|
2454
|
+
" return (",
|
|
2455
|
+
" <MissionIntegratePrompt",
|
|
2456
|
+
" missionGoal={plan.goal || ctx.input.prompt}",
|
|
2457
|
+
" milestone={milestone}",
|
|
2458
|
+
" results={results}",
|
|
2459
|
+
" useWorktrees={ctx.input.useWorktrees ?? false}",
|
|
2460
|
+
" />",
|
|
2461
|
+
" );",
|
|
2462
|
+
" }}",
|
|
2463
|
+
" </Task>",
|
|
2464
|
+
" <Task",
|
|
2465
|
+
" id={validationId}",
|
|
2466
|
+
" output={outputs.milestoneValidation}",
|
|
2467
|
+
" agent={agents.smart}",
|
|
2468
|
+
" needs={{ integration: integrationId }}",
|
|
2469
|
+
" deps={{ integration: outputs.milestoneIntegration }}",
|
|
2470
|
+
" timeoutMs={1_800_000}",
|
|
2471
|
+
" heartbeatTimeoutMs={900_000}",
|
|
2472
|
+
" memory={{ remember: { namespace: missionMemory, key: validationId } }}",
|
|
2473
|
+
" >",
|
|
2474
|
+
" {(deps: any) => (",
|
|
2475
|
+
" <MissionValidatePrompt",
|
|
2476
|
+
" missionGoal={plan.goal || ctx.input.prompt}",
|
|
2477
|
+
" milestone={milestone}",
|
|
2478
|
+
" integration={deps.integration}",
|
|
2479
|
+
" />",
|
|
2480
|
+
" )}",
|
|
2481
|
+
" </Task>",
|
|
2482
|
+
" {needsFollowUp && (",
|
|
2483
|
+
" <Sequence>",
|
|
2484
|
+
" <Task",
|
|
2485
|
+
" id={milestoneFollowUpId(milestoneIndex)}",
|
|
2486
|
+
" output={outputs.missionFeature}",
|
|
2487
|
+
" agent={agents.smart}",
|
|
2488
|
+
" needs={{ validation: validationId }}",
|
|
2489
|
+
" deps={{ validation: outputs.milestoneValidation }}",
|
|
2490
|
+
" timeoutMs={1_800_000}",
|
|
2491
|
+
" memory={{ remember: { namespace: missionMemory, key: milestoneFollowUpId(milestoneIndex) } }}",
|
|
2492
|
+
" >",
|
|
2493
|
+
" {(deps: any) => (",
|
|
2494
|
+
" <MissionFollowUpPrompt",
|
|
2495
|
+
" missionGoal={plan.goal || ctx.input.prompt}",
|
|
2496
|
+
" milestone={milestone}",
|
|
2497
|
+
" validation={deps.validation}",
|
|
2498
|
+
" />",
|
|
2499
|
+
" )}",
|
|
2500
|
+
" </Task>",
|
|
2501
|
+
" <Task",
|
|
2502
|
+
" id={milestoneRevalidationId(milestoneIndex)}",
|
|
2503
|
+
" output={outputs.milestoneValidation}",
|
|
2504
|
+
" agent={agents.smart}",
|
|
2505
|
+
" needs={{ followUp: milestoneFollowUpId(milestoneIndex) }}",
|
|
2506
|
+
" deps={{ followUp: outputs.missionFeature }}",
|
|
2507
|
+
" timeoutMs={1_800_000}",
|
|
2508
|
+
" heartbeatTimeoutMs={900_000}",
|
|
2509
|
+
" memory={{ remember: { namespace: missionMemory, key: milestoneRevalidationId(milestoneIndex) } }}",
|
|
2510
|
+
" >",
|
|
2511
|
+
" {(deps: any) => (",
|
|
2512
|
+
" <MissionValidatePrompt",
|
|
2513
|
+
" missionGoal={plan.goal || ctx.input.prompt}",
|
|
2514
|
+
" milestone={milestone}",
|
|
2515
|
+
" integration={integration}",
|
|
2516
|
+
" followUp={deps.followUp}",
|
|
2517
|
+
" />",
|
|
2518
|
+
" )}",
|
|
2519
|
+
" </Task>",
|
|
2520
|
+
" </Sequence>",
|
|
2521
|
+
" )}",
|
|
2522
|
+
" </Sequence>",
|
|
2523
|
+
" );",
|
|
2524
|
+
"}",
|
|
2525
|
+
"",
|
|
2526
|
+
"function renderFinal(ctx: any, plan: any, milestones: any[]) {",
|
|
2527
|
+
" return (",
|
|
2528
|
+
" <Task id=\"mission:final\" output={outputs.missionFinal} agent={agents.smartTool}>",
|
|
2529
|
+
" <MissionFinalPrompt",
|
|
2530
|
+
" plan={{ ...plan, milestones }}",
|
|
2531
|
+
" featureResults={ctx.outputs.missionFeature ?? []}",
|
|
2532
|
+
" integrationResults={ctx.outputs.milestoneIntegration ?? []}",
|
|
2533
|
+
" validationResults={ctx.outputs.milestoneValidation ?? []}",
|
|
2534
|
+
" />",
|
|
2535
|
+
" </Task>",
|
|
2536
|
+
" );",
|
|
2537
|
+
"}",
|
|
2538
|
+
"",
|
|
2539
|
+
"export default smithers((ctx) => {",
|
|
2540
|
+
" const plan = ctx.outputMaybe(\"missionPlan\", { nodeId: \"mission:plan\" });",
|
|
2541
|
+
" const approval = ctx.outputMaybe(\"missionApproval\", { nodeId: \"mission:approve-plan\" });",
|
|
2542
|
+
" const approvalRequired = ctx.input.requirePlanApproval;",
|
|
2543
|
+
" const approvalDenied = approvalRequired && approval && approval.approved === false;",
|
|
2544
|
+
" const approved = !approvalRequired || approval?.approved === true;",
|
|
2545
|
+
" const milestones = normalizeMilestones(plan, ctx.input.maxMilestones ?? 6, ctx.input.maxFeaturesPerMilestone ?? 6);",
|
|
2546
|
+
" const activeIndex = approved ? activeMilestoneIndex(ctx, milestones) : 0;",
|
|
2547
|
+
"",
|
|
2548
|
+
" return (",
|
|
2549
|
+
" <Workflow name=\"mission\">",
|
|
2550
|
+
" <Sequence>",
|
|
2551
|
+
" <Task",
|
|
2552
|
+
" id=\"mission:plan\"",
|
|
2553
|
+
" output={outputs.missionPlan}",
|
|
2554
|
+
" agent={agents.smartTool}",
|
|
2555
|
+
" timeoutMs={1_800_000}",
|
|
2556
|
+
" heartbeatTimeoutMs={900_000}",
|
|
2557
|
+
" memory={{ remember: { namespace: missionMemory, key: \"mission:plan\" } }}",
|
|
2558
|
+
" >",
|
|
2559
|
+
" <AskUserInstructions />",
|
|
2560
|
+
" <MissionPlanPrompt",
|
|
2561
|
+
" prompt={ctx.input.prompt}",
|
|
2562
|
+
" maxMilestones={ctx.input.maxMilestones ?? 6}",
|
|
2563
|
+
" maxFeaturesPerMilestone={ctx.input.maxFeaturesPerMilestone ?? 6}",
|
|
2564
|
+
" />",
|
|
2565
|
+
" </Task>",
|
|
2566
|
+
"",
|
|
2567
|
+
" {plan && approvalRequired && !approval && (",
|
|
2568
|
+
" <Approval",
|
|
2569
|
+
" id=\"mission:approve-plan\"",
|
|
2570
|
+
" output={outputs.missionApproval}",
|
|
2571
|
+
" request={{",
|
|
2572
|
+
" title: \"Approve mission plan?\",",
|
|
2573
|
+
" summary: plan.summary || \"Review the scoped mission plan before workers begin.\",",
|
|
2574
|
+
" metadata: { milestones: milestones.length, risks: plan.risks ?? [] },",
|
|
2575
|
+
" }}",
|
|
2576
|
+
" onDeny=\"continue\"",
|
|
2577
|
+
" />",
|
|
2578
|
+
" )}",
|
|
2579
|
+
"",
|
|
2580
|
+
" {approvalDenied && (",
|
|
2581
|
+
" <Task id=\"mission:cancelled\" output={outputs.missionFinal}>",
|
|
2582
|
+
" {{",
|
|
2583
|
+
" status: \"cancelled\",",
|
|
2584
|
+
" summary: `Mission plan was not approved. ${approval?.note ?? \"\"}`.trim(),",
|
|
2585
|
+
" completedMilestones: 0,",
|
|
2586
|
+
" totalMilestones: milestones.length,",
|
|
2587
|
+
" validationPassed: false,",
|
|
2588
|
+
" remainingRisks: plan?.risks ?? [],",
|
|
2589
|
+
" nextActions: [\"Revise the mission scope and rerun the workflow.\"],",
|
|
2590
|
+
" markdownBody: \"# Mission Cancelled\\n\\nThe plan was not approved.\",",
|
|
2591
|
+
" }}",
|
|
2592
|
+
" </Task>",
|
|
2593
|
+
" )}",
|
|
2594
|
+
"",
|
|
2595
|
+
" {plan && approved && activeIndex < milestones.length && renderMilestone(ctx, plan, milestones[activeIndex], activeIndex)}",
|
|
2596
|
+
" {plan && approved && activeIndex >= milestones.length && renderFinal(ctx, plan, milestones)}",
|
|
2597
|
+
" </Sequence>",
|
|
2598
|
+
" </Workflow>",
|
|
2599
|
+
" );",
|
|
2600
|
+
"});",
|
|
2601
|
+
]),
|
|
1977
2602
|
{
|
|
1978
2603
|
path: ".smithers/workflows/kanban.tsx",
|
|
1979
2604
|
contents: [
|
|
@@ -2291,8 +2916,10 @@ const WORKFLOW_FOLLOW_UPS = {
|
|
|
2291
2916
|
"research": [
|
|
2292
2917
|
{ command: "workflow run write-a-prd", description: "Formalize findings into a PRD" },
|
|
2293
2918
|
{ command: "workflow run plan", description: "Turn research into an implementation plan" },
|
|
2919
|
+
{ command: "workflow run mission", description: "Run a scoped long-horizon mission" },
|
|
2294
2920
|
],
|
|
2295
2921
|
"plan": [
|
|
2922
|
+
{ command: "workflow run mission", description: "Execute as a milestone-gated mission" },
|
|
2296
2923
|
{ command: "workflow run research-plan-implement", description: "Research, plan, and execute" },
|
|
2297
2924
|
{ command: "workflow run implement", description: "Execute the plan" },
|
|
2298
2925
|
{ command: "workflow run tickets-create", description: "Break plan into tickets" },
|
|
@@ -2315,6 +2942,7 @@ const WORKFLOW_FOLLOW_UPS = {
|
|
|
2315
2942
|
{ command: "workflow run tickets-create", description: "Break directly into tickets" },
|
|
2316
2943
|
],
|
|
2317
2944
|
"write-a-prd": [
|
|
2945
|
+
{ command: "workflow run mission", description: "Execute the PRD as a mission" },
|
|
2318
2946
|
{ command: "workflow run tickets-create", description: "Break PRD into implementable tickets" },
|
|
2319
2947
|
{ command: "workflow run plan", description: "Turn PRD into a phased plan" },
|
|
2320
2948
|
{ command: "workflow run implement", description: "Start building from the PRD" },
|
|
@@ -2331,6 +2959,11 @@ const WORKFLOW_FOLLOW_UPS = {
|
|
|
2331
2959
|
{ command: "workflow run review", description: "Review the changes" },
|
|
2332
2960
|
{ command: "workflow run improve-test-coverage", description: "Improve test coverage" },
|
|
2333
2961
|
],
|
|
2962
|
+
"mission": [
|
|
2963
|
+
{ command: "workflow run review", description: "Review mission changes" },
|
|
2964
|
+
{ command: "workflow run improve-test-coverage", description: "Fill validation gaps" },
|
|
2965
|
+
{ command: "workflow run audit", description: "Audit completed feature areas" },
|
|
2966
|
+
],
|
|
2334
2967
|
"review": [
|
|
2335
2968
|
{ command: "workflow run implement", description: "Address review feedback" },
|
|
2336
2969
|
],
|