@agent-relay/factory 0.1.58 → 0.1.60

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 (60) hide show
  1. package/README.md +13 -0
  2. package/dist/cli/fleet.d.ts +7 -1
  3. package/dist/cli/fleet.d.ts.map +1 -1
  4. package/dist/cli/fleet.js +126 -10
  5. package/dist/cli/fleet.js.map +1 -1
  6. package/dist/config/schema.d.ts +777 -273
  7. package/dist/config/schema.d.ts.map +1 -1
  8. package/dist/config/schema.js +37 -0
  9. package/dist/config/schema.js.map +1 -1
  10. package/dist/delivery/ticket-dispatch.d.ts +15 -0
  11. package/dist/delivery/ticket-dispatch.d.ts.map +1 -0
  12. package/dist/delivery/ticket-dispatch.js +20 -0
  13. package/dist/delivery/ticket-dispatch.js.map +1 -0
  14. package/dist/git/agent-worktree.d.ts.map +1 -1
  15. package/dist/git/agent-worktree.js +4 -0
  16. package/dist/git/agent-worktree.js.map +1 -1
  17. package/dist/index.d.ts +1 -1
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js.map +1 -1
  20. package/dist/issue-key-match.d.ts +6 -0
  21. package/dist/issue-key-match.d.ts.map +1 -1
  22. package/dist/issue-key-match.js +14 -0
  23. package/dist/issue-key-match.js.map +1 -1
  24. package/dist/mount/relayfile-github-connection-write.d.ts.map +1 -1
  25. package/dist/mount/relayfile-github-connection-write.js +6 -3
  26. package/dist/mount/relayfile-github-connection-write.js.map +1 -1
  27. package/dist/orchestrator/batch-tracker.d.ts +2 -1
  28. package/dist/orchestrator/batch-tracker.d.ts.map +1 -1
  29. package/dist/orchestrator/batch-tracker.js.map +1 -1
  30. package/dist/orchestrator/factory.d.ts.map +1 -1
  31. package/dist/orchestrator/factory.js +1473 -99
  32. package/dist/orchestrator/factory.js.map +1 -1
  33. package/dist/ports/fleet.d.ts +4 -0
  34. package/dist/ports/fleet.d.ts.map +1 -1
  35. package/dist/ports/mount.d.ts +2 -0
  36. package/dist/ports/mount.d.ts.map +1 -1
  37. package/dist/ports/state.d.ts +45 -1
  38. package/dist/ports/state.d.ts.map +1 -1
  39. package/dist/state/file-state-store.d.ts +6 -1
  40. package/dist/state/file-state-store.d.ts.map +1 -1
  41. package/dist/state/file-state-store.js +119 -2
  42. package/dist/state/file-state-store.js.map +1 -1
  43. package/dist/state/in-memory-state-store.d.ts +6 -1
  44. package/dist/state/in-memory-state-store.d.ts.map +1 -1
  45. package/dist/state/in-memory-state-store.js +62 -0
  46. package/dist/state/in-memory-state-store.js.map +1 -1
  47. package/dist/triage/schema.d.ts +36 -0
  48. package/dist/triage/schema.d.ts.map +1 -1
  49. package/dist/triage/schema.js +2 -0
  50. package/dist/triage/schema.js.map +1 -1
  51. package/dist/types.d.ts +31 -0
  52. package/dist/types.d.ts.map +1 -1
  53. package/dist/version-info.d.ts +21 -0
  54. package/dist/version-info.d.ts.map +1 -0
  55. package/dist/version-info.js +146 -0
  56. package/dist/version-info.js.map +1 -0
  57. package/dist/writeback/github.d.ts.map +1 -1
  58. package/dist/writeback/github.js +12 -0
  59. package/dist/writeback/github.js.map +1 -1
  60. package/package.json +1 -1
package/README.md CHANGED
@@ -143,6 +143,19 @@ After init, add the `factory` label to an open issue and run a dry run below.
143
143
  | `factory featuremap check [--manifest <path>] [--base <ref>]` | Validate the repository feature/test manifest and optionally report advisory drift for unchanged entries whose locations changed. |
144
144
  | `factory intake notion <manifest>` | Normalize ready specs from a read-only Notion mount into GitHub lifecycle issues or exact-path fleet work. Honors `--dry-run`. |
145
145
 
146
+ `factory status` includes `inFlightDispatches`, grouped by issue with agent
147
+ names and the provider-claim state (`pending`, `verified`, or `degraded`). This
148
+ view is read from Factory's local in-flight registry, so it remains available
149
+ when GitHub lifecycle writeback is the degraded subsystem.
150
+
151
+ Dispatch lifecycle writes are claim-critical. Factory applies the
152
+ `factory:in-progress` label/state before the dispatch comment, confirms the
153
+ GitHub label by provider read-back, and retries either write three times. An
154
+ exhausted write is logged at error level as dead-lettered, recorded as a
155
+ degraded claim in the registry, and fails the dispatch instead of reporting a
156
+ clean dispatch with missing GitHub state. Durable lifecycle recovery repeats
157
+ the same label-and-comment claim without respawning acknowledged agents.
158
+
146
159
  Global options work anywhere in the args: `--config <path>`, `--dry-run`,
147
160
  `--backend <internal|relay>`, and `--agent-exit-timeout <ms>`. The internal
148
161
  backend reuses a relay broker that's already running for your workspace, and
@@ -1,8 +1,9 @@
1
1
  import { ensureCloudSession, type CloudSession } from '@agent-relay/cloud';
2
2
  import { type LocalClonePathOptions } from '../config/local-clone-paths.js';
3
- import { createFactory, createFleet, ensureRelayBroker, reapFactoryEnvironmentsOnce, type Capability, type Factory, type FactoryEventReporter, type FactoryConfig, type FleetBackend, type FleetClient, type GhRunner, type FactoryStateResolution, type LocalMountOptions, type MountClient, type ProbeCloser, type RelayfileCloudMountClientConfig, type ResolvedFactoryWorkspace } from '../index.js';
3
+ import { createFactory, createFleet, ensureRelayBroker, reapFactoryEnvironmentsOnce, type Capability, type Factory, type FactoryEventReporter, type FactoryConfig, type FleetBackend, type FleetClient, type GhRunner, type FactoryStateResolution, type Logger, type LocalMountOptions, type MountClient, type ProbeCloser, type RelayfileCloudMountClientConfig, type ResolvedFactoryWorkspace } from '../index.js';
4
4
  import { type CheckFeatureMapOptions, type FeatureMapCheckReport } from '../featuremap/index.js';
5
5
  import type { FactoryIntegrationProvider } from '../ports/index.js';
6
+ import { type FactoryVersionInfo, type FactoryVersionInfoOptions } from '../version-info.js';
6
7
  import { type NotionIntakeClaimStore, type NotionContractPublisher } from '../intake/index.js';
7
8
  interface FleetCliDeps {
8
9
  fleet?: FleetClient;
@@ -40,6 +41,10 @@ interface FleetCliDeps {
40
41
  notionClaims?: NotionIntakeClaimStore;
41
42
  /** Hermetic verification-environment sweep for CLI tests and alternate runtimes. */
42
43
  reapEnvironments?: typeof reapFactoryEnvironmentsOnce;
44
+ /** Hermetic package/registry metadata for CLI tests and alternate runtimes. */
45
+ versionInfo?: (options?: FactoryVersionInfoOptions) => Promise<FactoryVersionInfo>;
46
+ /** Override the six-hour daemon drift check cadence in tests. */
47
+ versionCheckIntervalMs?: number;
43
48
  }
44
49
  interface GlobalOptions {
45
50
  backend: FleetBackend;
@@ -109,6 +114,7 @@ export declare function parseGlobalOptions(argv: string[]): {
109
114
  globals: GlobalOptions;
110
115
  args: string[];
111
116
  };
117
+ export declare function reportFactoryVersionDrift(provider: FleetCliDeps['versionInfo'], logger: Logger): Promise<void>;
112
118
  export declare function formatLogArgs(args: unknown[]): string;
113
119
  export declare function resolveBrokerConnectionPath(startCwd?: string, env?: NodeJS.ProcessEnv): string | undefined;
114
120
  export type GithubIssueSelector = {
@@ -1 +1 @@
1
- {"version":3,"file":"fleet.d.ts","sourceRoot":"","sources":["../../src/cli/fleet.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,kBAAkB,EAAE,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAG1E,OAAO,EAA6B,KAAK,qBAAqB,EAAE,MAAM,6BAA6B,CAAA;AAEnG,OAAO,EAKL,aAAa,EACb,WAAW,EAEX,iBAAiB,EAgBjB,2BAA2B,EAO3B,KAAK,UAAU,EACf,KAAK,OAAO,EACZ,KAAK,oBAAoB,EACzB,KAAK,aAAa,EAElB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,QAAQ,EACb,KAAK,sBAAsB,EAG3B,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAGhB,KAAK,WAAW,EAChB,KAAK,+BAA+B,EACpC,KAAK,wBAAwB,EAC9B,MAAM,UAAU,CAAA;AAIjB,OAAO,EAAmB,KAAK,sBAAsB,EAAE,KAAK,qBAAqB,EAAE,MAAM,eAAe,CAAA;AAQxG,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,UAAU,CAAA;AAI1D,OAAO,EAML,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,EAE7B,MAAM,WAAW,CAAA;AAElB,UAAU,YAAY;IACpB,KAAK,CAAC,EAAE,WAAW,CAAA;IACnB,qEAAqE;IACrE,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAA;IACvB,KAAK,CAAC,EAAE,WAAW,CAAA;IACnB,aAAa,CAAC,EAAE,OAAO,aAAa,CAAA;IACpC,WAAW,CAAC,EAAE,OAAO,WAAW,CAAA;IAChC,iBAAiB,CAAC,EAAE,OAAO,iBAAiB,CAAA;IAC5C,oBAAoB,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,+BAA+B,KAAK,OAAO,CAAC,WAAW,CAAC,CAAA;IACzF,gBAAgB,CAAC,EAAE,MAAM,OAAO,CAAC,wBAAwB,CAAC,CAAA;IAC1D,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,aAAa,KAAK,OAAO,CAAC,sBAAsB,CAAC,CAAA;IAC9F,gBAAgB,CAAC,EAAE,CACjB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,iBAAiB,KACxB,OAAO,CAAC,IAAI,CAAC,CAAA;IAClB,iBAAiB,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA;IAChD,MAAM,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAA;IAC1C,MAAM,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAA;IAC1C,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,eAAe,CAAC,EAAE,QAAQ,CAAA;IAC1B,iBAAiB,CAAC,EAAE,QAAQ,CAAA;IAC5B,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;IAClB,qBAAqB,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,KAAK,CAAC,CAAA;IAC5D,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACnC,iBAAiB,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IACvC,gEAAgE;IAChE,qBAAqB,CAAC,EAAE,qBAAqB,CAAA;IAC7C,QAAQ,CAAC,EAAE,oBAAoB,CAAA;IAC/B,oBAAoB,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,YAAY,CAAC,CAAA;IACpG,aAAa,CAAC,EAAE,MAAM,OAAO,CAAA;IAC7B,yBAAyB,CAAC,EAAE,CAAC,QAAQ,EAAE,0BAA0B,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IACtF,kBAAkB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1D,eAAe,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,sBAAsB,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAA;IACtF,2FAA2F;IAC3F,eAAe,CAAC,EAAE,uBAAuB,CAAA;IACzC,qFAAqF;IACrF,YAAY,CAAC,EAAE,sBAAsB,CAAA;IACrC,oFAAoF;IACpF,gBAAgB,CAAC,EAAE,OAAO,2BAA2B,CAAA;CACtD;AAED,UAAU,aAAa;IACrB,OAAO,EAAE,YAAY,CAAA;IACrB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,OAAO,CAAA;IACf,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAC5B;AAQD,KAAK,aAAa,GACd;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE;QAAE,UAAU,EAAE,UAAU,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GAChL;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAClD;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,aAAa,GAAG,WAAW,GAAG,cAAc,CAAA;CAAE,GAC1G;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GACnD;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACzC;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACzC;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC3C;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAC1E;IAAE,IAAI,EAAE,qBAAqB,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC9E;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GACrE;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7D;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAAA;AAEnD,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,GAAE,YAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,CA6V1F;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,aAAa,CAuB/D;AAoED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG;IAAE,OAAO,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CA8B7F;AA+vBD,wBAAgB,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,MAAM,CAGrD;AAED,wBAAgB,2BAA2B,CACzC,QAAQ,SAAgB,EACxB,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,GAAG,SAAS,CA2BpB;AAmeD,MAAM,MAAM,mBAAmB,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAEnE,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,mBAAmB,CA6BhG;AA6MD,wBAAgB,gCAAgC,CAC9C,OAAO,EAAE,OAAO,EAChB,IAAI,GAAE;IACJ,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC7B,WAAW,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,KAAK,CAAC,CAAA;CAC9C,GACL,MAAM,IAAI,CA4BZ;AAwED,wBAAsB,IAAI,CAAC,IAAI,WAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAGtE"}
1
+ {"version":3,"file":"fleet.d.ts","sourceRoot":"","sources":["../../src/cli/fleet.ts"],"names":[],"mappings":"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"}
package/dist/cli/fleet.js CHANGED
@@ -1,13 +1,13 @@
1
1
  import { existsSync } from 'node:fs';
2
2
  import { readFile } from 'node:fs/promises';
3
3
  import { dirname, join, resolve } from 'node:path';
4
- import { randomUUID } from 'node:crypto';
4
+ import { createHash, randomUUID } from 'node:crypto';
5
5
  import readline from 'node:readline/promises';
6
6
  import { ensureCloudSession } from '@agent-relay/cloud';
7
7
  import { stringifyLogValue } from '../logging.js';
8
8
  import { resolveLocalFactoryConfig } from '../config/local-clone-paths.js';
9
9
  import { initializeFactory } from './init.js';
10
- import { FileStateStore, RelayfileCloudMountClient, checkFactoryLoopLiveness, closeProbePr, createFactory, createFleet, createFactoryCloudEventV1, ensureRelayBroker, FactoryCloudReporter, FileFactoryCloudEventOutbox, defaultGhRunner, explicitLinkedIssueKey, githubIssuePathParts, githubWatchStatePath, isInFactoryScope, parseGithubFactoryIssue, publishFactoryMountHealth, parseOwnedBrokerAgentExitTimeoutMs, parseStandaloneBabysitTarget, readStandalonePullRequest, readLinearIssueWithCanonicalFallback, reapFactoryOrphansOnce, reapFactoryEnvironmentsOnce, readFactoryLoopHeartbeat, resolveFactoryStates, stateResolutionFromIds, standaloneBabysitterAgentName, renderAgentTask, resolveFactoryWorkspace, } from '../index.js';
10
+ import { FileStateStore, RelayfileCloudMountClient, checkFactoryLoopLiveness, closeProbePr, createFactory, createFleet, createFactoryCloudEventV1, ensureRelayBroker, FactoryCloudReporter, FileFactoryCloudEventOutbox, defaultGhRunner, explicitLinkedIssueKey, githubIssuePathParts, githubWatchStatePath, isInFactoryScope, parseGithubFactoryIssue, publishFactoryMountHealth, parseOwnedBrokerAgentExitTimeoutMs, parseStandaloneBabysitTarget, readStandalonePullRequest, readLinearIssueWithCanonicalFallback, reapFactoryOrphansOnce, reapFactoryEnvironmentsOnce, readFactoryLoopHeartbeat, readFactoryInFlightRegistry, resolveFactoryStates, stateResolutionFromIds, standaloneBabysitterAgentName, renderAgentTask, resolveFactoryWorkspace, } from '../index.js';
11
11
  import { resolveTestGuidance } from '../dispatch/test-guidance.js';
12
12
  import { FakeFleetClient, FakeMountClient } from '../testing/index.js';
13
13
  import { GitAgentWorktreeManager } from '../git/agent-worktree.js';
@@ -17,6 +17,7 @@ import { ensureFactoryIntegrations, inspectFactoryIntegration, openIntegrationUr
17
17
  import { checkMountStaleness } from '../mount/relayfile-binary.js';
18
18
  import { MountAuthScopeError } from '../mount/mount-auth-error.js';
19
19
  import { resolveRelayWorkspaceKey } from '../fleet/relay-workspace-key.js';
20
+ import { isMeaningfullyBehind, readFactoryVersionInfo, } from '../version-info.js';
20
21
  import { GhCliIssuePublisher, RelayChannelNotionClaimStore, RelayChannelNotionContractPublisher, loadNotionIntakeManifest, runNotionIntake, } from '../intake/index.js';
21
22
  const autoDetectedIssueSources = new WeakSet();
22
23
  export async function runFleetCli(argv, deps = {}) {
@@ -491,6 +492,18 @@ async function runFactoryCommand(command, factory, mount, fleet, config, globals
491
492
  if (command.action === 'start') {
492
493
  const waiter = createStopSignalWaiter();
493
494
  let stoppedBySignal = false;
495
+ const logger = streamLogger(mountStderr);
496
+ const installedVersion = await safeFactoryVersionInfo(deps.versionInfo, false);
497
+ logger.info?.('[factory] daemon starting', installedVersion);
498
+ // The registry lookup is deliberately detached from the startup path.
499
+ // stop() only joins the bounded in-flight lookup during shutdown.
500
+ const versionMonitor = deps.versionInfo || !hasInjectedFactoryRuntime(deps)
501
+ ? startFactoryVersionMonitor({
502
+ versionInfo: deps.versionInfo,
503
+ intervalMs: deps.versionCheckIntervalMs,
504
+ logger,
505
+ })
506
+ : { stop: async () => { } };
494
507
  const flushAndResolve = async (code) => {
495
508
  try {
496
509
  await (deps.flushDaemonOutput ?? flushProcessOutput)();
@@ -558,6 +571,7 @@ async function runFactoryCommand(command, factory, mount, fleet, config, globals
558
571
  return typeof code === 'number' ? code : 0;
559
572
  }
560
573
  finally {
574
+ await versionMonitor.stop();
561
575
  removeSignalHandlers();
562
576
  if (!stoppedBySignal) {
563
577
  await factory.stop();
@@ -570,7 +584,8 @@ async function runFactoryCommand(command, factory, mount, fleet, config, globals
570
584
  return 0;
571
585
  }
572
586
  if (command.action === 'status') {
573
- writeJson(out, await factoryStatusWithMountHealth(factory, mount, config.loop.heartbeatPath, config.loop.heartbeatStaleMs));
587
+ const versionInfo = await safeFactoryVersionInfo(deps.versionInfo, Boolean(deps.versionInfo) || !hasInjectedFactoryRuntime(deps));
588
+ writeJson(out, await factoryStatusWithMountHealth(factory, mount, config.loop.heartbeatPath, config.loop.registryPath, config.loop.heartbeatStaleMs, versionInfo));
574
589
  return 0;
575
590
  }
576
591
  if (command.action === 'loop-status') {
@@ -595,7 +610,7 @@ async function runFactoryCommand(command, factory, mount, fleet, config, globals
595
610
  const reports = await factory.runLoop({ dryRun: globals.dryRun });
596
611
  writeJson(out, {
597
612
  reports,
598
- status: await factoryStatusWithMountHealth(factory, mount, config.loop.heartbeatPath, config.loop.heartbeatStaleMs),
613
+ status: await factoryStatusWithMountHealth(factory, mount, config.loop.heartbeatPath, config.loop.registryPath, config.loop.heartbeatStaleMs),
599
614
  });
600
615
  }
601
616
  finally {
@@ -809,9 +824,18 @@ async function ensureMountPath(mountFn, workspaceId, path, mountOpts, stderr, lo
809
824
  function resolveIntegrationsMountRoot(mount) {
810
825
  return mount.getLocalMountRoot?.() ?? resolve(process.cwd(), '.integrations');
811
826
  }
812
- async function factoryStatusWithMountHealth(factory, mount, heartbeatPath, heartbeatStaleMs) {
827
+ async function factoryStatusWithMountHealth(factory, mount, heartbeatPath, registryPath, heartbeatStaleMs, versionInfo) {
813
828
  const status = factory.status();
814
- const heartbeat = await readFactoryLoopHeartbeat(heartbeatPath);
829
+ const [heartbeat, registry] = await Promise.all([
830
+ readFactoryLoopHeartbeat(heartbeatPath),
831
+ readFactoryInFlightRegistry(registryPath),
832
+ ]);
833
+ const registryDispatches = registry?.heartbeatPath && registry.heartbeatPath !== heartbeatPath
834
+ ? []
835
+ : inFlightDispatchesFromRegistry(registry);
836
+ const observableStatus = registryDispatches.length > 0
837
+ ? { ...status, inFlightDispatches: registryDispatches }
838
+ : status;
815
839
  const liveness = checkFactoryLoopLiveness(heartbeat, { staleMs: heartbeatStaleMs });
816
840
  const eventListener = liveness.ok
817
841
  ? heartbeat?.eventListener ?? {
@@ -824,9 +848,10 @@ async function factoryStatusWithMountHealth(factory, mount, heartbeatPath, heart
824
848
  };
825
849
  const health = mount.getLocalMountHealth?.();
826
850
  if (!health)
827
- return { ...status, eventListener };
851
+ return { ...observableStatus, ...versionInfo, eventListener };
828
852
  return {
829
- ...status,
853
+ ...observableStatus,
854
+ ...versionInfo,
830
855
  eventListener,
831
856
  localMountDegraded: health.degraded,
832
857
  ...(health.reason ? { localMountDegradedReason: health.reason } : {}),
@@ -839,6 +864,82 @@ async function factoryStatusWithMountHealth(factory, mount, heartbeatPath, heart
839
864
  },
840
865
  };
841
866
  }
867
+ function inFlightDispatchesFromRegistry(registry) {
868
+ if (!registry)
869
+ return [];
870
+ const grouped = new Map();
871
+ const claimPriority = { verified: 0, pending: 1, degraded: 2 };
872
+ for (const agent of registry.agents) {
873
+ if (!agent.issue)
874
+ continue;
875
+ const key = `${agent.issue.key}\u0000${agent.issue.uuid}\u0000${agent.issue.path}`;
876
+ const claim = agent.dispatchClaim ?? {
877
+ state: 'pending',
878
+ updatedAtMs: registry.updatedAtMs,
879
+ };
880
+ const existing = grouped.get(key);
881
+ const entry = existing ?? {
882
+ issue: { ...agent.issue },
883
+ agents: [],
884
+ claim: { ...claim },
885
+ };
886
+ if (claimPriority[claim.state] > claimPriority[entry.claim.state]) {
887
+ entry.claim = { ...claim };
888
+ }
889
+ if (!entry.agents.some((candidate) => candidate.name === agent.name)) {
890
+ entry.agents.push({
891
+ name: agent.name,
892
+ ...(agent.role ? { role: agent.role } : {}),
893
+ ...(agent.sessionRef ? { sessionRef: agent.sessionRef } : {}),
894
+ ...(agent.invocationId ? { invocationId: agent.invocationId } : {}),
895
+ ...(agent.node ? { node: agent.node } : {}),
896
+ });
897
+ }
898
+ grouped.set(key, entry);
899
+ }
900
+ return [...grouped.values()]
901
+ .map((entry) => ({
902
+ ...entry,
903
+ agents: entry.agents.sort((left, right) => left.name.localeCompare(right.name)),
904
+ }))
905
+ .sort((left, right) => left.issue.key.localeCompare(right.issue.key));
906
+ }
907
+ const DEFAULT_VERSION_CHECK_INTERVAL_MS = 6 * 60 * 60 * 1_000;
908
+ async function safeFactoryVersionInfo(provider, includeRegistry) {
909
+ try {
910
+ return await (provider ?? readFactoryVersionInfo)({ includeRegistry });
911
+ }
912
+ catch {
913
+ return { version: 'unknown' };
914
+ }
915
+ }
916
+ export async function reportFactoryVersionDrift(provider, logger) {
917
+ const info = await safeFactoryVersionInfo(provider, true);
918
+ if (!isMeaningfullyBehind(info) || !info.latestVersion)
919
+ return;
920
+ logger.warn?.(`[factory] version drift detected: running ${info.version}; published latest ${info.latestVersion}`, {
921
+ ...(info.versionsBehind !== undefined ? { versionsBehind: info.versionsBehind } : {}),
922
+ ...(info.installedAt ? { installedAt: info.installedAt } : {}),
923
+ });
924
+ }
925
+ function startFactoryVersionMonitor(input) {
926
+ let pending;
927
+ const check = () => {
928
+ if (pending)
929
+ return;
930
+ pending = reportFactoryVersionDrift(input.versionInfo, input.logger)
931
+ .finally(() => { pending = undefined; });
932
+ };
933
+ check();
934
+ const interval = setInterval(check, input.intervalMs ?? DEFAULT_VERSION_CHECK_INTERVAL_MS);
935
+ interval.unref?.();
936
+ return {
937
+ stop: async () => {
938
+ clearInterval(interval);
939
+ await pending;
940
+ },
941
+ };
942
+ }
842
943
  function writeMountRefreshSummary(refreshedStaleMounts, stderr, debug) {
843
944
  if (debug) {
844
945
  for (const mount of [...refreshedStaleMounts].sort((left, right) => left.path.localeCompare(right.path))) {
@@ -1291,7 +1392,7 @@ async function buildMount(loaded, deps, observability = {}) {
1291
1392
  if (deps.mount)
1292
1393
  return deps.mount;
1293
1394
  if (hasExplicitFixtureFiles(loaded))
1294
- return new FakeMountClient(loaded.fixtureFiles);
1395
+ return new FixtureMountClient(loaded.fixtureFiles);
1295
1396
  let mount;
1296
1397
  mount = await (deps.cloudMountFromConfig ?? RelayfileCloudMountClient.fromConfig)({
1297
1398
  workspaceId: loaded.config.workspaceId,
@@ -1303,6 +1404,21 @@ async function buildMount(loaded, deps, observability = {}) {
1303
1404
  return mount;
1304
1405
  }
1305
1406
  const hasExplicitFixtureFiles = (loaded) => loaded?.fixtureFiles !== undefined;
1407
+ /** Hermetic fixture runs have no server event feed, so expose the in-memory
1408
+ * tree shape as their change watermark. The discovery tree cache only
1409
+ * remembers which paths exist under a prefix, not their content, so the
1410
+ * watermark must track path membership only. Hashing full file entries
1411
+ * (as an earlier version of this did) also hashes each file's `revision`,
1412
+ * which FakeMountClient.writeFile bumps on every write — so any factory
1413
+ * writeback mid-sweep (a draft, a confirmed write) would change the digest
1414
+ * with no fixture change-event to explain the gap, and the checkpoint
1415
+ * would never persist across a sweep that actually dispatched anything. */
1416
+ class FixtureMountClient extends FakeMountClient {
1417
+ async getEventHighWatermark() {
1418
+ const paths = [...this.files.keys()].sort();
1419
+ return `fixture:${createHash('sha256').update(JSON.stringify(paths)).digest('hex')}`;
1420
+ }
1421
+ }
1306
1422
  async function isAllowedFactoryDraft(path, content, opts, mount, config) {
1307
1423
  if (!opts?.guarded)
1308
1424
  return false;
@@ -1481,7 +1597,7 @@ async function findGithubIssueThroughConnection(mount, selector, config, issueAr
1481
1597
  return found[0].issue;
1482
1598
  }
1483
1599
  async function issueProjectionStatus(factory, mount, config) {
1484
- const status = await factoryStatusWithMountHealth(factory, mount, config.loop.heartbeatPath, config.loop.heartbeatStaleMs);
1600
+ const status = await factoryStatusWithMountHealth(factory, mount, config.loop.heartbeatPath, config.loop.registryPath, config.loop.heartbeatStaleMs);
1485
1601
  const githubConnection = mount.integrationConnections
1486
1602
  ? await mount.integrationConnections.getStatus('github')
1487
1603
  : undefined;