fifony 0.1.27 → 0.1.29

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-BF5KYX3E.js} +1 -1
  3. package/app/dist/assets/OnboardingWizard-Cweg4Ch0.js +1 -0
  4. package/app/dist/assets/{analytics.lazy-BpH26eA2.js → analytics.lazy-BlFXDncv.js} +1 -1
  5. package/app/dist/assets/{createLucideIcon-BWC-guQt.js → createLucideIcon-DgMTp0yx.js} +1 -1
  6. package/app/dist/assets/index-CSquFPSf.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
@@ -13,11 +13,11 @@
13
13
  <link rel="manifest" href="/assets/manifest.webmanifest" />
14
14
  <link rel="icon" href="/assets/icon.svg" type="image/svg+xml" />
15
15
  <link rel="apple-touch-icon" href="/assets/icon.svg" />
16
- <script type="module" crossorigin src="/assets/assets/index-D6jtlB7h.js"></script>
16
+ <script type="module" crossorigin src="/assets/assets/index-CSquFPSf.js"></script>
17
17
  <link rel="modulepreload" crossorigin href="/assets/assets/rolldown-runtime-DF2fYuay.js">
18
- <link rel="modulepreload" crossorigin href="/assets/assets/vendor-BTlTWMUF.js">
19
- <link rel="modulepreload" crossorigin href="/assets/assets/createLucideIcon-BWC-guQt.js">
20
- <link rel="stylesheet" crossorigin href="/assets/assets/index-DntTEHv8.css">
18
+ <link rel="modulepreload" crossorigin href="/assets/assets/vendor-D-IqxHHu.js">
19
+ <link rel="modulepreload" crossorigin href="/assets/assets/createLucideIcon-DgMTp0yx.js">
20
+ <link rel="stylesheet" crossorigin href="/assets/assets/index-ZlyvZ7KI.css">
21
21
  </head>
22
22
  <body>
23
23
  <div id="root"></div>
@@ -1,4 +1,4 @@
1
- const CACHE_VERSION = "1774032581374";
1
+ const CACHE_VERSION = "1774157361593";
2
2
  const CORE_CACHE = `fifony-core-${CACHE_VERSION}`;
3
3
  const ASSET_CACHE = `fifony-assets-${CACHE_VERSION}`;
4
4
  const APP_SHELL_ROUTES = ["/kanban", "/issues", "/agents", "/settings", "/onboarding"];
@@ -5,18 +5,14 @@ import {
5
5
  applyWorkflowConfig,
6
6
  buildQueueTitle,
7
7
  buildRuntimeState,
8
- cleanStalePidFile,
9
8
  closeStateStore,
10
9
  createContainer,
11
10
  deriveConfig,
12
11
  detectProjectName,
13
- ensureNotStale,
14
12
  hasTerminalQueue,
15
13
  hydrate,
16
14
  initStateStore,
17
15
  installGracefulShutdown,
18
- isAgentStillRunning,
19
- isShuttingDown,
20
16
  loadPersistedState,
21
17
  loadRuntimeSettings,
22
18
  persistDetectedProvidersSetting,
@@ -27,58 +23,48 @@ import {
27
23
  startApiServer,
28
24
  syncRuntimeConfigSettings,
29
25
  validateConfig
30
- } from "../chunk-G7W4NEOA.js";
26
+ } from "../chunk-3FCJI2GK.js";
31
27
  import {
32
- enqueueForExecution,
33
- enqueueForPlanning,
34
- enqueueForReview,
35
- initQueueWorkers,
36
- stopQueueWorkers
37
- } from "../chunk-MT3S55TM.js";
28
+ computeMetrics
29
+ } from "../chunk-2G6SRDOC.js";
38
30
  import {
39
- cleanWorkspace,
40
- computeMetrics,
41
31
  detectAvailableProviders,
42
32
  detectDefaultBranch,
43
- executeTransition,
33
+ getGitRepoStatus,
44
34
  getProviderDefaultCommand,
45
- hasDirtyState,
46
35
  resolveDefaultProvider,
47
36
  setSkipSource
48
- } from "../chunk-XN2QKKMY.js";
37
+ } from "../chunk-XVF6GOVS.js";
49
38
  import {
50
- CLI_ARGS,
51
- PACKAGE_ROOT,
52
- STATE_ROOT,
53
- TARGET_ROOT,
54
39
  debugBoot,
55
40
  fail,
56
41
  now,
57
- parseIntArg,
58
- sleep
59
- } from "../chunk-AMOGDOM7.js";
42
+ parseIntArg
43
+ } from "../chunk-O5AEQXUV.js";
44
+ import {
45
+ cleanTerminalWorkspaces,
46
+ initQueueWorkers,
47
+ recoverOrphans,
48
+ recoverState,
49
+ stopQueueWorkers
50
+ } from "../chunk-VOQT7RVT.js";
60
51
  import {
61
52
  initLogger,
62
53
  logger
63
54
  } from "../chunk-DVU3CXWA.js";
55
+ import {
56
+ CLI_ARGS,
57
+ PACKAGE_ROOT,
58
+ STATE_ROOT,
59
+ TARGET_ROOT
60
+ } from "../chunk-OONOOWNC.js";
64
61
 
65
62
  // src/boot.ts
66
- import { mkdirSync } from "fs";
63
+ import { mkdirSync, readFileSync } from "fs";
67
64
  import { env, exit, argv } from "process";
65
+
66
+ // src/persistence/plugins/dev-server.ts
68
67
  import { resolve } from "path";
69
- function parsePort(args) {
70
- for (let i = 0; i < args.length; i += 1) {
71
- const arg = args[i];
72
- if (arg === "--port") {
73
- const value = args[i + 1];
74
- if (!value || !/^\d+$/.test(value)) {
75
- fail(`Invalid value for --port: ${value ?? "<empty>"}`);
76
- }
77
- return parseIntArg(value, 4040);
78
- }
79
- }
80
- return void 0;
81
- }
82
68
  async function startDevFrontend(apiPort, devPort) {
83
69
  const VITE_CONFIG_PATH = resolve(PACKAGE_ROOT, "app/vite.config.js");
84
70
  let createViteServer;
@@ -150,6 +136,22 @@ async function startDevFrontend(apiPort, devPort) {
150
136
  logger.warn(`Failed to start Vite dev server: ${String(error)}`);
151
137
  }
152
138
  }
139
+
140
+ // src/boot.ts
141
+ import { join } from "path";
142
+ function parsePort(args) {
143
+ for (let i = 0; i < args.length; i += 1) {
144
+ const arg = args[i];
145
+ if (arg === "--port") {
146
+ const value = args[i + 1];
147
+ if (!value || !/^\d+$/.test(value)) {
148
+ fail(`Invalid value for --port: ${value ?? "<empty>"}`);
149
+ }
150
+ return parseIntArg(value, 4040);
151
+ }
152
+ }
153
+ return void 0;
154
+ }
153
155
  function usage() {
154
156
  console.log(
155
157
  `Usage: ${argv[1]} [options]
@@ -258,37 +260,29 @@ async function main() {
258
260
  state.config.dashboardPort = dashboardPort ? String(dashboardPort) : void 0;
259
261
  state.updatedAt = now();
260
262
  state.booting = false;
261
- try {
262
- const { getIssueStateMachinePlugin, ISSUE_STATE_MACHINE_ID } = await import("../issue-state-machine-SKODQ6MG.js");
263
- const fsmPlugin = getIssueStateMachinePlugin();
264
- if (fsmPlugin?.getState) {
265
- for (const issue of state.issues) {
266
- try {
267
- const fsmState = await fsmPlugin.getState(ISSUE_STATE_MACHINE_ID, issue.id);
268
- if (fsmState && fsmState !== issue.state) {
269
- logger.warn({ issueId: issue.id, memoryState: issue.state, fsmState }, "[Boot] Reconciling desync \u2014 FSM is source of truth");
270
- issue.state = fsmState;
271
- }
272
- } catch {
273
- }
274
- }
275
- }
276
- } catch {
277
- }
278
263
  if (!state.config.defaultBranch) {
279
264
  try {
280
- const detectedBranch = detectDefaultBranch(TARGET_ROOT);
281
- state.config.defaultBranch = detectedBranch;
282
- logger.info({ defaultBranch: detectedBranch }, "[Agent] Default branch detected");
265
+ state.config.defaultBranch = detectDefaultBranch(TARGET_ROOT);
266
+ logger.info({ defaultBranch: state.config.defaultBranch }, "[Boot] Default branch detected");
283
267
  } catch {
284
268
  }
285
269
  }
286
- if (state.config.agentCommand) {
287
- state.notes.push(`Using agent command: ${state.config.agentCommand}`);
270
+ const gitStatus = getGitRepoStatus(TARGET_ROOT);
271
+ if (!gitStatus.isGit) {
272
+ logger.warn({ workspace: TARGET_ROOT }, "[Boot] Target workspace is not a git repository. Issue execution and merge will stay blocked until git is initialized.");
273
+ } else if (!gitStatus.hasCommits) {
274
+ logger.warn({ workspace: TARGET_ROOT, branch: gitStatus.branch }, "[Boot] Target workspace has no commits. Create an initial commit before running issues because git worktree needs a base commit.");
275
+ }
276
+ if (!state.config.testCommand) {
277
+ try {
278
+ const pkg = JSON.parse(readFileSync(join(TARGET_ROOT, "package.json"), "utf8"));
279
+ if (pkg?.scripts?.test && !pkg.scripts.test.includes("no test specified")) {
280
+ state.config.testCommand = "pnpm test";
281
+ logger.info({ testCommand: state.config.testCommand }, "[Boot] Test command auto-detected");
282
+ }
283
+ } catch {
284
+ }
288
285
  }
289
- state.notes.push(`Agent session max turns: ${state.config.maxTurns}`);
290
- state.notes.push(`Agent provider: ${state.config.agentProvider}`);
291
- state.notes.push(`Interface mode: ${interfaceMode}`);
292
286
  if (!state.config.agentCommand.trim()) {
293
287
  const available = detectedProviders.filter((p) => p.available).map((p) => p.name);
294
288
  fail(
@@ -299,48 +293,8 @@ async function main() {
299
293
  if (configErrors.length > 0) {
300
294
  for (const err of configErrors) logger.warn(`Config validation: ${err}`);
301
295
  }
302
- const terminalIssues = state.issues.filter((i) => i.state === "Merged" || i.state === "Cancelled");
303
- if (terminalIssues.length > 0) {
304
- logger.info(`Scheduling cleanup of ${terminalIssues.length} terminal workspace(s) in background...`);
305
- setImmediate(async () => {
306
- for (const issue of terminalIssues) {
307
- try {
308
- await cleanWorkspace(issue.id, issue, state);
309
- } catch {
310
- }
311
- }
312
- logger.info("Background workspace cleanup complete.");
313
- });
314
- }
315
- if (!skipRecovery) {
316
- logger.debug({ issueCount: state.issues.filter((i) => i.state === "Running" || i.state === "Queued").length }, "[Boot] Checking for orphaned agent processes");
317
- for (const issue of state.issues) {
318
- if (issue.state === "Running" || issue.state === "Queued") {
319
- const { alive, pid } = isAgentStillRunning(issue);
320
- if (alive && pid) {
321
- logger.info(`Agent for ${issue.identifier} still alive (PID ${pid.pid}), keeping state as Running.`);
322
- if (issue.state !== "Running") {
323
- try {
324
- await executeTransition(issue, "RUN", { issue, note: `Orphaned agent detected (PID ${pid.pid}), still alive \u2014 tracking resumed.` });
325
- } catch {
326
- issue.state = "Running";
327
- }
328
- }
329
- addEvent(state, issue.id, "info", `Orphaned agent detected (PID ${pid.pid}), still alive \u2014 tracking resumed.`);
330
- } else {
331
- if (issue.workspacePath) cleanStalePidFile(issue.workspacePath);
332
- if (issue.state === "Running") {
333
- try {
334
- await executeTransition(issue, "REQUEUE", { issue, note: `Agent process not found on boot \u2014 marked Queued.` });
335
- } catch {
336
- issue.state = "Queued";
337
- }
338
- addEvent(state, issue.id, "info", `Agent for ${issue.identifier} not found, marked Queued.`);
339
- }
340
- }
341
- }
342
- }
343
- }
296
+ cleanTerminalWorkspaces();
297
+ if (!skipRecovery) await recoverOrphans();
344
298
  state.metrics = computeMetrics(state.issues);
345
299
  if (dashboardPort) {
346
300
  Object.assign(apiState, state);
@@ -354,8 +308,7 @@ async function main() {
354
308
  } catch (error) {
355
309
  logger.warn({ err: error }, "[Boot] Queue workers failed to initialize \u2014 continuing without queue-based dispatch");
356
310
  }
357
- const running = /* @__PURE__ */ new Set();
358
- installGracefulShutdown(state, running);
311
+ installGracefulShutdown(state);
359
312
  logger.info("[Boot] Runtime ready");
360
313
  hydrate(state.issues);
361
314
  logger.info(`Loaded issues: ${state.issues.length}`);
@@ -367,47 +320,14 @@ async function main() {
367
320
  try {
368
321
  addEvent(state, void 0, "info", `Runtime started in local-only mode (filesystem tracker).`);
369
322
  const runForever = !runOnce && (Boolean(dashboardPort) || interfaceMode === "mcp");
370
- logger.info({ runForever, runOnce, dashboardPort, interfaceMode }, "[Boot] Entering queue supervisor loop");
371
- for (const issue of state.issues) {
372
- try {
373
- if (issue.state === "Planning" && issue.planningStatus !== "planning") {
374
- await enqueueForPlanning(issue);
375
- } else if (issue.state === "Queued" || issue.state === "Running") {
376
- await enqueueForExecution(issue);
377
- } else if (issue.state === "Reviewing") {
378
- await enqueueForReview(issue);
379
- }
380
- } catch (err) {
381
- logger.error({ err, issueId: issue.id, state: issue.state }, "[Boot] Failed to enqueue issue for recovery");
382
- }
383
- }
384
- const PERSIST_DEBOUNCE_MS = 5e3;
385
- let lastPersistAt = 0;
323
+ logger.info({ runForever, runOnce, dashboardPort, interfaceMode }, "[Boot] Queue-driven dispatch active");
324
+ await recoverState();
386
325
  if (runForever) {
387
- while (!isShuttingDown()) {
388
- const statesBefore = new Map(state.issues.map((i) => [i.id, i.state]));
389
- await ensureNotStale(state, state.config.staleInProgressTimeoutMs);
390
- for (const issue of state.issues) {
391
- const prev = statesBefore.get(issue.id);
392
- if (prev !== issue.state) {
393
- if (issue.state === "Queued") enqueueForExecution(issue).catch(() => {
394
- });
395
- else if (issue.state === "Reviewing") enqueueForReview(issue).catch(() => {
396
- });
397
- else if (issue.state === "Planning") enqueueForPlanning(issue).catch(() => {
398
- });
399
- }
400
- }
401
- state.updatedAt = now();
402
- if (hasDirtyState() || Date.now() - lastPersistAt > PERSIST_DEBOUNCE_MS) {
403
- await persistState(state);
404
- lastPersistAt = Date.now();
405
- }
406
- await sleep(1e3);
407
- }
326
+ await new Promise(() => {
327
+ });
408
328
  } else {
409
329
  while (!hasTerminalQueue(state)) {
410
- await sleep(state.config.pollIntervalMs);
330
+ await new Promise((r) => setTimeout(r, state.config.pollIntervalMs));
411
331
  }
412
332
  }
413
333
  } catch (error) {
@@ -0,0 +1,74 @@
1
+ import {
2
+ addTokenUsage,
3
+ cleanStalePidFile,
4
+ extractTokenUsage,
5
+ isAgentStillRunning,
6
+ isProcessAlive,
7
+ issueHasResumableSession,
8
+ loadAgentPipelineSnapshotForIssue,
9
+ loadAgentPipelineState,
10
+ loadAgentSessionSnapshotsForIssue,
11
+ readAgentDirective,
12
+ readAgentPid,
13
+ runAgentPipeline,
14
+ runAgentSession,
15
+ runIssueOnce,
16
+ runPlanningJob,
17
+ tryParseJsonOutput
18
+ } from "./chunk-3FCJI2GK.js";
19
+ import "./chunk-2G6SRDOC.js";
20
+ import {
21
+ buildPrompt,
22
+ buildProviderBasePrompt,
23
+ buildTurnPrompt,
24
+ cleanWorkspace,
25
+ computeDiffStats,
26
+ createGitWorktree,
27
+ ensureWorktreeCommitted,
28
+ hydrateIssuePathsFromWorkspace,
29
+ inferChangedWorkspacePaths,
30
+ mergeWorkspace,
31
+ parseDiffStats,
32
+ prepareWorkspace,
33
+ runCommandWithTimeout,
34
+ runHook,
35
+ shouldSkipMergePath
36
+ } from "./chunk-XVF6GOVS.js";
37
+ import "./chunk-O5AEQXUV.js";
38
+ import "./chunk-VOQT7RVT.js";
39
+ import "./chunk-DVU3CXWA.js";
40
+ import "./chunk-OONOOWNC.js";
41
+ export {
42
+ addTokenUsage,
43
+ buildPrompt,
44
+ buildProviderBasePrompt,
45
+ buildTurnPrompt,
46
+ cleanStalePidFile,
47
+ cleanWorkspace,
48
+ computeDiffStats,
49
+ createGitWorktree,
50
+ ensureWorktreeCommitted,
51
+ extractTokenUsage,
52
+ hydrateIssuePathsFromWorkspace,
53
+ inferChangedWorkspacePaths,
54
+ isAgentStillRunning,
55
+ isProcessAlive,
56
+ issueHasResumableSession,
57
+ loadAgentPipelineSnapshotForIssue,
58
+ loadAgentPipelineState,
59
+ loadAgentSessionSnapshotsForIssue,
60
+ mergeWorkspace,
61
+ parseDiffStats,
62
+ prepareWorkspace,
63
+ readAgentDirective,
64
+ readAgentPid,
65
+ runAgentPipeline,
66
+ runAgentSession,
67
+ runCommandWithTimeout,
68
+ runHook,
69
+ runIssueOnce,
70
+ runPlanningJob,
71
+ shouldSkipMergePath,
72
+ tryParseJsonOutput
73
+ };
74
+ //# sourceMappingURL=agent-FPUYBJZD.js.map