fifony 0.1.23 → 0.1.24

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 (34) hide show
  1. package/README.md +1 -2
  2. package/app/dist/assets/{KeyboardShortcutsHelp-BB5jLK_E.js → KeyboardShortcutsHelp-DghUbt7X.js} +1 -1
  3. package/app/dist/assets/{OnboardingWizard-xyM3Okjv.js → OnboardingWizard-DmR2BUmf.js} +1 -1
  4. package/app/dist/assets/{analytics.lazy-CfJXsh6r.js → analytics.lazy-dj9i_px8.js} +1 -1
  5. package/app/dist/assets/index-Dau_ep-t.js +43 -0
  6. package/app/dist/assets/index-Qr2OPvRO.css +1 -0
  7. package/app/dist/index.html +2 -2
  8. package/app/dist/service-worker.js +1 -1
  9. package/dist/agent/run-local.js +7 -7
  10. package/dist/agent/run-local.js.map +1 -1
  11. package/dist/{chunk-NLIVWBNV.js → chunk-D6WNSDQ5.js} +4 -4
  12. package/dist/{chunk-KT5V7N5H.js → chunk-HJFRXKDS.js} +27 -48
  13. package/dist/chunk-HJFRXKDS.js.map +1 -0
  14. package/dist/{chunk-DD5BE2W6.js → chunk-RINIJIFO.js} +5 -2
  15. package/dist/chunk-RINIJIFO.js.map +1 -0
  16. package/dist/{chunk-G6CQK2WH.js → chunk-V6IHUFZB.js} +45 -10
  17. package/dist/{chunk-G6CQK2WH.js.map → chunk-V6IHUFZB.js.map} +1 -1
  18. package/dist/cli.js +4 -4
  19. package/dist/issue-runner-QSUROSNX.js +13 -0
  20. package/dist/{issue-state-machine-NSDN4MV4.js → issue-state-machine-H4BWOONX.js} +3 -3
  21. package/dist/mcp/server.js +1 -1
  22. package/dist/{queue-workers-VHYQYYLG.js → queue-workers-BW4XANJJ.js} +2 -2
  23. package/dist/{store-FH7L6KR2.js → store-JFDHTPVH.js} +5 -5
  24. package/package.json +1 -1
  25. package/app/dist/assets/index-C1QEwHZG.js +0 -43
  26. package/app/dist/assets/index-DjmUHXd1.css +0 -1
  27. package/dist/chunk-DD5BE2W6.js.map +0 -1
  28. package/dist/chunk-KT5V7N5H.js.map +0 -1
  29. package/dist/issue-runner-6VFNHYJL.js +0 -13
  30. /package/dist/{chunk-NLIVWBNV.js.map → chunk-D6WNSDQ5.js.map} +0 -0
  31. /package/dist/{issue-runner-6VFNHYJL.js.map → issue-runner-QSUROSNX.js.map} +0 -0
  32. /package/dist/{issue-state-machine-NSDN4MV4.js.map → issue-state-machine-H4BWOONX.js.map} +0 -0
  33. /package/dist/{queue-workers-VHYQYYLG.js.map → queue-workers-BW4XANJJ.js.map} +0 -0
  34. /package/dist/{store-FH7L6KR2.js.map → store-JFDHTPVH.js.map} +0 -0
@@ -63,9 +63,11 @@ var ALLOWED_STATES = [
63
63
  "Reviewed",
64
64
  "Blocked",
65
65
  "Done",
66
+ "Merged",
66
67
  "Cancelled"
67
68
  ];
68
- var TERMINAL_STATES = /* @__PURE__ */ new Set(["Done", "Cancelled"]);
69
+ var TERMINAL_STATES = /* @__PURE__ */ new Set(["Merged", "Cancelled"]);
70
+ var COMPLETED_STATES = /* @__PURE__ */ new Set(["Done", "Merged", "Cancelled"]);
69
71
  var EXECUTING_STATES = /* @__PURE__ */ new Set(["Running", "Reviewing"]);
70
72
  var PERSIST_EVENTS_MAX = 500;
71
73
  var FAST_BOOT = CLI_ARGS.includes("--fast-boot");
@@ -753,6 +755,7 @@ export {
753
755
  FRONTEND_OFFLINE_HTML,
754
756
  ALLOWED_STATES,
755
757
  TERMINAL_STATES,
758
+ COMPLETED_STATES,
756
759
  EXECUTING_STATES,
757
760
  PERSIST_EVENTS_MAX,
758
761
  now,
@@ -779,4 +782,4 @@ export {
779
782
  mergeCapabilityProviders,
780
783
  renderPrompt
781
784
  };
782
- //# sourceMappingURL=chunk-DD5BE2W6.js.map
785
+ //# sourceMappingURL=chunk-RINIJIFO.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/concerns/constants.ts","../src/concerns/helpers.ts","../src/routing/capability-resolver.ts","../src/agents/prompting.ts","../src/agents/generated/prompts.ts"],"sourcesContent":["import { basename, dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { env, argv, cwd as getCwd } from \"node:process\";\nimport { homedir } from \"node:os\";\nimport type { IssueState } from \"../types.ts\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\nexport const PACKAGE_ROOT = resolve(__dirname, \"../..\");\nexport const CLI_ARGS = argv.slice(2);\n\nfunction readArgValue(args: string[], flag: string): string | undefined {\n const index = args.indexOf(flag);\n if (index === -1) return undefined;\n const value = args[index + 1];\n if (!value || value.startsWith(\"--\")) return undefined;\n return value;\n}\n\nfunction resolveInputPath(value: string): string {\n if (value.startsWith(\"~/\")) {\n return resolve(homedir(), value.slice(2));\n }\n return resolve(value);\n}\n\nexport function resolvePersistenceRoot(value: string): string {\n const resolved = value.startsWith(\"file://\")\n ? fileURLToPath(value)\n : resolveInputPath(value);\n\n return basename(resolved) === \".fifony\"\n ? resolved\n : join(resolved, \".fifony\");\n}\n\nconst CLI_WORKSPACE_ROOT = readArgValue(CLI_ARGS, \"--workspace\");\nconst CLI_PERSISTENCE = readArgValue(CLI_ARGS, \"--persistence\");\n\nexport const TARGET_ROOT = resolveInputPath(\n env.FIFONY_WORKSPACE_ROOT ?? CLI_WORKSPACE_ROOT ?? getCwd(),\n);\n\nexport const STATE_ROOT = resolvePersistenceRoot(\n env.FIFONY_PERSISTENCE\n ?? CLI_PERSISTENCE\n ?? env.FIFONY_BOOTSTRAP_ROOT\n ?? TARGET_ROOT,\n);\n\nexport const SOURCE_ROOT = `${STATE_ROOT}/source`;\nexport const WORKSPACE_ROOT = `${STATE_ROOT}/workspaces`;\nexport const SOURCE_MARKER = `${SOURCE_ROOT}/.fifony-local-source-ready`;\n\nexport const ATTACHMENTS_ROOT = `${STATE_ROOT}/attachments`;\n\nexport const S3DB_DATABASE_PATH = `${STATE_ROOT}/fifony.sqlite`;\n\nexport const S3DB_RUNTIME_RESOURCE = \"runtime_state\";\nexport const S3DB_ISSUE_RESOURCE = \"issues\";\nexport const S3DB_ISSUE_PLAN_RESOURCE = \"issue_plans\";\nexport const S3DB_EVENT_RESOURCE = \"events\";\nexport const S3DB_SETTINGS_RESOURCE = \"settings\";\nexport const S3DB_AGENT_SESSION_RESOURCE = \"agent_sessions\";\nexport const S3DB_AGENT_PIPELINE_RESOURCE = \"agent_pipelines\";\nexport const S3DB_RUNTIME_RECORD_ID = \"current\";\nexport const S3DB_RUNTIME_SCHEMA_VERSION = 1;\n\nexport const FRONTEND_DIR = `${PACKAGE_ROOT}/app/dist`;\nexport const FRONTEND_INDEX = `${FRONTEND_DIR}/index.html`;\nexport const FRONTEND_MANIFEST_JSON = `${FRONTEND_DIR}/manifest.webmanifest`;\nexport const FRONTEND_SERVICE_WORKER_JS = `${FRONTEND_DIR}/service-worker.js`;\nexport const FRONTEND_ICON_SVG = `${FRONTEND_DIR}/icon.svg`;\nexport const FRONTEND_MASKABLE_ICON_SVG = `${FRONTEND_DIR}/icon-maskable.svg`;\nexport const FRONTEND_OFFLINE_HTML = `${FRONTEND_DIR}/offline.html`;\n\nexport const DEBUG_BOOT = env.FIFONY_DEBUG_BOOT === \"1\";\n\nexport const ALLOWED_STATES: IssueState[] = [\n \"Planning\",\n \"Planned\",\n \"Queued\",\n \"Running\",\n \"Reviewing\",\n \"Reviewed\",\n \"Blocked\",\n \"Done\",\n \"Merged\",\n \"Cancelled\",\n];\n\n/** Truly final — workspace can be cleaned, no more work expected. */\nexport const TERMINAL_STATES = new Set<IssueState>([\"Merged\", \"Cancelled\"]);\n/** Done or final — no more automated work, but merge may still be pending. */\nexport const COMPLETED_STATES = new Set<IssueState>([\"Done\", \"Merged\", \"Cancelled\"]);\nexport const EXECUTING_STATES = new Set<IssueState>([\"Running\", \"Reviewing\"]);\nexport const PERSIST_EVENTS_MAX = 500;\n\n// ── CLI skip flags ──────────────────────────────────────────────────────────\nconst FAST_BOOT = CLI_ARGS.includes(\"--fast-boot\");\nexport const SKIP_SOURCE = FAST_BOOT || CLI_ARGS.includes(\"--skip-source\");\nexport const SKIP_SCAN = FAST_BOOT || CLI_ARGS.includes(\"--skip-scan\");\nexport const SKIP_RECOVERY = FAST_BOOT || CLI_ARGS.includes(\"--skip-recovery\");\n","import { env } from \"node:process\";\nimport { parse as parseYaml } from \"yaml\";\nimport type { IssueState, JsonRecord } from \"../types.ts\";\nimport { ALLOWED_STATES, DEBUG_BOOT } from \"./constants.ts\";\n\nexport function now(): string {\n return new Date().toISOString();\n}\n\n/** Returns ISO week string like \"2026-W12\" for a given date (defaults to now). */\nexport function isoWeek(date?: Date | string): string {\n const d = date ? new Date(date) : new Date();\n if (Number.isNaN(d.getTime())) return \"\";\n // ISO week: week starts Monday, week 1 contains Jan 4\n const tmp = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate()));\n const dayNum = tmp.getUTCDay() || 7; // Monday=1 ... Sunday=7\n tmp.setUTCDate(tmp.getUTCDate() + 4 - dayNum);\n const yearStart = new Date(Date.UTC(tmp.getUTCFullYear(), 0, 1));\n const weekNo = Math.ceil(((tmp.getTime() - yearStart.getTime()) / 86_400_000 + 1) / 7);\n return `${tmp.getUTCFullYear()}-W${String(weekNo).padStart(2, \"0\")}`;\n}\n\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction resolveEnvVar(value: string): string {\n if (!value.startsWith(\"$\")) return value;\n const varName = value.slice(1);\n const resolved = env[varName];\n return resolved && resolved.trim().length > 0 ? resolved.trim() : \"\";\n}\n\nexport function toStringValue(value: unknown, fallback = \"\"): string {\n if (typeof value !== \"string\" || value.trim().length === 0) return fallback;\n const trimmed = value.trim();\n // Resolve $VAR_NAME indirection (full value is a single env var reference)\n if (trimmed.startsWith(\"$\") && /^\\$[A-Za-z_][A-Za-z0-9_]*$/.test(trimmed)) {\n const resolved = resolveEnvVar(trimmed);\n return resolved.length > 0 ? resolved : fallback;\n }\n return trimmed;\n}\n\nexport function toNumberValue(value: unknown, fallback = 1): number {\n const parsed =\n typeof value === \"number\"\n ? value\n : typeof value === \"string\"\n ? Number.parseInt(value, 10)\n : Number.NaN;\n\n return Number.isFinite(parsed) && parsed > 0 ? Math.round(parsed) : fallback;\n}\n\nexport function toBooleanValue(value: unknown, fallback: boolean): boolean {\n return typeof value === \"boolean\" ? value : fallback;\n}\n\nexport function toStringArray(value: unknown): string[] {\n if (!Array.isArray(value)) return [];\n return value\n .filter((entry): entry is string => typeof entry === \"string\" && entry.trim().length > 0)\n .map((entry) => entry.trim());\n}\n\nexport function clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n}\n\nexport function parseIssueState(value: unknown): IssueState | undefined {\n const raw = typeof value === \"string\" ? value.trim() : \"\";\n if ((ALLOWED_STATES as readonly string[]).includes(raw)) {\n return raw as IssueState;\n }\n return undefined;\n}\n\nexport function normalizeState(value: unknown, fallback: IssueState = \"Planning\"): IssueState {\n return parseIssueState(value) ?? fallback;\n}\n\nexport function parseEnvNumber(name: string, fallback: number): number {\n return toNumberValue(env[name], fallback);\n}\n\nexport function parseIntArg(value: string, fallback: number): number {\n const parsed = Number.parseInt(value, 10);\n return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;\n}\n\nexport function parsePositiveIntEnv(name: string, fallback: number): number {\n const source = env[name];\n if (!source) return fallback;\n return parseIntArg(source, fallback);\n}\n\nexport function withRetryBackoff(attempt: number, baseDelayMs: number): number {\n return Math.min(baseDelayMs * 2 ** attempt, 5 * 60 * 1000);\n}\n\nexport function idToSafePath(value: string): string {\n return value.toLowerCase().replace(/[^a-z0-9._-]/g, \"-\");\n}\n\nexport function appendFileTail(target: string, text: string, maxLength: number): string {\n const merged = `${target}\\n${text}`;\n if (merged.length <= maxLength) return merged;\n return `…${merged.slice(-(maxLength - 1))}`;\n}\n\nexport function parseFrontMatter(source: string): { config: JsonRecord; body: string } {\n const match = source.match(/^---\\s*\\n([\\s\\S]*?)\\n---\\s*\\n?([\\s\\S]*)$/);\n if (!match) {\n return { config: {}, body: source.trim() };\n }\n\n const rawConfig = parseYaml(match[1]) as unknown;\n const config = rawConfig && typeof rawConfig === \"object\" && !Array.isArray(rawConfig)\n ? rawConfig as JsonRecord\n : {};\n\n return { config, body: match[2].trim() };\n}\n\nexport function getNestedRecord(source: unknown, key: string): JsonRecord {\n if (!source || typeof source !== \"object\" || Array.isArray(source)) return {};\n const value = (source as JsonRecord)[key];\n return value && typeof value === \"object\" && !Array.isArray(value)\n ? value as JsonRecord\n : {};\n}\n\nexport function getNestedString(source: unknown, key: string, fallback = \"\"): string {\n if (!source || typeof source !== \"object\" || Array.isArray(source)) return fallback;\n return toStringValue((source as JsonRecord)[key], fallback);\n}\n\nexport function getNestedNumber(source: unknown, key: string, fallback: number): number {\n if (!source || typeof source !== \"object\" || Array.isArray(source)) return fallback;\n return toNumberValue((source as JsonRecord)[key], fallback);\n}\n\nexport function debugBoot(message: string): void {\n if (!DEBUG_BOOT) return;\n console.error(`[FIFONY_DEBUG_BOOT] ${message}`);\n}\n\nexport function fail(message: string): never {\n console.error(message);\n process.exit(1);\n}\n\n/** Extract top-level JSON object candidates from a text that may contain prose around them. */\nexport function extractJsonObjects(text: string): string[] {\n const results: string[] = [];\n let depth = 0;\n let start = -1;\n let inStr = false;\n let esc = false;\n\n for (let i = 0; i < text.length; i++) {\n const ch = text[i];\n if (inStr) {\n if (esc) { esc = false; continue; }\n if (ch === \"\\\\\") { esc = true; continue; }\n if (ch === \"\\\"\") { inStr = false; }\n continue;\n }\n if (ch === \"\\\"\") { inStr = true; continue; }\n if (ch === \"{\") {\n if (depth === 0) start = i;\n depth++;\n } else if (ch === \"}\") {\n depth = Math.max(0, depth - 1);\n if (depth === 0 && start >= 0) {\n results.push(text.slice(start, i + 1));\n start = -1;\n }\n }\n }\n return results;\n}\n\n/**\n * Attempt to repair truncated JSON by closing open strings, arrays, and objects.\n * Returns the repaired string or null if no valid JSON start was found.\n */\nexport function repairTruncatedJson(text: string): string | null {\n // Find the first top-level '{' to start from\n const firstBrace = text.indexOf(\"{\");\n if (firstBrace < 0) return null;\n\n let json = text.slice(firstBrace);\n\n // Track nesting to figure out what needs closing\n let inStr = false;\n let esc = false;\n const stack: string[] = []; // tracks '{' and '['\n\n for (let i = 0; i < json.length; i++) {\n const ch = json[i];\n if (inStr) {\n if (esc) { esc = false; continue; }\n if (ch === \"\\\\\") { esc = true; continue; }\n if (ch === \"\\\"\") { inStr = false; }\n continue;\n }\n if (ch === \"\\\"\") { inStr = true; continue; }\n if (ch === \"{\") stack.push(\"{\");\n else if (ch === \"[\") stack.push(\"[\");\n else if (ch === \"}\") { if (stack.length > 0 && stack[stack.length - 1] === \"{\") stack.pop(); }\n else if (ch === \"]\") { if (stack.length > 0 && stack[stack.length - 1] === \"[\") stack.pop(); }\n }\n\n // Nothing to repair — JSON is already complete\n if (!inStr && stack.length === 0) return json;\n\n // Close open string\n if (inStr) {\n // Remove trailing incomplete escape sequence\n if (json.endsWith(\"\\\\\")) json = json.slice(0, -1);\n json += \"\\\"\";\n }\n\n // Remove trailing comma or colon (invalid before closing bracket)\n json = json.replace(/[,:\\s]+$/, \"\");\n\n // Close open brackets in reverse order\n while (stack.length > 0) {\n const open = stack.pop();\n json += open === \"{\" ? \"}\" : \"]\";\n }\n\n return json;\n}\n","export type CapabilityResolverRole = \"planner\" | \"executor\" | \"reviewer\";\n\nexport type CapabilityResolverIssue = {\n id?: string;\n identifier?: string;\n title: string;\n description?: string;\n labels?: string[];\n paths?: string[];\n};\n\nexport type CapabilityResolverBaseProvider = {\n provider: string;\n role: CapabilityResolverRole;\n command: string;\n profile?: string;\n profilePath?: string;\n profileInstructions?: string;\n};\n\nexport type CapabilityResolverSuggestion = {\n provider: string;\n role: CapabilityResolverRole;\n profile: string;\n reason: string;\n};\n\nexport type CapabilityResolution = {\n category: string;\n rationale: string[];\n overlays: string[];\n providers: CapabilityResolverSuggestion[];\n};\n\nexport type CapabilityResolverOverride = {\n match?: {\n labels?: string[];\n terms?: string[];\n category?: string;\n paths?: string[];\n };\n category?: string;\n rationale?: string[];\n overlays?: string[];\n providers?: CapabilityResolverSuggestion[];\n};\n\nexport type CapabilityResolverOptions = {\n enabled?: boolean;\n overrides?: CapabilityResolverOverride[];\n};\n\nfunction tokenize(issue: CapabilityResolverIssue): string {\n const labels = (issue.labels ?? []).filter((label) => !label.startsWith(\"capability:\") && !label.startsWith(\"overlay:\"));\n return [\n issue.identifier ?? \"\",\n issue.title,\n issue.description ?? \"\",\n ...labels,\n ...(issue.paths ?? []),\n ].join(\" \").toLowerCase();\n}\n\nfunction normalizePath(value: string): string {\n return value.trim().replaceAll(\"\\\\\", \"/\").toLowerCase();\n}\n\nexport function inferCapabilityPaths(issue: CapabilityResolverIssue): string[] {\n const labels = (issue.labels ?? []).filter((label) => !label.startsWith(\"capability:\") && !label.startsWith(\"overlay:\"));\n const sources = [issue.title, issue.description ?? \"\", ...labels];\n const matches = new Set<string>();\n const pattern = /(?:[A-Za-z0-9._-]+\\/)+(?:[A-Za-z0-9._-]+)|(?:[A-Za-z0-9._-]+\\.(?:ts|tsx|js|jsx|mjs|cjs|css|scss|sass|less|html|md|mdx|json|yml|yaml|sql|sh))+/g;\n\n for (const source of sources) {\n for (const match of source.match(pattern) ?? []) {\n matches.add(normalizePath(match));\n }\n }\n\n return [...matches];\n}\n\nfunction getIssuePaths(issue: CapabilityResolverIssue): string[] {\n return [...new Set([\n ...(issue.paths ?? [])\n .filter((value): value is string => typeof value === \"string\" && value.trim().length > 0)\n .map(normalizePath),\n ...inferCapabilityPaths(issue),\n ])];\n}\n\nfunction hasAny(text: string, terms: string[]): boolean {\n return terms.some((term) => text.includes(term));\n}\n\nfunction hasPathMatch(paths: string[], fragments: string[] = [], extensions: string[] = []): boolean {\n return paths.some((path) => {\n if (fragments.some((fragment) => path.includes(fragment))) {\n return true;\n }\n\n return extensions.some((extension) => path.endsWith(extension));\n });\n}\n\nfunction buildResolution(\n category: string,\n rationale: string[],\n overlays: string[],\n providers: CapabilityResolverSuggestion[],\n): CapabilityResolution {\n return {\n category,\n rationale,\n overlays,\n providers,\n };\n}\n\nfunction uniq(values: string[]): string[] {\n return [...new Set(values.filter(Boolean))];\n}\n\nfunction matchesOverride(\n issue: CapabilityResolverIssue,\n resolution: CapabilityResolution,\n override: CapabilityResolverOverride,\n): boolean {\n const match = override.match ?? {};\n const issueLabels = new Set((issue.labels ?? []).map((label) => label.toLowerCase()));\n const text = tokenize(issue);\n const paths = getIssuePaths(issue);\n\n if (match.category && match.category !== resolution.category) {\n return false;\n }\n\n if (match.labels?.length) {\n const requiredLabels = match.labels.map((label) => label.toLowerCase());\n if (!requiredLabels.every((label) => issueLabels.has(label))) {\n return false;\n }\n }\n\n if (match.terms?.length) {\n if (!match.terms.some((term) => text.includes(term.toLowerCase()))) {\n return false;\n }\n }\n\n if (match.paths?.length) {\n const expectedPaths = match.paths.map((path) => normalizePath(path));\n if (!expectedPaths.some((expectedPath) => paths.some((path) => path.includes(expectedPath)))) {\n return false;\n }\n }\n\n return Boolean(match.category || match.labels?.length || match.terms?.length || match.paths?.length);\n}\n\nfunction applyOverrides(\n issue: CapabilityResolverIssue,\n resolution: CapabilityResolution,\n options?: CapabilityResolverOptions,\n): CapabilityResolution {\n if (options?.enabled === false) {\n return buildResolution(\n \"workflow-disabled\",\n [\"Automatic capability routing was disabled by workflow configuration.\"],\n [],\n [\n { provider: \"codex\", role: \"executor\", profile: \"\", reason: \"Fallback executor because routing is disabled.\" },\n ],\n );\n }\n\n const override = options?.overrides?.find((entry) => matchesOverride(issue, resolution, entry));\n if (!override) {\n return resolution;\n }\n\n return {\n category: override.category ?? resolution.category,\n rationale: uniq([...(resolution.rationale ?? []), ...(override.rationale ?? []), \"Workflow routing override applied.\"]),\n overlays: uniq([...(resolution.overlays ?? []), ...(override.overlays ?? [])]),\n providers: override.providers?.length ? override.providers : resolution.providers,\n };\n}\n\nexport function resolveTaskCapabilities(\n issue: CapabilityResolverIssue,\n options?: CapabilityResolverOptions,\n): CapabilityResolution {\n const text = tokenize(issue);\n const paths = getIssuePaths(issue);\n const frontendPathMatch = hasPathMatch(\n paths,\n [\"src/web\", \"web\", \"frontend\", \"ui\", \"component\", \"dashboard\", \"style\", \"apps/web\"],\n [\".css\", \".scss\", \".sass\", \".less\", \".html\", \".tsx\", \".jsx\", \".vue\", \".svelte\"],\n );\n const securityPathMatch = hasPathMatch(\n paths,\n [\"security\", \"auth\", \"crypto\", \"secret\", \"permission\", \"token\"],\n [\".pem\", \".key\", \".crt\"],\n );\n const architecturePathMatch = hasPathMatch(\n paths,\n [\"workflow.md\", \"architecture.md\", \"spec.md\", \"claude.md\", \"openspec/\"],\n [],\n );\n const devopsPathMatch = hasPathMatch(\n paths,\n [\".github/workflows\", \"docker\", \"k8s\", \"helm\", \"terraform\", \"infra\", \"deploy\", \"release\"],\n [\".yml\", \".yaml\", \".tf\"],\n );\n const backendPathMatch = hasPathMatch(\n paths,\n [\"src/api\", \"api\", \"src/protocol\", \"protocol\", \"server\", \"persistence\", \"scanner\", \"ws\", \"websocket\", \"db\", \"apps/api\"],\n [\".sql\"],\n );\n const docsPathMatch = hasPathMatch(\n paths,\n [\"docs\", \"readme\", \"guide\", \"tutorial\"],\n [\".md\", \".mdx\"],\n );\n let resolution: CapabilityResolution;\n\n if (frontendPathMatch || hasAny(text, [\"frontend\", \"ui\", \"ux\", \"design\", \"css\", \"html\", \"layout\", \"component\", \"react\", \"vue\"])) {\n resolution = buildResolution(\n \"frontend-ui\",\n [\n ...(frontendPathMatch ? [\"Detected frontend-oriented target paths or file extensions.\"] : []),\n \"Detected frontend or design-oriented keywords in the task.\",\n \"Use Claude to plan and review, Codex to implement.\",\n \"Apply impeccable-style polish as a review overlay when available.\",\n ],\n [\"impeccable\", \"frontend-design\"],\n [\n { provider: \"claude\", role: \"planner\", profile: \"agency-ui-designer\", reason: \"UI planning and structure.\" },\n { provider: \"codex\", role: \"executor\", profile: \"agency-frontend-developer\", reason: \"Frontend implementation.\" },\n { provider: \"claude\", role: \"reviewer\", profile: \"agency-accessibility-auditor\", reason: \"Critical UX and accessibility review.\" },\n ],\n );\n return applyOverrides(issue, resolution, options);\n }\n\n if (securityPathMatch || hasAny(text, [\"security\", \"auth\", \"oauth\", \"token\", \"secret\", \"permission\", \"compliance\", \"vulnerability\"])) {\n resolution = buildResolution(\n \"security\",\n [\n ...(securityPathMatch ? [\"Detected security-sensitive target paths or file extensions.\"] : []),\n \"Detected security-sensitive keywords.\",\n \"Use a security profile to scope the work and keep a strict review pass.\",\n ],\n [\"security-review\"],\n [\n { provider: \"claude\", role: \"planner\", profile: \"agency-security-engineer\", reason: \"Threat and risk framing.\" },\n { provider: \"codex\", role: \"executor\", profile: \"agency-security-engineer\", reason: \"Implementation with security context.\" },\n { provider: \"claude\", role: \"reviewer\", profile: \"agency-code-reviewer\", reason: \"Independent correctness review.\" },\n ],\n );\n return applyOverrides(issue, resolution, options);\n }\n\n if (architecturePathMatch || hasAny(text, [\"architecture\", \"design doc\", \"spec\", \"workflow\", \"orchestr\", \"roadmap\", \"plan\"])) {\n resolution = buildResolution(\n \"architecture\",\n [\n ...(architecturePathMatch ? [\"Detected workflow, architecture, or specification files in the targeted paths.\"] : []),\n \"Detected architecture or planning-oriented keywords.\",\n \"Favor stronger planning and review roles around the executor.\",\n ],\n [\"spec-review\"],\n [\n { provider: \"claude\", role: \"planner\", profile: \"agency-software-architect\", reason: \"Architecture and system framing.\" },\n { provider: \"codex\", role: \"executor\", profile: \"agency-senior-developer\", reason: \"Translate architecture into implementation.\" },\n { provider: \"claude\", role: \"reviewer\", profile: \"agency-code-reviewer\", reason: \"Challenge assumptions and regressions.\" },\n ],\n );\n return applyOverrides(issue, resolution, options);\n }\n\n if (devopsPathMatch || hasAny(text, [\"deploy\", \"release\", \"ci\", \"cicd\", \"github actions\", \"docker\", \"terraform\", \"kubernetes\"])) {\n resolution = buildResolution(\n \"devops\",\n [\n ...(devopsPathMatch ? [\"Detected deployment, infrastructure, or CI/CD paths in the task scope.\"] : []),\n \"Detected release, deployment, or infrastructure keywords.\",\n \"Use a delivery-focused planner and a stricter reliability review pass.\",\n ],\n [\"delivery-review\"],\n [\n { provider: \"claude\", role: \"planner\", profile: \"agency-devops-automator\", reason: \"CI/CD and deployment framing.\" },\n { provider: \"codex\", role: \"executor\", profile: \"agency-devops-automator\", reason: \"Implement workflow and release changes.\" },\n { provider: \"claude\", role: \"reviewer\", profile: \"agency-sre-site-reliability-engineer\", reason: \"Reliability and rollback review.\" },\n ],\n );\n return applyOverrides(issue, resolution, options);\n }\n\n if (hasAny(text, [\"bug\", \"fix\", \"regression\", \"debug\", \"crash\", \"broken\", \"error\", \"fail\"])) {\n resolution = buildResolution(\n \"bugfix\",\n [\n \"Detected bug-fix or debugging keywords.\",\n \"Use Codex to execute the fix and Claude to frame and verify the change.\",\n ],\n [\"debug\"],\n [\n { provider: \"claude\", role: \"planner\", profile: \"agency-code-reviewer\", reason: \"Clarify failure mode and acceptance criteria.\" },\n { provider: \"codex\", role: \"executor\", profile: \"agency-senior-developer\", reason: \"Implement and iterate quickly.\" },\n { provider: \"claude\", role: \"reviewer\", profile: \"agency-code-reviewer\", reason: \"Catch regressions and weak reasoning.\" },\n ],\n );\n return applyOverrides(issue, resolution, options);\n }\n\n if (backendPathMatch || hasAny(text, [\"api\", \"backend\", \"database\", \"protocol\", \"server\", \"ws\", \"websocket\", \"persistence\"])) {\n resolution = buildResolution(\n \"backend\",\n [\n ...(backendPathMatch ? [\"Detected backend, protocol, or persistence paths in the task scope.\"] : []),\n \"Detected backend, API, protocol, or persistence keywords.\",\n \"Use backend-oriented planning and critical review around the executor.\",\n ],\n [\"backend-review\"],\n [\n { provider: \"claude\", role: \"planner\", profile: \"agency-backend-architect\", reason: \"API and data-model framing.\" },\n { provider: \"codex\", role: \"executor\", profile: \"agency-senior-developer\", reason: \"Implement the backend changes.\" },\n { provider: \"claude\", role: \"reviewer\", profile: \"agency-code-reviewer\", reason: \"Critical regression review.\" },\n ],\n );\n return applyOverrides(issue, resolution, options);\n }\n\n if (docsPathMatch || hasAny(text, [\"docs\", \"readme\", \"guide\", \"documentation\", \"tutorial\"])) {\n resolution = buildResolution(\n \"documentation\",\n [\n ...(docsPathMatch ? [\"Detected documentation-oriented paths or file extensions.\"] : []),\n \"Detected documentation keywords.\",\n \"Use writing-oriented planning with an implementation pass that can still edit code and docs together.\",\n ],\n [\"documentation\"],\n [\n { provider: \"claude\", role: \"planner\", profile: \"agency-technical-writer\", reason: \"Structure and narrative.\" },\n { provider: \"codex\", role: \"executor\", profile: \"agency-technical-writer\", reason: \"Apply documentation edits in repo context.\" },\n { provider: \"claude\", role: \"reviewer\", profile: \"agency-code-reviewer\", reason: \"Check coherence with the implementation.\" },\n ],\n );\n return applyOverrides(issue, resolution, options);\n }\n\n resolution = buildResolution(\n \"default\",\n [\n \"No specialized pattern matched strongly.\",\n \"Default to a balanced planner/executor/reviewer pipeline using both Claude and Codex.\",\n ],\n [],\n [\n { provider: \"claude\", role: \"planner\", profile: \"agency-senior-project-manager\", reason: \"Clarify scope and acceptance criteria.\" },\n { provider: \"codex\", role: \"executor\", profile: \"agency-senior-developer\", reason: \"Implement the requested change.\" },\n { provider: \"claude\", role: \"reviewer\", profile: \"agency-code-reviewer\", reason: \"Critical review before closure.\" },\n ],\n );\n\n return applyOverrides(issue, resolution, options);\n}\n\nexport function mergeCapabilityProviders(\n baseProviders: CapabilityResolverBaseProvider[],\n resolution: CapabilityResolution,\n): CapabilityResolverBaseProvider[] {\n return resolution.providers.map((suggestion) => {\n const exact = baseProviders.find((provider) => provider.provider === suggestion.provider && provider.role === suggestion.role);\n const sameRole = baseProviders.find((provider) => provider.role === suggestion.role);\n const sameProvider = baseProviders.find((provider) => provider.provider === suggestion.provider);\n const base = exact ?? sameRole ?? sameProvider;\n\n return {\n provider: suggestion.provider,\n role: suggestion.role,\n command: base?.command ?? \"\",\n profile: suggestion.profile || base?.profile || \"\",\n profilePath: base?.profilePath ?? \"\",\n profileInstructions: base?.profileInstructions ?? \"\",\n };\n });\n}\n","import { TemplateEngine } from \"recker\";\nimport { PROMPT_TEMPLATES, type PromptTemplateName } from \"./generated/prompts.ts\";\n\nconst engine = new TemplateEngine({\n cache: true,\n format: \"raw\",\n strict: false,\n});\n\nfunction normalizePrompt(text: string): string {\n return text\n .replace(/\\r\\n/g, \"\\n\")\n .replace(/\\n{3,}/g, \"\\n\\n\")\n .trim();\n}\n\nexport async function renderPrompt(\n name: PromptTemplateName,\n context: Record<string, unknown> = {},\n): Promise<string> {\n return renderPromptString(PROMPT_TEMPLATES[name], context);\n}\n\nexport async function renderPromptString(\n template: string,\n context: Record<string, unknown> = {},\n): Promise<string> {\n const rendered = await engine.render(template, context);\n return normalizePrompt(rendered);\n}\n","// Generated by scripts/generate-prompts.ts. Do not edit directly.\n\nexport const PROMPT_TEMPLATES = {\n \"agent-provider-base\": \"{{#if isPlanner}}\\nRole: planner.\\nAnalyze the issue and prepare an execution plan for the implementation agents.\\nDo not claim the issue is complete unless the plan itself is the deliverable.\\n{{else}}\\n{{#if isReviewer}}\\nRole: reviewer.\\nInspect the workspace and review the current implementation critically.\\nIf rework is required, emit `FIFONY_STATUS=continue` and provide actionable `nextPrompt` feedback.\\nEmit `FIFONY_STATUS=done` only when the work is acceptable.\\n{{else}}\\nRole: executor.\\nImplement the required changes in the workspace.\\nUse any planner guidance or prior reviewer feedback already persisted in the workspace.\\n{{/if}}\\n{{/if}}\\n\\n{{#if hasImpeccableOverlay}}\\nImpeccable overlay is active.\\nRaise the bar on UI polish, clarity, responsiveness, visual hierarchy, and interaction quality.\\n{{#if isReviewer}}\\nReview with a stricter frontend and product-quality standard than a normal correctness-only pass.\\n{{else}}\\nWhen touching frontend work, do not settle for baseline implementation quality.\\n{{/if}}\\n{{/if}}\\n\\n{{#if hasFrontendDesignOverlay}}\\nFrontend-design overlay is active.\\nPrefer stronger hierarchy, spacing, and readability decisions over generic implementation choices.\\n{{/if}}\\n\\n{{#if profileInstructions}}\\n## Agent Profile\\n{{profileInstructions}}\\n{{/if}}\\n\\n{{#if skillContext}}\\n{{skillContext}}\\n{{/if}}\\n\\n{{#if capabilityCategory}}\\nCapability routing: {{capabilityCategory}}.\\nSelection reason: {{selectionReason}}\\n{{#if overlays.length}}\\nOverlays: {{overlays | join \\\", \\\"}}.\\n{{/if}}\\n{{/if}}\\n\\n{{#if targetPaths.length}}\\nTarget paths: {{targetPaths | join \\\", \\\"}}\\n{{/if}}\\n\\nWorkspace: {{workspacePath}}\\n\\n{{basePrompt}}\\n\", // src/agents/prompts/agent-provider-base.stub.md\n \"agent-turn\": \"Continue working on {{issueIdentifier}}.\\nTurn {{turnIndex}} of {{maxTurns}}.\\n\\nBase objective:\\n{{basePrompt}}\\n\\nContinuation guidance:\\n{{continuation}}\\n\\nPrevious command output tail:\\n```text\\n{{outputTail}}\\n```\\n\\nBefore exiting successfully, emit one of the following control markers:\\n- `FIFONY_STATUS=continue` if more turns are required.\\n- `FIFONY_STATUS=done` if the issue is complete.\\n- `FIFONY_STATUS=blocked` if manual intervention is required.\\nYou may also write `fifony-result.json` with `{ \\\"status\\\": \\\"...\\\", \\\"summary\\\": \\\"...\\\", \\\"nextPrompt\\\": \\\"...\\\" }`.\\n\", // src/agents/prompts/agent-turn.stub.md\n \"compile-execution-claude\": \"{{#if isPlanner}}\\nRole: planner. Analyze the issue and prepare an execution plan.\\n{{else}}\\n{{#if isReviewer}}\\nRole: reviewer. Inspect and review the implementation critically.\\n{{else}}\\nRole: executor. Implement the required changes.\\n{{/if}}\\n{{/if}}\\n\\n{{#if profileInstructions}}\\n## Agent Profile\\n{{profileInstructions}}\\n{{/if}}\\n\\n{{#if skillContext}}\\n{{skillContext}}\\n{{/if}}\\n\\n{{planPrompt}}\\n\\n{{#if subagentsToUse.length}}\\n## Subagent Strategy (Claude-specific)\\nYou have access to the Agent tool for spawning subagents. Use them for:\\n{{#each subagentsToUse}}\\n- **{{name}}** ({{role}}): {{why}}\\n{{/each}}\\n\\nLaunch subagents for independent subtasks to maximize parallelism.\\nUse the main thread for coordination and integration.\\n{{/if}}\\n\\n{{#if skillsToUse.length}}\\n## Skills to Activate\\n{{#each skillsToUse}}\\n- Invoke **/{{name}}** - {{why}}\\n{{/each}}\\n{{/if}}\\n\\n{{#if suggestedPaths.length}}\\nTarget paths: {{suggestedPaths | join \\\", \\\"}}\\n{{/if}}\\n\\nWorkspace: {{workspacePath}}\\n\\nIssue: {{issueIdentifier}}\\nTitle: {{title}}\\nDescription: {{description}}\\n\\n## Structured Input\\nThe file `fifony-execution-payload.json` in the workspace contains the canonical structured data for this task.\\nUse it as the source of truth for constraints, success criteria, execution intent, and plan details.\\nIf there is any conflict between this prompt and the structured fields in the payload, prioritize the payload.\\n\\n{{#if validationItems.length}}\\n## Pre-completion enforcement\\nBefore reporting done, verify:\\n{{#each validationItems}}\\n- {{value}}\\n{{/each}}\\n{{/if}}\\n\", // src/agents/prompts/compile-execution-claude.stub.md\n \"compile-execution-codex\": \"{{#if isReviewer}}\\nRole: reviewer. Inspect and review the implementation critically.\\n{{else}}\\n{{#if isPlanner}}\\nRole: planner. Analyze and prepare an execution plan.\\n{{else}}\\nRole: executor. Implement the required changes in the workspace.\\n{{/if}}\\n{{/if}}\\n\\n{{#if profileInstructions}}\\n## Agent Profile\\n{{profileInstructions}}\\n{{/if}}\\n\\n{{#if skillContext}}\\n{{skillContext}}\\n{{/if}}\\n\\nIssue: {{issueIdentifier}}\\nTitle: {{title}}\\nDescription: {{description}}\\nWorkspace: {{workspacePath}}\\n\\n{{planPrompt}}\\n\\n{{#if phases.length}}\\n## Checkpoint Execution (Codex mode)\\nExecute in strict phases. After each phase, verify outputs before proceeding.\\n{{#each phases}}\\n- **{{phaseName}}**: {{goal}}\\n{{#if outputs.length}} Checkpoint: verify {{outputs | join \\\", \\\"}} before next phase.{{/if}}\\n{{/each}}\\n{{else}}\\n## Execution Order\\nExecute steps in order. Verify each step's `doneWhen` criterion before proceeding.\\n{{/if}}\\n\\n{{#if suggestedPaths.length}}\\nTarget paths: {{suggestedPaths | join \\\", \\\"}}\\nFocus changes on these paths. Do not make unnecessary changes elsewhere.\\n{{/if}}\\n\\n{{#if skillsToUse.length}}\\n## Specialized Procedures\\n{{#each skillsToUse}}\\n- Apply **{{name}}** procedure: {{why}}\\n{{/each}}\\n{{/if}}\\n\\n{{#if validationItems.length}}\\n## Pre-completion checks\\nBefore reporting done, run:\\n{{#each validationItems}}\\n- {{value}}\\n{{/each}}\\n{{/if}}\\n\\n## Structured Input\\nThe file `fifony-execution-payload.json` in the workspace contains the canonical structured data for this task.\\nUse it as the source of truth for constraints, success criteria, execution intent, and plan details.\\nIf there is any conflict between this prompt and the structured fields in the payload, prioritize the payload.\\n\\n## Output Format\\n\\n{{outputContract}}\\n\", // src/agents/prompts/compile-execution-codex.stub.md\n \"compile-review\": \"Review the work done for {{issueIdentifier}}.\\n\\nTitle: {{title}}\\nDescription: {{description}}\\nWorkspace: {{workspacePath}}\\n\\n{{#if planPrompt}}\\n# Original Execution Plan\\n\\n{{planPrompt}}\\n{{/if}}\\n\\n{{#if successCriteria.length}}\\n# Success Criteria (evaluate against these)\\n{{#each successCriteria}}\\n- [ ] {{value}}\\n{{/each}}\\n{{/if}}\\n\\n{{#if deliverables.length}}\\n# Expected Deliverables\\n{{#each deliverables}}\\n- [ ] {{value}}\\n{{/each}}\\n{{/if}}\\n\\n{{#if diffSummary}}\\n# Changes Made (diff summary)\\n```\\n{{diffSummary}}\\n```\\n{{/if}}\\n\\n# Structured Context\\nIf `fifony-execution-payload.json` exists in the workspace, read it for the canonical structured task data.\\nUse the `successCriteria`, `constraints`, and `deliverables` fields as your evaluation checklist.\\n\\n# Review Instructions\\n\\n1. Verify each success criterion from the plan is met.\\n2. Check that all expected deliverables are present.\\n3. Review the diff for correctness, security issues, and code quality.\\n4. Verify validation checks pass (run commands if specified in the plan).\\n5. Check for unintended side effects or regressions.\\n\\nIf the work is acceptable, emit FIFONY_STATUS=done.\\nIf rework is needed, emit FIFONY_STATUS=continue and provide actionable feedback in nextPrompt.\\nIf the work is fundamentally broken, emit FIFONY_STATUS=blocked.\\n\", // src/agents/prompts/compile-review.stub.md\n \"integrations-agency-agents\": \"---\\nagent:\\n providers:\\n - provider: claude\\n role: planner\\n profile: agency-senior-project-manager\\n - provider: codex\\n role: executor\\n profile: agency-senior-developer\\n - provider: claude\\n role: reviewer\\n profile: agency-code-reviewer\\ncodex:\\n command: \\\"codex\\\"\\nclaude:\\n command: \\\"claude\\\"\\n---\\n\\nUse local agency agent profiles discovered from workspace or home directories.\\nWorkspace: {{workspaceRoot}}\\n\", // src/agents/prompts/integrations-agency-agents.stub.md\n \"integrations-impeccable\": \"# Impeccable integration idea\\n\\nUse impeccable-oriented skills as a frontend review layer around fifony issues.\\n\\nSuggested pattern:\\n\\n1. Use `agency-senior-developer` or `codex` as executor.\\n2. Route UI-heavy issues to a reviewer prompt that explicitly asks for impeccable-style critique.\\n3. Expose the resulting review through the fifony MCP prompts or as a follow-up review issue.\\n\\nSuggested labels:\\n- frontend\\n- ui\\n- design-system\\n\\nSuggested reviewer prompt seed:\\n\\\"Review this implementation using impeccable standards for frontend quality, polish, hierarchy, spacing, responsiveness, and interaction clarity.\\\"\\n\", // src/agents/prompts/integrations-impeccable.stub.md\n \"issue-enhancer-description\": \"You are helping improve issue metadata for a software execution queue.\\nRewrite the description to be clearer, complete, and directly actionable.\\nReturn strict JSON only with this schema:\\n{ \\\"field\\\": \\\"description\\\", \\\"value\\\": \\\"...\\\" }\\n\\nIssue type: {{issueType}}\\nCurrent title: {{title}}\\nCurrent description: {{description}}\\n{{#if images}}\\nVisual evidence (attached screenshots for context):\\n{{#each images}}\\n- {{this}}\\n{{/each}}\\n{{/if}}\\n\\nRules:\\n- Keep it concise but include meaningful acceptance criteria tailored to the issue type.\\n- For \\\"bug\\\": focus on problem description, expected behavior, and steps to reproduce.\\n- For \\\"feature\\\": focus on goal, acceptance criteria, and any relevant notes.\\n- For \\\"refactor\\\": describe current state, desired state, and scope.\\n- For \\\"docs\\\": describe what to document and target audience.\\n- For \\\"chore\\\": describe the task and why it's needed now.\\n- Use markdown formatting appropriate for the type (## headings, bullet points).\\n- Avoid extra wrappers, outer quotes, or extra explanation.\\n- The value should be in Portuguese if the input is in Portuguese; otherwise in English.\\n\", // src/agents/prompts/issue-enhancer-description.stub.md\n \"issue-enhancer-title\": \"You are helping improve issue metadata for a software execution queue.\\nRewrite the title for clarity, actionability, and specificity.\\nReturn strict JSON only with this schema:\\n{ \\\"field\\\": \\\"title\\\", \\\"value\\\": \\\"...\\\" }\\n\\nIssue type: {{issueType}}\\nCurrent title: {{title}}\\nDescription context: {{description}}\\n{{#if images}}\\nVisual evidence (attached screenshots for context):\\n{{#each images}}\\n- {{this}}\\n{{/each}}\\n{{/if}}\\n\\nRules:\\n- Keep it concise and suitable as a task title.\\n- Use imperative language when possible.\\n- If the issue type is \\\"bug\\\", start with \\\"fix: \\\". If \\\"feature\\\", start with \\\"feat: \\\". If \\\"refactor\\\", start with \\\"refactor: \\\". If \\\"docs\\\", start with \\\"docs: \\\". If \\\"chore\\\", start with \\\"chore: \\\". For \\\"blank\\\", use no prefix.\\n- Do not include markdown, quotes, or extra explanation.\\n- The value should be in Portuguese if the input is in Portuguese; otherwise in English.\\n\", // src/agents/prompts/issue-enhancer-title.stub.md\n \"issue-planner\": \"You are a senior technical execution planner.\\nProduce the best possible plan for the issue below, filling the JSON schema precisely.\\n{{#if fast}}\\n\\nFAST MODE: Be brief and direct. Minimize reasoning depth.\\n- 2-4 steps maximum. Skip optional fields (unknowns, risks, alternatives).\\n- No tooling reflection needed — set shouldUseSkills: false, shouldUseSubagents: false.\\n- Focus only on: summary, steps, estimatedComplexity, suggestedPaths, suggestedLabels.\\n{{/if}}\\n\\nIssue title: {{title}}\\nIssue description: {{description}}\\n{{#if images}}\\nVisual evidence (attached screenshots for context):\\n{{#each images}}\\n- {{this}}\\n{{/each}}\\n{{/if}}\\n{{#unless fast}}\\n\\nQuality rules:\\n- Be concrete, not generic. No vague phrases like 'implement' or 'improve' without detail.\\n- Break work into actionable steps (2-8 steps). Each step describes WHAT, not HOW.\\n- Each step must have a clear 'doneWhen' acceptance criterion.\\n- Identify assumptions, constraints, unknowns, and risks.\\n- For unknowns, specify what question needs answering and how to resolve it.\\n- Suggest file paths that are likely relevant to the changes.\\n- Suggest labels: bug, feature, frontend, backend, docs, refactor, security, performance, etc.\\n\\nComplexity estimation:\\n- trivial: < 5 min, single-file cosmetic change\\n- low: 5-15 min, small focused change\\n- medium: 15-60 min, multi-file change with testing\\n- high: > 1 hour, architectural change or new feature\\n\\nTooling reflection (REQUIRED):\\n- Evaluate whether the task benefits from using skills (specialized instructions for quality/consistency).\\n- Evaluate whether subtasks should use subagents (parallel work, isolated context, specialization).\\n- Only recommend skills/agents when there is a concrete justification.\\n- For each step, set ownerType: 'agent' for automated work, 'human' for manual review, 'skill' for specialized skills, 'subagent' for delegated work.\\n\\nEffort suggestion:\\n- low: simple fixes, no deep reasoning needed\\n- medium: standard development work\\n- high: complex architecture, security, or cross-cutting changes\\n- Set per-role if different: planner, executor, reviewer\\n{{/unless}}\\n\\nReturn strict JSON matching this schema. No text outside JSON. Use these exact field names.\\nIMPORTANT: Replace ALL placeholder values with real content specific to the issue above. Do NOT copy the example values literally — every field must contain actual plan content derived from the issue.\\n\\n```json\\n{\\n \\\"summary\\\": \\\"<YOUR one-line summary here>\\\",\\n \\\"estimatedComplexity\\\": \\\"trivial|low|medium|high\\\",\\n \\\"steps\\\": [\\n {\\n \\\"step\\\": 1,\\n \\\"action\\\": \\\"<YOUR concrete action here>\\\",\\n \\\"files\\\": [\\\"<real/path/to/file.ts>\\\"],\\n \\\"details\\\": \\\"<YOUR additional context>\\\",\\n \\\"ownerType\\\": \\\"agent|human|skill|subagent|tool\\\",\\n \\\"doneWhen\\\": \\\"<YOUR acceptance criterion>\\\"\\n }\\n ],\\n \\\"assumptions\\\": [\\\"<YOUR assumptions>\\\"],\\n \\\"constraints\\\": [\\\"<YOUR constraints>\\\"],\\n \\\"unknowns\\\": [\\n { \\\"question\\\": \\\"<YOUR question>\\\", \\\"whyItMatters\\\": \\\"<YOUR reason>\\\", \\\"howToResolve\\\": \\\"<YOUR approach>\\\" }\\n ],\\n \\\"successCriteria\\\": [\\\"<YOUR criteria>\\\"],\\n \\\"risks\\\": [\\n { \\\"risk\\\": \\\"<YOUR risk>\\\", \\\"impact\\\": \\\"<YOUR impact>\\\", \\\"mitigation\\\": \\\"<YOUR mitigation>\\\" }\\n ],\\n \\\"suggestedPaths\\\": [\\\"<real/path/to/relevant/file.ts>\\\"],\\n \\\"suggestedLabels\\\": [\\\"frontend\\\", \\\"bug\\\", \\\"feature\\\"],\\n \\\"suggestedEffort\\\": { \\\"default\\\": \\\"medium\\\", \\\"planner\\\": \\\"low\\\", \\\"executor\\\": \\\"medium\\\", \\\"reviewer\\\": \\\"medium\\\" }\\n}\\n```\\n\", // src/agents/prompts/issue-planner.stub.md\n \"issue-planner-refine\": \"You are a senior technical execution planner refining an existing plan based on user feedback.\\n\\n## Original Issue\\nTitle: {{title}}\\nDescription: {{description}}\\n\\n## Current Plan (JSON)\\n```json\\n{{currentPlan}}\\n```\\n\\n## User Feedback\\n{{feedback}}\\n\\n## Instructions\\n\\nRevise the plan above to address the user's feedback precisely.\\n\\nRules:\\n- Keep all parts of the plan that are NOT affected by the feedback unchanged.\\n- Only modify, add, or remove elements that the feedback specifically requests.\\n- Preserve the same JSON schema structure as the current plan.\\n- Maintain step numbering consistency after changes.\\n- If feedback asks to add steps, insert them in the logical position and renumber.\\n- If feedback asks to remove steps, renumber remaining steps sequentially.\\n- Update the summary if the overall direction changed.\\n- Re-evaluate estimatedComplexity if the scope changed significantly.\\n- Update suggestedPaths and suggestedLabels if affected by the changes.\\n\\nReturn strict JSON. No text outside JSON.\\n\", // src/agents/prompts/issue-planner-refine.stub.md\n \"mcp-integrate-client\": \"Integrate {{client}} with the local fifony MCP server.\\n\\nGoal: {{goal}}\\n\\n{{integrationGuide}}\\n\\nUse the available fifony resources and tools instead of inventing your own persistence model.\\n\", // src/agents/prompts/mcp-integrate-client.stub.md\n \"mcp-integration-guide\": \"# fifony MCP integration\\n\\nWorkspace root: `{{workspaceRoot}}`\\nPersistence root: `{{persistenceRoot}}`\\nState root: `{{stateRoot}}`\\n\\nRecommended MCP client command:\\n\\n```json\\n{\\n \\\"mcpServers\\\": {\\n \\\"fifony\\\": {\\n \\\"command\\\": \\\"npx\\\",\\n \\\"args\\\": [\\\"fifony\\\", \\\"mcp\\\", \\\"--workspace\\\", \\\"{{workspaceRoot}}\\\", \\\"--persistence\\\", \\\"{{persistenceRoot}}\\\"]\\n }\\n }\\n}\\n```\\n\\nExpected workflow:\\n\\n1. Read `fifony://guide/overview` and `fifony://state/summary`.\\n2. Use `fifony.list_issues` or read `fifony://issues`.\\n3. Create work with `fifony.create_issue`.\\n4. Update workflow state with `fifony.update_issue_state`.\\n5. Use the prompts exposed by this MCP server to structure planning or execution.\\n\\nThe MCP server is read-write against the same `s3db` filesystem store used by the fifony runtime.\\n\", // src/agents/prompts/mcp-integration-guide.stub.md\n \"mcp-issue\": \"You are integrating with fifony as the {{role}} using {{provider}}.\\n\\nIssue ID: {{id}}\\nTitle: {{title}}\\nState: {{state}}\\nCapability category: {{capabilityCategory}}\\n{{#if overlays.length}}\\nOverlays: {{overlays | join \\\", \\\"}}\\n{{/if}}\\n{{#if paths.length}}\\nPaths: {{paths | join \\\", \\\"}}\\n{{/if}}\\nDescription:\\n{{description}}\\n\\nUse fifony as the source of truth:\\n- Persist transitions through the fifony tools instead of inventing local state.\\n- Keep outputs actionable and aligned with the tracked issue lifecycle.\\n\", // src/agents/prompts/mcp-issue.stub.md\n \"mcp-review-workflow\": \"Review the pipeline configuration for this fifony workspace as {{provider}}.\\n\\nWorkspace: {{workspaceRoot}}\\n\\nFocus on:\\n- provider orchestration quality (plan/execute/review stages)\\n- hooks safety (beforeRun, afterRun, afterCreate, beforeRemove)\\n- prompt clarity\\n- issue lifecycle correctness\\n- what an MCP client needs in order to integrate cleanly\\n\", // src/agents/prompts/mcp-review-workflow.stub.md\n \"mcp-route-task\": \"Use this routing decision as the execution plan for the task.\\n\\n{{resolutionJson}}\\n\", // src/agents/prompts/mcp-route-task.stub.md\n \"project-analysis\": \"You are analyzing a software project to help configure an AI-powered development assistant.\\n\\nLook at the project structure, source code, configuration files, and any documentation you can find. Pay special attention to:\\n- README, CLAUDE.md, AGENTS.md, or any project documentation\\n- Build files: package.json, Cargo.toml, pyproject.toml, build.gradle, Gemfile, go.mod, Makefile, CMakeLists.txt, pom.xml, etc.\\n- Source code directories and their contents\\n- Configuration files (.env, docker-compose, terraform, etc.)\\n- CI/CD pipelines (.github/workflows, .gitlab-ci, Jenkinsfile, etc.)\\n\\nReturn a JSON object with exactly these fields:\\n\\n{\\n \\\"description\\\": \\\"A concise 2-3 sentence description of what this project does, its purpose, and who it's for.\\\",\\n \\\"language\\\": \\\"The primary programming language (e.g. typescript, python, rust, java, kotlin, ruby, go, swift, c++)\\\",\\n \\\"domains\\\": [\\\"Array of relevant domain tags that apply to this project\\\"],\\n \\\"stack\\\": [\\\"Array of key technologies, frameworks, and tools used\\\"],\\n \\\"suggestedAgents\\\": [\\\"Array of specialist agent names that would help develop this project\\\"]\\n}\\n\\nFor \\\"domains\\\", choose from: frontend, backend, mobile, devops, database, ai-ml, security, testing, games, ecommerce, fintech, healthcare, education, saas, design, product, marketing, embedded, blockchain, spatial-computing, data-engineering.\\n\\nFor \\\"suggestedAgents\\\", choose from: frontend-developer, backend-architect, database-optimizer, security-engineer, devops-automator, mobile-app-builder, ai-engineer, ui-designer, ux-architect, code-reviewer, technical-writer, sre, data-engineer, software-architect, game-designer.\\n\\nReturn ONLY the JSON object. No markdown fences, no explanation, no extra text.\\n\", // src/agents/prompts/project-analysis.stub.md\n \"workflow-default\": \"You are working on {{issue.identifier}}.\\n\\nTitle: {{issue.title}}\\nDescription:\\n{{issue.description}}\\n\", // src/agents/prompts/workflow-default.stub.md\n \"workflow-plan-section\": \"## Execution Plan\\n\\nComplexity: {{estimatedComplexity}}\\nSummary: {{summary}}\\n\\nSteps:\\n{{#each steps}}\\n{{step}}. {{action}}{{#if files.length}} (files: {{files | join \\\", \\\"}}){{/if}}{{#if details}} - {{details}}{{/if}}\\n{{/each}}\\n\\nFollow this plan. Complete each step in order.\\n\", // src/agents/prompts/workflow-plan-section.stub.md\n} as const;\n\nexport type PromptTemplateName = keyof typeof PROMPT_TEMPLATES;\n"],"mappings":"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","names":["env","resolve","env","env"]}
@@ -13,7 +13,7 @@ import {
13
13
  now,
14
14
  renderPrompt,
15
15
  resolveTaskCapabilities
16
- } from "./chunk-DD5BE2W6.js";
16
+ } from "./chunk-RINIJIFO.js";
17
17
  import {
18
18
  logger
19
19
  } from "./chunk-DVU3CXWA.js";
@@ -1520,11 +1520,12 @@ function computeMetrics(issues) {
1520
1520
  let inProgress = 0;
1521
1521
  let blocked = 0;
1522
1522
  let done = 0;
1523
+ let merged = 0;
1523
1524
  let cancelled = 0;
1524
1525
  const completionTimes = [];
1525
1526
  for (const issue of issues) {
1526
- const duration = issue.durationMs;
1527
- if (issue.state === "Done") {
1527
+ if (issue.state === "Merged") {
1528
+ const duration = issue.durationMs;
1528
1529
  const candidate = typeof duration === "number" && Number.isFinite(duration) ? duration : Number.isFinite(Date.parse(issue.startedAt ?? "")) && Number.isFinite(Date.parse(issue.completedAt ?? "")) ? Date.parse(issue.completedAt) - Date.parse(issue.startedAt) : NaN;
1529
1530
  if (Number.isFinite(candidate) && candidate >= 0) {
1530
1531
  completionTimes.push(candidate);
@@ -1549,6 +1550,9 @@ function computeMetrics(issues) {
1549
1550
  case "Done":
1550
1551
  done += 1;
1551
1552
  break;
1553
+ case "Merged":
1554
+ merged += 1;
1555
+ break;
1552
1556
  case "Cancelled":
1553
1557
  cancelled += 1;
1554
1558
  break;
@@ -1562,6 +1566,7 @@ function computeMetrics(issues) {
1562
1566
  inProgress,
1563
1567
  blocked,
1564
1568
  done,
1569
+ merged,
1565
1570
  cancelled,
1566
1571
  activeWorkers: 0
1567
1572
  };
@@ -1577,6 +1582,7 @@ function computeMetrics(issues) {
1577
1582
  inProgress,
1578
1583
  blocked,
1579
1584
  done,
1585
+ merged,
1580
1586
  cancelled,
1581
1587
  activeWorkers: 0,
1582
1588
  avgCompletionMs: Math.round(totalCompletionMs / completionTimes.length),
@@ -1667,15 +1673,15 @@ function emitFsmEvent(issueId, kind, message) {
1667
1673
  }
1668
1674
  }
1669
1675
  async function lazyEnqueueForPlanning(issue) {
1670
- const { enqueueForPlanning } = await import("./queue-workers-VHYQYYLG.js");
1676
+ const { enqueueForPlanning } = await import("./queue-workers-BW4XANJJ.js");
1671
1677
  return enqueueForPlanning(issue);
1672
1678
  }
1673
1679
  async function lazyEnqueueForExecution(issue) {
1674
- const { enqueueForExecution } = await import("./queue-workers-VHYQYYLG.js");
1680
+ const { enqueueForExecution } = await import("./queue-workers-BW4XANJJ.js");
1675
1681
  return enqueueForExecution(issue);
1676
1682
  }
1677
1683
  async function lazyEnqueueForReview(issue) {
1678
- const { enqueueForReview } = await import("./queue-workers-VHYQYYLG.js");
1684
+ const { enqueueForReview } = await import("./queue-workers-BW4XANJJ.js");
1679
1685
  return enqueueForReview(issue);
1680
1686
  }
1681
1687
  var ISSUE_STATE_MACHINE_ID = "issue-lifecycle";
@@ -1748,9 +1754,13 @@ var issueStateMachineConfig = {
1748
1754
  entry: "onEnterBlocked"
1749
1755
  },
1750
1756
  Done: {
1757
+ on: { MERGE: "Merged", REOPEN: "Planning" },
1758
+ entry: "onEnterDone"
1759
+ },
1760
+ Merged: {
1751
1761
  on: { REOPEN: "Planning" },
1752
1762
  type: "final",
1753
- entry: "onEnterDone"
1763
+ entry: "onEnterMerged"
1754
1764
  },
1755
1765
  Cancelled: {
1756
1766
  on: { REOPEN: "Planning" },
@@ -1824,7 +1834,18 @@ var issueStateMachineConfig = {
1824
1834
  emitFsmEvent(issue.id, "error", `${issue.identifier} blocked: ${note}`);
1825
1835
  }
1826
1836
  },
1827
- onEnterDone: async (context, _event, machine) => {
1837
+ onEnterDone: async (context, _event, _machine) => {
1838
+ const issue = resolveIssue(context);
1839
+ if (issue) {
1840
+ issue.nextRetryAt = void 0;
1841
+ issue.lastError = void 0;
1842
+ if (!issue.linesAdded && !issue.linesRemoved && issue.baseBranch && issue.branchName) {
1843
+ computeDiffStats(issue);
1844
+ }
1845
+ emitFsmEvent(issue.id, "state", `${issue.identifier} approved \u2014 waiting for merge.`);
1846
+ }
1847
+ },
1848
+ onEnterMerged: async (context, _event, machine) => {
1828
1849
  const issue = resolveIssue(context);
1829
1850
  const ts = (/* @__PURE__ */ new Date()).toISOString();
1830
1851
  const week = isoWeek();
@@ -1834,15 +1855,17 @@ var issueStateMachineConfig = {
1834
1855
  }
1835
1856
  issue.completedAt = ts;
1836
1857
  issue.terminalWeek = week;
1858
+ if (!issue.mergedAt) issue.mergedAt = ts;
1837
1859
  issue.nextRetryAt = void 0;
1838
1860
  issue.lastError = void 0;
1839
- emitFsmEvent(issue.id, "state", `${issue.identifier} completed.`);
1861
+ emitFsmEvent(issue.id, "state", `${issue.identifier} merged.`);
1840
1862
  }
1841
1863
  const res = issueResource(machine);
1842
1864
  if (res) {
1843
1865
  res.patch(machine.entityId, {
1844
1866
  completedAt: ts,
1845
1867
  terminalWeek: week,
1868
+ mergedAt: issue?.mergedAt ?? ts,
1846
1869
  nextRetryAt: void 0,
1847
1870
  lastError: void 0,
1848
1871
  linesAdded: issue?.linesAdded,
@@ -1853,6 +1876,17 @@ var issueStateMachineConfig = {
1853
1876
  worktreePath: issue?.worktreePath
1854
1877
  }).catch(() => {
1855
1878
  });
1879
+ const add = res.add;
1880
+ if (typeof add === "function" && issue) {
1881
+ try {
1882
+ if (issue.linesAdded) await add.call(res, machine.entityId, "linesAdded", issue.linesAdded);
1883
+ if (issue.linesRemoved) await add.call(res, machine.entityId, "linesRemoved", issue.linesRemoved);
1884
+ if (issue.filesChanged) await add.call(res, machine.entityId, "filesChanged", issue.filesChanged);
1885
+ logger.info({ issueId: issue.id, linesAdded: issue.linesAdded, linesRemoved: issue.linesRemoved, filesChanged: issue.filesChanged }, "[FSM] EC add() for diff stats on merge");
1886
+ } catch (err) {
1887
+ logger.warn({ err: String(err), issueId: issue?.id }, "[FSM] EC add() failed for diff stats");
1888
+ }
1889
+ }
1856
1890
  }
1857
1891
  },
1858
1892
  onEnterCancelled: async (context, _event, machine) => {
@@ -1890,6 +1924,7 @@ var EVENT_TO_STATE = {
1890
1924
  REVIEW: "Reviewing",
1891
1925
  REVIEWED: "Reviewed",
1892
1926
  DONE: "Done",
1927
+ MERGE: "Merged",
1893
1928
  CANCEL: "Cancelled",
1894
1929
  BLOCK: "Blocked",
1895
1930
  UNBLOCK: "Queued",
@@ -2134,4 +2169,4 @@ export {
2134
2169
  canTransitionIssue,
2135
2170
  visualizeStateMachine
2136
2171
  };
2137
- //# sourceMappingURL=chunk-G6CQK2WH.js.map
2172
+ //# sourceMappingURL=chunk-V6IHUFZB.js.map