bitfab-cli 0.2.474 → 0.2.475

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +1365 -953
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -31890,7 +31890,7 @@ async function runUpdate(currentVersion, platform2, mode = "all") {
31890
31890
  }
31891
31891
  }
31892
31892
 
31893
- // ../bitfab-flow/dist/commands.js
31893
+ // ../node_modules/.pnpm/@agent-flows+core@0.1.1_zod@4.6.7/node_modules/@agent-flows/core/dist/commands.js
31894
31894
  function defineCommandCatalog(catalog) {
31895
31895
  return {
31896
31896
  defineCommands(defs) {
@@ -31912,239 +31912,12 @@ function defineCommandCatalog(catalog) {
31912
31912
  };
31913
31913
  }
31914
31914
 
31915
- // ../bitfab-flow/dist/shared.js
31916
- var CODEX_RESOLVE_PLUGIN_DIR_BASH = `\`\`\`bash
31917
- if [ -z "$BITFAB_PLUGIN_DIR" ]; then
31918
- BITFAB_PLUGIN_DIR=$(
31919
- hit=$(find "\${CODEX_HOME:-$HOME/.codex}/plugins/cache" -maxdepth 6 -type f -name status.js \\
31920
- \\( -path '*/bitfab-internal/bitfab/local/dist/commands/*' \\
31921
- -o -path '*/bitfab/bitfab/*/dist/commands/*' \\) 2>/dev/null | head -1)
31922
- echo "\${hit%/dist/commands/status.js}"
31923
- )
31924
- export BITFAB_PLUGIN_DIR
31925
- fi
31926
- test -n "$BITFAB_PLUGIN_DIR" || { echo "ERROR: Bitfab plugin not installed"; exit 1; }
31927
- \`\`\``;
31928
- var AMP_RESOLVE_PLUGIN_DIR_BASH = `\`\`\`bash
31929
- if [ -z "$BITFAB_PLUGIN_DIR" ]; then
31930
- project_root=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
31931
- for candidate in "$project_root/.amp/plugins/bitfab" "\${XDG_CONFIG_HOME:-$HOME/.config}/amp/plugins/bitfab"; do
31932
- if [ -f "$candidate/dist/commands/status.js" ]; then
31933
- BITFAB_PLUGIN_DIR="$candidate"
31934
- break
31935
- fi
31936
- done
31937
- export BITFAB_PLUGIN_DIR
31938
- fi
31939
- test -n "$BITFAB_PLUGIN_DIR" || { echo "ERROR: Bitfab plugin not installed"; exit 1; }
31940
- \`\`\``;
31941
-
31942
- // ../bitfab-flow/dist/targets.js
31943
- var TARGET_NAMES = ["claude", "cursor", "codex", "amp"];
31944
- var SECTION_TARGETS = {
31945
- claude: ["claude"],
31946
- cursor: ["cursor"],
31947
- codex: ["codex"],
31948
- amp: ["amp"],
31949
- "ask-user-question": ["claude", "cursor"],
31950
- "plugin-dir-lookup": ["codex", "amp"],
31951
- "exec-polling": ["codex", "amp"],
31952
- "no-startup-banner": ["codex", "amp"],
31953
- "web-fetch-tool": ["claude", "cursor"]
31954
- };
31955
- function formatAllowedTools(allowedTools) {
31956
- return `[${allowedTools.map((t) => JSON.stringify(t)).join(", ")}]`;
31957
- }
31958
- var renderClaudeFrontmatter = ({ description, argumentHint, model, allowedTools }) => {
31959
- const lines = ["---", `description: ${description}`];
31960
- if (argumentHint !== void 0) {
31961
- lines.push(`argument-hint: ${JSON.stringify(argumentHint)}`);
31962
- }
31963
- if (model !== void 0) {
31964
- lines.push(`model: ${model}`);
31965
- }
31966
- if (allowedTools !== void 0) {
31967
- lines.push(`allowed-tools: ${formatAllowedTools(allowedTools)}`);
31968
- }
31969
- lines.push("---");
31970
- return lines.join("\n");
31971
- };
31972
- var renderClaudeSkillFrontmatter = ({ flowId, description, model, allowedTools }) => {
31973
- const lines = [
31974
- "---",
31975
- `name: ${flowId}`,
31976
- `description: ${description}`,
31977
- "user-invocable: false"
31978
- ];
31979
- if (model !== void 0) {
31980
- lines.push(`model: ${model}`);
31981
- }
31982
- if (allowedTools !== void 0) {
31983
- lines.push(`allowed-tools: ${formatAllowedTools(allowedTools)}`);
31984
- }
31985
- lines.push("---");
31986
- return lines.join("\n");
31987
- };
31988
- function renderNamedFrontmatter(name, description, usage, usageInBody = false) {
31989
- const frontmatter = [
31990
- "---",
31991
- `name: ${name}`,
31992
- `description: "${description}${usageInBody ? "" : usage}"`,
31993
- "---"
31994
- ].join("\n");
31995
- return usageInBody && usage !== "" ? `${frontmatter}
31996
-
31997
- ${usage.slice(2)}` : frontmatter;
31998
- }
31999
- var renderCursorFrontmatter = ({ flowId, description, argumentHint }) => {
32000
- const usage = argumentHint !== void 0 ? `. Usage: /bitfab-${flowId} ${argumentHint}` : "";
32001
- return renderNamedFrontmatter(`bitfab-${flowId}`, description, usage);
32002
- };
32003
- var renderCodexFrontmatter = ({ flowId, description, argumentHint }) => {
32004
- const usage = argumentHint !== void 0 ? `. Invoke with $bitfab:${flowId} ${argumentHint}.` : "";
32005
- return renderNamedFrontmatter(flowId, description, usage);
32006
- };
32007
- var renderAmpFrontmatter = ({ flowId, description, argumentHint }) => {
32008
- const usage = argumentHint !== void 0 ? `. Invoke as bitfab:${flowId} ${argumentHint}.` : "";
32009
- return renderNamedFrontmatter(flowId, description, usage);
32010
- };
32011
- var renderCursorDevFrontmatter = ({ flowId, description, argumentHint }) => {
32012
- const usage = argumentHint !== void 0 ? `. Usage: /bitfab-dev-${flowId} ${argumentHint}` : "";
32013
- return renderNamedFrontmatter(`bitfab-dev-${flowId}`, description, usage, true);
32014
- };
32015
- var renderCodexDevFrontmatter = ({ flowId, description, argumentHint }) => {
32016
- const usage = argumentHint !== void 0 ? `. Invoke with $bitfab-dev:${flowId} ${argumentHint}.` : "";
32017
- return renderNamedFrontmatter(flowId, description, usage, true);
32018
- };
32019
- var renderAmpDevFrontmatter = ({ flowId, description, argumentHint }) => {
32020
- const usage = argumentHint !== void 0 ? `. Invoke as bitfab-dev:${flowId} ${argumentHint}.` : "";
32021
- return renderNamedFrontmatter(flowId, description, usage, true);
32022
- };
32023
- var ASK_USER_QUESTION_TOKENS = {
32024
- askUser: "with `AskUserQuestion` ",
32025
- askVerb: "use `AskUserQuestion`",
32026
- askVerbCap: "Use `AskUserQuestion`",
32027
- askNoun: "AskUserQuestion"
32028
- };
32029
- var PLAIN_PROMPT_TOKENS = {
32030
- askUser: "",
32031
- askVerb: "ask the user",
32032
- askVerbCap: "Ask the user",
32033
- askNoun: "choice prompt"
32034
- };
32035
- var TARGETS = {
32036
- claude: {
32037
- name: "claude",
32038
- tokens: {
32039
- cmd: "/bitfab:",
32040
- devCmd: "/bitfab-dev:",
32041
- editor: "Claude Code",
32042
- // biome-ignore lint/suspicious/noTemplateCurlyInString: shell variable reference rendered into skill markdown, not a JS template
32043
- pluginRoot: "${CLAUDE_PLUGIN_ROOT}",
32044
- pluginDirLookup: "",
32045
- ...ASK_USER_QUESTION_TOKENS
32046
- },
32047
- mcpPrefix: "mcp__plugin_bitfab_Bitfab__",
32048
- argsToken: "$ARGUMENTS",
32049
- frontmatter: renderClaudeFrontmatter,
32050
- subSkillFrontmatter: renderClaudeSkillFrontmatter,
32051
- subSkillTool: "Skill"
32052
- },
32053
- cursor: {
32054
- name: "cursor",
32055
- tokens: {
32056
- cmd: "/bitfab-",
32057
- devCmd: "/bitfab-dev-",
32058
- editor: "Cursor",
32059
- // biome-ignore lint/suspicious/noTemplateCurlyInString: shell variable reference rendered into skill markdown, not a JS template
32060
- pluginRoot: "${CURSOR_PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT}}",
32061
- pluginDirLookup: "",
32062
- ...ASK_USER_QUESTION_TOKENS
32063
- },
32064
- mcpPrefix: "mcp__Bitfab__",
32065
- argsToken: "$ARGUMENTS",
32066
- frontmatter: renderCursorFrontmatter,
32067
- subSkillFrontmatter: renderCursorFrontmatter
32068
- },
32069
- codex: {
32070
- name: "codex",
32071
- tokens: {
32072
- cmd: "$bitfab:",
32073
- devCmd: "$bitfab-dev:",
32074
- editor: "Codex",
32075
- // biome-ignore lint/suspicious/noTemplateCurlyInString: shell variable reference rendered into skill markdown, not a JS template
32076
- pluginRoot: "${BITFAB_PLUGIN_DIR}",
32077
- pluginDirLookup: CODEX_RESOLVE_PLUGIN_DIR_BASH,
32078
- ...PLAIN_PROMPT_TOKENS
32079
- },
32080
- mcpPrefix: "mcp__Bitfab__",
32081
- argsToken: "$ARGUMENTS",
32082
- frontmatter: renderCodexFrontmatter,
32083
- subSkillFrontmatter: renderCodexFrontmatter,
32084
- dispatchRef: (skillName) => `\`$bitfab:${skillName}\``
32085
- },
32086
- amp: {
32087
- name: "amp",
32088
- tokens: {
32089
- cmd: "bitfab:",
32090
- devCmd: "bitfab-dev:",
32091
- editor: "Amp",
32092
- // biome-ignore lint/suspicious/noTemplateCurlyInString: shell variable reference rendered into skill markdown, not a JS template
32093
- pluginRoot: "${BITFAB_PLUGIN_DIR}",
32094
- pluginDirLookup: AMP_RESOLVE_PLUGIN_DIR_BASH,
32095
- ...PLAIN_PROMPT_TOKENS
32096
- },
32097
- mcpPrefix: "",
32098
- argsToken: "the user's request",
32099
- frontmatter: renderAmpFrontmatter,
32100
- subSkillFrontmatter: renderAmpFrontmatter,
32101
- subSkillTool: "skill",
32102
- dispatchRef: (skillName) => `\`bitfab:${skillName}\``
32103
- }
32104
- };
32105
- var DEV_TARGETS = {
32106
- claude: {
32107
- ...TARGETS.claude,
32108
- frontmatter: renderClaudeFrontmatter,
32109
- subSkillFrontmatter: renderClaudeSkillFrontmatter
32110
- },
32111
- cursor: {
32112
- ...TARGETS.cursor,
32113
- frontmatter: renderCursorDevFrontmatter,
32114
- subSkillFrontmatter: renderCursorDevFrontmatter
32115
- },
32116
- codex: {
32117
- ...TARGETS.codex,
32118
- frontmatter: renderCodexDevFrontmatter,
32119
- subSkillFrontmatter: renderCodexDevFrontmatter,
32120
- dispatchRef: (skillName) => `\`$bitfab-dev:${skillName}\``
32121
- },
32122
- amp: {
32123
- ...TARGETS.amp,
32124
- frontmatter: renderAmpDevFrontmatter,
32125
- subSkillFrontmatter: renderAmpDevFrontmatter,
32126
- dispatchRef: (skillName) => `\`bitfab-dev:${skillName}\``
32127
- }
32128
- };
32129
-
32130
- // ../bitfab-flow/dist/schema.js
31915
+ // ../node_modules/.pnpm/@agent-flows+core@0.1.1_zod@4.6.7/node_modules/@agent-flows/core/dist/schema.js
32131
31916
  var StepIdRef = external_exports.string().regex(/^[a-z0-9-]+\/[a-z0-9-]+$/, {
32132
31917
  message: "Step references must use the form 'phase-id/step-id'"
32133
31918
  });
32134
31919
  var StepLocalId = external_exports.string().regex(/^[a-z0-9-]+$/);
32135
31920
  var PhaseId = external_exports.string().regex(/^[a-z0-9-]+$/);
32136
- function PerTarget(inner) {
32137
- const objectForm = external_exports.object({
32138
- default: inner.optional(),
32139
- claude: inner.optional(),
32140
- cursor: inner.optional(),
32141
- codex: inner.optional(),
32142
- amp: inner.optional()
32143
- }).refine((v) => v.default !== void 0 || TARGET_NAMES.every((target) => v[target] !== void 0), {
32144
- message: `Per-target object must have \`default\` or define all of ${TARGET_NAMES.join("/")}.`
32145
- });
32146
- return external_exports.union([inner, objectForm]);
32147
- }
32148
31921
  function resolvePerTarget(value, target) {
32149
31922
  if (typeof value !== "object" || value === null) {
32150
31923
  return value;
@@ -32152,23 +31925,6 @@ function resolvePerTarget(value, target) {
32152
31925
  const map2 = value;
32153
31926
  return map2[target] ?? map2.default;
32154
31927
  }
32155
- var TargetableString = PerTarget(external_exports.string());
32156
- var TargetableNonEmptyString = PerTarget(external_exports.string().min(1));
32157
- var RESERVED_TOKEN_NAMES = [
32158
- "cmd",
32159
- "devCmd",
32160
- "editor",
32161
- "pluginRoot",
32162
- "pluginDirLookup",
32163
- "askUser",
32164
- "askVerb",
32165
- "askVerbCap",
32166
- "askNoun",
32167
- "argsToken"
32168
- ];
32169
- var MUSTACHE_SECTION_NAMES = Object.keys(SECTION_TARGETS);
32170
- var MODE_SECTION_RE = /\{\{([#^])mode:([a-z0-9-]+)\}\}/g;
32171
- var MODE_SECTION_CLOSE_RE = /\{\{\/mode:([a-z0-9-]+)\}\}/g;
32172
31928
  function resolveTargetableString(value, target, label) {
32173
31929
  const resolved = resolvePerTarget(value, target);
32174
31930
  if (resolved === void 0) {
@@ -32176,6 +31932,11 @@ function resolveTargetableString(value, target, label) {
32176
31932
  }
32177
31933
  return resolved;
32178
31934
  }
31935
+ var MODE_SECTION_RE = /\{\{([#^])mode:([a-z0-9-]+)\}\}/g;
31936
+ var MODE_SECTION_CLOSE_RE = /\{\{\/mode:([a-z0-9-]+)\}\}/g;
31937
+ var TOOL_PLACEHOLDER_RE = /\{\{tool:([a-zA-Z][a-zA-Z0-9_-]*)\}\}/g;
31938
+ var COMMAND_PLACEHOLDER_RE = /\{\{command:([a-zA-Z][a-zA-Z0-9_-]*)\}\}/g;
31939
+ var TABLE_PLACEHOLDER_RE = /\{\{(table|list):([a-zA-Z][a-zA-Z0-9_-]*):([a-zA-Z0-9_,-]+)\}\}/g;
32179
31940
  var NextRef = StepIdRef.nullable();
32180
31941
  var ByModeNext = external_exports.object({
32181
31942
  byMode: external_exports.record(external_exports.string(), NextRef)
@@ -32188,56 +31949,50 @@ var EmitLabel = external_exports.union([
32188
31949
  action: external_exports.enum(["started", "completed"])
32189
31950
  })
32190
31951
  ]);
31952
+ var BranchOption = external_exports.object({
31953
+ /** Letter shown in the choice prompt, e.g. "A", "B", "C". */
31954
+ letter: external_exports.string().min(1),
31955
+ /** Bolded option name, e.g. "Update all N outdated workspaces". */
31956
+ label: external_exports.string().min(1),
31957
+ /** Optional explanation that follows the label. */
31958
+ description: external_exports.string().optional()
31959
+ });
31960
+ var CompileMode = external_exports.enum(["monolith", "split", "split-chain"]);
31961
+ function PerTarget(inner) {
31962
+ return external_exports.union([inner, external_exports.record(external_exports.string(), inner)]);
31963
+ }
31964
+ var TargetableString = PerTarget(external_exports.string());
31965
+ var TargetableNonEmptyString = PerTarget(external_exports.string().min(1));
32191
31966
  var Base = external_exports.object({
32192
31967
  id: StepLocalId,
32193
31968
  title: TargetableNonEmptyString,
32194
31969
  /**
32195
31970
  * Concise inline name for cross-phase prose references via
32196
- * `{{step-ref:phase/id}}`. Falls back to `title` when omitted. Set it when
32197
- * the header `title` reads clumsily mid-sentence (e.g. title "Mark ready,
32198
- * then merge" -> refName "merge", so a ref renders "the merge step"). Unlike
31971
+ * `{{step-ref:phase/id}}`. Falls back to `title` when omitted. Unlike
32199
31972
  * `{{step:...}}` (a file-local number), `{{step-ref:...}}` renders a stable
32200
31973
  * name, so it stays meaningful across phases and across split-unit files.
32201
31974
  */
32202
31975
  refName: TargetableNonEmptyString.optional(),
32203
31976
  body: TargetableString,
32204
31977
  /**
32205
- * Value emitted through the flow-level `emitTemplate` when this step
32206
- * is reached.
32207
- *
32208
- * - String shorthand: display name, action defaults to "started".
32209
- * - Object form: explicit `displayName` + `action`.
32210
- *
32211
- * How the value is rendered is determined by `flow.emitTemplate`.
31978
+ * Value emitted through the flow-level `emitTemplate` when this step is
31979
+ * reached. String shorthand = display name with action "started".
32212
31980
  * Steps with `emit` but no flow-level template are silently ignored.
32213
31981
  */
32214
31982
  emit: EmitLabel.optional(),
32215
31983
  /**
32216
31984
  * Logical ids of tools this step calls (must exist in `flow.tools`). Used
32217
- * to auto-derive `frontmatter.allowedTools` and to render `{{tool:id}}`
32218
- * placeholders in the body.
31985
+ * to auto-derive `frontmatter.allowedTools`.
32219
31986
  */
32220
31987
  toolCalls: external_exports.array(external_exports.string()).optional(),
32221
- /**
32222
- * Logical ids of commands this step invokes (must exist in `flow.commands`).
32223
- * Mirrors `toolCalls` for the command registry so consumers don't need to
32224
- * regex-scan the body for `{{command:id}}` placeholders.
32225
- */
31988
+ /** Logical ids of commands this step invokes (must exist in `flow.commands`). */
32226
31989
  commandCalls: external_exports.array(external_exports.string()).optional(),
32227
31990
  /**
32228
- * If true (in a "headers" phase), the step is numbered as "0" instead of
32229
- * 1-indexed among non-preamble visible steps. Used for setup-style preamble
32230
- * sections like Codex's "Resolve BITFAB_PLUGIN_DIR" that conceptually sit
32231
- * before step 1 even though they execute first.
31991
+ * In a "headers" phase, number the step "0" instead of joining the
31992
+ * 1-indexed sequence. For setup-style preambles that sit before step 1.
32232
31993
  */
32233
31994
  preamble: external_exports.boolean().optional(),
32234
- /**
32235
- * Optional list of appendix ids this step consults. Available on every step
32236
- * kind so that an action or branch step can document its references to
32237
- * appendices (validated against `flow.appendices` at parse time). The
32238
- * `kind: "reference"` discriminant carries a stricter `min(1)` requirement
32239
- * since consulting an appendix is its primary purpose.
32240
- */
31995
+ /** Appendix ids this step consults (validated against `flow.appendices`). */
32241
31996
  refs: external_exports.array(external_exports.string().min(1)).optional(),
32242
31997
  meta: external_exports.record(external_exports.string(), external_exports.unknown()).optional()
32243
31998
  });
@@ -32245,54 +32000,28 @@ var Action = Base.extend({
32245
32000
  kind: external_exports.literal("action"),
32246
32001
  next: Next
32247
32002
  });
32248
- var BranchOption = external_exports.object({
32249
- /** Letter shown in the AskUserQuestion prompt, e.g. "A", "B", "C". */
32250
- letter: external_exports.string().min(1),
32251
- /** Bolded option name, e.g. "Update all N outdated workspaces". */
32252
- label: external_exports.string().min(1),
32253
- /** Optional explanation that follows the label after an em dash. */
32254
- description: external_exports.string().optional()
32255
- });
32256
32003
  var Branch = Base.extend({
32257
32004
  kind: external_exports.literal("branch"),
32258
32005
  branches: external_exports.array(external_exports.object({
32259
32006
  /**
32260
- * Edge label in the schema diagram. Required for runtime branches
32261
- * (exit conditions, not user choices). Optional for user-choice
32262
- * branches - when omitted, the diagram label defaults to
32263
- * `${option.letter} - ${option.label}`.
32007
+ * Runtime condition (agent decides). Required unless the branch
32008
+ * is a user choice (`option`); also the diagram edge label.
32264
32009
  */
32265
32010
  when: external_exports.string().optional(),
32266
- /**
32267
- * Where this branch goes after the user picks it (or after the
32268
- * runtime condition resolves). Linear `NextRef` form for the common
32269
- * case where every mode goes to the same place; `byMode` dispatch
32270
- * for branches that need per-mode targets - e.g. an "exit" option
32271
- * that hands off to the next phase in `all` mode but terminates in
32272
- * sub-modes.
32273
- */
32011
+ /** Where this branch goes; linear or `byMode`. */
32274
32012
  next: Next,
32275
32013
  /** Marks the option the agent should default to. */
32276
32014
  recommended: external_exports.boolean().optional(),
32277
32015
  /**
32278
- * Tags the prompt this option belongs to when a single step exposes
32279
- * multiple AskUserQuestion forks. Lets the renderer pick a subset
32280
- * with `{{branches:prompt-name}}`.
32016
+ * Tags the prompt this option belongs to when one step exposes
32017
+ * several user prompts; render a subset with `{{branches:name}}`.
32281
32018
  */
32282
32019
  prompt: external_exports.string().optional(),
32283
- /**
32284
- * Present on user-choice branches - drives the rendered prompt
32285
- * block via `{{branches}}` and supersedes `when` as the source of
32286
- * truth for option text. Absent on runtime branches.
32287
- */
32020
+ /** User-choice option rendered by `{{branches}}`. */
32288
32021
  option: BranchOption.optional(),
32289
32022
  /**
32290
- * Optional action description for runtime (`when`) branches - the
32291
- * "what to do" text that appears after the em-dash in the
32292
- * `{{whens}}` rendering. When omitted, falls back to "stop the
32293
- * flow" (for `next: null`) or "continue" (for any step ref). Has
32294
- * no effect on user-choice (`option`) branches; those use
32295
- * `option.description`.
32023
+ * Action text for runtime (`when`) branches in `{{whens}}`. Falls
32024
+ * back to "stop the flow" (`next: null`) or "continue".
32296
32025
  */
32297
32026
  description: external_exports.string().optional()
32298
32027
  }).strict().refine((b) => b.when !== void 0 || b.option !== void 0, {
@@ -32332,11 +32061,8 @@ var Phase = external_exports.object({
32332
32061
  steps: external_exports.array(Step).min(1),
32333
32062
  outro: TargetableString.optional(),
32334
32063
  /**
32335
- * How steps inside this phase are rendered.
32336
- * - "list": phase renders as `## {title}`, intro paragraph, then steps as a `1. ... 2. ...` numbered markdown list.
32337
- * - "headers": phase title is hidden; each step renders as its own `## {N}. {title}` H2 section with body below.
32338
- *
32339
- * In "headers" mode, steps marked `preamble: true` are numbered "0" instead of joining the 1-indexed sequence.
32064
+ * - "list": `## {title}`, intro, then steps as a numbered markdown list.
32065
+ * - "headers": title hidden; each step is its own `## {N}. {title}` section.
32340
32066
  */
32341
32067
  stepStyle: external_exports.enum(["list", "headers"]).default("list")
32342
32068
  });
@@ -32360,143 +32086,83 @@ var Frontmatter = external_exports.object({
32360
32086
  ]).optional(),
32361
32087
  model: external_exports.string().optional(),
32362
32088
  /**
32363
- * Optional manual override. When omitted and `flow.tools` is non-empty,
32364
- * the renderer auto-derives the list from the union of step `toolCalls`.
32089
+ * Manual override. When omitted and `flow.tools` is non-empty, the
32090
+ * renderer derives the list from the tools the flow actually calls.
32365
32091
  */
32366
32092
  allowedTools: external_exports.array(external_exports.string()).optional()
32367
32093
  });
32368
32094
  var ToolDef = external_exports.object({
32369
32095
  name: PerTarget(external_exports.string()),
32370
32096
  kind: external_exports.enum(["builtin", "mcp"]),
32371
- targets: external_exports.array(external_exports.enum(TARGET_NAMES)).nonempty().optional()
32097
+ targets: external_exports.array(external_exports.string()).nonempty().optional()
32372
32098
  });
32373
32099
  var CommandDef = external_exports.object({
32374
32100
  file: external_exports.string().min(1),
32375
32101
  description: external_exports.string().min(1),
32376
32102
  args: external_exports.string().optional()
32377
32103
  });
32378
- var Language = external_exports.object({
32379
- /** Lowercase id used in tables (typescript, python, ruby, go). */
32380
- name: external_exports.string().min(1),
32381
- /** Capitalized name used in bullet lists (TypeScript, Python, Ruby, Go). */
32382
- displayName: external_exports.string().min(1),
32383
- /** Markdown snippet used by `{{languages:imports}}`. */
32384
- imports: external_exports.string().optional(),
32385
- /** Markdown snippet used by `{{languages:detection}}`. */
32386
- detection: external_exports.string().optional(),
32387
- /** Markdown snippet used by `{{languages:outdated}}`. */
32388
- outdated: external_exports.string().optional(),
32389
- /** Markdown snippet used by `{{languages:update}}`. */
32390
- update: external_exports.string().optional()
32391
- });
32392
- var Flow = external_exports.object({
32104
+ var Table = external_exports.object({
32105
+ /** Header of the leading key column. */
32106
+ keyHeader: external_exports.string().min(1).default("Name"),
32107
+ /** Column header per field; unset fields fall back to the title-cased field name. */
32108
+ columns: external_exports.record(external_exports.string(), external_exports.string()).default({}),
32109
+ rows: external_exports.array(external_exports.object({
32110
+ key: external_exports.string().min(1),
32111
+ /** Display name for `{{list:...}}`; falls back to `key`. */
32112
+ label: external_exports.string().optional(),
32113
+ cells: external_exports.record(external_exports.string(), external_exports.string())
32114
+ })).min(1)
32115
+ });
32116
+ var FlowBase = external_exports.object({
32393
32117
  schemaVersion: external_exports.literal(1),
32394
- id: external_exports.string().min(1),
32118
+ id: external_exports.string().regex(/^[a-z0-9-]+$/),
32395
32119
  title: TargetableNonEmptyString,
32396
32120
  frontmatter: Frontmatter,
32397
32121
  intro: TargetableString.optional(),
32398
32122
  /**
32399
- * Entry step per invocation mode. Each entry is either a bare step id
32400
- * (every target enters at the same step) or a per-target object so a
32401
- * target can start at a different step than the others - for example,
32402
- * Codex enters at the `resolve-plugin-dir` preamble while Claude and
32403
- * Cursor enter directly at `run-update-script`.
32123
+ * Entry step per invocation mode: a bare step id, or a per-target map so a
32124
+ * target can start elsewhere (e.g. at a host-specific preamble).
32404
32125
  */
32405
32126
  entries: external_exports.record(external_exports.string(), PerTarget(StepIdRef)),
32406
- /** Which mode is invoked when the user passes no argument. Must be a key in `entries`. */
32127
+ /** Mode invoked when the user passes no argument. Must be a key in `entries`. */
32407
32128
  defaultMode: external_exports.string().optional(),
32408
32129
  /**
32409
- * Optional one-line description per mode, keyed by mode name (a subset of
32410
- * `entries` keys). When a monolith flow has more than one mode, the renderer
32411
- * emits an auto-generated "Modes" dispatch table at the top of the file so
32412
- * the agent can map `$ARGUMENTS` to the right mode without hand-authored
32413
- * routing prose. A mode without a hint falls back to its entry phase's
32414
- * title. Values are `TargetableString`, so a hint can differ per target
32415
- * (e.g. editor-specific wording) and standard placeholders resolve normally.
32130
+ * One-line description per mode. Declaring any opts a multi-mode flow
32131
+ * into an auto-generated "Modes" routing table.
32416
32132
  */
32417
32133
  modeHints: external_exports.record(external_exports.string(), TargetableString).default({}),
32418
32134
  /**
32419
- * Template for rendering step `emit` values into the markdown.
32420
- * The renderer substitutes `{action}` and `{displayName}` from the
32421
- * step's `emit` field. All other placeholders (`{{pluginRoot}}`,
32422
- * Mustache sections, etc.) are resolved by the normal pipeline.
32423
- *
32424
- * If absent, steps with `emit` are silently ignored (no output
32425
- * rendered). This keeps flows that don't need emission from having
32426
- * to declare a no-op template.
32135
+ * Template rendered for each step `emit`. `{action}` and `{displayName}`
32136
+ * are substituted; every other placeholder resolves normally.
32427
32137
  */
32428
32138
  emitTemplate: TargetableString.optional(),
32429
32139
  phases: external_exports.array(Phase).min(1),
32430
32140
  appendices: external_exports.array(Appendix).default([]),
32431
32141
  invariants: external_exports.array(external_exports.string()).default([]),
32432
- languages: external_exports.array(Language).default([]),
32433
- /**
32434
- * Headers for the columns rendered by `{{languages:FIELD}}` placeholders.
32435
- * Keyed by Language field name (`imports`, `detection`, `outdated`,
32436
- * `update`). When unset for a column, the renderer falls back to the
32437
- * field's title-cased name.
32438
- */
32439
- languageColumnHeaders: external_exports.record(external_exports.string(), external_exports.string()).default({}),
32440
- /**
32441
- * Tool registry keyed by logical id. `step.toolCalls` references entries
32442
- * here; `{{tool:id}}` placeholders render the per-target name.
32443
- */
32142
+ tables: external_exports.record(external_exports.string(), Table).default({}),
32444
32143
  tools: external_exports.record(external_exports.string(), ToolDef).default({}),
32445
- /**
32446
- * CLI command registry keyed by logical id. `{{command:id}}` placeholders
32447
- * in step/intro/appendix text render as the full invocation path. When
32448
- * non-empty, the renderer emits a reference table after the flow intro.
32449
- */
32450
32144
  commands: external_exports.record(external_exports.string(), CommandDef).default({}),
32451
32145
  /**
32452
- * User-defined variables. Each value is either a bare string (applies to
32453
- * all targets) or a per-target map. Referenced via `{{name}}` placeholders
32454
- * in any string field. Must not collide with target-level tokens (cmd,
32455
- * editor, pluginRoot, askUser).
32146
+ * User-defined `{{name}}` variables (bare or per-target). Must not collide
32147
+ * with target token names.
32456
32148
  */
32457
32149
  variables: external_exports.record(external_exports.string(), TargetableString).default({}),
32458
32150
  /**
32459
- * How this flow compiles to skill files.
32460
- * - `monolith` (default): one skill file per (flow, target) - today's
32461
- * behavior, rendered by `renderMarkdown`.
32462
- * - `split`: an orchestrator skill plus one menu-hidden, model-invocable
32463
- * sub-skill per phase. The orchestrator dispatches call-and-return:
32464
- * one section per sub-phase, "invoke X, then return here".
32465
- * `inlinePhases` lists phases kept inside the orchestrator (infra
32466
- * phases like preamble/cleanup) rather than emitted as their own
32467
- * sub-skills.
32468
- * - `split-chain`: same file layout as `split`, but routing compiles to
32469
- * tail-call dispatch. The orchestrator never says "return here";
32470
- * instead every step whose outgoing edge crosses a unit boundary
32471
- * (orchestrator-with-inline-phases, or a sub-skill) gets a generated
32472
- * "Next:" annotation with one line per (target phase, mode set) group,
32473
- * mode literals baked in. Cross-phase loops are legal under
32474
- * `split-chain` (a dispatch edge back to an earlier sub-skill renders
32475
- * like any other), which the sequential `split` orchestrator cannot
32476
- * express.
32477
- * Codex writes non-inline phases to ordinary `references/<phase>.md`
32478
- * files and routes by reading them, keeping phase names out of skill
32479
- * discovery. Other targets emit phase sub-skills.
32151
+ * How the flow compiles to files.
32152
+ * - `monolith`: one skill file per target.
32153
+ * - `split`: an orchestrator plus one sub-skill per non-inline phase,
32154
+ * dispatched call-and-return ("invoke X, then return here").
32155
+ * - `split-chain`: same layout, tail-call routing. Every step whose edge
32156
+ * crosses a file boundary gets a generated "**Next:**" block with mode
32157
+ * literals baked in. Targets with `phaseReferences` emit phases as
32158
+ * reference files instead of discoverable sub-skills.
32480
32159
  *
32481
- * `mode` is per-target (the standard default-plus-override form), so split
32482
- * can roll out one target at a time: `{ default: "monolith", claude:
32483
- * "split" }` splits Claude and leaves Cursor/Codex monolith. A bare
32484
- * `"split"` / `"monolith"` applies to every target.
32485
- *
32486
- * `continuousStepNumbers` (monolith only) numbers step headers 1…N
32487
- * continuously across phases instead of restarting at 1 per phase. Set it
32488
- * when the phases run **sequentially** in one file (e.g. preflight then a
32489
- * run phase): restarting would emit duplicate `## 1.` headers with nothing
32490
- * to disambiguate them. Leave it off (the default) when phases are
32491
- * **mutually exclusive** alternatives each gated by "Run only when mode is
32492
- * X" (e.g. subcommands): there the per-phase restart is correct, since only
32493
- * one phase is ever followed and its own steps read naturally from 1, and
32494
- * the mode gate, not the number, is what disambiguates. Split modes ignore
32495
- * this flag entirely: each phase compiles to its own file and always
32496
- * restarts at 1.
32160
+ * `mode` is per-target, so split can roll out one host at a time.
32161
+ * `continuousStepNumbers` (monolith only) numbers headers 1…N across
32162
+ * sequential phases instead of restarting per phase.
32497
32163
  */
32498
32164
  compile: external_exports.object({
32499
- mode: PerTarget(external_exports.enum(["monolith", "split", "split-chain"])).default("monolith"),
32165
+ mode: PerTarget(CompileMode).default("monolith"),
32500
32166
  inlinePhases: external_exports.array(external_exports.string()).default([]),
32501
32167
  continuousStepNumbers: external_exports.boolean().default(false)
32502
32168
  }).default({
@@ -32504,465 +32170,320 @@ var Flow = external_exports.object({
32504
32170
  inlinePhases: [],
32505
32171
  continuousStepNumbers: false
32506
32172
  })
32507
- }).superRefine((flow, ctx) => {
32508
- const allStepIds = /* @__PURE__ */ new Set();
32509
- const phaseIds = /* @__PURE__ */ new Set();
32510
- for (const phase of flow.phases) {
32511
- if (phaseIds.has(phase.id)) {
32512
- ctx.addIssue({
32513
- code: "custom",
32514
- path: ["phases", phase.id],
32515
- message: `duplicate phase id "${phase.id}"`
32516
- });
32517
- }
32518
- phaseIds.add(phase.id);
32519
- const localIds = /* @__PURE__ */ new Set();
32520
- for (const step of phase.steps) {
32521
- if (localIds.has(step.id)) {
32522
- ctx.addIssue({
32523
- code: "custom",
32524
- path: ["phases", phase.id, "steps"],
32525
- message: `duplicate step id "${step.id}" in phase "${phase.id}"`
32526
- });
32173
+ });
32174
+ function createFlowSchema(options) {
32175
+ const targetNames = [...options.targetNames];
32176
+ const reservedTokenNames = /* @__PURE__ */ new Set([
32177
+ ...options.reservedTokenNames ?? [],
32178
+ "argsToken"
32179
+ ]);
32180
+ const allowedKeys = /* @__PURE__ */ new Set(["default", ...targetNames]);
32181
+ return FlowBase.superRefine((flow, ctx) => {
32182
+ const issue2 = (path15, message) => ctx.addIssue({ code: "custom", path: path15, message });
32183
+ for (const { path: path15, value } of targetableFields(flow)) {
32184
+ if (typeof value !== "object" || value === null) {
32185
+ continue;
32186
+ }
32187
+ const map2 = value;
32188
+ for (const key of Object.keys(map2)) {
32189
+ if (!allowedKeys.has(key)) {
32190
+ issue2(path15, `Unknown target "${key}" in per-target object. Known targets: ${targetNames.join(", ")}.`);
32191
+ }
32192
+ }
32193
+ if (map2.default === void 0 && !targetNames.every((target) => map2[target] !== void 0)) {
32194
+ issue2(path15, `Per-target object must have \`default\` or define all of ${targetNames.join("/")}.`);
32527
32195
  }
32528
- localIds.add(step.id);
32529
- allStepIds.add(`${phase.id}/${step.id}`);
32530
- }
32531
- }
32532
- for (const phaseId of flow.compile.inlinePhases) {
32533
- if (!phaseIds.has(phaseId)) {
32534
- ctx.addIssue({
32535
- code: "custom",
32536
- path: ["compile", "inlinePhases"],
32537
- message: `inlinePhases lists unknown phase "${phaseId}"`
32538
- });
32539
32196
  }
32540
- }
32541
- const declaredModes = Object.keys(flow.entries);
32542
- const declaredModeSet = new Set(declaredModes);
32543
- const argumentHint = flow.frontmatter.argumentHint;
32544
- const argumentHintModes = declaredModes.filter((mode) => mode !== "default" || flow.defaultMode !== "default");
32545
- if (typeof argumentHint === "object" && "deriveFromModes" in argumentHint && argumentHintModes.length === 0) {
32546
- ctx.addIssue({
32547
- code: "custom",
32548
- path: ["frontmatter", "argumentHint"],
32549
- message: "deriveFromModes requires at least one non-default mode in entries"
32550
- });
32551
- }
32552
- if (flow.defaultMode !== void 0 && !declaredModeSet.has(flow.defaultMode)) {
32553
- ctx.addIssue({
32554
- code: "custom",
32555
- path: ["defaultMode"],
32556
- message: `defaultMode "${flow.defaultMode}" not declared in entries`
32557
- });
32558
- }
32559
- for (const mode of Object.keys(flow.modeHints)) {
32560
- if (!declaredModeSet.has(mode)) {
32561
- ctx.addIssue({
32562
- code: "custom",
32563
- path: ["modeHints", mode],
32564
- message: `modeHints key "${mode}" not declared in entries`
32565
- });
32197
+ const allStepIds = /* @__PURE__ */ new Set();
32198
+ const phaseIds = /* @__PURE__ */ new Set();
32199
+ for (const phase of flow.phases) {
32200
+ if (phaseIds.has(phase.id)) {
32201
+ issue2(["phases", phase.id], `duplicate phase id "${phase.id}"`);
32202
+ }
32203
+ phaseIds.add(phase.id);
32204
+ const localIds = /* @__PURE__ */ new Set();
32205
+ for (const step of phase.steps) {
32206
+ if (localIds.has(step.id)) {
32207
+ issue2(["phases", phase.id, "steps"], `duplicate step id "${step.id}" in phase "${phase.id}"`);
32208
+ }
32209
+ localIds.add(step.id);
32210
+ allStepIds.add(`${phase.id}/${step.id}`);
32211
+ }
32566
32212
  }
32567
- }
32568
- const refsFromNext = (next) => {
32569
- if (next === null) {
32570
- return [];
32213
+ for (const phaseId of flow.compile.inlinePhases) {
32214
+ if (!phaseIds.has(phaseId)) {
32215
+ issue2(["compile", "inlinePhases"], `inlinePhases lists unknown phase "${phaseId}"`);
32216
+ }
32571
32217
  }
32572
- if (typeof next === "string") {
32573
- return [next];
32218
+ const declaredModes = Object.keys(flow.entries);
32219
+ const declaredModeSet = new Set(declaredModes);
32220
+ const argumentHint = flow.frontmatter.argumentHint;
32221
+ const argumentHintModes = declaredModes.filter((mode) => mode !== "default" || flow.defaultMode !== "default");
32222
+ if (typeof argumentHint === "object" && "deriveFromModes" in argumentHint && argumentHintModes.length === 0) {
32223
+ issue2(["frontmatter", "argumentHint"], "deriveFromModes requires at least one non-default mode in entries");
32574
32224
  }
32575
- return Object.values(next.byMode).filter((v) => typeof v === "string");
32576
- };
32577
- const refsFromStep = (s2) => {
32578
- switch (s2.kind) {
32579
- case "action":
32580
- case "reference":
32581
- case "parallel":
32582
- return refsFromNext(s2.next);
32583
- case "branch":
32584
- return s2.branches.flatMap((b) => refsFromNext(b.next));
32585
- case "loop":
32586
- return [s2.backTo, s2.onExit];
32225
+ if (flow.defaultMode !== void 0 && !declaredModeSet.has(flow.defaultMode)) {
32226
+ issue2(["defaultMode"], `defaultMode "${flow.defaultMode}" not declared in entries`);
32587
32227
  }
32588
- };
32589
- for (const phase of flow.phases) {
32590
- for (const step of phase.steps) {
32591
- for (const ref of refsFromStep(step)) {
32592
- if (!allStepIds.has(ref)) {
32593
- ctx.addIssue({
32594
- code: "custom",
32595
- path: ["phases", phase.id, "steps", step.id],
32596
- message: `edge \u2192 unknown step "${ref}"`
32597
- });
32598
- }
32228
+ for (const mode of Object.keys(flow.modeHints)) {
32229
+ if (!declaredModeSet.has(mode)) {
32230
+ issue2(["modeHints", mode], `modeHints key "${mode}" not declared in entries`);
32599
32231
  }
32600
- const validateByMode = (byMode, path15, label) => {
32601
- for (const mode of Object.keys(byMode)) {
32602
- if (!declaredModeSet.has(mode)) {
32603
- ctx.addIssue({
32604
- code: "custom",
32605
- path: path15,
32606
- message: `${label} lists mode "${mode}" not declared in flow.entries`
32607
- });
32232
+ }
32233
+ for (const phase of flow.phases) {
32234
+ for (const step of phase.steps) {
32235
+ for (const ref of refsFromStep(step)) {
32236
+ if (!allStepIds.has(ref)) {
32237
+ issue2(["phases", phase.id, "steps", step.id], `edge \u2192 unknown step "${ref}"`);
32608
32238
  }
32609
32239
  }
32610
- const missingModes = declaredModes.filter((m) => !(m in byMode));
32611
- if (missingModes.length > 0) {
32612
- ctx.addIssue({
32613
- code: "custom",
32614
- path: path15,
32615
- message: `${label} byMode is missing entries for mode(s): ${missingModes.join(", ")}`
32616
- });
32240
+ const validateByMode = (byMode, path15, label) => {
32241
+ for (const mode of Object.keys(byMode)) {
32242
+ if (!declaredModeSet.has(mode)) {
32243
+ issue2(path15, `${label} lists mode "${mode}" not declared in flow.entries`);
32244
+ }
32245
+ }
32246
+ const missingModes = declaredModes.filter((m) => !(m in byMode));
32247
+ if (missingModes.length > 0) {
32248
+ issue2(path15, `${label} byMode is missing entries for mode(s): ${missingModes.join(", ")}`);
32249
+ }
32250
+ };
32251
+ if ((step.kind === "action" || step.kind === "reference" || step.kind === "parallel") && typeof step.next === "object" && step.next !== null) {
32252
+ validateByMode(step.next.byMode, ["phases", phase.id, "steps", step.id, "next", "byMode"], `step "${step.id}" next`);
32253
+ }
32254
+ if (step.kind === "branch") {
32255
+ for (const [i, branch] of step.branches.entries()) {
32256
+ if (typeof branch.next === "object" && branch.next !== null) {
32257
+ const branchLabelText = branch.option !== void 0 ? `option "${branch.option.letter}"` : branch.when ?? `branch[${i}]`;
32258
+ validateByMode(branch.next.byMode, [
32259
+ "phases",
32260
+ phase.id,
32261
+ "steps",
32262
+ step.id,
32263
+ "branches",
32264
+ i,
32265
+ "next",
32266
+ "byMode"
32267
+ ], `step "${step.id}" branch ${branchLabelText}`);
32268
+ }
32269
+ }
32617
32270
  }
32618
- };
32619
- if ((step.kind === "action" || step.kind === "reference" || step.kind === "parallel") && typeof step.next === "object" && step.next !== null) {
32620
- validateByMode(step.next.byMode, ["phases", phase.id, "steps", step.id, "next", "byMode"], `step "${step.id}" next`);
32621
32271
  }
32622
- if (step.kind === "branch") {
32623
- for (const [i, branch] of step.branches.entries()) {
32624
- if (typeof branch.next === "object" && branch.next !== null) {
32625
- const branchLabelText = branch.option !== void 0 ? `option "${branch.option.letter}"` : branch.when ?? `branch[${i}]`;
32626
- validateByMode(branch.next.byMode, [
32627
- "phases",
32628
- phase.id,
32629
- "steps",
32630
- step.id,
32631
- "branches",
32632
- i,
32633
- "next",
32634
- "byMode"
32635
- ], `step "${step.id}" branch ${branchLabelText}`);
32272
+ }
32273
+ for (const phase of flow.phases) {
32274
+ const preambleCount = phase.steps.filter((s2) => s2.preamble === true).length;
32275
+ if (preambleCount > 1) {
32276
+ issue2(["phases", phase.id, "steps"], `phase "${phase.id}" has ${preambleCount} preamble steps; only one is allowed per phase`);
32277
+ }
32278
+ }
32279
+ const appendixIds = new Set(flow.appendices.map((a) => a.id));
32280
+ for (const phase of flow.phases) {
32281
+ for (const step of phase.steps) {
32282
+ for (const r of step.refs ?? []) {
32283
+ if (!appendixIds.has(r)) {
32284
+ issue2(["phases", phase.id, "steps", step.id, "refs"], `unknown appendix "${r}"`);
32636
32285
  }
32637
32286
  }
32638
32287
  }
32639
32288
  }
32640
- }
32641
- for (const phase of flow.phases) {
32642
- const preambleCount = phase.steps.filter((s2) => s2.preamble === true).length;
32643
- if (preambleCount > 1) {
32644
- ctx.addIssue({
32645
- code: "custom",
32646
- path: ["phases", phase.id, "steps"],
32647
- message: `phase "${phase.id}" has ${preambleCount} preamble steps; only one is allowed per phase`
32648
- });
32649
- }
32650
- }
32651
- const appendixIds = new Set(flow.appendices.map((a) => a.id));
32652
- for (const phase of flow.phases) {
32653
- for (const step of phase.steps) {
32654
- const refs = step.refs ?? [];
32655
- for (const r of refs) {
32656
- if (!appendixIds.has(r)) {
32657
- ctx.addIssue({
32658
- code: "custom",
32659
- path: ["phases", phase.id, "steps", step.id, "refs"],
32660
- message: `unknown appendix "${r}"`
32661
- });
32289
+ for (const [mode, entry] of Object.entries(flow.entries)) {
32290
+ for (const target of targetNames) {
32291
+ const resolved = resolvePerTarget(entry, target);
32292
+ if (resolved === void 0) {
32293
+ issue2(["entries", mode], `entry for mode "${mode}" has no value for target "${target}" (and no default)`);
32294
+ continue;
32295
+ }
32296
+ if (!allStepIds.has(resolved)) {
32297
+ issue2(["entries", mode], `entry "${mode}" \u2192 "${target}" \u2192 unknown step "${resolved}"`);
32662
32298
  }
32663
32299
  }
32664
32300
  }
32665
- }
32666
- const targetNames = ["claude", "cursor", "codex"];
32667
- for (const [mode, entry] of Object.entries(flow.entries)) {
32301
+ const reachableUnion = /* @__PURE__ */ new Set();
32668
32302
  for (const target of targetNames) {
32669
- const resolved = resolvePerTarget(entry, target);
32670
- if (resolved === void 0) {
32671
- ctx.addIssue({
32672
- code: "custom",
32673
- path: ["entries", mode],
32674
- message: `entry for mode "${mode}" has no value for target "${target}" (and no default)`
32675
- });
32676
- continue;
32303
+ for (const id of computeReachableSteps(flow, target)) {
32304
+ reachableUnion.add(id);
32677
32305
  }
32678
- if (!allStepIds.has(resolved)) {
32679
- ctx.addIssue({
32680
- code: "custom",
32681
- path: ["entries", mode],
32682
- message: `entry "${mode}" \u2192 "${target}" \u2192 unknown step "${resolved}"`
32683
- });
32306
+ }
32307
+ for (const id of allStepIds) {
32308
+ if (!reachableUnion.has(id)) {
32309
+ issue2(["phases"], `unreachable step "${id}" in any (mode, target) combination`);
32684
32310
  }
32685
32311
  }
32686
- }
32687
- const reachableUnion = /* @__PURE__ */ new Set();
32688
- for (const [mode, entry] of Object.entries(flow.entries)) {
32312
+ const inlinePhaseSet = new Set(flow.compile.inlinePhases);
32313
+ const phaseOf = (ref) => ref.split("/")[0];
32689
32314
  for (const target of targetNames) {
32690
- const start = resolvePerTarget(entry, target);
32691
- if (start === void 0) {
32315
+ if (resolvePerTarget(flow.compile.mode, target) !== "split-chain") {
32692
32316
  continue;
32693
32317
  }
32694
- const queue = [start];
32695
- const seen = /* @__PURE__ */ new Set();
32696
- while (queue.length > 0) {
32697
- const id = queue.shift();
32698
- if (id === void 0 || seen.has(id)) {
32318
+ for (const [mode, entry] of Object.entries(flow.entries)) {
32319
+ const resolved = resolvePerTarget(entry, target);
32320
+ if (resolved === void 0 || !allStepIds.has(resolved)) {
32699
32321
  continue;
32700
32322
  }
32701
- seen.add(id);
32702
- reachableUnion.add(id);
32703
- const [phaseId, stepId] = id.split("/");
32704
- const step = flow.phases.find((p9) => p9.id === phaseId)?.steps.find((s2) => s2.id === stepId);
32705
- if (step === void 0) {
32323
+ const entryPhase = phaseOf(resolved);
32324
+ if (inlinePhaseSet.has(entryPhase)) {
32706
32325
  continue;
32707
32326
  }
32708
- for (const n of nextRefsForMode(step, mode)) {
32709
- if (n !== null) {
32710
- queue.push(n);
32711
- }
32327
+ const firstStep = flow.phases.find((p9) => p9.id === entryPhase)?.steps[0];
32328
+ if (firstStep !== void 0 && resolved !== `${entryPhase}/${firstStep.id}`) {
32329
+ issue2(["entries", mode], `split-chain: entry "${mode}" \u2192 "${target}" points mid-phase at "${resolved}"; a sub-skill starts at its first step ("${entryPhase}/${firstStep.id}"). Reorder the phase or inline it.`);
32712
32330
  }
32713
32331
  }
32714
- }
32715
- }
32716
- for (const id of allStepIds) {
32717
- if (reachableUnion.has(id)) {
32718
- continue;
32719
- }
32720
- ctx.addIssue({
32721
- code: "custom",
32722
- path: ["phases"],
32723
- message: `unreachable step "${id}" in any (mode, target) combination`
32724
- });
32725
- }
32726
- const inlinePhaseSet = new Set(flow.compile.inlinePhases);
32727
- const phaseOf = (ref) => ref.split("/")[0];
32728
- for (const target of targetNames) {
32729
- if (resolvePerTarget(flow.compile.mode, target) !== "split-chain") {
32730
- continue;
32731
- }
32732
- for (const [mode, entry] of Object.entries(flow.entries)) {
32733
- const resolved = resolvePerTarget(entry, target);
32734
- if (resolved === void 0 || !allStepIds.has(resolved)) {
32735
- continue;
32736
- }
32737
- const entryPhase = phaseOf(resolved);
32738
- if (inlinePhaseSet.has(entryPhase)) {
32739
- continue;
32740
- }
32741
- const phase = flow.phases.find((p9) => p9.id === entryPhase);
32742
- const firstStep = phase?.steps[0];
32743
- if (firstStep !== void 0 && resolved !== `${entryPhase}/${firstStep.id}`) {
32744
- ctx.addIssue({
32745
- code: "custom",
32746
- path: ["entries", mode],
32747
- message: `split-chain: entry "${mode}" \u2192 "${target}" points mid-phase at "${resolved}"; a sub-skill starts at its first step ("${entryPhase}/${firstStep.id}"). Reorder the phase or inline it.`
32748
- });
32749
- }
32750
- }
32751
- const reachable = computeReachableSteps(flow, target);
32752
- for (const phase of flow.phases) {
32753
- if (inlinePhaseSet.has(phase.id)) {
32754
- continue;
32755
- }
32756
- for (const step of phase.steps) {
32757
- if (!reachable.has(`${phase.id}/${step.id}`)) {
32332
+ const reachable = computeReachableSteps(flow, target);
32333
+ for (const phase of flow.phases) {
32334
+ if (inlinePhaseSet.has(phase.id)) {
32758
32335
  continue;
32759
32336
  }
32760
- for (const ref of refsFromStep(step)) {
32761
- if (inlinePhaseSet.has(phaseOf(ref))) {
32762
- ctx.addIssue({
32763
- code: "custom",
32764
- path: ["phases", phase.id, "steps", step.id],
32765
- message: `split-chain: step "${phase.id}/${step.id}" routes to "${ref}" in inline phase "${phaseOf(ref)}" (target "${target}"). Sub-skills may not re-enter the orchestrator; make the shared work its own phase.`
32766
- });
32337
+ for (const step of phase.steps) {
32338
+ if (!reachable.has(`${phase.id}/${step.id}`)) {
32339
+ continue;
32340
+ }
32341
+ for (const ref of refsFromStep(step)) {
32342
+ if (inlinePhaseSet.has(phaseOf(ref))) {
32343
+ issue2(["phases", phase.id, "steps", step.id], `split-chain: step "${phase.id}/${step.id}" routes to "${ref}" in inline phase "${phaseOf(ref)}" (target "${target}"). Sub-skills may not re-enter the orchestrator; make the shared work its own phase.`);
32344
+ }
32767
32345
  }
32768
32346
  }
32769
32347
  }
32770
32348
  }
32771
- }
32772
- const toolIds = new Set(Object.keys(flow.tools));
32773
- for (const phase of flow.phases) {
32774
- for (const step of phase.steps) {
32775
- if (step.toolCalls === void 0) {
32776
- continue;
32777
- }
32778
- for (const toolId of step.toolCalls) {
32779
- if (!toolIds.has(toolId)) {
32780
- ctx.addIssue({
32781
- code: "custom",
32782
- path: ["phases", phase.id, "steps", step.id, "toolCalls"],
32783
- message: `step "${step.id}" calls tool "${toolId}" not declared in flow.tools`
32784
- });
32785
- }
32786
- }
32787
- }
32788
- }
32789
- const commandIds = new Set(Object.keys(flow.commands));
32790
- for (const phase of flow.phases) {
32791
- for (const step of phase.steps) {
32792
- if (step.commandCalls === void 0) {
32793
- continue;
32794
- }
32795
- for (const cmdId of step.commandCalls) {
32796
- if (!commandIds.has(cmdId)) {
32797
- ctx.addIssue({
32798
- code: "custom",
32799
- path: ["phases", phase.id, "steps", step.id, "commandCalls"],
32800
- message: `step "${step.id}" calls command "${cmdId}" not declared in flow.commands`
32801
- });
32349
+ const toolIds = new Set(Object.keys(flow.tools));
32350
+ const commandIds = new Set(Object.keys(flow.commands));
32351
+ const knownTargets = new Set(targetNames);
32352
+ for (const [toolId, tool] of Object.entries(flow.tools)) {
32353
+ for (const t of tool.targets ?? []) {
32354
+ if (!knownTargets.has(t)) {
32355
+ issue2(["tools", toolId, "targets"], `tool "${toolId}" lists unknown target "${t}"`);
32802
32356
  }
32803
32357
  }
32804
32358
  }
32805
- }
32806
- const COMMAND_PLACEHOLDER_RE = /\{\{command:([a-zA-Z][a-zA-Z0-9_-]*)\}\}/g;
32807
- const scanForCommandRefs = (value) => {
32808
- const refs = [];
32809
- const scan = (text2) => {
32810
- if (!text2) {
32811
- return;
32812
- }
32813
- for (const match of text2.matchAll(COMMAND_PLACEHOLDER_RE)) {
32814
- refs.push(match[1]);
32815
- }
32816
- };
32817
- if (value === void 0) {
32818
- return refs;
32819
- }
32820
- if (typeof value === "string") {
32821
- scan(value);
32822
- return refs;
32823
- }
32824
- scan(value.default);
32825
- scan(value.claude);
32826
- scan(value.cursor);
32827
- scan(value.codex);
32828
- return refs;
32829
- };
32830
- if (commandIds.size > 0) {
32831
- const allCommandRefs = [];
32832
- for (const ref of scanForCommandRefs(flow.intro)) {
32833
- allCommandRefs.push({ ref, location: "flow.intro" });
32834
- }
32835
- for (const ref of scanForCommandRefs(flow.emitTemplate)) {
32836
- allCommandRefs.push({ ref, location: "flow.emitTemplate" });
32837
- }
32838
32359
  for (const phase of flow.phases) {
32839
- for (const ref of scanForCommandRefs(phase.intro)) {
32840
- allCommandRefs.push({ ref, location: `phase "${phase.id}" intro` });
32841
- }
32842
32360
  for (const step of phase.steps) {
32843
- for (const ref of scanForCommandRefs(step.body)) {
32844
- allCommandRefs.push({
32845
- ref,
32846
- location: `step "${phase.id}/${step.id}"`
32847
- });
32361
+ for (const toolId of step.toolCalls ?? []) {
32362
+ if (!toolIds.has(toolId)) {
32363
+ issue2(["phases", phase.id, "steps", step.id, "toolCalls"], `step "${step.id}" calls tool "${toolId}" not declared in flow.tools`);
32364
+ }
32365
+ }
32366
+ for (const cmdId of step.commandCalls ?? []) {
32367
+ if (!commandIds.has(cmdId)) {
32368
+ issue2(["phases", phase.id, "steps", step.id, "commandCalls"], `step "${step.id}" calls command "${cmdId}" not declared in flow.commands`);
32369
+ }
32848
32370
  }
32849
32371
  }
32850
32372
  }
32851
- for (const appendix of flow.appendices) {
32852
- for (const ref of scanForCommandRefs(appendix.body)) {
32853
- allCommandRefs.push({
32854
- ref,
32855
- location: `appendix "${appendix.id}"`
32856
- });
32373
+ for (const { location, text: text2 } of flowTexts(flow)) {
32374
+ for (const match of text2.matchAll(COMMAND_PLACEHOLDER_RE)) {
32375
+ if (!commandIds.has(match[1])) {
32376
+ issue2(["commands"], `{{command:${match[1]}}} in ${location} not declared in flow.commands`);
32377
+ }
32857
32378
  }
32858
- }
32859
- for (const { ref, location } of allCommandRefs) {
32860
- if (!commandIds.has(ref)) {
32861
- ctx.addIssue({
32862
- code: "custom",
32863
- path: ["commands"],
32864
- message: `{{command:${ref}}} in ${location} not declared in flow.commands`
32865
- });
32379
+ for (const match of text2.matchAll(TOOL_PLACEHOLDER_RE)) {
32380
+ if (!toolIds.has(match[1])) {
32381
+ issue2(["tools"], `{{tool:${match[1]}}} in ${location} not declared in flow.tools`);
32382
+ }
32866
32383
  }
32867
- }
32868
- }
32869
- const modeNames = new Set(Object.keys(flow.entries));
32870
- const scanForModeSections = (value, location) => {
32871
- const scan = (text2) => {
32872
- if (!text2) {
32873
- return;
32384
+ for (const match of text2.matchAll(TABLE_PLACEHOLDER_RE)) {
32385
+ if (flow.tables[match[2]] === void 0) {
32386
+ issue2(["tables"], `{{${match[1]}:${match[2]}:\u2026}} in ${location} names an undeclared table`);
32387
+ }
32874
32388
  }
32875
32389
  for (const match of text2.matchAll(MODE_SECTION_RE)) {
32876
- const mode = match[2];
32877
- if (!modeNames.has(mode)) {
32878
- ctx.addIssue({
32879
- code: "custom",
32880
- path: ["phases"],
32881
- message: `{{${match[1]}mode:${mode}}} in ${location} names a mode that does not exist. Declared modes: ${[...modeNames].sort().join(", ")}.`
32882
- });
32390
+ if (!declaredModeSet.has(match[2])) {
32391
+ issue2(["phases"], `{{${match[1]}mode:${match[2]}}} in ${location} names a mode that does not exist. Declared modes: ${[...declaredModeSet].sort().join(", ")}.`);
32883
32392
  }
32884
32393
  }
32885
32394
  for (const match of text2.matchAll(MODE_SECTION_CLOSE_RE)) {
32886
- const mode = match[1];
32887
- if (!modeNames.has(mode)) {
32888
- ctx.addIssue({
32889
- code: "custom",
32890
- path: ["phases"],
32891
- message: `{{/mode:${mode}}} in ${location} closes a mode that does not exist. Declared modes: ${[...modeNames].sort().join(", ")}.`
32892
- });
32395
+ if (!declaredModeSet.has(match[1])) {
32396
+ issue2(["phases"], `{{/mode:${match[1]}}} in ${location} closes a mode that does not exist. Declared modes: ${[...declaredModeSet].sort().join(", ")}.`);
32893
32397
  }
32894
32398
  }
32895
- };
32896
- if (value === void 0) {
32897
- return;
32898
32399
  }
32899
- if (typeof value === "string") {
32900
- scan(value);
32901
- return;
32902
- }
32903
- scan(value.default);
32904
- scan(value.claude);
32905
- scan(value.cursor);
32906
- scan(value.codex);
32907
- };
32908
- scanForModeSections(flow.intro, "flow.intro");
32909
- for (const phase of flow.phases) {
32910
- scanForModeSections(phase.intro, `phase "${phase.id}" intro`);
32911
- for (const step of phase.steps) {
32912
- scanForModeSections(step.body, `step "${phase.id}/${step.id}"`);
32400
+ for (const name of Object.keys(flow.variables)) {
32401
+ if (reservedTokenNames.has(name)) {
32402
+ issue2(["variables", name], `variable "${name}" collides with the target token of the same name`);
32403
+ }
32913
32404
  }
32405
+ });
32406
+ }
32407
+ function refsFromNext(next) {
32408
+ if (next === null) {
32409
+ return [];
32914
32410
  }
32915
- for (const appendix of flow.appendices) {
32916
- scanForModeSections(appendix.body, `appendix "${appendix.id}"`);
32917
- }
32918
- const reservedNames = new Set(RESERVED_TOKEN_NAMES);
32919
- for (const name of Object.keys(flow.variables)) {
32920
- if (reservedNames.has(name)) {
32921
- ctx.addIssue({
32922
- code: "custom",
32923
- path: ["variables", name],
32924
- message: `variable "${name}" collides with the target token of the same name`
32925
- });
32926
- }
32411
+ if (typeof next === "string") {
32412
+ return [next];
32927
32413
  }
32928
- });
32929
- var TOOL_PLACEHOLDER_RE = /\{\{tool:([a-zA-Z][a-zA-Z0-9_-]*)\}\}/g;
32930
- function harvestToolRefs(value, out) {
32414
+ return Object.values(next.byMode).filter((v) => typeof v === "string");
32415
+ }
32416
+ function refsFromStep(s2) {
32417
+ switch (s2.kind) {
32418
+ case "action":
32419
+ case "reference":
32420
+ case "parallel":
32421
+ return refsFromNext(s2.next);
32422
+ case "branch":
32423
+ return s2.branches.flatMap((b) => refsFromNext(b.next));
32424
+ case "loop":
32425
+ return [s2.backTo, s2.onExit];
32426
+ }
32427
+ }
32428
+ function variants(value) {
32931
32429
  if (value === void 0) {
32932
- return;
32430
+ return [];
32933
32431
  }
32934
- const scan = (text2) => {
32935
- if (!text2) {
32936
- return;
32937
- }
32938
- for (const match of text2.matchAll(TOOL_PLACEHOLDER_RE)) {
32939
- out.add(match[1]);
32432
+ if (typeof value === "string") {
32433
+ return [value];
32434
+ }
32435
+ return Object.values(value).filter((v) => v !== void 0);
32436
+ }
32437
+ function flowTexts(flow) {
32438
+ const out = [];
32439
+ const push = (location, value, phaseId) => {
32440
+ for (const text2 of variants(value)) {
32441
+ out.push({ location, text: text2, phaseId });
32940
32442
  }
32941
32443
  };
32942
- if (typeof value === "string") {
32943
- scan(value);
32944
- return;
32444
+ push("flow.intro", flow.intro);
32445
+ push("flow.emitTemplate", flow.emitTemplate);
32446
+ for (const inv of flow.invariants) {
32447
+ push("flow.invariants", inv);
32448
+ }
32449
+ for (const [name, value] of Object.entries(flow.variables)) {
32450
+ push(`variable "${name}"`, value);
32451
+ }
32452
+ for (const phase of flow.phases) {
32453
+ push(`phase "${phase.id}" intro`, phase.intro, phase.id);
32454
+ push(`phase "${phase.id}" outro`, phase.outro, phase.id);
32455
+ for (const step of phase.steps) {
32456
+ const where = `step "${phase.id}/${step.id}"`;
32457
+ push(where, step.body, phase.id);
32458
+ if (step.kind === "branch") {
32459
+ for (const branch of step.branches) {
32460
+ push(where, branch.description, phase.id);
32461
+ }
32462
+ }
32463
+ if (step.kind === "parallel") {
32464
+ for (const branch of step.branches) {
32465
+ push(where, branch.body, phase.id);
32466
+ }
32467
+ }
32468
+ }
32469
+ }
32470
+ for (const appendix of flow.appendices) {
32471
+ push(`appendix "${appendix.id}"`, appendix.body);
32945
32472
  }
32946
- scan(value.default);
32947
- scan(value.claude);
32948
- scan(value.cursor);
32949
- scan(value.codex);
32473
+ return out;
32950
32474
  }
32951
32475
  function collectCalledToolIds(flow) {
32952
32476
  const called = /* @__PURE__ */ new Set();
32953
- harvestToolRefs(flow.intro, called);
32954
32477
  for (const phase of flow.phases) {
32955
- harvestToolRefs(phase.intro, called);
32956
32478
  for (const step of phase.steps) {
32957
32479
  for (const id of step.toolCalls ?? []) {
32958
32480
  called.add(id);
32959
32481
  }
32960
- harvestToolRefs(step.body, called);
32961
- if (step.kind === "branch") {
32962
- for (const branch of step.branches) {
32963
- harvestToolRefs(branch.description, called);
32964
- }
32965
- }
32482
+ }
32483
+ }
32484
+ for (const { text: text2 } of flowTexts(flow)) {
32485
+ for (const match of text2.matchAll(TOOL_PLACEHOLDER_RE)) {
32486
+ called.add(match[1]);
32966
32487
  }
32967
32488
  }
32968
32489
  return Object.keys(flow.tools).filter((id) => called.has(id));
@@ -33036,10 +32557,82 @@ function branchLabel(branch) {
33036
32557
  }
33037
32558
  return "(unlabeled branch)";
33038
32559
  }
32560
+ function targetableFields(flow) {
32561
+ const out = [];
32562
+ const push = (path15, value) => {
32563
+ if (value !== void 0) {
32564
+ out.push({ path: path15, value });
32565
+ }
32566
+ };
32567
+ push(["title"], flow.title);
32568
+ push(["intro"], flow.intro);
32569
+ push(["emitTemplate"], flow.emitTemplate);
32570
+ push(["frontmatter", "description"], flow.frontmatter.description);
32571
+ const hint = flow.frontmatter.argumentHint;
32572
+ if (typeof hint === "object" && hint !== null && "deriveFromModes" in hint) {
32573
+ push(["frontmatter", "argumentHint", "suffix"], hint.suffix);
32574
+ } else {
32575
+ push(["frontmatter", "argumentHint"], hint);
32576
+ }
32577
+ push(["compile", "mode"], flow.compile.mode);
32578
+ for (const [mode, entry] of Object.entries(flow.entries)) {
32579
+ push(["entries", mode], entry);
32580
+ }
32581
+ for (const [mode, value] of Object.entries(flow.modeHints)) {
32582
+ push(["modeHints", mode], value);
32583
+ }
32584
+ for (const [name, value] of Object.entries(flow.variables)) {
32585
+ push(["variables", name], value);
32586
+ }
32587
+ for (const [id, tool] of Object.entries(flow.tools)) {
32588
+ push(["tools", id, "name"], tool.name);
32589
+ }
32590
+ for (const phase of flow.phases) {
32591
+ push(["phases", phase.id, "title"], phase.title);
32592
+ push(["phases", phase.id, "intro"], phase.intro);
32593
+ push(["phases", phase.id, "outro"], phase.outro);
32594
+ for (const step of phase.steps) {
32595
+ const base = ["phases", phase.id, "steps", step.id];
32596
+ push([...base, "title"], step.title);
32597
+ push([...base, "refName"], step.refName);
32598
+ push([...base, "body"], step.body);
32599
+ }
32600
+ }
32601
+ for (const appendix of flow.appendices) {
32602
+ push(["appendices", appendix.id, "title"], appendix.title);
32603
+ push(["appendices", appendix.id, "body"], appendix.body);
32604
+ }
32605
+ return out;
32606
+ }
33039
32607
 
33040
- // ../bitfab-flow/dist/mermaid.js
33041
- var DIAGRAM_TARGET = "claude";
33042
- function renderMermaid(flow, mode) {
32608
+ // ../node_modules/.pnpm/@agent-flows+core@0.1.1_zod@4.6.7/node_modules/@agent-flows/core/dist/mermaid.js
32609
+ function diagramValue(value, target) {
32610
+ const resolved = resolvePerTarget(value, target ?? "default");
32611
+ if (resolved !== void 0 || typeof value !== "object" || value === null) {
32612
+ return resolved;
32613
+ }
32614
+ return Object.values(value).find((v) => v !== void 0);
32615
+ }
32616
+ function diagramString(value, target) {
32617
+ return diagramValue(value, target) ?? "";
32618
+ }
32619
+ function reachabilityTarget(flow, target) {
32620
+ if (target !== void 0) {
32621
+ return target;
32622
+ }
32623
+ for (const entry of Object.values(flow.entries)) {
32624
+ if (typeof entry === "object" && entry !== null && entry.default === void 0) {
32625
+ const first = Object.keys(entry)[0];
32626
+ if (first !== void 0) {
32627
+ return first;
32628
+ }
32629
+ }
32630
+ }
32631
+ return "default";
32632
+ }
32633
+ function renderMermaid(flow, options = {}) {
32634
+ const { mode, target } = typeof options === "string" ? { mode: options, target: void 0 } : options;
32635
+ const graphTarget = reachabilityTarget(flow, target);
33043
32636
  const lines = ["flowchart TD"];
33044
32637
  const stepById = /* @__PURE__ */ new Map();
33045
32638
  for (const phase of flow.phases) {
@@ -33050,19 +32643,19 @@ function renderMermaid(flow, mode) {
33050
32643
  const nodeId = (key) => key.replace(/[^a-zA-Z0-9]/g, "_");
33051
32644
  const allModes = Object.keys(flow.entries);
33052
32645
  const activeModes = mode !== void 0 ? [mode] : allModes;
33053
- const reachable = mode !== void 0 ? new Set([...computeModesPerStep(flow, DIAGRAM_TARGET).entries()].filter(([, modes]) => modes.has(mode)).map(([key]) => key)) : computeReachableSteps(flow, DIAGRAM_TARGET);
32646
+ const reachable = mode !== void 0 ? new Set([...computeModesPerStep(flow, graphTarget).entries()].filter(([, modes]) => modes.has(mode)).map(([key]) => key)) : computeReachableSteps(flow, graphTarget);
33054
32647
  for (const phase of flow.phases) {
33055
32648
  const phaseSteps = phase.steps.filter((s2) => reachable.has(`${phase.id}/${s2.id}`));
33056
32649
  if (phaseSteps.length === 0) {
33057
32650
  continue;
33058
32651
  }
33059
- const phaseTitle = escapeMermaidLabel(resolveTargetableString(phase.title, DIAGRAM_TARGET, "phase.title"));
32652
+ const phaseTitle = escapeMermaidLabel(diagramString(phase.title, target));
33060
32653
  lines.push(` subgraph ${nodeId(phase.id)}["${phaseTitle}"]`);
33061
32654
  let counter = 1;
33062
32655
  for (const step of phaseSteps) {
33063
32656
  const stepKey = `${phase.id}/${step.id}`;
33064
32657
  const id = nodeId(stepKey);
33065
- const baseLabel = escapeMermaidLabel(resolveTargetableString(step.title, DIAGRAM_TARGET, "step.title"));
32658
+ const baseLabel = escapeMermaidLabel(diagramString(step.title, target));
33066
32659
  const num = step.preamble === true ? 0 : counter;
33067
32660
  if (step.preamble !== true) {
33068
32661
  counter += 1;
@@ -33093,18 +32686,18 @@ function renderMermaid(flow, mode) {
33093
32686
  }
33094
32687
  } else {
33095
32688
  for (const m of activeModes) {
33096
- const target = step.next.byMode[m] ?? null;
33097
- if (target === null || !isReachable(target)) {
32689
+ const target2 = step.next.byMode[m] ?? null;
32690
+ if (target2 === null || !isReachable(target2)) {
33098
32691
  continue;
33099
32692
  }
33100
32693
  if (mode !== void 0) {
33101
- const edge = `${src}->${target}`;
32694
+ const edge = `${src}->${target2}`;
33102
32695
  if (!seenLinearEdges.has(edge)) {
33103
32696
  seenLinearEdges.add(edge);
33104
- lines.push(` ${nodeId(src)} --> ${nodeId(target)}`);
32697
+ lines.push(` ${nodeId(src)} --> ${nodeId(target2)}`);
33105
32698
  }
33106
32699
  } else {
33107
- lines.push(` ${nodeId(src)} -->|"${escapeMermaidLabel(m)}"| ${nodeId(target)}`);
32700
+ lines.push(` ${nodeId(src)} -->|"${escapeMermaidLabel(m)}"| ${nodeId(target2)}`);
33108
32701
  }
33109
32702
  }
33110
32703
  }
@@ -33116,20 +32709,20 @@ function renderMermaid(flow, mode) {
33116
32709
  if (branch.next !== null && !isReachable(branch.next)) {
33117
32710
  continue;
33118
32711
  }
33119
- const target = branch.next === null ? "flow_end" : nodeId(branch.next);
33120
- lines.push(` ${nodeId(src)} -->|"${escapeMermaidLabel(labelWithRec)}"| ${target}`);
32712
+ const target2 = branch.next === null ? "flow_end" : nodeId(branch.next);
32713
+ lines.push(` ${nodeId(src)} -->|"${escapeMermaidLabel(labelWithRec)}"| ${target2}`);
33121
32714
  } else {
33122
32715
  for (const m of activeModes) {
33123
32716
  const dest = branch.next.byMode[m] ?? null;
33124
32717
  if (dest !== null && !isReachable(dest)) {
33125
32718
  continue;
33126
32719
  }
33127
- const target = dest === null ? "flow_end" : nodeId(dest);
32720
+ const target2 = dest === null ? "flow_end" : nodeId(dest);
33128
32721
  if (mode !== void 0) {
33129
- lines.push(` ${nodeId(src)} -->|"${escapeMermaidLabel(labelWithRec)}"| ${target}`);
32722
+ lines.push(` ${nodeId(src)} -->|"${escapeMermaidLabel(labelWithRec)}"| ${target2}`);
33130
32723
  } else {
33131
32724
  const modeLabel = `${labelWithRec} [${m}]`;
33132
- lines.push(` ${nodeId(src)} -->|"${escapeMermaidLabel(modeLabel)}"| ${target}`);
32725
+ lines.push(` ${nodeId(src)} -->|"${escapeMermaidLabel(modeLabel)}"| ${target2}`);
33133
32726
  }
33134
32727
  }
33135
32728
  }
@@ -33154,7 +32747,7 @@ function renderMermaid(flow, mode) {
33154
32747
  if (entry === void 0) {
33155
32748
  continue;
33156
32749
  }
33157
- const resolved = resolvePerTarget(entry, DIAGRAM_TARGET);
32750
+ const resolved = diagramValue(entry, target);
33158
32751
  if (resolved === void 0) {
33159
32752
  continue;
33160
32753
  }
@@ -33193,13 +32786,187 @@ function branchForkClass(step) {
33193
32786
  function escapeMermaidLabel(s2) {
33194
32787
  return s2.replace(/"/g, "&quot;").replace(/\|/g, "&#124;");
33195
32788
  }
32789
+ function describeFlow(flow, target) {
32790
+ const lines = [];
32791
+ const title = diagramString(flow.title, target);
32792
+ lines.push(`Flow: ${flow.id} (${title})`);
32793
+ if (flow.defaultMode !== void 0) {
32794
+ lines.push(`Default mode: ${flow.defaultMode}`);
32795
+ }
32796
+ lines.push("Entries:");
32797
+ for (const [mode, entry] of Object.entries(flow.entries)) {
32798
+ const resolved = diagramValue(entry, target);
32799
+ lines.push(` ${mode} \u2192 ${resolved ?? "<no entry for diagram target>"}`);
32800
+ }
32801
+ lines.push("");
32802
+ for (const phase of flow.phases) {
32803
+ lines.push(`Phase: ${phase.id}`);
32804
+ for (const step of phase.steps) {
32805
+ const key = `${phase.id}/${step.id}`;
32806
+ lines.push(` ${key} [${step.kind}]`);
32807
+ const modes = Object.keys(flow.entries);
32808
+ for (const mode of modes) {
32809
+ const targets = nextRefsForMode(step, mode);
32810
+ const desc = targets.map((t) => t ?? "<end>").join(", ");
32811
+ lines.push(` ${mode} \u2192 ${desc}`);
32812
+ }
32813
+ }
32814
+ }
32815
+ return lines.join("\n");
32816
+ }
33196
32817
 
33197
- // ../bitfab-flow/dist/render.js
32818
+ // ../node_modules/.pnpm/@agent-flows+core@0.1.1_zod@4.6.7/node_modules/@agent-flows/core/dist/render.js
33198
32819
  function s(value, target, label) {
33199
32820
  return resolveTargetableString(value, target, label);
33200
32821
  }
32822
+ function renderFlow(flow, target) {
32823
+ const mode = resolvePerTarget(flow.compile.mode, target.name);
32824
+ if (mode === "split" || mode === "split-chain") {
32825
+ return renderSplit(flow, target, mode === "split-chain");
32826
+ }
32827
+ return [{ slug: "", kind: "monolith", content: renderMarkdown(flow, target) }];
32828
+ }
33201
32829
  function usesPhaseReferences(flow, target) {
33202
- return target.name === "codex" && resolvePerTarget(flow.compile.mode, target.name) === "split-chain";
32830
+ return target.phaseReferences === true && resolvePerTarget(flow.compile.mode, target.name) === "split-chain";
32831
+ }
32832
+ function makeRenderContext(flow, target) {
32833
+ return {
32834
+ allModes: Object.keys(flow.entries),
32835
+ modesPerStep: computeModesPerStep(flow, target.name),
32836
+ reachable: computeReachableSteps(flow, target.name),
32837
+ emitTemplate: flow.emitTemplate !== void 0 ? s(flow.emitTemplate, target.name, "flow.emitTemplate") : void 0
32838
+ };
32839
+ }
32840
+ function phaseHasReachableSteps(phase, reachable) {
32841
+ return phase.steps.some((step) => reachable.has(`${phase.id}/${step.id}`));
32842
+ }
32843
+ function renderSplit(flow, target, chain = false) {
32844
+ const ctx = makeRenderContext(flow, target);
32845
+ const inlineSet = new Set(flow.compile.inlinePhases);
32846
+ const subPhases = flow.phases.filter((phase) => !inlineSet.has(phase.id) && phaseHasReachableSteps(phase, ctx.reachable));
32847
+ const files = [
32848
+ {
32849
+ slug: "",
32850
+ kind: "orchestrator",
32851
+ content: renderOrchestrator(flow, target, ctx, inlineSet, subPhases, chain)
32852
+ }
32853
+ ];
32854
+ for (const phase of subPhases) {
32855
+ files.push({
32856
+ slug: phase.id,
32857
+ kind: usesPhaseReferences(flow, target) ? "reference" : "phase",
32858
+ content: renderSubSkill(flow, target, ctx, phase, chain)
32859
+ });
32860
+ }
32861
+ return files;
32862
+ }
32863
+ function labeledRefsForMode(step, mode) {
32864
+ switch (step.kind) {
32865
+ case "action":
32866
+ case "reference":
32867
+ case "parallel": {
32868
+ const next = step.next;
32869
+ const ref = next === null || typeof next === "string" ? next : next.byMode[mode] ?? null;
32870
+ return [{ label: null, ref }];
32871
+ }
32872
+ case "branch":
32873
+ return step.branches.map((branch) => {
32874
+ const next = branch.next;
32875
+ const ref = next === null || typeof next === "string" ? next : next.byMode[mode] ?? null;
32876
+ return { label: dispatchBranchLabel(branch), ref };
32877
+ });
32878
+ case "loop":
32879
+ return [
32880
+ { label: step.exitWhen, ref: step.onExit },
32881
+ { label: "otherwise", ref: step.backTo }
32882
+ ];
32883
+ }
32884
+ }
32885
+ function dispatchBranchLabel(branch) {
32886
+ if (branch.option !== void 0) {
32887
+ return `option ${branch.option.letter} (${branch.option.label})`;
32888
+ }
32889
+ return branch.when ?? "branch";
32890
+ }
32891
+ function computeDispatchEdges(step, stepKey, unitPhases, ctx) {
32892
+ const stepModeSet = modesForStep(stepKey, ctx.modesPerStep, ctx.allModes);
32893
+ const stepModes = ctx.allModes.filter((m) => stepModeSet.has(m));
32894
+ const groups = /* @__PURE__ */ new Map();
32895
+ const order = [];
32896
+ const labelHasDispatch = /* @__PURE__ */ new Set();
32897
+ for (const mode of stepModes) {
32898
+ for (const { label, ref } of labeledRefsForMode(step, mode)) {
32899
+ let kind = "done";
32900
+ let targetPhase = null;
32901
+ if (ref !== null) {
32902
+ const phaseId = ref.split("/")[0];
32903
+ if (unitPhases.has(phaseId)) {
32904
+ kind = "continue";
32905
+ } else {
32906
+ kind = "dispatch";
32907
+ targetPhase = phaseId;
32908
+ }
32909
+ }
32910
+ const key = `${label ?? "\0"}|${kind}|${targetPhase ?? ""}`;
32911
+ const existing = groups.get(key);
32912
+ if (existing !== void 0) {
32913
+ if (!existing.modes.includes(mode)) {
32914
+ existing.modes.push(mode);
32915
+ }
32916
+ } else {
32917
+ groups.set(key, { label, kind, targetPhase, modes: [mode] });
32918
+ order.push(key);
32919
+ }
32920
+ if (kind === "dispatch") {
32921
+ labelHasDispatch.add(label);
32922
+ }
32923
+ }
32924
+ }
32925
+ return order.map((key) => groups.get(key)).filter((edge) => labelHasDispatch.has(edge.label));
32926
+ }
32927
+ function renderDispatchSuffix(flow, target, edges, allModes, unitPhases) {
32928
+ if (edges.length === 0) {
32929
+ return null;
32930
+ }
32931
+ const singleMode = allModes.length === 1;
32932
+ const lines = edges.map((edge) => {
32933
+ const modeList = edge.modes.map((m) => `\`${m}\``).join(" or ");
32934
+ let prefix = "";
32935
+ if (edge.label !== null) {
32936
+ prefix = singleMode ? titleCase(edge.label) : `${titleCase(edge.label)} (mode ${modeList})`;
32937
+ } else if (!singleMode) {
32938
+ prefix = `Mode ${modeList}`;
32939
+ }
32940
+ let action;
32941
+ switch (edge.kind) {
32942
+ case "done":
32943
+ action = "stop here.";
32944
+ break;
32945
+ case "continue":
32946
+ action = usesPhaseReferences(flow, target) ? "continue below in this file." : "continue below in this skill.";
32947
+ break;
32948
+ case "dispatch": {
32949
+ if (edge.targetPhase === null) {
32950
+ throw new Error("Dispatch edge is missing its target phase");
32951
+ }
32952
+ const destination = phaseDestination(flow, target, edge.targetPhase, unitPhases);
32953
+ const actionVerb = usesPhaseReferences(flow, target) ? "read and follow" : "invoke";
32954
+ const fwd = `, forwarding \`${target.argsToken}\` minus the leading mode keyword (if the user typed one).`;
32955
+ if (singleMode) {
32956
+ action = `${actionVerb} ${destination}${fwd}`;
32957
+ } else if (edge.modes.length === 1) {
32958
+ action = `${actionVerb} ${destination} with mode \`${edge.modes[0]}\`${fwd}`;
32959
+ } else {
32960
+ action = `${actionVerb} ${destination} with the current mode (${modeList})${fwd}`;
32961
+ }
32962
+ break;
32963
+ }
32964
+ }
32965
+ return prefix.length > 0 ? `- ${prefix}: ${action}` : `- ${titleCase(action)}`;
32966
+ });
32967
+ return `**Next:**
32968
+
32969
+ ${lines.join("\n")}`;
33203
32970
  }
33204
32971
  function dispatchSkillRef(target, skillName) {
33205
32972
  return target.dispatchRef?.(skillName) ?? `\`${skillName}\``;
@@ -33217,6 +32984,208 @@ function phaseDestination(flow, target, phaseId, unitPhases) {
33217
32984
  const title = s(phase.title, target.name, `phase[${phaseId}].title`);
33218
32985
  return `the [${title}](${prefix}${phaseId}.md) reference`;
33219
32986
  }
32987
+ function dispatchSuffixForUnit(flow, target, ctx, unitPhases) {
32988
+ return (step, stepKey) => renderDispatchSuffix(flow, target, computeDispatchEdges(step, stepKey, unitPhases, ctx), ctx.allModes, unitPhases);
32989
+ }
32990
+ function interactiveDefaultDispatchPointer(flow, target) {
32991
+ const action = usesPhaseReferences(flow, target) ? "read and follow that mode's reference" : "invoke that mode's skill";
32992
+ return `**Next:** once the user picks a mode, ${action} from the \`## Dispatch\` section above, forwarding the arguments the user gave with their pick minus the mode keyword. Ignore the dispatch lines' \`${target.argsToken}\` here: this is the no-argument entry, so it is empty and the user's pick is the only source of those arguments.`;
32993
+ }
32994
+ function orchestratorDispatchSuffix(flow, target, ctx, inlineSet, hasEntryDispatch) {
32995
+ const base = dispatchSuffixForUnit(flow, target, ctx, inlineSet);
32996
+ const defaultEntry = flow.entries.default === void 0 ? void 0 : resolvePerTarget(flow.entries.default, target.name);
32997
+ return (step, stepKey) => {
32998
+ if (hasEntryDispatch && defaultEntry !== void 0 && stepKey === defaultEntry && "next" in step && step.next === null) {
32999
+ return interactiveDefaultDispatchPointer(flow, target);
33000
+ }
33001
+ return base(step, stepKey);
33002
+ };
33003
+ }
33004
+ function renderEntryDispatch(flow, target, ctx, inlineSet) {
33005
+ const groups = /* @__PURE__ */ new Map();
33006
+ for (const [mode, entry] of Object.entries(flow.entries)) {
33007
+ const resolved = resolvePerTarget(entry, target.name);
33008
+ if (resolved === void 0) {
33009
+ continue;
33010
+ }
33011
+ const phaseId = resolved.split("/")[0];
33012
+ if (inlineSet.has(phaseId)) {
33013
+ continue;
33014
+ }
33015
+ const modes = groups.get(phaseId) ?? [];
33016
+ modes.push(mode);
33017
+ groups.set(phaseId, modes);
33018
+ }
33019
+ if (groups.size === 0) {
33020
+ return null;
33021
+ }
33022
+ const singleMode = ctx.allModes.length === 1;
33023
+ const lines = [...groups.entries()].map(([phaseId, modes]) => {
33024
+ const destination = phaseDestination(flow, target, phaseId, inlineSet);
33025
+ const action = usesPhaseReferences(flow, target) ? "read and follow" : "invoke";
33026
+ const fwd = `, forwarding \`${target.argsToken}\` minus the leading mode keyword (if the user typed one).`;
33027
+ if (singleMode) {
33028
+ return `- ${titleCase(action)} ${destination}${fwd}`;
33029
+ }
33030
+ const modeList = modes.map((m) => `\`${m}\``).join(" or ");
33031
+ const arg = modes.length === 1 ? `mode \`${modes[0]}\`` : `the current mode (${modeList})`;
33032
+ return `- Mode ${modeList}: ${action} ${destination} with ${arg}${fwd}`;
33033
+ });
33034
+ return `## Dispatch
33035
+
33036
+ ${lines.join("\n")}`;
33037
+ }
33038
+ function appendicesForUnit(flow, ctx, unitPhases, includeUnreferenced) {
33039
+ const referencingPhases = /* @__PURE__ */ new Map();
33040
+ for (const phase of flow.phases) {
33041
+ for (const step of phase.steps) {
33042
+ if (!ctx.reachable.has(`${phase.id}/${step.id}`)) {
33043
+ continue;
33044
+ }
33045
+ for (const ref of step.refs ?? []) {
33046
+ const phases = referencingPhases.get(ref) ?? /* @__PURE__ */ new Set();
33047
+ phases.add(phase.id);
33048
+ referencingPhases.set(ref, phases);
33049
+ }
33050
+ }
33051
+ }
33052
+ return flow.appendices.filter((appendix) => {
33053
+ const phases = referencingPhases.get(appendix.id);
33054
+ if (phases === void 0) {
33055
+ return includeUnreferenced;
33056
+ }
33057
+ return [...phases].some((id) => unitPhases.has(id));
33058
+ });
33059
+ }
33060
+ function renderOrchestrator(flow, target, ctx, inlineSet, subPhases, chain) {
33061
+ const inlinePhaseIds = flow.phases.filter((phase) => inlineSet.has(phase.id)).map((phase) => phase.id);
33062
+ const sections = [
33063
+ target.frontmatter({
33064
+ flowId: flow.id,
33065
+ description: s(flow.frontmatter.description, target.name, "flow.frontmatter.description"),
33066
+ argumentHint: resolveArgumentHint(flow, target),
33067
+ model: flow.frontmatter.model,
33068
+ allowedTools: orchestratorAllowedTools(flow, target, inlinePhaseIds, subPhases.length > 0)
33069
+ }),
33070
+ `# ${s(flow.title, target.name, "flow.title")}`
33071
+ ];
33072
+ pushIntro(sections, flow, target);
33073
+ if (usesPhaseReferences(flow, target) && subPhases.length > 0) {
33074
+ sections.push("Load phase references only when routing reaches them. Read and follow the linked file in this same session, retaining the current mode, arguments, shared rules, and prior results. Resolve links relative to the file containing them. If an installed shim redirected you here, use this worktree skill's directory, not the shim directory or shell working directory. References are ordinary instruction files, not separately invocable skills.");
33075
+ }
33076
+ if (Object.keys(flow.commands).length > 0) {
33077
+ sections.push(renderCommandsTable(flow, target));
33078
+ }
33079
+ pushInvariants(sections, flow);
33080
+ const modesDispatch = renderModesDispatch(flow, target, true);
33081
+ if (modesDispatch !== null) {
33082
+ sections.push(modesDispatch);
33083
+ }
33084
+ let hasEntryDispatch = false;
33085
+ if (chain) {
33086
+ const entryDispatch = renderEntryDispatch(flow, target, ctx, inlineSet);
33087
+ if (entryDispatch !== null) {
33088
+ sections.push(entryDispatch);
33089
+ hasEntryDispatch = true;
33090
+ }
33091
+ }
33092
+ const subPhaseIds = new Set(subPhases.map((phase) => phase.id));
33093
+ for (const phase of flow.phases) {
33094
+ if (inlineSet.has(phase.id)) {
33095
+ const rendered = renderPhase(
33096
+ phase,
33097
+ target.name,
33098
+ ctx.allModes,
33099
+ ctx.modesPerStep,
33100
+ ctx.reachable,
33101
+ ctx.emitTemplate,
33102
+ true,
33103
+ chain ? orchestratorDispatchSuffix(flow, target, ctx, inlineSet, hasEntryDispatch) : void 0,
33104
+ destinationRenderer(flow, target, inlineSet),
33105
+ 0,
33106
+ // Split-chain orchestrators emit a `## Dispatch` block above the inline
33107
+ // phase; fold a single-mode gate under the first step heading so it can't
33108
+ // be misread as gating the dispatch. Non-chain/monolith keep the float.
33109
+ chain
33110
+ );
33111
+ if (rendered.length > 0) {
33112
+ sections.push(rendered);
33113
+ }
33114
+ } else if (!chain && subPhaseIds.has(phase.id)) {
33115
+ sections.push(renderDispatch(flow, target, ctx, phase));
33116
+ }
33117
+ }
33118
+ pushAppendices(sections, flow, target, chain ? appendicesForUnit(flow, ctx, inlineSet, true) : flow.appendices);
33119
+ return finalize2(sections, flow, target, inlineSet);
33120
+ }
33121
+ function renderDispatch(flow, target, ctx, phase) {
33122
+ const title = s(phase.title, target.name, `phase[${phase.id}].title`);
33123
+ const stepKeys = phase.steps.map((step) => `${phase.id}/${step.id}`).filter((key) => ctx.reachable.has(key));
33124
+ const { phaseGate } = precomputePhaseAndStepGates(stepKeys, ctx.modesPerStep, ctx.allModes);
33125
+ const blocks = [`## ${title}`];
33126
+ if (phaseGate !== null) {
33127
+ blocks.push(phaseGate);
33128
+ }
33129
+ blocks.push(`Invoke the \`${flow.id}-${phase.id}\` skill, then return here.`);
33130
+ return blocks.join("\n\n");
33131
+ }
33132
+ function renderSubSkill(flow, target, ctx, phase, chain) {
33133
+ const phaseTitle = s(phase.title, target.name, `phase[${phase.id}].title`);
33134
+ const flowTitle = s(flow.title, target.name, "flow.title");
33135
+ const unitPhases = /* @__PURE__ */ new Set([phase.id]);
33136
+ const reachableSteps = phase.steps.filter((step) => ctx.reachable.has(`${phase.id}/${step.id}`));
33137
+ const hasDispatch = chain && reachableSteps.some((step) => computeDispatchEdges(step, `${phase.id}/${step.id}`, unitPhases, ctx).some((edge) => edge.kind === "dispatch"));
33138
+ const invokedBy = chain ? `Invoked by the ${flow.id} flow; not run directly` : `Invoked by the ${flow.id} orchestrator; not run directly`;
33139
+ const description = `${phaseTitle} phase of the ${flowTitle} flow. ${invokedBy}`;
33140
+ const sections = [];
33141
+ if (!usesPhaseReferences(flow, target)) {
33142
+ sections.push(target.subSkillFrontmatter({
33143
+ flowId: `${flow.id}-${phase.id}`,
33144
+ description,
33145
+ argumentHint: resolveArgumentHint(flow, target),
33146
+ model: flow.frontmatter.model,
33147
+ allowedTools: subSkillAllowedTools(flow, target, phase.id, hasDispatch)
33148
+ }));
33149
+ }
33150
+ sections.push(`# ${flowTitle}: ${phaseTitle}`);
33151
+ if (chain) {
33152
+ const preface = renderModePreface(ctx, phase, reachableSteps);
33153
+ if (preface !== null) {
33154
+ sections.push(preface);
33155
+ }
33156
+ }
33157
+ const rendered = renderPhase(phase, target.name, ctx.allModes, ctx.modesPerStep, ctx.reachable, ctx.emitTemplate, false, chain ? dispatchSuffixForUnit(flow, target, ctx, unitPhases) : void 0, destinationRenderer(flow, target, unitPhases));
33158
+ if (rendered.length > 0) {
33159
+ sections.push(rendered);
33160
+ }
33161
+ if (chain) {
33162
+ pushAppendices(sections, flow, target, appendicesForUnit(flow, ctx, unitPhases, false));
33163
+ }
33164
+ return finalize2(sections, flow, target, unitPhases);
33165
+ }
33166
+ function renderModePreface(ctx, phase, reachableSteps) {
33167
+ const phaseModes = /* @__PURE__ */ new Set();
33168
+ for (const step of reachableSteps) {
33169
+ for (const mode of modesForStep(`${phase.id}/${step.id}`, ctx.modesPerStep, ctx.allModes)) {
33170
+ phaseModes.add(mode);
33171
+ }
33172
+ }
33173
+ if (phaseModes.size < 2) {
33174
+ return null;
33175
+ }
33176
+ const modeList = ctx.allModes.filter((m) => phaseModes.has(m)).map((m) => `\`${m}\``).join(" or ");
33177
+ return `**Mode:** you were dispatched with a mode (${modeList}); which steps apply and where they route below depend on it.`;
33178
+ }
33179
+ function subSkillAllowedTools(flow, target, phaseId, hasDispatch) {
33180
+ const tools = resolveAllowedToolsForPhases(flow, target, [phaseId]);
33181
+ if (tools === void 0 || !hasDispatch) {
33182
+ return tools;
33183
+ }
33184
+ if (target.subSkillTool && !tools.includes(target.subSkillTool)) {
33185
+ return [...tools, target.subSkillTool];
33186
+ }
33187
+ return tools;
33188
+ }
33220
33189
  function resolveArgumentHint(flow, target) {
33221
33190
  const argumentHint = flow.frontmatter.argumentHint;
33222
33191
  if (argumentHint === void 0) {
@@ -33232,8 +33201,91 @@ function resolveArgumentHint(flow, target) {
33232
33201
  if (argumentHint.suffix === void 0) {
33233
33202
  return modeHint;
33234
33203
  }
33235
- const suffix = s(argumentHint.suffix, target.name, "frontmatter.argumentHint.suffix");
33236
- return suffix.length > 0 ? `${modeHint} ${suffix}` : modeHint;
33204
+ const suffix = s(argumentHint.suffix, target.name, "frontmatter.argumentHint.suffix");
33205
+ return suffix.length > 0 ? `${modeHint} ${suffix}` : modeHint;
33206
+ }
33207
+ function pushIntro(sections, flow, target) {
33208
+ if (flow.intro === void 0) {
33209
+ return;
33210
+ }
33211
+ const introStr = s(flow.intro, target.name, "flow.intro");
33212
+ if (introStr.length > 0) {
33213
+ sections.push(introStr);
33214
+ }
33215
+ }
33216
+ function pushInvariants(sections, flow) {
33217
+ if (flow.invariants.length > 0) {
33218
+ const items = flow.invariants.map((inv) => `- ${inv}`).join("\n");
33219
+ sections.push(`## Invariants
33220
+
33221
+ ${items}`);
33222
+ }
33223
+ }
33224
+ function pushAppendices(sections, flow, target, appendices = flow.appendices) {
33225
+ for (const appendix of appendices) {
33226
+ const title = s(appendix.title, target.name, `appendix[${appendix.id}].title`);
33227
+ const body = s(appendix.body, target.name, `appendix[${appendix.id}].body`);
33228
+ sections.push(`## ${title}
33229
+
33230
+ ${body}`);
33231
+ }
33232
+ }
33233
+ function orchestratorAllowedTools(flow, target, inlinePhaseIds, hasSubSkills) {
33234
+ const tools = resolveAllowedToolsForPhases(flow, target, inlinePhaseIds);
33235
+ if (tools === void 0) {
33236
+ return void 0;
33237
+ }
33238
+ if (hasSubSkills && target.subSkillTool && !tools.includes(target.subSkillTool)) {
33239
+ return [...tools, target.subSkillTool];
33240
+ }
33241
+ return tools;
33242
+ }
33243
+ function resolveAllowedToolsForPhases(flow, target, phaseIds) {
33244
+ if (Object.keys(flow.tools).length === 0) {
33245
+ return flow.frontmatter.allowedTools;
33246
+ }
33247
+ const ids = collectPhaseToolIds(flow, target, phaseIds).filter((id) => toolAvailableOnTarget(flow.tools[id], target.name));
33248
+ if (ids.length === 0) {
33249
+ return void 0;
33250
+ }
33251
+ return ids.map((id) => fullToolName(flow, id, target));
33252
+ }
33253
+ var HAS_COMMAND_RE = new RegExp(COMMAND_PLACEHOLDER_RE.source);
33254
+ function collectPhaseToolIds(flow, target, phaseIds) {
33255
+ const wanted = new Set(phaseIds);
33256
+ const called = /* @__PURE__ */ new Set();
33257
+ const runnerId = Object.entries(flow.tools).find(([, tool]) => tool.kind === "builtin" && resolvePerTarget(tool.name, target.name) === target.commandRunnerTool)?.[0];
33258
+ const emitTemplate = flow.emitTemplate !== void 0 ? s(flow.emitTemplate, target.name, "flow.emitTemplate") : void 0;
33259
+ const emitUsesCommand = emitTemplate !== void 0 && HAS_COMMAND_RE.test(emitTemplate);
33260
+ const scan = (text2) => {
33261
+ if (text2 === void 0) {
33262
+ return;
33263
+ }
33264
+ for (const match of text2.matchAll(TOOL_PLACEHOLDER_RE)) {
33265
+ called.add(match[1]);
33266
+ }
33267
+ if (runnerId !== void 0 && HAS_COMMAND_RE.test(text2)) {
33268
+ called.add(runnerId);
33269
+ }
33270
+ };
33271
+ for (const phase of flow.phases) {
33272
+ if (!wanted.has(phase.id)) {
33273
+ continue;
33274
+ }
33275
+ if (phase.intro !== void 0) {
33276
+ scan(s(phase.intro, target.name, `phase[${phase.id}].intro`));
33277
+ }
33278
+ for (const step of phase.steps) {
33279
+ for (const id of step.toolCalls ?? []) {
33280
+ called.add(id);
33281
+ }
33282
+ if (runnerId !== void 0 && ((step.commandCalls?.length ?? 0) > 0 || step.emit !== void 0 && emitUsesCommand)) {
33283
+ called.add(runnerId);
33284
+ }
33285
+ scan(s(step.body, target.name, `step[${step.id}].body`));
33286
+ }
33287
+ }
33288
+ return Object.keys(flow.tools).filter((id) => called.has(id));
33237
33289
  }
33238
33290
  function renderMarkdown(flow, target) {
33239
33291
  const sections = [];
@@ -33254,7 +33306,7 @@ function renderMarkdown(flow, target) {
33254
33306
  }
33255
33307
  }
33256
33308
  if (Object.keys(flow.commands).length > 0) {
33257
- sections.push(renderCommandsTable(flow));
33309
+ sections.push(renderCommandsTable(flow, target));
33258
33310
  }
33259
33311
  if (flow.invariants.length > 0) {
33260
33312
  const items = flow.invariants.map((inv) => `- ${inv}`).join("\n");
@@ -33294,7 +33346,7 @@ ${body}`);
33294
33346
  }
33295
33347
  function finalize2(sections, flow, target, unitPhases) {
33296
33348
  const joined = sections.join("\n\n");
33297
- const afterSections = applyModeSections(applyMustacheSections(joined, target.name), flow, target.name, unitPhases);
33349
+ const afterSections = applyModeSections(applyMustacheSections(joined, target), flow, target.name, unitPhases);
33298
33350
  const withFlowData = applyFlowPlaceholders(afterSections, flow, target, unitPhases);
33299
33351
  const substituted = applyTokens(withFlowData, target, flow);
33300
33352
  return ensureTrailingNewline(substituted);
@@ -33353,16 +33405,11 @@ function applyFlowPlaceholders(text2, flow, target, unitPhases) {
33353
33405
  if (def === void 0) {
33354
33406
  throw new Error(`Command "${commandId}" not declared in flow.commands`);
33355
33407
  }
33356
- return `node "{{pluginRoot}}/dist/commands/${def.file}"`;
33408
+ return target.invokeCommand(def);
33357
33409
  });
33358
- result = result.replace(/\{\{languages:([a-z,]+)\}\}/g, (_match, columnsRaw, offset) => {
33359
- const block = renderLanguagesBlock(flow, columnsRaw.split(","));
33360
- const lineStart = result.lastIndexOf("\n", offset - 1) + 1;
33361
- const before = result.slice(lineStart, offset);
33362
- if (!/^[ \t]*$/.test(before)) {
33363
- return block;
33364
- }
33365
- return block.split("\n").map((line, i) => i === 0 || line.length === 0 ? line : before + line).join("\n");
33410
+ result = result.replace(/\{\{(table|list):([a-zA-Z][a-zA-Z0-9_-]*):([a-zA-Z0-9_,-]+)\}\}/g, (_match, kind, tableName, columnsRaw, offset) => {
33411
+ const block = renderTableBlock(flow, kind, tableName, columnsRaw.split(","));
33412
+ return inheritLineIndent(result, offset, block);
33366
33413
  });
33367
33414
  return result;
33368
33415
  }
@@ -33448,65 +33495,61 @@ function renderModesDispatch(flow, target, dispatches) {
33448
33495
  ...rows
33449
33496
  ].join("\n");
33450
33497
  }
33451
- function renderCommandsTable(flow) {
33498
+ function renderCommandsTable(flow, target) {
33452
33499
  const rows = [];
33453
33500
  for (const def of Object.values(flow.commands)) {
33454
33501
  const sig = def.args !== void 0 ? `${def.file} ${def.args}` : def.file;
33455
33502
  rows.push(`| \`${sig}\` | ${def.description} |`);
33456
33503
  }
33457
33504
  return [
33458
- "**CLI commands** available via Bash (all paths relative to `{{pluginRoot}}/dist/commands/`):",
33505
+ target.commandsTableIntro,
33459
33506
  "",
33460
33507
  "| Command | Description |",
33461
33508
  "|---------|-------------|",
33462
33509
  ...rows
33463
33510
  ].join("\n");
33464
33511
  }
33465
- function renderLanguagesBlock(flow, columns) {
33466
- if (flow.languages.length === 0) {
33467
- return "";
33512
+ function renderTableBlock(flow, kind, tableName, columns) {
33513
+ const table = flow.tables[tableName];
33514
+ if (table === void 0) {
33515
+ throw new Error(`Table "${tableName}" not declared in flow.tables`);
33468
33516
  }
33469
- if (columns.length === 1 && columns[0] === "imports") {
33470
- const lines2 = [];
33471
- for (const lang of flow.languages) {
33472
- if (lang.imports !== void 0) {
33473
- lines2.push(` - ${lang.displayName}: ${lang.imports}`);
33474
- }
33517
+ if (kind === "list") {
33518
+ if (columns.length !== 1) {
33519
+ throw new Error(`{{list:${tableName}:\u2026}} takes exactly one column, got ${columns.join(",")}`);
33475
33520
  }
33476
- return lines2.join("\n");
33521
+ const column = columns[0];
33522
+ return table.rows.filter((row) => row.cells[column] !== void 0).map((row) => `- ${row.label ?? row.key}: ${row.cells[column]}`).join("\n");
33477
33523
  }
33478
- const headers = ["Language", ...columns.map((c) => columnHeader(flow, c))];
33524
+ const headers = [
33525
+ table.keyHeader,
33526
+ ...columns.map((c) => table.columns[c] ?? titleCase(c))
33527
+ ];
33479
33528
  const lines = [
33480
33529
  `| ${headers.join(" | ")} |`,
33481
33530
  `|${headers.map(() => "---").join("|")}|`
33482
33531
  ];
33483
- for (const lang of flow.languages) {
33484
- const cells = columns.map((col) => readLanguageField(lang, col));
33532
+ for (const row of table.rows) {
33533
+ const cells = columns.map((col) => row.cells[col]);
33485
33534
  if (cells.every((c) => c !== void 0)) {
33486
- lines.push(`| ${lang.name} | ${cells.join(" | ")} |`);
33535
+ lines.push(`| ${row.key} | ${cells.join(" | ")} |`);
33487
33536
  }
33488
33537
  }
33489
33538
  return lines.join("\n");
33490
33539
  }
33491
- function columnHeader(flow, column) {
33492
- return flow.languageColumnHeaders[column] ?? titleCase(column);
33493
- }
33494
33540
  function titleCase(s2) {
33495
33541
  return s2.charAt(0).toUpperCase() + s2.slice(1);
33496
33542
  }
33497
- function readLanguageField(lang, column) {
33498
- switch (column) {
33499
- case "imports":
33500
- return lang.imports;
33501
- case "detection":
33502
- return lang.detection;
33503
- case "outdated":
33504
- return lang.outdated;
33505
- case "update":
33506
- return lang.update;
33507
- default:
33508
- throw new Error(`Unknown languages field "${column}"`);
33543
+ function inheritLineIndent(text2, offset, value) {
33544
+ if (!value.includes("\n")) {
33545
+ return value;
33546
+ }
33547
+ const lineStart = text2.lastIndexOf("\n", offset - 1) + 1;
33548
+ const before = text2.slice(lineStart, offset);
33549
+ if (!/^[ \t]*$/.test(before)) {
33550
+ return value;
33509
33551
  }
33552
+ return value.split("\n").map((line, i) => i === 0 || line.length === 0 ? line : before + line).join("\n");
33510
33553
  }
33511
33554
  function destinationRenderer(flow, target, unitPhases) {
33512
33555
  const one = (ref, sourcePhaseId) => {
@@ -33750,14 +33793,13 @@ function indentBody(body) {
33750
33793
  const lines = body.split("\n");
33751
33794
  return lines.map((line, i) => i === 0 ? line : line.length > 0 ? ` ${line}` : line).join("\n");
33752
33795
  }
33753
- function applyMustacheSections(text2, targetName) {
33754
- const sectionRegex = /\{\{([#^])([a-z][a-z-]*)\}\}([\s\S]*?)\{\{\/\2\}\}/g;
33796
+ function applyMustacheSections(text2, target) {
33797
+ const sectionRegex = /\{\{([#^])([a-z][a-z0-9-]*)\}\}([\s\S]*?)\{\{\/\2\}\}/g;
33755
33798
  return text2.replace(sectionRegex, (_match, kind, name, inner) => {
33756
- const members2 = SECTION_TARGETS[name];
33757
- if (members2 === void 0) {
33758
- throw new Error(`Unknown target name "${name}" in Mustache section. Valid names: ${MUSTACHE_SECTION_NAMES.join(", ")}.`);
33799
+ const isMatch = target.sections[name];
33800
+ if (isMatch === void 0) {
33801
+ throw new Error(`Unknown section "${name}". Valid sections: ${Object.keys(target.sections).join(", ")}.`);
33759
33802
  }
33760
- const isMatch = members2.includes(targetName);
33761
33803
  const include = kind === "#" ? isMatch : !isMatch;
33762
33804
  return include ? inner : "";
33763
33805
  });
@@ -33820,20 +33862,11 @@ function applyTokens(text2, target, flow) {
33820
33862
  if (!Object.hasOwn(pool, key)) {
33821
33863
  throw new Error(`Unresolved placeholder {{${key}}} - not a target token or flow variable. Define it in flow.variables, fix the typo, or remove the placeholder.`);
33822
33864
  }
33823
- const value = pool[key];
33824
- if (!value.includes("\n")) {
33825
- return value;
33826
- }
33827
- const lineStart = text2.lastIndexOf("\n", offset - 1) + 1;
33828
- const before = text2.slice(lineStart, offset);
33829
- if (!/^[ \t]*$/.test(before)) {
33830
- return value;
33831
- }
33832
- return value.split("\n").map((line, i) => i === 0 || line.length === 0 ? line : before + line).join("\n");
33865
+ return inheritLineIndent(text2, offset, pool[key]);
33833
33866
  });
33834
33867
  const leftovers = result.match(/\{\{[^}]+\}\}/g);
33835
33868
  if (leftovers) {
33836
- throw new Error(`Unresolved placeholder(s): ${leftovers.join(", ")}. Check spelling and namespace (step:, step-ref:, skill-ref:, dispatch-ref:, tool:, languages:, branches, branches:).`);
33869
+ throw new Error(`Unresolved placeholder(s): ${leftovers.join(", ")}. Check spelling and namespace (step:, step-ref:, skill-ref:, dispatch-ref:, tool:, command:, table:, list:, branches, branches:).`);
33837
33870
  }
33838
33871
  return result;
33839
33872
  }
@@ -33842,27 +33875,318 @@ function ensureTrailingNewline(text2) {
33842
33875
  `;
33843
33876
  }
33844
33877
 
33845
- // ../bitfab-flow/dist/sharedVariables.js
33846
- var SHARED_VARIABLES = {
33847
- /**
33848
- * Connector phrase used when describing instrumentation that races (or
33849
- * sequentially writes, on codex) work in another file. Grammatically
33850
- * expects a continuation: "writes them {{parallelism}} the X edits."
33851
- */
33852
- parallelism: {
33853
- default: "in parallel with",
33854
- codex: "in the same cycle as"
33855
- },
33856
- /**
33857
- * Adverbial phrase used in tabular or bullet contexts where the
33858
- * surrounding grammar doesn't carry over. "(... {{togetherness}} per
33859
- * workflow)".
33860
- */
33861
- togetherness: {
33862
- default: "in parallel",
33863
- codex: "together"
33878
+ // ../node_modules/.pnpm/@agent-flows+core@0.1.1_zod@4.6.7/node_modules/@agent-flows/core/dist/kit.js
33879
+ var NAME_RE = /^[a-z][a-z0-9-]*$/;
33880
+ function createFlowKit(config4) {
33881
+ const targetNames = Object.keys(config4.targets);
33882
+ if (targetNames.length === 0) {
33883
+ throw new Error("createFlowKit: at least one target is required");
33884
+ }
33885
+ for (const name of targetNames) {
33886
+ if (!NAME_RE.test(name) || name === "default") {
33887
+ throw new Error(`createFlowKit: invalid target name "${name}" (use lowercase kebab-case; "default" is reserved)`);
33888
+ }
33889
+ }
33890
+ const groups = {};
33891
+ for (const name of targetNames) {
33892
+ groups[name] = [name];
33893
+ }
33894
+ for (const [section, members2] of Object.entries(config4.sections ?? {})) {
33895
+ if (!NAME_RE.test(section)) {
33896
+ throw new Error(`createFlowKit: invalid section name "${section}"`);
33897
+ }
33898
+ if (section in groups) {
33899
+ throw new Error(`createFlowKit: section "${section}" collides with a target name`);
33900
+ }
33901
+ for (const member of members2) {
33902
+ if (!targetNames.includes(member)) {
33903
+ throw new Error(`createFlowKit: section "${section}" lists unknown target "${member}"`);
33904
+ }
33905
+ }
33906
+ groups[section] = members2;
33907
+ }
33908
+ const commands = config4.commands ?? {};
33909
+ const runnerTool = commands.runnerTool ?? "Bash";
33910
+ const targets = {};
33911
+ for (const name of targetNames) {
33912
+ const spec = config4.targets[name];
33913
+ const target = { ...spec, name };
33914
+ const sections = {};
33915
+ for (const [section, members2] of Object.entries(groups)) {
33916
+ sections[section] = members2.includes(name);
33917
+ }
33918
+ const tableIntro = commands.tableIntro;
33919
+ targets[name] = {
33920
+ ...target,
33921
+ sections,
33922
+ invokeCommand: (command) => commands.invoke?.(command, target) ?? command.file,
33923
+ commandsTableIntro: typeof tableIntro === "function" ? tableIntro(target) : tableIntro ?? `**CLI commands** available via \`${runnerTool}\`:`,
33924
+ commandRunnerTool: runnerTool
33925
+ };
33926
+ }
33927
+ const reservedTokenNames = /* @__PURE__ */ new Set();
33928
+ for (const name of targetNames) {
33929
+ for (const token of Object.keys(config4.targets[name].tokens)) {
33930
+ reservedTokenNames.add(token);
33931
+ }
33932
+ }
33933
+ const schemaOptions = {
33934
+ targetNames,
33935
+ reservedTokenNames: [...reservedTokenNames]
33936
+ };
33937
+ const schema = createFlowSchema(schemaOptions);
33938
+ const getTarget = (name) => {
33939
+ const target = targets[name];
33940
+ if (target === void 0) {
33941
+ throw new Error(`Unknown target "${name}". Known targets: ${targetNames.join(", ")}.`);
33942
+ }
33943
+ return target;
33944
+ };
33945
+ return {
33946
+ targetNames,
33947
+ targets,
33948
+ schema,
33949
+ defineFlow(input2) {
33950
+ const result = schema.safeParse(input2);
33951
+ if (!result.success) {
33952
+ const id = typeof input2 === "object" && input2 !== null && "id" in input2 ? String(input2.id) : "<unknown>";
33953
+ throw new Error(`Invalid flow "${id}":
33954
+ ${external_exports.prettifyError(result.error)}`);
33955
+ }
33956
+ return result.data;
33957
+ },
33958
+ render: (flow, name) => renderFlow(flow, getTarget(name)),
33959
+ renderMarkdown: (flow, name) => renderMarkdown(flow, getTarget(name)),
33960
+ renderProject(projects) {
33961
+ const out = [];
33962
+ for (const { flow, outputs } of projects) {
33963
+ for (const name of targetNames) {
33964
+ const output2 = outputs[name];
33965
+ if (output2 === void 0) {
33966
+ continue;
33967
+ }
33968
+ for (const file2 of renderFlow(flow, getTarget(name))) {
33969
+ out.push({
33970
+ flowId: flow.id,
33971
+ target: name,
33972
+ kind: file2.kind,
33973
+ path: resolveOutputPath(output2, file2),
33974
+ content: file2.content
33975
+ });
33976
+ }
33977
+ }
33978
+ }
33979
+ return out;
33980
+ },
33981
+ renderMermaid,
33982
+ describeFlow
33983
+ };
33984
+ }
33985
+ function dirname(path15) {
33986
+ const i = path15.lastIndexOf("/");
33987
+ return i === -1 ? "." : path15.slice(0, i);
33988
+ }
33989
+ function basename(path15) {
33990
+ return path15.slice(path15.lastIndexOf("/") + 1);
33991
+ }
33992
+ function resolveOutputPath(output2, file2) {
33993
+ const main2 = typeof output2 === "string" ? output2 : output2.main;
33994
+ if (file2.slug === "") {
33995
+ return main2;
33996
+ }
33997
+ if (file2.kind === "reference") {
33998
+ return `${dirname(main2)}/references/${file2.slug}.md`;
33999
+ }
34000
+ if (typeof output2 !== "string") {
34001
+ return output2.phase.replace(/\{phase\}/g, file2.slug);
34002
+ }
34003
+ const skillDir = dirname(main2);
34004
+ if (skillDir === ".") {
34005
+ throw new Error(`Cannot derive a sub-skill path for phase "${file2.slug}" from "${main2}"; use { main, phase } output paths.`);
34006
+ }
34007
+ return `${dirname(skillDir)}/${basename(skillDir)}-${file2.slug}/${basename(main2)}`;
34008
+ }
34009
+
34010
+ // ../node_modules/.pnpm/@agent-flows+core@0.1.1_zod@4.6.7/node_modules/@agent-flows/core/dist/targets.js
34011
+ function formatAllowedTools(allowedTools) {
34012
+ return `[${allowedTools.map((t) => JSON.stringify(t)).join(", ")}]`;
34013
+ }
34014
+ function claudeFrontmatter({ description, argumentHint, model, allowedTools }) {
34015
+ const lines = ["---", `description: ${description}`];
34016
+ if (argumentHint !== void 0) {
34017
+ lines.push(`argument-hint: ${JSON.stringify(argumentHint)}`);
34018
+ }
34019
+ if (model !== void 0) {
34020
+ lines.push(`model: ${model}`);
34021
+ }
34022
+ if (allowedTools !== void 0) {
34023
+ lines.push(`allowed-tools: ${formatAllowedTools(allowedTools)}`);
34024
+ }
34025
+ lines.push("---");
34026
+ return lines.join("\n");
34027
+ }
34028
+ function claudeSubSkillFrontmatter({ flowId, description, model, allowedTools }) {
34029
+ const lines = [
34030
+ "---",
34031
+ `name: ${flowId}`,
34032
+ `description: ${description}`,
34033
+ "user-invocable: false"
34034
+ ];
34035
+ if (model !== void 0) {
34036
+ lines.push(`model: ${model}`);
34037
+ }
34038
+ if (allowedTools !== void 0) {
34039
+ lines.push(`allowed-tools: ${formatAllowedTools(allowedTools)}`);
33864
34040
  }
34041
+ lines.push("---");
34042
+ return lines.join("\n");
34043
+ }
34044
+ function namedFrontmatter(name, description, usage, usageInBody = false) {
34045
+ const frontmatter = [
34046
+ "---",
34047
+ `name: ${name}`,
34048
+ `description: "${description}${usageInBody ? "" : usage}"`,
34049
+ "---"
34050
+ ].join("\n");
34051
+ return usageInBody && usage !== "" ? `${frontmatter}
34052
+
34053
+ ${usage.slice(2)}` : frontmatter;
34054
+ }
34055
+ var ASK_USER_QUESTION_TOKENS = {
34056
+ askUser: "with `AskUserQuestion` ",
34057
+ askVerb: "use `AskUserQuestion`",
34058
+ askVerbCap: "Use `AskUserQuestion`",
34059
+ askNoun: "AskUserQuestion"
33865
34060
  };
34061
+ var PLAIN_PROMPT_TOKENS = {
34062
+ askUser: "",
34063
+ askVerb: "ask the user",
34064
+ askVerbCap: "Ask the user",
34065
+ askNoun: "choice prompt"
34066
+ };
34067
+ function claudeCode(options) {
34068
+ return {
34069
+ tokens: {
34070
+ cmd: `/${options.plugin}:`,
34071
+ editor: "Claude Code",
34072
+ // biome-ignore lint/suspicious/noTemplateCurlyInString: shell variable rendered into skill markdown
34073
+ pluginRoot: "${CLAUDE_PLUGIN_ROOT}",
34074
+ pluginDirLookup: "",
34075
+ ...ASK_USER_QUESTION_TOKENS,
34076
+ ...options.tokens
34077
+ },
34078
+ mcpPrefix: options.mcpPrefix ?? (options.mcpServer !== void 0 ? `mcp__plugin_${options.plugin}_${options.mcpServer}__` : ""),
34079
+ argsToken: "$ARGUMENTS",
34080
+ frontmatter: claudeFrontmatter,
34081
+ subSkillFrontmatter: claudeSubSkillFrontmatter,
34082
+ subSkillTool: "Skill"
34083
+ };
34084
+ }
34085
+ function cursor(options) {
34086
+ const render = ({ flowId, description, argumentHint }) => {
34087
+ const name = `${options.plugin}-${flowId}`;
34088
+ const usage = argumentHint !== void 0 ? `. Usage: /${name} ${argumentHint}` : "";
34089
+ return namedFrontmatter(name, description, usage, options.usageInBody);
34090
+ };
34091
+ return {
34092
+ tokens: {
34093
+ cmd: `/${options.plugin}-`,
34094
+ editor: "Cursor",
34095
+ // biome-ignore lint/suspicious/noTemplateCurlyInString: shell variable rendered into skill markdown
34096
+ pluginRoot: "${CURSOR_PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT}}",
34097
+ pluginDirLookup: "",
34098
+ ...ASK_USER_QUESTION_TOKENS,
34099
+ ...options.tokens
34100
+ },
34101
+ mcpPrefix: options.mcpPrefix ?? (options.mcpServer !== void 0 ? `mcp__${options.mcpServer}__` : ""),
34102
+ argsToken: "$ARGUMENTS",
34103
+ frontmatter: render,
34104
+ subSkillFrontmatter: render
34105
+ };
34106
+ }
34107
+ function defaultEnvVar(plugin) {
34108
+ return `${plugin.toUpperCase().replace(/[^A-Z0-9]/g, "_")}_PLUGIN_DIR`;
34109
+ }
34110
+ function codexPluginDirLookup(plugin, { envVar = defaultEnvVar(plugin), markerFile }) {
34111
+ return `\`\`\`bash
34112
+ if [ -z "$${envVar}" ]; then
34113
+ ${envVar}=$(
34114
+ hit=$(find "\${CODEX_HOME:-$HOME/.codex}/plugins/cache" -maxdepth 8 -type f \\
34115
+ -path '*/${plugin}/*/${markerFile}' 2>/dev/null | head -1)
34116
+ echo "\${hit%/${markerFile}}"
34117
+ )
34118
+ export ${envVar}
34119
+ fi
34120
+ test -n "$${envVar}" || { echo "ERROR: ${plugin} plugin not installed"; exit 1; }
34121
+ \`\`\``;
34122
+ }
34123
+ function ampPluginDirLookup(plugin, { envVar = defaultEnvVar(plugin), markerFile }) {
34124
+ return `\`\`\`bash
34125
+ if [ -z "$${envVar}" ]; then
34126
+ project_root=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
34127
+ for candidate in "$project_root/.amp/plugins/${plugin}" "\${XDG_CONFIG_HOME:-$HOME/.config}/amp/plugins/${plugin}"; do
34128
+ if [ -f "$candidate/${markerFile}" ]; then
34129
+ ${envVar}="$candidate"
34130
+ break
34131
+ fi
34132
+ done
34133
+ export ${envVar}
34134
+ fi
34135
+ test -n "$${envVar}" || { echo "ERROR: ${plugin} plugin not installed"; exit 1; }
34136
+ \`\`\``;
34137
+ }
34138
+ function pluginDirTokens(plugin, pluginDir, lookup) {
34139
+ if (pluginDir === void 0) {
34140
+ return {};
34141
+ }
34142
+ return {
34143
+ pluginRoot: `\${${pluginDir.envVar ?? defaultEnvVar(plugin)}}`,
34144
+ pluginDirLookup: lookup(plugin, pluginDir)
34145
+ };
34146
+ }
34147
+ function codex(options) {
34148
+ const render = ({ flowId, description, argumentHint }) => {
34149
+ const usage = argumentHint !== void 0 ? `. Invoke with $${options.plugin}:${flowId} ${argumentHint}.` : "";
34150
+ return namedFrontmatter(flowId, description, usage, options.usageInBody);
34151
+ };
34152
+ return {
34153
+ tokens: {
34154
+ cmd: `$${options.plugin}:`,
34155
+ editor: "Codex",
34156
+ ...pluginDirTokens(options.plugin, options.pluginDir, codexPluginDirLookup),
34157
+ ...PLAIN_PROMPT_TOKENS,
34158
+ ...options.tokens
34159
+ },
34160
+ mcpPrefix: options.mcpPrefix ?? (options.mcpServer !== void 0 ? `mcp__${options.mcpServer}__` : ""),
34161
+ argsToken: "$ARGUMENTS",
34162
+ frontmatter: render,
34163
+ subSkillFrontmatter: render,
34164
+ dispatchRef: (skillName) => `\`$${options.plugin}:${skillName}\``,
34165
+ phaseReferences: options.phaseReferences ?? true
34166
+ };
34167
+ }
34168
+ function amp(options) {
34169
+ const render = ({ flowId, description, argumentHint }) => {
34170
+ const usage = argumentHint !== void 0 ? `. Invoke as ${options.plugin}:${flowId} ${argumentHint}.` : "";
34171
+ return namedFrontmatter(flowId, description, usage, options.usageInBody);
34172
+ };
34173
+ return {
34174
+ tokens: {
34175
+ cmd: `${options.plugin}:`,
34176
+ editor: "Amp",
34177
+ ...pluginDirTokens(options.plugin, options.pluginDir, ampPluginDirLookup),
34178
+ ...PLAIN_PROMPT_TOKENS,
34179
+ ...options.tokens
34180
+ },
34181
+ // Amp exposes MCP tools under their bare names.
34182
+ mcpPrefix: options.mcpPrefix ?? "",
34183
+ argsToken: "the user's request",
34184
+ frontmatter: render,
34185
+ subSkillFrontmatter: render,
34186
+ subSkillTool: "skill",
34187
+ dispatchRef: (skillName) => `\`${options.plugin}:${skillName}\``
34188
+ };
34189
+ }
33866
34190
 
33867
34191
  // ../bitfab-plugin-lib/dist/retiredAssistant.js
33868
34192
  var RETIRED_ASSISTANT_EXAMPLE_REQUESTS = [
@@ -33872,9 +34196,84 @@ var RETIRED_ASSISTANT_EXAMPLE_REQUESTS = [
33872
34196
  "Compare the baseline experiment with the two prompt-variant experiments"
33873
34197
  ];
33874
34198
 
34199
+ // ../bitfab-plugin-lib/dist/flows/kit.js
34200
+ var BITFAB_PLUGIN = "bitfab";
34201
+ var MCP_SERVER = "Bitfab";
34202
+ var CODEX_RESOLVE_PLUGIN_DIR_BASH = `\`\`\`bash
34203
+ if [ -z "$BITFAB_PLUGIN_DIR" ]; then
34204
+ BITFAB_PLUGIN_DIR=$(
34205
+ hit=$(find "\${CODEX_HOME:-$HOME/.codex}/plugins/cache" -maxdepth 6 -type f -name status.js \\
34206
+ \\( -path '*/bitfab-internal/bitfab/local/dist/commands/*' \\
34207
+ -o -path '*/bitfab/bitfab/*/dist/commands/*' \\) 2>/dev/null | head -1)
34208
+ echo "\${hit%/dist/commands/status.js}"
34209
+ )
34210
+ export BITFAB_PLUGIN_DIR
34211
+ fi
34212
+ test -n "$BITFAB_PLUGIN_DIR" || { echo "ERROR: Bitfab plugin not installed"; exit 1; }
34213
+ \`\`\``;
34214
+ var AMP_RESOLVE_PLUGIN_DIR_BASH = `\`\`\`bash
34215
+ if [ -z "$BITFAB_PLUGIN_DIR" ]; then
34216
+ project_root=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
34217
+ for candidate in "$project_root/.amp/plugins/bitfab" "\${XDG_CONFIG_HOME:-$HOME/.config}/amp/plugins/bitfab"; do
34218
+ if [ -f "$candidate/dist/commands/status.js" ]; then
34219
+ BITFAB_PLUGIN_DIR="$candidate"
34220
+ break
34221
+ fi
34222
+ done
34223
+ export BITFAB_PLUGIN_DIR
34224
+ fi
34225
+ test -n "$BITFAB_PLUGIN_DIR" || { echo "ERROR: Bitfab plugin not installed"; exit 1; }
34226
+ \`\`\``;
34227
+ var bitfabKit = createFlowKit({
34228
+ targets: {
34229
+ claude: claudeCode({ plugin: BITFAB_PLUGIN, mcpServer: MCP_SERVER }),
34230
+ cursor: cursor({ plugin: BITFAB_PLUGIN, mcpServer: MCP_SERVER }),
34231
+ codex: codex({
34232
+ plugin: BITFAB_PLUGIN,
34233
+ mcpServer: MCP_SERVER,
34234
+ tokens: {
34235
+ // biome-ignore lint/suspicious/noTemplateCurlyInString: shell variable reference rendered into skill markdown, not a JS template
34236
+ pluginRoot: "${BITFAB_PLUGIN_DIR}",
34237
+ pluginDirLookup: CODEX_RESOLVE_PLUGIN_DIR_BASH
34238
+ }
34239
+ }),
34240
+ amp: amp({
34241
+ plugin: BITFAB_PLUGIN,
34242
+ tokens: {
34243
+ // biome-ignore lint/suspicious/noTemplateCurlyInString: shell variable reference rendered into skill markdown, not a JS template
34244
+ pluginRoot: "${BITFAB_PLUGIN_DIR}",
34245
+ pluginDirLookup: AMP_RESOLVE_PLUGIN_DIR_BASH
34246
+ }
34247
+ })
34248
+ },
34249
+ sections: {
34250
+ "ask-user-question": ["claude", "cursor"],
34251
+ "plugin-dir-lookup": ["codex", "amp"],
34252
+ "exec-polling": ["codex", "amp"],
34253
+ "no-startup-banner": ["codex", "amp"],
34254
+ "web-fetch-tool": ["claude", "cursor"]
34255
+ },
34256
+ commands: {
34257
+ invoke: (command) => `node "{{pluginRoot}}/dist/commands/${command.file}"`,
34258
+ tableIntro: "**CLI commands** available via Bash (all paths relative to `{{pluginRoot}}/dist/commands/`):"
34259
+ }
34260
+ });
34261
+ var TARGET_NAMES = bitfabKit.targetNames;
34262
+ var TARGETS = bitfabKit.targets;
34263
+ var SHARED_VARIABLES = {
34264
+ parallelism: {
34265
+ default: "in parallel with",
34266
+ codex: "in the same cycle as"
34267
+ },
34268
+ togetherness: {
34269
+ default: "in parallel",
34270
+ codex: "together"
34271
+ }
34272
+ };
34273
+
33875
34274
  // ../bitfab-plugin-lib/dist/flows/assistant.js
33876
34275
  var EXAMPLE_LINES = RETIRED_ASSISTANT_EXAMPLE_REQUESTS.map((request) => `> - "${request}"`).join("\n");
33877
- var assistantFlow = Flow.parse({
34276
+ var assistantFlow = bitfabKit.defineFlow({
33878
34277
  schemaVersion: 1,
33879
34278
  id: "assistant",
33880
34279
  title: "Bitfab Assistant (retired)",
@@ -34304,7 +34703,7 @@ var REPLAY_REGISTRY_VARIABLES = {
34304
34703
  };
34305
34704
 
34306
34705
  // ../bitfab-plugin-lib/dist/flows/setup.js
34307
- var setupFlow = Flow.parse({
34706
+ var setupFlow = bitfabKit.defineFlow({
34308
34707
  schemaVersion: 1,
34309
34708
  id: "setup",
34310
34709
  title: "Bitfab Setup",
@@ -35995,7 +36394,7 @@ If **zero** valid candidates remain, skip to step {{step:analyze-repo/report}} a
35995
36394
  });
35996
36395
 
35997
36396
  // ../bitfab-plugin-lib/dist/flows/update.js
35998
- var updateFlow = Flow.parse({
36397
+ var updateFlow = bitfabKit.defineFlow({
35999
36398
  schemaVersion: 1,
36000
36399
  id: "update",
36001
36400
  title: "Bitfab Update",
@@ -36047,45 +36446,58 @@ var updateFlow = Flow.parse({
36047
36446
  plugin: "Update only the Bitfab plugin to the latest version.",
36048
36447
  sdk: "Update only the Bitfab SDK to the latest version."
36049
36448
  },
36050
- languageColumnHeaders: {
36051
- detection: "Detection (from workspace/repo)",
36052
- outdated: "Command (run from workspace dir)",
36053
- update: "Command"
36054
- },
36055
- languages: [
36056
- {
36057
- name: "typescript",
36058
- displayName: "TypeScript",
36059
- imports: "`import .* from [\"'](?:@bitfab/sdk|bitfab)[\"']` or `require\\([\"'](?:@bitfab/sdk|bitfab)[\"']\\)`",
36060
- detection: "`pnpm-lock.yaml` at repo root \u2192 pnpm; `yarn.lock` \u2192 yarn; `bun.lock` \u2192 bun; otherwise npm",
36061
- outdated: "`pnpm outdated @bitfab/sdk --json` / `npm outdated @bitfab/sdk --json` / `yarn outdated @bitfab/sdk` / `bun outdated @bitfab/sdk`",
36062
- update: "If `renameFrom` is set (legacy `bitfab` package): remove the old package and add the new one in a single command: `pnpm remove bitfab && pnpm add @bitfab/sdk@latest` / `npm uninstall bitfab && npm install @bitfab/sdk@latest` / `yarn remove bitfab && yarn add @bitfab/sdk@latest` / `bun remove bitfab && bun add @bitfab/sdk@latest`. Then update imports in source files from `bitfab` to `@bitfab/sdk`. If no rename: `pnpm update @bitfab/sdk@latest` / `yarn upgrade @bitfab/sdk@latest` / `bun update @bitfab/sdk` / `npm install @bitfab/sdk@latest`"
36063
- },
36064
- {
36065
- name: "python",
36066
- displayName: "Python",
36067
- imports: "`^\\s*(from|import) bitfab\\b`",
36068
- detection: "`uv.lock` \u2192 uv; `poetry.lock` \u2192 poetry; otherwise pip",
36069
- outdated: "`uv pip list --outdated --format=json` / `poetry show -o bitfab-py` / `pip list --outdated --format=json`",
36070
- update: "`uv add bitfab-py@latest` / `poetry add bitfab-py@latest` / `pip install -U bitfab-py` (and bump the pin in `requirements.txt` via Edit)"
36071
- },
36072
- {
36073
- name: "ruby",
36074
- displayName: "Ruby",
36075
- imports: "`require ['\"]bitfab['\"]`",
36076
- detection: "`Gemfile.lock`",
36077
- outdated: "`bundle outdated bitfab --parseable`",
36078
- update: "`bundle update bitfab`"
36079
- },
36080
- {
36081
- name: "go",
36082
- displayName: "Go",
36083
- imports: '`"github.com/Project-White-Rabbit/bitfab-go"`',
36084
- detection: "`go.mod`",
36085
- outdated: "`go list -m -u -json github.com/Project-White-Rabbit/bitfab-go`",
36086
- update: "`go get github.com/Project-White-Rabbit/bitfab-go@latest && go mod tidy`"
36449
+ tables: {
36450
+ languages: {
36451
+ keyHeader: "Language",
36452
+ columns: {
36453
+ detection: "Detection (from workspace/repo)",
36454
+ outdated: "Command (run from workspace dir)",
36455
+ update: "Command"
36456
+ },
36457
+ rows: [
36458
+ {
36459
+ key: "typescript",
36460
+ label: "TypeScript",
36461
+ cells: {
36462
+ imports: "`import .* from [\"'](?:@bitfab/sdk|bitfab)[\"']` or `require\\([\"'](?:@bitfab/sdk|bitfab)[\"']\\)`",
36463
+ detection: "`pnpm-lock.yaml` at repo root \u2192 pnpm; `yarn.lock` \u2192 yarn; `bun.lock` \u2192 bun; otherwise npm",
36464
+ outdated: "`pnpm outdated @bitfab/sdk --json` / `npm outdated @bitfab/sdk --json` / `yarn outdated @bitfab/sdk` / `bun outdated @bitfab/sdk`",
36465
+ update: "If `renameFrom` is set (legacy `bitfab` package): remove the old package and add the new one in a single command: `pnpm remove bitfab && pnpm add @bitfab/sdk@latest` / `npm uninstall bitfab && npm install @bitfab/sdk@latest` / `yarn remove bitfab && yarn add @bitfab/sdk@latest` / `bun remove bitfab && bun add @bitfab/sdk@latest`. Then update imports in source files from `bitfab` to `@bitfab/sdk`. If no rename: `pnpm update @bitfab/sdk@latest` / `yarn upgrade @bitfab/sdk@latest` / `bun update @bitfab/sdk` / `npm install @bitfab/sdk@latest`"
36466
+ }
36467
+ },
36468
+ {
36469
+ key: "python",
36470
+ label: "Python",
36471
+ cells: {
36472
+ imports: "`^\\s*(from|import) bitfab\\b`",
36473
+ detection: "`uv.lock` \u2192 uv; `poetry.lock` \u2192 poetry; otherwise pip",
36474
+ outdated: "`uv pip list --outdated --format=json` / `poetry show -o bitfab-py` / `pip list --outdated --format=json`",
36475
+ update: "`uv add bitfab-py@latest` / `poetry add bitfab-py@latest` / `pip install -U bitfab-py` (and bump the pin in `requirements.txt` via Edit)"
36476
+ }
36477
+ },
36478
+ {
36479
+ key: "ruby",
36480
+ label: "Ruby",
36481
+ cells: {
36482
+ imports: "`require ['\"]bitfab['\"]`",
36483
+ detection: "`Gemfile.lock`",
36484
+ outdated: "`bundle outdated bitfab --parseable`",
36485
+ update: "`bundle update bitfab`"
36486
+ }
36487
+ },
36488
+ {
36489
+ key: "go",
36490
+ label: "Go",
36491
+ cells: {
36492
+ imports: '`"github.com/Project-White-Rabbit/bitfab-go"`',
36493
+ detection: "`go.mod`",
36494
+ outdated: "`go list -m -u -json github.com/Project-White-Rabbit/bitfab-go`",
36495
+ update: "`go get github.com/Project-White-Rabbit/bitfab-go@latest && go mod tidy`"
36496
+ }
36497
+ }
36498
+ ]
36087
36499
  }
36088
- ],
36500
+ },
36089
36501
  phases: [
36090
36502
  {
36091
36503
  id: "setup",
@@ -36193,7 +36605,7 @@ If there are **no lines** inside \`<bitfab-sdk-status>\`, the programmatic check
36193
36605
  body: `The programmatic detection is regex-based and only knows the workspace formats we hand-coded (pnpm/npm/yarn workspaces, uv workspaces, go.work). It can miss unusual monorepo layouts, vendored SDKs, or projects using package managers we don't parse. **Always run this verification** before offering updates.
36194
36606
 
36195
36607
  - Grep the project for SDK imports (run these in parallel):
36196
- {{languages:imports}}
36608
+ {{list:languages:imports}}
36197
36609
  - For each import, find its workspace directory by walking up to the nearest \`package.json\` / \`pyproject.toml\` / \`Gemfile\` / \`go.mod\`.
36198
36610
  - Compare that set against the \`workspacePath\` values in \`<bitfab-sdk-status>\`.
36199
36611
  - For each workspace that has imports but **no** corresponding status entry, treat it as a missed detection: ask the user which package manager that workspace uses, then go to step {{step:sdk/agent-fallback}} for it (same flow as \`remoteCheckFailed: true\`).
@@ -36207,7 +36619,7 @@ If there are **no lines** inside \`<bitfab-sdk-status>\`, the programmatic check
36207
36619
  title: "Agent fallback for `remoteCheckFailed` or detection gaps",
36208
36620
  body: `For each entry where \`remoteCheckFailed: true\`, or any workspace discovered only in step {{step:sdk/verify-with-agent}}, run the package manager's native outdated command from the workspace directory. The command is authoritative, it respects private registries, mirrors, and offline caches.
36209
36621
 
36210
- {{languages:detection,outdated}}
36622
+ {{table:languages:detection,outdated}}
36211
36623
 
36212
36624
  Use the real latest from the command's output in place of \`latest\` when deciding whether to offer an upgrade.`,
36213
36625
  next: "sdk/ask-batch"
@@ -36291,7 +36703,7 @@ When no outdated workspaces remain, exit and acknowledge.`,
36291
36703
  title: "Run the update for the chosen workspace",
36292
36704
  body: `Detect the package manager from the lockfiles and run the update **from the workspace directory** (not repo root, matters in monorepos):
36293
36705
 
36294
- {{languages:update}}
36706
+ {{table:languages:update}}
36295
36707
 
36296
36708
  After the update, Read the manifest to verify the new version and confirm to the user. If a rename was performed (\`renameFrom\` was set), also grep the workspace for old import paths and update them (e.g. \`from "bitfab"\` to \`from "@bitfab/sdk"\`). Then return to the per-workspace prompt for the next workspace.`,
36297
36709
  next: "sdk/ask-per-workspace"
@@ -36303,7 +36715,7 @@ After the update, Read the manifest to verify the new version and confirm to the
36303
36715
  title: "Run updates for every outdated workspace",
36304
36716
  body: `For every workspace with \`updateAvailable: true\`, detect the package manager from the lockfiles and run the update **from each workspace directory** (not repo root):
36305
36717
 
36306
- {{languages:update}}
36718
+ {{table:languages:update}}
36307
36719
 
36308
36720
  After each update, Read the manifest to verify the new version and confirm to the user. If a rename was performed (\`renameFrom\` was set), also grep the workspace for old import paths and update them (e.g. \`from "bitfab"\` to \`from "@bitfab/sdk"\`).`,
36309
36721
  next: null
@@ -36513,7 +36925,7 @@ var SUPPORTED_COMMANDS = /* @__PURE__ */ new Set([
36513
36925
  "switchOrg",
36514
36926
  "update"
36515
36927
  ]);
36516
- var setupV2Flow = Flow.parse({
36928
+ var setupV2Flow = bitfabKit.defineFlow({
36517
36929
  ...setupFlow,
36518
36930
  id: "setup-v2",
36519
36931
  title: "Bitfab Terminal Setup",
@@ -44575,8 +44987,8 @@ var Protocol = class {
44575
44987
  }
44576
44988
  }
44577
44989
  },
44578
- listTasks: (cursor) => {
44579
- return taskStore.listTasks(cursor, sessionId);
44990
+ listTasks: (cursor2) => {
44991
+ return taskStore.listTasks(cursor2, sessionId);
44580
44992
  }
44581
44993
  };
44582
44994
  }
@@ -44866,8 +45278,8 @@ var ExperimentalServerTasks = class {
44866
45278
  *
44867
45279
  * @experimental
44868
45280
  */
44869
- async listTasks(cursor, options) {
44870
- return this._server.listTasks(cursor ? { cursor } : void 0, options);
45281
+ async listTasks(cursor2, options) {
45282
+ return this._server.listTasks(cursor2 ? { cursor: cursor2 } : void 0, options);
44871
45283
  }
44872
45284
  /**
44873
45285
  * Cancels a running task.
@@ -48666,7 +49078,7 @@ import * as p8 from "@clack/prompts";
48666
49078
  // src/setupV2Verification.ts
48667
49079
  import { spawnSync as spawnSync4 } from "child_process";
48668
49080
  import { existsSync, readFileSync } from "fs";
48669
- import { basename, relative, resolve as resolve2 } from "path";
49081
+ import { basename as basename2, relative, resolve as resolve2 } from "path";
48670
49082
  var MUTATING_TOOLS = /* @__PURE__ */ new Set(["Edit", "Write"]);
48671
49083
  var CODE_EXTENSIONS = /* @__PURE__ */ new Set([
48672
49084
  ".cjs",
@@ -48728,7 +49140,7 @@ function isReplayRuntimeCommand(command, registryPath) {
48728
49140
  return false;
48729
49141
  }
48730
49142
  const displayedPath = registryPath.replaceAll("\\", "/");
48731
- const registryName = basename(registryPath);
49143
+ const registryName = basename2(registryPath);
48732
49144
  return /(?:^|\s)(?:[^\s]+\s+)*bitfab-replay(?:\s|$)/i.test(command) && /(?:^|\s)--registry(?:\s|=)/.test(command) && (command.includes(displayedPath) || command.includes(registryName));
48733
49145
  }
48734
49146
  function isWorkflowRuntimeCommand(command) {
@@ -48936,7 +49348,7 @@ var SetupV2VerificationGate = class {
48936
49348
  message: "Edited text files must end with exactly one newline."
48937
49349
  });
48938
49350
  }
48939
- if (/BITFAB_API_KEY\s*=/.test(source) && basename(path15).startsWith(".env") && !/BITFAB_SERVICE_URL\s*=/.test(source)) {
49351
+ if (/BITFAB_API_KEY\s*=/.test(source) && basename2(path15).startsWith(".env") && !/BITFAB_SERVICE_URL\s*=/.test(source)) {
48940
49352
  issues.push({
48941
49353
  code: "missing-service-url",
48942
49354
  path: displayPath(this.cwd, path15),
@@ -49019,7 +49431,7 @@ var SetupV2VerificationGate = class {
49019
49431
  }
49020
49432
  }
49021
49433
  const registryRevision = this.touchedPaths.get(registryPath) ?? 0;
49022
- const registryName = basename(registryPath);
49434
+ const registryName = basename2(registryPath);
49023
49435
  const registryVerified = this.verificationCommands.some(
49024
49436
  ({ command, revision }) => revision >= registryRevision && (command.includes(registryPath) || command.includes(displayPath(this.cwd, registryPath)) || command.includes(registryName) || /\btsc\b/.test(command) && projectTypecheckCoversRegistry(this.cwd, registryPath))
49025
49437
  );