fifony 0.1.27 → 0.1.28

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 (35) hide show
  1. package/README.md +51 -29
  2. package/app/dist/assets/{KeyboardShortcutsHelp-NmaeCZMn.js → KeyboardShortcutsHelp-BrI56bfa.js} +1 -1
  3. package/app/dist/assets/OnboardingWizard-7MvouAkN.js +1 -0
  4. package/app/dist/assets/{analytics.lazy-BpH26eA2.js → analytics.lazy-D99c8M-T.js} +1 -1
  5. package/app/dist/assets/{createLucideIcon-BWC-guQt.js → createLucideIcon-DgMTp0yx.js} +1 -1
  6. package/app/dist/assets/index-DHHTOl-9.js +45 -0
  7. package/app/dist/assets/{index-DntTEHv8.css → index-ZlyvZ7KI.css} +1 -1
  8. package/app/dist/assets/vendor-D-IqxHHu.js +9 -0
  9. package/app/dist/index.html +4 -4
  10. package/app/dist/service-worker.js +1 -1
  11. package/dist/agent/run-local.js +64 -144
  12. package/dist/agent-FPUYBJZD.js +74 -0
  13. package/dist/chunk-2G6SRDOC.js +847 -0
  14. package/dist/{chunk-G7W4NEOA.js → chunk-3FCJI2GK.js} +1232 -633
  15. package/dist/chunk-O5AEQXUV.js +311 -0
  16. package/dist/chunk-OONOOWNC.js +123 -0
  17. package/dist/chunk-VOQT7RVT.js +295 -0
  18. package/dist/{chunk-XN2QKKMY.js → chunk-XVF6GOVS.js} +456 -814
  19. package/dist/cli.js +6 -4
  20. package/dist/issue-runner-MRHO5ZAB.js +15 -0
  21. package/dist/{issue-state-machine-SKODQ6MG.js → issue-state-machine-V2KPUYPW.js} +5 -3
  22. package/dist/issues-3PUMY63N.js +40 -0
  23. package/dist/mcp/server.js +23 -121
  24. package/dist/queue-workers-EGHCDDLB.js +23 -0
  25. package/dist/scheduler-V4GMCBTE.js +21 -0
  26. package/dist/{store-366NGWR4.js → store-RVKQ6UEY.js} +7 -5
  27. package/dist/workspace-KEHFITYR.js +52 -0
  28. package/package.json +6 -6
  29. package/app/dist/assets/OnboardingWizard-CwW6b_X4.js +0 -1
  30. package/app/dist/assets/index-D6jtlB7h.js +0 -43
  31. package/app/dist/assets/vendor-BTlTWMUF.js +0 -9
  32. package/dist/chunk-AMOGDOM7.js +0 -796
  33. package/dist/chunk-MT3S55TM.js +0 -91
  34. package/dist/issue-runner-MTAIYNVN.js +0 -13
  35. package/dist/queue-workers-Q3IWRFLI.js +0 -20
package/dist/cli.js CHANGED
@@ -3,11 +3,13 @@ import {
3
3
  importReferenceArtifacts,
4
4
  listReferenceRepositories,
5
5
  syncReferenceRepositories
6
- } from "./chunk-G7W4NEOA.js";
7
- import "./chunk-MT3S55TM.js";
8
- import "./chunk-XN2QKKMY.js";
9
- import "./chunk-AMOGDOM7.js";
6
+ } from "./chunk-3FCJI2GK.js";
7
+ import "./chunk-2G6SRDOC.js";
8
+ import "./chunk-XVF6GOVS.js";
9
+ import "./chunk-O5AEQXUV.js";
10
+ import "./chunk-VOQT7RVT.js";
10
11
  import "./chunk-DVU3CXWA.js";
12
+ import "./chunk-OONOOWNC.js";
11
13
 
12
14
  // src/cli.ts
13
15
  import { spawn } from "child_process";
@@ -0,0 +1,15 @@
1
+ import {
2
+ runIssueOnce,
3
+ runPlanningJob
4
+ } from "./chunk-3FCJI2GK.js";
5
+ import "./chunk-2G6SRDOC.js";
6
+ import "./chunk-XVF6GOVS.js";
7
+ import "./chunk-O5AEQXUV.js";
8
+ import "./chunk-VOQT7RVT.js";
9
+ import "./chunk-DVU3CXWA.js";
10
+ import "./chunk-OONOOWNC.js";
11
+ export {
12
+ runIssueOnce,
13
+ runPlanningJob
14
+ };
15
+ //# sourceMappingURL=issue-runner-MRHO5ZAB.js.map
@@ -15,9 +15,11 @@ import {
15
15
  setIssueResourceStateApi,
16
16
  setIssueStateMachinePlugin,
17
17
  visualizeStateMachine
18
- } from "./chunk-XN2QKKMY.js";
19
- import "./chunk-AMOGDOM7.js";
18
+ } from "./chunk-2G6SRDOC.js";
19
+ import "./chunk-XVF6GOVS.js";
20
+ import "./chunk-O5AEQXUV.js";
20
21
  import "./chunk-DVU3CXWA.js";
22
+ import "./chunk-OONOOWNC.js";
21
23
  export {
22
24
  ISSUE_STATE_MACHINE_ID,
23
25
  canTransitionIssue,
@@ -36,4 +38,4 @@ export {
36
38
  setIssueStateMachinePlugin,
37
39
  visualizeStateMachine
38
40
  };
39
- //# sourceMappingURL=issue-state-machine-SKODQ6MG.js.map
41
+ //# sourceMappingURL=issue-state-machine-V2KPUYPW.js.map
@@ -0,0 +1,40 @@
1
+ import {
2
+ addEvent,
3
+ applyWorkflowConfig,
4
+ buildRuntimeState,
5
+ createIssueFromPayload,
6
+ dedupHistoryEntries,
7
+ deriveConfig,
8
+ getNextRetryAt,
9
+ handleStatePatch,
10
+ issueDependenciesResolved,
11
+ nextLocalIssueId,
12
+ normalizeIssue,
13
+ transitionIssue,
14
+ validateConfig
15
+ } from "./chunk-3FCJI2GK.js";
16
+ import {
17
+ computeMetrics
18
+ } from "./chunk-2G6SRDOC.js";
19
+ import "./chunk-XVF6GOVS.js";
20
+ import "./chunk-O5AEQXUV.js";
21
+ import "./chunk-VOQT7RVT.js";
22
+ import "./chunk-DVU3CXWA.js";
23
+ import "./chunk-OONOOWNC.js";
24
+ export {
25
+ addEvent,
26
+ applyWorkflowConfig,
27
+ buildRuntimeState,
28
+ computeMetrics,
29
+ createIssueFromPayload,
30
+ dedupHistoryEntries,
31
+ deriveConfig,
32
+ getNextRetryAt,
33
+ handleStatePatch,
34
+ issueDependenciesResolved,
35
+ nextLocalIssueId,
36
+ normalizeIssue,
37
+ transitionIssue,
38
+ validateConfig
39
+ };
40
+ //# sourceMappingURL=issues-3PUMY63N.js.map
@@ -1,9 +1,8 @@
1
1
  import {
2
- inferCapabilityPaths,
3
2
  parseIssueState,
4
- renderPrompt,
5
- resolveTaskCapabilities
6
- } from "../chunk-AMOGDOM7.js";
3
+ renderPrompt
4
+ } from "../chunk-O5AEQXUV.js";
5
+ import "../chunk-OONOOWNC.js";
7
6
 
8
7
  // src/mcp/server.ts
9
8
  import { env as env3, stdin } from "process";
@@ -88,15 +87,10 @@ async function initDatabase() {
88
87
  identifier: "string|required",
89
88
  title: "string|required",
90
89
  description: "string|optional",
91
- priority: "number|required",
92
90
  state: "string|required",
93
91
  branchName: "string|optional",
94
92
  labels: "json|required",
95
93
  paths: "json|optional",
96
- inferredPaths: "json|optional",
97
- capabilityCategory: "string|optional",
98
- capabilityOverlays: "json|optional",
99
- capabilityRationale: "json|optional",
100
94
  blockedBy: "json|required",
101
95
  assignedToWorker: "boolean|required",
102
96
  createdAt: "datetime|required",
@@ -117,11 +111,7 @@ async function initDatabase() {
117
111
  commandOutputTail: "string|optional"
118
112
  },
119
113
  partitions: {
120
- byState: { fields: { state: "string" } },
121
- byCapabilityCategory: { fields: { capabilityCategory: "string" } },
122
- byStateAndCapability: {
123
- fields: { state: "string", capabilityCategory: "string" }
124
- }
114
+ byState: { fields: { state: "string" } }
125
115
  },
126
116
  asyncPartitions: true
127
117
  });
@@ -190,10 +180,10 @@ async function listRecords(resource, limit = 100) {
190
180
  }
191
181
  async function listIssues(filters = {}) {
192
182
  await initDatabase();
193
- const { state, capabilityCategory } = filters;
183
+ const { state } = filters;
194
184
  if (!issueResource) return [];
195
- const partition = state && capabilityCategory ? "byStateAndCapability" : state ? "byState" : capabilityCategory ? "byCapabilityCategory" : null;
196
- const partitionValues = state && capabilityCategory ? { state, capabilityCategory } : state ? { state } : capabilityCategory ? { capabilityCategory } : {};
185
+ const partition = state ? "byState" : null;
186
+ const partitionValues = state ? { state } : {};
197
187
  const records = await issueResource.list({ partition, partitionValues, limit: 500 });
198
188
  return records.map((record) => record);
199
189
  }
@@ -367,13 +357,6 @@ async function buildIntegrationGuide() {
367
357
  stateRoot: STATE_ROOT
368
358
  });
369
359
  }
370
- function computeCapabilityCounts(issues) {
371
- return issues.reduce((accumulator, issue) => {
372
- const key = typeof issue.capabilityCategory === "string" && issue.capabilityCategory.trim() ? issue.capabilityCategory.trim() : "default";
373
- accumulator[key] = (accumulator[key] ?? 0) + 1;
374
- return accumulator;
375
- }, {});
376
- }
377
360
  async function buildStateSummary() {
378
361
  const runtime = await getRuntimeSnapshot();
379
362
  const issues = await getIssues();
@@ -386,7 +369,6 @@ async function buildStateSummary() {
386
369
  accumulator[key] = (accumulator[key] ?? 0) + 1;
387
370
  return accumulator;
388
371
  }, {});
389
- const byCapability = computeCapabilityCounts(issues);
390
372
  return JSON.stringify({
391
373
  workspaceRoot: WORKSPACE_ROOT,
392
374
  persistenceRoot: PERSISTENCE_ROOT,
@@ -394,29 +376,20 @@ async function buildStateSummary() {
394
376
  runtimeUpdatedAt: runtime.updatedAt ?? null,
395
377
  issueCount: issues.length,
396
378
  issuesByState: byState,
397
- issuesByCapability: byCapability,
398
379
  sessionCount: sessions.length,
399
380
  pipelineCount: pipelines.length,
400
381
  recentEventCount: events.length
401
382
  }, null, 2);
402
383
  }
403
384
  async function buildIssuePrompt(issue, provider, role) {
404
- const resolution = resolveTaskCapabilities({
405
- id: issue.id,
406
- identifier: issue.identifier,
407
- title: issue.title,
408
- description: typeof issue.description === "string" ? issue.description : "",
409
- labels: Array.isArray(issue.labels) ? issue.labels.filter((value) => typeof value === "string") : [],
410
- paths: Array.isArray(issue.paths) ? issue.paths.filter((value) => typeof value === "string") : []
411
- });
412
385
  return renderPrompt("mcp-issue", {
413
386
  role,
414
387
  provider,
415
388
  id: issue.id,
416
389
  title: issue.title,
417
390
  state: issue.state ?? "Planning",
418
- capabilityCategory: resolution.category,
419
- overlays: resolution.overlays,
391
+ capabilityCategory: "",
392
+ overlays: [],
420
393
  paths: Array.isArray(issue.paths) ? issue.paths.filter((value) => typeof value === "string") : [],
421
394
  description: issue.description || "No description provided."
422
395
  });
@@ -431,8 +404,7 @@ async function listResourcesMcp() {
431
404
  { uri: "fifony://guide/integration", name: "Fifony MCP integration guide", description: "How to wire an MCP client to this Fifony workspace.", mimeType: "text/markdown" },
432
405
  { uri: "fifony://state/summary", name: "Fifony state summary", description: "Compact summary of the current runtime, issue, and pipeline state.", mimeType: "application/json" },
433
406
  { uri: "fifony://issues", name: "Fifony issues", description: "Full issue list from the durable Fifony store.", mimeType: "application/json" },
434
- { uri: "fifony://integrations", name: "Fifony integrations", description: "Discovered local integrations such as agency-agents and impeccable skills.", mimeType: "application/json" },
435
- { uri: "fifony://capabilities", name: "Fifony capability routing", description: "How Fifony would route current issues to providers, profiles, and overlays.", mimeType: "application/json" }
407
+ { uri: "fifony://integrations", name: "Fifony integrations", description: "Discovered local integrations such as agency-agents and impeccable skills.", mimeType: "application/json" }
436
408
  ];
437
409
  resources.push(
438
410
  { uri: "fifony://analytics", name: "Token usage analytics", description: "Token usage analytics snapshot including totals, cost estimates, and per-model breakdown.", mimeType: "application/json" },
@@ -460,38 +432,6 @@ async function readResource(uri) {
460
432
  if (uri === "fifony://integrations") {
461
433
  return [{ uri, mimeType: "application/json", text: JSON.stringify(discoverIntegrations(WORKSPACE_ROOT), null, 2) }];
462
434
  }
463
- if (uri === "fifony://capabilities") {
464
- const issues = await getIssues();
465
- return [{
466
- uri,
467
- mimeType: "application/json",
468
- text: JSON.stringify(
469
- issues.map((issue) => ({
470
- issueId: issue.id,
471
- title: issue.title,
472
- paths: Array.isArray(issue.paths) ? issue.paths.filter((value) => typeof value === "string") : [],
473
- inferredPaths: inferCapabilityPaths({
474
- id: issue.id,
475
- identifier: issue.identifier,
476
- title: issue.title,
477
- description: issue.description,
478
- labels: Array.isArray(issue.labels) ? issue.labels.filter((value) => typeof value === "string") : [],
479
- paths: Array.isArray(issue.paths) ? issue.paths.filter((value) => typeof value === "string") : []
480
- }),
481
- resolution: resolveTaskCapabilities({
482
- id: issue.id,
483
- identifier: issue.identifier,
484
- title: issue.title,
485
- description: issue.description,
486
- labels: Array.isArray(issue.labels) ? issue.labels.filter((value) => typeof value === "string") : [],
487
- paths: Array.isArray(issue.paths) ? issue.paths.filter((value) => typeof value === "string") : []
488
- })
489
- })),
490
- null,
491
- 2
492
- )
493
- }];
494
- }
495
435
  if (uri === "fifony://analytics") {
496
436
  try {
497
437
  const result = await apiGet("/api/analytics/tokens");
@@ -578,21 +518,20 @@ async function readResource(uri) {
578
518
  function listTools() {
579
519
  return [
580
520
  { name: "fifony.status", description: "Return a compact status summary for the current Fifony workspace.", inputSchema: { type: "object", properties: {}, additionalProperties: false } },
581
- { name: "fifony.list_issues", description: "List issues from the Fifony durable store.", inputSchema: { type: "object", properties: { state: { type: "string" }, capabilityCategory: { type: "string" }, category: { type: "string" } }, additionalProperties: false } },
582
- { name: "fifony.create_issue", description: "Create a new issue directly in the Fifony durable store.", inputSchema: { type: "object", properties: { id: { type: "string" }, title: { type: "string" }, description: { type: "string" }, priority: { type: "number" }, state: { type: "string" }, labels: { type: "array", items: { type: "string" } }, paths: { type: "array", items: { type: "string" } } }, required: ["title"], additionalProperties: false } },
521
+ { name: "fifony.list_issues", description: "List issues from the Fifony durable store.", inputSchema: { type: "object", properties: { state: { type: "string" } }, additionalProperties: false } },
522
+ { name: "fifony.create_issue", description: "Create a new issue directly in the Fifony durable store.", inputSchema: { type: "object", properties: { id: { type: "string" }, title: { type: "string" }, description: { type: "string" }, state: { type: "string" }, paths: { type: "array", items: { type: "string" } } }, required: ["title"], additionalProperties: false } },
583
523
  { name: "fifony.update_issue_state", description: "Update an issue state in the Fifony store and append an event.", inputSchema: { type: "object", properties: { issueId: { type: "string" }, state: { type: "string" }, note: { type: "string" } }, required: ["issueId", "state"], additionalProperties: false } },
584
524
  { name: "fifony.plan", description: "Generate an AI plan for an issue. The issue must be in Planning state. Returns the plan summary and step count.", inputSchema: { type: "object", properties: { issueId: { type: "string", description: "The issue identifier to plan." }, fast: { type: "boolean", description: "Use fast planning mode (less thorough but quicker)." } }, required: ["issueId"], additionalProperties: false } },
585
525
  { name: "fifony.refine", description: "Refine an existing plan with feedback. The issue must already have a plan.", inputSchema: { type: "object", properties: { issueId: { type: "string", description: "The issue identifier whose plan to refine." }, feedback: { type: "string", description: "Feedback to guide the plan refinement." } }, required: ["issueId", "feedback"], additionalProperties: false } },
586
- { name: "fifony.approve", description: "Approve a plan and move the issue to Planned for execution.", inputSchema: { type: "object", properties: { issueId: { type: "string", description: "The issue identifier to approve." } }, required: ["issueId"], additionalProperties: false } },
526
+ { name: "fifony.approve", description: "Approve a plan and queue the issue for execution.", inputSchema: { type: "object", properties: { issueId: { type: "string", description: "The issue identifier to approve." } }, required: ["issueId"], additionalProperties: false } },
587
527
  { name: "fifony.merge", description: "Merge workspace changes back into the project root. Copies new/modified files from the issue workspace to TARGET_ROOT and removes files that were deleted. Skips fifony internal files, node_modules, .git, and dist.", inputSchema: { type: "object", properties: { issueId: { type: "string", description: "The issue identifier whose workspace to merge." } }, required: ["issueId"], additionalProperties: false } },
588
528
  { name: "fifony.analytics", description: "Get token usage analytics including overall totals, cost estimates, and top issues by token consumption.", inputSchema: { type: "object", properties: {}, additionalProperties: false } },
589
529
  { name: "fifony.integration_config", description: "Generate a ready-to-paste MCP client configuration snippet for this Fifony workspace.", inputSchema: { type: "object", properties: { client: { type: "string" } }, additionalProperties: false } },
590
530
  { name: "fifony.list_integrations", description: "List discovered local integrations such as agency-agents profiles and impeccable skills.", inputSchema: { type: "object", properties: {}, additionalProperties: false } },
591
531
  { name: "fifony.integration_snippet", description: "Generate a workflow or prompt snippet for a discovered integration.", inputSchema: { type: "object", properties: { integration: { type: "string" } }, required: ["integration"], additionalProperties: false } },
592
- { name: "fifony.resolve_capabilities", description: "Resolve which providers, roles, profiles, and overlays Fifony should use for a task.", inputSchema: { type: "object", properties: { title: { type: "string" }, description: { type: "string" }, labels: { type: "array", items: { type: "string" } }, paths: { type: "array", items: { type: "string" } } }, required: ["title"], additionalProperties: false } },
593
532
  { name: "fifony.get_issue", description: "Get full detail of a single issue including plan, history, events, and diff status.", inputSchema: { type: "object", properties: { issueId: { type: "string", description: "The issue identifier." } }, required: ["issueId"], additionalProperties: false } },
594
533
  { name: "fifony.cancel_issue", description: "Cancel an issue, moving it to Cancelled state.", inputSchema: { type: "object", properties: { issueId: { type: "string", description: "The issue identifier to cancel." } }, required: ["issueId"], additionalProperties: false } },
595
- { name: "fifony.retry_issue", description: "Retry a failed or blocked issue, resetting it to Planned state.", inputSchema: { type: "object", properties: { issueId: { type: "string", description: "The issue identifier to retry." } }, required: ["issueId"], additionalProperties: false } },
534
+ { name: "fifony.retry_issue", description: "Retry a failed or blocked issue, re-queuing it for execution.", inputSchema: { type: "object", properties: { issueId: { type: "string", description: "The issue identifier to retry." } }, required: ["issueId"], additionalProperties: false } },
596
535
  { name: "fifony.enhance", description: "AI-enhance an issue title or description. Provide either an issueId to enhance an existing issue, or title+description for standalone enhancement.", inputSchema: { type: "object", properties: { issueId: { type: "string", description: "Issue identifier (optional, for existing issues)." }, title: { type: "string", description: "Issue title (for standalone enhancement)." }, description: { type: "string", description: "Issue description (for standalone enhancement)." }, field: { type: "string", enum: ["title", "description"], description: "Which field to enhance." } }, required: ["field"], additionalProperties: false } },
597
536
  { name: "fifony.get_diff", description: "Get git diff for an issue's workspace, including per-file summary and full diff text.", inputSchema: { type: "object", properties: { issueId: { type: "string", description: "The issue identifier." } }, required: ["issueId"], additionalProperties: false } },
598
537
  { name: "fifony.get_live", description: "Get live agent output for a running issue, including log tail, PID, elapsed time, and status.", inputSchema: { type: "object", properties: { issueId: { type: "string", description: "The issue identifier." } }, required: ["issueId"], additionalProperties: false } },
@@ -617,8 +556,7 @@ async function callTool(name, args = {}) {
617
556
  if (name === "fifony.status") return toolText(await buildStateSummary());
618
557
  if (name === "fifony.list_issues") {
619
558
  const stateFilter = typeof args.state === "string" && args.state.trim() ? args.state.trim() : "";
620
- const capabilityCategory = typeof args.capabilityCategory === "string" && args.capabilityCategory.trim() ? args.capabilityCategory.trim() : typeof args.category === "string" && args.category.trim() ? args.category.trim() : "";
621
- return toolText(JSON.stringify(await listIssues({ state: stateFilter || void 0, capabilityCategory: capabilityCategory || void 0 }), null, 2));
559
+ return toolText(JSON.stringify(await listIssues({ state: stateFilter || void 0 }), null, 2));
622
560
  }
623
561
  if (name === "fifony.create_issue") {
624
562
  await initDatabase();
@@ -628,26 +566,17 @@ async function callTool(name, args = {}) {
628
566
  const explicitId = typeof args.id === "string" && args.id.trim() ? args.id.trim() : "";
629
567
  const issueId = explicitId || `LOCAL-${hashInput(`${title}:${nowIso()}`)}`.toUpperCase();
630
568
  const description = typeof args.description === "string" ? args.description : "";
631
- const priority = typeof args.priority === "number" ? args.priority : 2;
632
569
  const state = parseIssueState(args.state) ?? "Planning";
633
- const baseLabels = Array.isArray(args.labels) ? args.labels.filter((value) => typeof value === "string") : ["fifony", "mcp"];
634
570
  const paths = Array.isArray(args.paths) ? args.paths.filter((value) => typeof value === "string") : [];
635
- const inferredPaths = inferCapabilityPaths({ id: issueId, identifier: issueId, title, description, labels: baseLabels, paths });
636
- const resolution = resolveTaskCapabilities({ id: issueId, identifier: issueId, title, description, labels: baseLabels, paths });
637
- const labels = [...new Set([...baseLabels, resolution.category ? `capability:${resolution.category}` : "", ...resolution.overlays.map((overlay) => `overlay:${overlay}`)].filter(Boolean))];
571
+ const labels = [];
638
572
  const record = await issueResource2?.insert({
639
573
  id: issueId,
640
574
  identifier: issueId,
641
575
  title,
642
576
  description,
643
- priority,
644
577
  state,
645
578
  labels,
646
579
  paths,
647
- inferredPaths,
648
- capabilityCategory: resolution.category,
649
- capabilityOverlays: resolution.overlays,
650
- capabilityRationale: resolution.rationale,
651
580
  blockedBy: [],
652
581
  assignedToWorker: false,
653
582
  createdAt: nowIso(),
@@ -657,7 +586,7 @@ async function callTool(name, args = {}) {
657
586
  attempts: 0,
658
587
  maxAttempts: 3
659
588
  });
660
- await appendEvent("info", `Issue ${issueId} created through MCP.`, { title, state, labels, paths, inferredPaths, capabilityCategory: resolution.category }, issueId);
589
+ await appendEvent("info", `Issue ${issueId} created through MCP.`, { title, state, labels, paths }, issueId);
661
590
  return toolText(JSON.stringify(record ?? { id: issueId }, null, 2));
662
591
  }
663
592
  if (name === "fifony.update_issue_state") {
@@ -714,8 +643,8 @@ async function callTool(name, args = {}) {
714
643
  const issue = result.issue;
715
644
  return toolText(JSON.stringify({
716
645
  issueId,
717
- state: issue?.state ?? "Planned",
718
- message: `Plan approved for ${issueId}. Issue moved to Planned and is ready for execution.`
646
+ state: issue?.state ?? "PendingApproval",
647
+ message: `Plan approved for ${issueId}. Issue moved to PendingApproval and is ready for execution.`
719
648
  }, null, 2));
720
649
  }
721
650
  if (name === "fifony.merge") {
@@ -755,13 +684,6 @@ async function callTool(name, args = {}) {
755
684
  const integration = typeof args.integration === "string" ? args.integration : "";
756
685
  return toolText(await buildIntegrationSnippet(integration, WORKSPACE_ROOT));
757
686
  }
758
- if (name === "fifony.resolve_capabilities") {
759
- const title = typeof args.title === "string" ? args.title : "";
760
- const description = typeof args.description === "string" ? args.description : "";
761
- const labels = Array.isArray(args.labels) ? args.labels.filter((value) => typeof value === "string") : [];
762
- const paths = Array.isArray(args.paths) ? args.paths.filter((value) => typeof value === "string") : [];
763
- return toolText(JSON.stringify({ inferredPaths: inferCapabilityPaths({ title, description, labels, paths }), resolution: resolveTaskCapabilities({ title, description, labels, paths }) }, null, 2));
764
- }
765
687
  if (name === "fifony.get_issue") {
766
688
  const issueId = typeof args.issueId === "string" ? args.issueId.trim() : "";
767
689
  if (!issueId) throw new Error("issueId is required");
@@ -804,7 +726,7 @@ async function callTool(name, args = {}) {
804
726
  try {
805
727
  const result = await apiPost(`/api/issues/${encodeURIComponent(issueId)}/retry`);
806
728
  const issue = result.issue;
807
- return toolText(JSON.stringify({ issueId, state: issue?.state ?? "Planned", message: `Issue ${issueId} has been retried and reset to Planned.` }, null, 2));
729
+ return toolText(JSON.stringify({ issueId, state: issue?.state ?? "PendingApproval", message: `Issue ${issueId} has been retried.` }, null, 2));
808
730
  } catch (error) {
809
731
  throw new Error(`Failed to retry issue ${issueId}: ${String(error)}`);
810
732
  }
@@ -927,7 +849,6 @@ function listPrompts() {
927
849
  { name: "fifony-integrate-client", description: "Generate setup instructions for connecting an MCP-capable client to Fifony.", arguments: [{ name: "client", description: "Client name, e.g. codex or claude.", required: true }, { name: "goal", description: "What the client should do with Fifony.", required: false }] },
928
850
  { name: "fifony-plan-issue", description: "Generate a planning prompt for a specific issue in the Fifony store.", arguments: [{ name: "issueId", description: "Issue identifier.", required: true }, { name: "provider", description: "Agent provider name.", required: false }] },
929
851
  { name: "fifony-use-integration", description: "Generate a concrete integration prompt for agency-agents or impeccable.", arguments: [{ name: "integration", description: "Integration id: agency-agents or impeccable.", required: true }] },
930
- { name: "fifony-route-task", description: "Explain which providers, profiles, and overlays Fifony would choose for a task.", arguments: [{ name: "title", description: "Task title.", required: true }, { name: "description", description: "Task description.", required: false }, { name: "labels", description: "Comma-separated labels.", required: false }, { name: "paths", description: "Comma-separated target paths or files.", required: false }] },
931
852
  { name: "fifony-diagnose-blocked", description: "Help diagnose why an issue is blocked or failing, analyzing the issue plan, last error, history, and events.", arguments: [{ name: "issueId", description: "Issue identifier to diagnose.", required: true }] },
932
853
  { name: "fifony-weekly-summary", description: "Generate a weekly progress summary including issues created, completed, blocked, and token usage.", arguments: [] },
933
854
  { name: "fifony-refine-plan", description: "Guided plan refinement prompt that shows the current plan and helps provide specific feedback.", arguments: [{ name: "issueId", description: "Issue identifier whose plan to refine.", required: true }, { name: "concern", description: "Optional specific concern to address in refinement.", required: false }] },
@@ -975,25 +896,6 @@ async function getPrompt(name, args = {}) {
975
896
  }]
976
897
  };
977
898
  }
978
- if (name === "fifony-route-task") {
979
- const title = typeof args.title === "string" ? args.title : "";
980
- const description = typeof args.description === "string" ? args.description : "";
981
- const labels = typeof args.labels === "string" ? args.labels.split(",").map((label) => label.trim()).filter(Boolean) : [];
982
- const paths = typeof args.paths === "string" ? args.paths.split(",").map((value) => value.trim()).filter(Boolean) : [];
983
- const resolution = resolveTaskCapabilities({ title, description, labels, paths });
984
- return {
985
- description: "Task routing prompt produced by the Fifony capability resolver.",
986
- messages: [{
987
- role: "user",
988
- content: {
989
- type: "text",
990
- text: await renderPrompt("mcp-route-task", {
991
- resolutionJson: JSON.stringify(resolution, null, 2)
992
- })
993
- }
994
- }]
995
- };
996
- }
997
899
  if (name === "fifony-diagnose-blocked") {
998
900
  const issueId = typeof args.issueId === "string" ? args.issueId.trim() : "";
999
901
  if (!issueId) throw new Error("issueId is required");
@@ -1065,10 +967,10 @@ async function getPrompt(name, args = {}) {
1065
967
  return accumulator;
1066
968
  }, {});
1067
969
  const totalIssues = issues.length;
1068
- const completed = byState["Done"] ?? 0;
970
+ const completed = byState["Approved"] ?? 0;
1069
971
  const blocked = (byState["Blocked"] ?? 0) + (byState["Failed"] ?? 0);
1070
- const inProgress = (byState["Running"] ?? 0) + (byState["Reviewing"] ?? 0) + (byState["Reviewed"] ?? 0) + (byState["Queued"] ?? 0);
1071
- const planned = byState["Planned"] ?? 0;
972
+ const inProgress = (byState["Running"] ?? 0) + (byState["Reviewing"] ?? 0) + (byState["PendingDecision"] ?? 0) + (byState["Queued"] ?? 0);
973
+ const planned = byState["PendingApproval"] ?? 0;
1072
974
  const planning = byState["Planning"] ?? 0;
1073
975
  const cancelled = byState["Cancelled"] ?? 0;
1074
976
  const inputTokens = typeof overall.inputTokens === "number" ? overall.inputTokens : 0;
@@ -0,0 +1,23 @@
1
+ import {
2
+ areQueueWorkersActive,
3
+ cleanTerminalWorkspaces,
4
+ enqueue,
5
+ getQueueStats,
6
+ initQueueWorkers,
7
+ recoverOrphans,
8
+ recoverState,
9
+ stopQueueWorkers
10
+ } from "./chunk-VOQT7RVT.js";
11
+ import "./chunk-DVU3CXWA.js";
12
+ import "./chunk-OONOOWNC.js";
13
+ export {
14
+ areQueueWorkersActive,
15
+ cleanTerminalWorkspaces,
16
+ enqueue,
17
+ getQueueStats,
18
+ initQueueWorkers,
19
+ recoverOrphans,
20
+ recoverState,
21
+ stopQueueWorkers
22
+ };
23
+ //# sourceMappingURL=queue-workers-EGHCDDLB.js.map
@@ -0,0 +1,21 @@
1
+ import {
2
+ analyzeParallelizability,
3
+ ensureNotStale,
4
+ hasTerminalQueue,
5
+ installGracefulShutdown,
6
+ isShuttingDown
7
+ } from "./chunk-3FCJI2GK.js";
8
+ import "./chunk-2G6SRDOC.js";
9
+ import "./chunk-XVF6GOVS.js";
10
+ import "./chunk-O5AEQXUV.js";
11
+ import "./chunk-VOQT7RVT.js";
12
+ import "./chunk-DVU3CXWA.js";
13
+ import "./chunk-OONOOWNC.js";
14
+ export {
15
+ analyzeParallelizability,
16
+ ensureNotStale,
17
+ hasTerminalQueue,
18
+ installGracefulShutdown,
19
+ isShuttingDown
20
+ };
21
+ //# sourceMappingURL=scheduler-V4GMCBTE.js.map
@@ -18,16 +18,18 @@ import {
18
18
  persistStateFull,
19
19
  replacePersistedSetting,
20
20
  setActiveApiPlugin
21
- } from "./chunk-G7W4NEOA.js";
22
- import "./chunk-MT3S55TM.js";
21
+ } from "./chunk-3FCJI2GK.js";
23
22
  import {
24
23
  hasDirtyState,
25
24
  markEventDirty,
26
25
  markIssueDirty,
27
26
  markIssuePlanDirty
28
- } from "./chunk-XN2QKKMY.js";
29
- import "./chunk-AMOGDOM7.js";
27
+ } from "./chunk-2G6SRDOC.js";
28
+ import "./chunk-XVF6GOVS.js";
29
+ import "./chunk-O5AEQXUV.js";
30
+ import "./chunk-VOQT7RVT.js";
30
31
  import "./chunk-DVU3CXWA.js";
32
+ import "./chunk-OONOOWNC.js";
31
33
  export {
32
34
  closeStateStore,
33
35
  getAgentPipelineResource,
@@ -53,4 +55,4 @@ export {
53
55
  replacePersistedSetting,
54
56
  setActiveApiPlugin
55
57
  };
56
- //# sourceMappingURL=store-366NGWR4.js.map
58
+ //# sourceMappingURL=store-RVKQ6UEY.js.map
@@ -0,0 +1,52 @@
1
+ import {
2
+ assertIssueHasGitWorktree,
3
+ bootstrapSource,
4
+ cleanWorkspace,
5
+ computeDiffStats,
6
+ createGitWorktree,
7
+ detectDefaultBranch,
8
+ dryMerge,
9
+ ensureGitRepoReadyForWorktrees,
10
+ ensureSourceReady,
11
+ ensureWorktreeCommitted,
12
+ getGitRepoStatus,
13
+ hydrateIssuePathsFromWorkspace,
14
+ inferChangedWorkspacePaths,
15
+ initializeGitRepoForWorktrees,
16
+ mergeWorkspace,
17
+ parseDiffStats,
18
+ prepareWorkspace,
19
+ rebaseWorktree,
20
+ setSkipSource,
21
+ shouldSkipMergePath,
22
+ syncIssueDiffStatsToStore,
23
+ writeVersionedArtifacts
24
+ } from "./chunk-XVF6GOVS.js";
25
+ import "./chunk-O5AEQXUV.js";
26
+ import "./chunk-DVU3CXWA.js";
27
+ import "./chunk-OONOOWNC.js";
28
+ export {
29
+ assertIssueHasGitWorktree,
30
+ bootstrapSource,
31
+ cleanWorkspace,
32
+ computeDiffStats,
33
+ createGitWorktree,
34
+ detectDefaultBranch,
35
+ dryMerge,
36
+ ensureGitRepoReadyForWorktrees,
37
+ ensureSourceReady,
38
+ ensureWorktreeCommitted,
39
+ getGitRepoStatus,
40
+ hydrateIssuePathsFromWorkspace,
41
+ inferChangedWorkspacePaths,
42
+ initializeGitRepoForWorktrees,
43
+ mergeWorkspace,
44
+ parseDiffStats,
45
+ prepareWorkspace,
46
+ rebaseWorktree,
47
+ setSkipSource,
48
+ shouldSkipMergePath,
49
+ syncIssueDiffStatsToStore,
50
+ writeVersionedArtifacts
51
+ };
52
+ //# sourceMappingURL=workspace-KEHFITYR.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fifony",
3
- "version": "0.1.27",
3
+ "version": "0.1.28",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -50,14 +50,14 @@
50
50
  "pino-pretty": "^13.1.3",
51
51
  "raffel": "^1.0.18",
52
52
  "recker": "^1.0.86",
53
- "s3db.js": "21.3.2",
54
- "yaml": "^2.8.2"
53
+ "s3db.js": "21.3.8",
54
+ "yaml": "^2.8.3"
55
55
  },
56
56
  "devDependencies": {
57
57
  "@tailwindcss/vite": "^4.2.2",
58
- "@tanstack/react-query": "^5.91.2",
59
- "@tanstack/react-router": "^1.167.5",
60
- "@tanstack/router-plugin": "^1.166.14",
58
+ "@tanstack/react-query": "^5.94.5",
59
+ "@tanstack/react-router": "^1.168.1",
60
+ "@tanstack/router-plugin": "^1.167.2",
61
61
  "@vitejs/plugin-react": "^6.0.1",
62
62
  "daisyui": "^5.5.19",
63
63
  "lucide-react": "^0.577.0",