opencode-swarm 7.164.11 → 7.164.13

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 (127) hide show
  1. package/.opencode/skills/engineering-conventions/SKILL.md +1 -1
  2. package/.opencode/skills/loop/SKILL.md +1 -1
  3. package/.opencode/skills/{plan → swarm-plan}/SKILL.md +1 -1
  4. package/dist/background/pending-delegations.d.ts +7 -2
  5. package/dist/background/pr-subscriptions.d.ts +3 -3
  6. package/dist/cli/{coder-settlement-0rfk8y11.js → coder-settlement-em2fgg4p.js} +16 -17
  7. package/dist/cli/{config-doctor-j17b7qq2.js → config-doctor-1m4mrybp.js} +4 -4
  8. package/dist/cli/{core-evhjjrtt.js → core-zbzdffha.js} +3 -3
  9. package/dist/cli/{curation-policy-vj6z5hvr.js → curation-policy-bqpmry2n.js} +5 -6
  10. package/dist/cli/{curator-drift-ez81vg2t.js → curator-drift-hbc3w5zj.js} +14 -12
  11. package/dist/cli/curator-llm-factory-j76c96t7.js +70 -0
  12. package/dist/cli/{curator-vqd5yeck.js → curator-tn3x5j02.js} +49 -47
  13. package/dist/cli/{dispatch-dqybvj8v.js → dispatch-c7xjt7js.js} +3 -3
  14. package/dist/cli/{evidence-summary-service-937x7rbg.js → evidence-summary-service-7cn9z4sn.js} +25 -24
  15. package/dist/cli/{gate-evidence-q1cehr4k.js → gate-evidence-deyzt3hz.js} +10 -11
  16. package/dist/cli/guardrail-explain-4k2pqj46.js +71 -0
  17. package/dist/cli/{guardrail-log-3g93f3g2.js → guardrail-log-cnbv6vry.js} +11 -11
  18. package/dist/cli/{guardrail-reset-qe2r5qzq.js → guardrail-reset-xhh61cax.js} +49 -47
  19. package/dist/cli/hive-promoter-1m8zpz4d.js +85 -0
  20. package/dist/cli/{index-rhqdsc1x.js → index-0mwjamha.js} +9 -9
  21. package/dist/cli/{index-y1yqmkv7.js → index-3c0z1jnc.js} +56 -52
  22. package/dist/cli/{index-kch6yenm.js → index-4fhcbe14.js} +8 -8
  23. package/dist/cli/{index-ww6zm5hr.js → index-5ebgzb5a.js} +3 -3
  24. package/dist/cli/{index-4vb6qa73.js → index-5h60rtaa.js} +37 -3
  25. package/dist/cli/{index-w3gtqey0.js → index-6chhqq2n.js} +4 -4
  26. package/dist/cli/index-6m24v15v.js +429 -0
  27. package/dist/cli/{index-vdn32nws.js → index-6rx1rdaq.js} +3 -3
  28. package/dist/cli/{index-x43debgx.js → index-74514zkh.js} +15 -17
  29. package/dist/cli/{index-1ww7wj8d.js → index-7f2r3ysr.js} +41 -17
  30. package/dist/cli/{index-kc2tgcm7.js → index-7z9zqxqt.js} +4 -4
  31. package/dist/cli/{index-n8688d12.js → index-8bdk7124.js} +2 -2
  32. package/dist/cli/{index-3146wmgv.js → index-8d90gzaz.js} +1 -1
  33. package/dist/cli/{index-b2nj04q6.js → index-9ss2m4rs.js} +1 -434
  34. package/dist/cli/{index-50j914b5.js → index-a0d4fp6r.js} +29 -7
  35. package/dist/cli/{index-ggtmsm84.js → index-ajknebrc.js} +1 -1
  36. package/dist/cli/{index-zjg4chy2.js → index-anxs69ad.js} +2 -2
  37. package/dist/cli/{index-aqppaaqx.js → index-asey3tb3.js} +6 -4
  38. package/dist/cli/{index-kv2tdkk5.js → index-bvkd7at6.js} +1 -1
  39. package/dist/cli/{index-r656jh9j.js → index-c98rjgjq.js} +4301 -2877
  40. package/dist/cli/{index-r5q5gd2a.js → index-d224mhr9.js} +3 -3
  41. package/dist/cli/{index-nqsj0g5y.js → index-dh5th4jn.js} +8 -8
  42. package/dist/cli/index-e45htt92.js +361 -0
  43. package/dist/cli/{index-w95vxjde.js → index-f36hy1x4.js} +39 -8
  44. package/dist/cli/{index-hp22pzn5.js → index-f8jdar6q.js} +2 -2
  45. package/dist/cli/{index-47kh2103.js → index-fnyw5rzg.js} +14 -14
  46. package/dist/cli/{index-7m32fjb4.js → index-g11h1qpk.js} +9 -9
  47. package/dist/cli/{index-d9entpn3.js → index-g9weyhq6.js} +4 -4
  48. package/dist/cli/{index-qbw3yw2d.js → index-grn6tkbt.js} +11 -11
  49. package/dist/cli/{index-9gxbjkts.js → index-gy0nyfbw.js} +24 -21
  50. package/dist/cli/{index-5jx22kwc.js → index-hhzzyjm3.js} +544 -15
  51. package/dist/cli/{index-dsg9dw3b.js → index-j2svfhzk.js} +2 -2
  52. package/dist/cli/{index-2bgr671r.js → index-jre6tm3v.js} +20 -2
  53. package/dist/cli/{index-77z98j76.js → index-mpf1tvwf.js} +314 -130
  54. package/dist/cli/{index-e90em0x4.js → index-ndjjvxzz.js} +12 -17
  55. package/dist/cli/{index-r3mvsbtq.js → index-p612v1mv.js} +7 -1
  56. package/dist/cli/{index-zfs3zqeq.js → index-ptsqnxwd.js} +771 -21
  57. package/dist/cli/{index-ggrp3v00.js → index-qtxevgdx.js} +15 -17
  58. package/dist/cli/{index-c5v1w13g.js → index-s3k7xbqd.js} +807 -629
  59. package/dist/cli/{index-pp2nya9v.js → index-tqw8w2n5.js} +2 -4
  60. package/dist/cli/index-w6988bbc.js +675 -0
  61. package/dist/cli/{index-4gqxppcx.js → index-xwbn7c8m.js} +2 -2
  62. package/dist/cli/{index-mmjamc9b.js → index-y5hfk7ya.js} +6 -6
  63. package/dist/cli/{index-5kcvrpkt.js → index-zb6gdym8.js} +2 -2
  64. package/dist/cli/index.js +161 -80
  65. package/dist/cli/{knowledge-escalator-j04g450p.js → knowledge-escalator-3fax9y3s.js} +18 -19
  66. package/dist/cli/{knowledge-events-53z45rs0.js → knowledge-events-9cpdyhmb.js} +16 -17
  67. package/dist/cli/{knowledge-link-a6kfg3qm.js → knowledge-link-dgvbqjqg.js} +4 -5
  68. package/dist/cli/{knowledge-store-whm0gagt.js → knowledge-store-y35rka0p.js} +6 -7
  69. package/dist/cli/{knowledge-validator-h8m7065g.js → knowledge-validator-fd761gpx.js} +8 -9
  70. package/dist/cli/{model-preflight-288nsgpw.js → model-preflight-3s1c0zpc.js} +1 -1
  71. package/dist/cli/{pending-delegations-6hkpe5ze.js → pending-delegations-t3y19j3n.js} +17 -8
  72. package/dist/cli/{pr-subscriptions-11zca1mh.js → pr-subscriptions-00zp69mt.js} +17 -8
  73. package/dist/cli/{pr-workflow-gate-6g29rkg7.js → pr-workflow-gate-2h0j8c92.js} +51 -49
  74. package/dist/cli/{runner-5abw3t35.js → runner-0e3bjeev.js} +6 -7
  75. package/dist/cli/{scan-cursor-mkfx410t.js → scan-cursor-wppe2gxw.js} +9 -10
  76. package/dist/cli/{schema-jbbam3ev.js → schema-sec49ppy.js} +2 -2
  77. package/dist/cli/{scope-persistence-q1ct4k42.js → scope-persistence-59eyqaz4.js} +20 -13
  78. package/dist/cli/{skill-generator-cv8fg96x.js → skill-generator-56rbmpj7.js} +21 -22
  79. package/dist/cli/snapshot-coordination-init-dnkdc7gx.js +84 -0
  80. package/dist/cli/{telemetry-mbqqamsj.js → telemetry-a1yvjerj.js} +1 -1
  81. package/dist/cli/{workspace-snapshot-eh18vgkn.js → workspace-snapshot-6z9rk7xw.js} +3 -3
  82. package/dist/cli/{worktree-collision-ownership-xgnn8dsq.js → worktree-collision-ownership-fj9n4mhk.js} +21 -12
  83. package/dist/cli/{worktree-isolation-k2dgfmeg.js → worktree-isolation-vd1s86ya.js} +49 -47
  84. package/dist/commands/benchmark.d.ts +5 -1
  85. package/dist/commands/close.d.ts +13 -6
  86. package/dist/commands/registry.d.ts +34 -43
  87. package/dist/commands/reset-session.d.ts +4 -0
  88. package/dist/commands/turbo.d.ts +1 -1
  89. package/dist/config/bundled-skills.d.ts +4 -3
  90. package/dist/config/constants.d.ts +13 -0
  91. package/dist/db/coordination-store.d.ts +85 -0
  92. package/dist/db/durability.d.ts +22 -5
  93. package/dist/db/index.d.ts +1 -0
  94. package/dist/db/project-db.d.ts +12 -0
  95. package/dist/hooks/extractors.d.ts +9 -0
  96. package/dist/hooks/non-architect-advisory.d.ts +18 -0
  97. package/dist/hooks/repo-graph-injection.d.ts +16 -0
  98. package/dist/index.js +837 -730
  99. package/dist/memory/schema.d.ts +3 -3
  100. package/dist/pr-review/authorization.d.ts +5 -4
  101. package/dist/pr-review/persistence.d.ts +10 -1
  102. package/dist/scope/scope-binding.d.ts +10 -0
  103. package/dist/scope/scope-persistence.d.ts +10 -0
  104. package/dist/services/decision-drift-analyzer.d.ts +7 -0
  105. package/dist/services/handoff-service.d.ts +12 -0
  106. package/dist/services/status-service.d.ts +31 -0
  107. package/dist/session/snapshot-coordination-init.d.ts +49 -0
  108. package/dist/session/snapshot-reader.d.ts +2 -0
  109. package/dist/session/snapshot-store.d.ts +42 -0
  110. package/dist/session/snapshot-writer.d.ts +4 -1
  111. package/dist/state.d.ts +14 -3
  112. package/dist/tools/repo-graph/builder.d.ts +1 -25
  113. package/dist/tools/repo-graph/cache.d.ts +5 -1
  114. package/dist/tools/repo-graph/fallback-scanner.d.ts +71 -0
  115. package/dist/tools/repo-graph/indexed-storage.d.ts +11 -0
  116. package/dist/tools/repo-graph/storage.d.ts +7 -0
  117. package/dist/turbo/epic/state.d.ts +4 -20
  118. package/dist/utils/bun-compat.d.ts +10 -0
  119. package/dist/utils/context-decisions.d.ts +77 -0
  120. package/dist/utils/external-tool-runner.d.ts +2 -0
  121. package/dist/utils/sanitize-display.d.ts +7 -0
  122. package/package.json +5 -3
  123. package/dist/cli/curator-llm-factory-sxcpmcqq.js +0 -68
  124. package/dist/cli/guardrail-explain-xv9aw1bf.js +0 -69
  125. package/dist/cli/hive-promoter-09yc9mp5.js +0 -83
  126. package/dist/cli/index-xnb3tk7x.js +0 -24
  127. package/dist/cli/{ast-diff-ekd9v10f.js → ast-diff-b0esr2kf.js} +3 -3
@@ -54,8 +54,8 @@ export declare const MemorySourceSchema: z.ZodObject<{
54
54
  tool: "tool";
55
55
  test: "test";
56
56
  manual: "manual";
57
- commit: "commit";
58
57
  user: "user";
58
+ commit: "commit";
59
59
  repo: "repo";
60
60
  web: "web";
61
61
  }>;
@@ -119,8 +119,8 @@ export declare const MemoryRecordSchema: z.ZodObject<{
119
119
  tool: "tool";
120
120
  test: "test";
121
121
  manual: "manual";
122
- commit: "commit";
123
122
  user: "user";
123
+ commit: "commit";
124
124
  repo: "repo";
125
125
  web: "web";
126
126
  }>;
@@ -217,8 +217,8 @@ export declare const MemoryProposalSchema: z.ZodObject<{
217
217
  tool: "tool";
218
218
  test: "test";
219
219
  manual: "manual";
220
- commit: "commit";
221
220
  user: "user";
221
+ commit: "commit";
222
222
  repo: "repo";
223
223
  web: "web";
224
224
  }>;
@@ -19,10 +19,9 @@
19
19
  * orchestration gate back. The gate binds its
20
20
  * `readPrReviewReentryBindingContext` at module init.
21
21
  *
22
- * Persistence: `.swarm/pr-review/reentry-authorizations/<session-stem>.json`,
23
- * guarded by a `proper-lockfile` lock (the same dependency the candidate
24
- * sidecar store uses). Bounded: at most MAX_ACTIVE_AUTHORIZATIONS unconsumed
25
- * authorizations per session; expired/unconsumed records are pruned on write.
22
+ * Persistence: SQLite coordination state is authoritative; the legacy
23
+ * `.swarm/pr-review/reentry-authorizations/<session-stem>.json` path remains a
24
+ * post-commit shadow projection and one-time import source only.
26
25
  */
27
26
  import { z } from 'zod';
28
27
  export type PrReviewReentryRole = 'reviewer' | 'test_engineer';
@@ -79,6 +78,7 @@ declare const AuthorizationFileSchema: z.ZodObject<{
79
78
  }, z.core.$strict>;
80
79
  type AuthorizationFile = z.infer<typeof AuthorizationFileSchema>;
81
80
  declare function reentryAuthorizationFilePath(directory: string, sessionID: string): string;
81
+ declare function reentryAuthorizationCoordinationNamespace(sessionID: string): string;
82
82
  declare function renameWithRetryAsync(tempPath: string, targetPath: string): Promise<void>;
83
83
  declare function writeAuthorizationFile(filePath: string, file: AuthorizationFile): Promise<void>;
84
84
  /**
@@ -122,6 +122,7 @@ export declare const _internals: {
122
122
  AUTHORIZATION_TTL_MS: number;
123
123
  MAX_ACTIVE_AUTHORIZATIONS: number;
124
124
  reentryAuthorizationFilePath: typeof reentryAuthorizationFilePath;
125
+ reentryAuthorizationCoordinationNamespace: typeof reentryAuthorizationCoordinationNamespace;
125
126
  pruneAuthorizations: typeof pruneAuthorizations;
126
127
  authorizationMatchesBinding: typeof authorizationMatchesBinding;
127
128
  hasPrReviewReentryAuthorizationAgainstBinding: typeof hasPrReviewReentryAuthorizationAgainstBinding;
@@ -88,12 +88,21 @@ export declare function writeAtomicJson(directory: string, filePath: string, val
88
88
  * rename contention as canonical gate state.
89
89
  */
90
90
  export declare function writePrWorkflowAtomicJson(directory: string, filePath: string, value: unknown): Promise<void>;
91
- export declare function readPrWorkflowGateStateFromDisk<S extends PrWorkflowPersistedStateBase>(directory: string, sessionID: string): Promise<S | null>;
91
+ export declare function readPrWorkflowGateStateFromDisk<S extends PrWorkflowPersistedStateBase>(directory: string, sessionID: string, options?: {
92
+ allowSalvagedImport?: boolean;
93
+ }): Promise<S | null>;
94
+ export declare function readPrWorkflowGateStateFileRawFromDisk<S extends PrWorkflowPersistedStateBase>(filePath: string, stateLabel: string): Promise<S | null>;
92
95
  export declare function readPrWorkflowGateStateFileFromDisk<S extends PrWorkflowPersistedStateBase>(filePath: string, stateLabel: string): Promise<S | null>;
96
+ export declare function readPrWorkflowGateStateFromCoordination<S extends PrWorkflowPersistedStateBase>(directory: string, sessionID: string): Promise<S | null>;
93
97
  /** Persist one CAS-checked state replacement while the session lock is held. */
94
98
  export declare function writeStateWhileLocked<S extends PrWorkflowPersistedStateBase>(directory: string, state: S, options?: {
95
99
  replaceWorkflowInstanceId?: string;
96
100
  }): Promise<S>;
101
+ /** Remove authoritative PR workflow state while the session mutation lock is held. */
102
+ export declare function deleteStateWhileLocked(directory: string, sessionID: string, options?: {
103
+ expectedStateRevision?: number;
104
+ allowSalvagedRead?: boolean;
105
+ }): Promise<void>;
97
106
  /** A bounded checkout-mutation refusal that never permits unsafe late overlap. */
98
107
  export declare class PrWorkflowCheckoutMutationTimeoutError extends Error {
99
108
  readonly phase: 'queue' | 'action';
@@ -92,6 +92,16 @@ export declare function getScopeBinding(input: {
92
92
  ownerSessionId: string;
93
93
  ownerMessageId?: string;
94
94
  }): ScopeBinding | null;
95
+ /**
96
+ * Resolve active child bindings that were minted in this process. The
97
+ * synchronous scope API is still used by a few host integrations that cannot
98
+ * await the durable claim path; those bindings remain valid for the current
99
+ * process while the SQLite authority is used on restart/cross-process reads.
100
+ */
101
+ export declare function getActiveScopeBindingsForSession(input: {
102
+ directory: string;
103
+ activeSessionId: string;
104
+ }): ScopeBinding[];
95
105
  export declare function createPrFeedbackScopeBinding(input: {
96
106
  directory: string;
97
107
  taskId: string;
@@ -83,6 +83,14 @@ export interface PersistedScope {
83
83
  files: string[];
84
84
  }
85
85
  export type PersistedScopeBinding = ScopeBinding;
86
+ declare function transitionScopeBindingState(directory: string, binding: ScopeBinding, expectedRevision: number | null): ScopePersistenceResult;
87
+ /**
88
+ * Scope replacement rollback owns one coordination transaction across the
89
+ * successor revocation and every predecessor restore. Re-entering the public
90
+ * transition helper would create nested SQLite transaction scopes that cannot
91
+ * make that whole compensation batch atomic.
92
+ */
93
+ declare function transitionScopeBindingStateWithinTransaction(directory: string, binding: ScopeBinding, expectedRevision: number | null): ScopePersistenceResult;
86
94
  /**
87
95
  * Write the legacy v1 `.swarm/scopes/scope-{taskId}.json` projection atomically.
88
96
  * Safe to call concurrently — proper-lockfile serialises writers per-file.
@@ -190,6 +198,8 @@ export declare function resolveAuthorizedPrFeedbackScopeBindingFromDisk(input: {
190
198
  taskId?: string;
191
199
  }): ScopeBinding | null;
192
200
  export declare const _scopePersistenceInternals: {
201
+ transitionScopeBindingState: typeof transitionScopeBindingState;
202
+ transitionScopeBindingStateWithinTransaction: typeof transitionScopeBindingStateWithinTransaction;
193
203
  liveBindingCapacity: number;
194
204
  bindingFileScanCapacity: number;
195
205
  maintenanceFileScanCapacity: number;
@@ -78,6 +78,13 @@ export interface DriftAnalyzerConfig {
78
78
  export declare const DEFAULT_DRIFT_CONFIG: DriftAnalyzerConfig;
79
79
  /**
80
80
  * Extract decisions from context.md content
81
+ *
82
+ * #2493 W9a: the section scan itself now lives in the shared extractor
83
+ * (`src/utils/context-decisions.ts`) so all four historical consumers of
84
+ * the `## Decisions` section agree on boundaries. This delegate preserves
85
+ * this module's public shape exactly — `ContextDecision` is a structural
86
+ * superset of `Decision` (it additionally carries the raw source line), so
87
+ * the mapping is the identity.
81
88
  */
82
89
  export declare function extractDecisionsFromContext(contextContent: string): Decision[];
83
90
  /**
@@ -6,6 +6,7 @@
6
6
  */
7
7
  import type { ExecutionProfile } from '../config/plan-schema';
8
8
  import { loadPlanJsonOnly } from '../plan/manager';
9
+ import { readSnapshotRows } from '../session/snapshot-store.js';
9
10
  /**
10
11
  * Escape HTML special characters to prevent XSS attacks
11
12
  */
@@ -97,6 +98,16 @@ declare function parseSessionState(content: string | null): {
97
98
  } | null;
98
99
  /**
99
100
  * Extract decisions from context.md content
101
+ *
102
+ * #2493 W9a: derives from the shared section extractor
103
+ * (`src/utils/context-decisions.ts`) instead of a private line-scan.
104
+ * Mapping preserves this consumer's historical output exactly:
105
+ * - cleaned text: bracket groups (timestamps, [confirmed]) and the ✅
106
+ * marker removed (the shared `text` already strips bracket groups, so
107
+ * only ✅ removal remains here);
108
+ * - empty results dropped;
109
+ * - RTL-sanitized and truncated to MAX_DECISION_LENGTH;
110
+ * - LAST 5 decisions kept.
100
111
  */
101
112
  declare function extractDecisions(content: string | null): string[];
102
113
  /**
@@ -134,5 +145,6 @@ export declare const _internals: {
134
145
  parseSessionState: typeof parseSessionState;
135
146
  extractDecisions: typeof extractDecisions;
136
147
  extractPhaseMetrics: typeof extractPhaseMetrics;
148
+ readSnapshotRows: typeof readSnapshotRows;
137
149
  };
138
150
  export {};
@@ -2,6 +2,7 @@ import type { AgentDefinition } from '../agents';
2
2
  import { type DelegationHealthMaintenanceSection, type DelegationLedgerHealth } from '../background/delegation-health';
3
3
  import { loadFullAutoRunState } from '../full-auto/state';
4
4
  import { type RecentEscalation } from '../hooks/knowledge-escalator';
5
+ import { type SnapshotCoordinationStatus } from '../session/snapshot-coordination-init.js';
5
6
  import { getActiveFullAutoSessionID, hasActiveFullAuto, hasActiveLeanTurbo } from '../state';
6
7
  import { loadLeanTurboRunState } from '../turbo/lean/state';
7
8
  import { summarizeTelemetryCosts } from './cost-accounting.js';
@@ -16,6 +17,7 @@ export declare const _internals: {
16
17
  getActiveFullAutoSessionID: typeof getActiveFullAutoSessionID;
17
18
  loadFullAutoRunState: typeof loadFullAutoRunState;
18
19
  summarizeTelemetryCosts: typeof summarizeTelemetryCosts;
20
+ renderNoActivePlanStatusTail: typeof renderNoActivePlanStatusTail;
19
21
  };
20
22
  /**
21
23
  * Structured status data returned by the status service.
@@ -101,6 +103,22 @@ export interface StatusData {
101
103
  specStaleStoredHash?: string;
102
104
  /** Current spec.md hash on disk (null when spec.md is missing) */
103
105
  specStaleCurrentHash?: string | null;
106
+ /**
107
+ * #2493 W9b: decision-drift visibility. Counts derived from running the
108
+ * same analyzer the architect context injection uses
109
+ * (`analyzeDecisionDrift`) over `.swarm/context.md`. `undefined` when
110
+ * detection is disabled (`automation.capabilities.decision_drift_detection:
111
+ * false`), when there is no drift, or when the analysis fails (fail-open —
112
+ * a status command must never fail because an optional signal hiccupped).
113
+ */
114
+ decisionDrift?: {
115
+ /** Number of stale-decision signals */
116
+ staleCount: number;
117
+ /** Number of contradictory-decision signals */
118
+ contradictionCount: number;
119
+ /** Timestamp of the most recent timestamped decision, when any exist */
120
+ lastDecisionAt?: string;
121
+ };
104
122
  /** Directives auto-escalated in the last 7 days (Change 3). */
105
123
  recentEscalations?: RecentEscalation[];
106
124
  /** #1234 Part 3: pending skill/motif proposals in .swarm/skills/proposals/ */
@@ -195,6 +213,8 @@ export interface StatusData {
195
213
  * stores surface as typed uncertainty, never partially-trusted counts.
196
214
  */
197
215
  backgroundWork?: BackgroundWorkStatus;
216
+ /** Post-resolution SQLite import/readiness health (#2481). */
217
+ coordination?: SnapshotCoordinationStatus;
198
218
  /** Issue #2043: compatibility total plus provenance completeness. */
199
219
  costs?: {
200
220
  totalCostUsd: number;
@@ -216,6 +236,7 @@ export interface BackgroundWorkStatus {
216
236
  consumed: number;
217
237
  stale: number;
218
238
  cancelled: number;
239
+ rejected: number;
219
240
  error: number;
220
241
  ingestion_error: number;
221
242
  };
@@ -258,6 +279,15 @@ export declare function getStatusData(directory: string, agents: Record<string,
258
279
  * This is the thin adapter that delegates to the service.
259
280
  */
260
281
  export declare function formatStatusMarkdown(status: StatusData): string;
282
+ /**
283
+ * No-active-plan status tail (#853 Layer C, #2493 W9b, #2034/#1659): spec
284
+ * drift, decision drift, and delegation-ledger health must COMPOSE — none of
285
+ * the three signals may suppress another. Extracted from
286
+ * handleStatusCommand so the composition is directly unit-testable
287
+ * (#2493 review: the old inline decision-drift early-return silently
288
+ * suppressed the ledger-health block when both signals coexisted).
289
+ */
290
+ declare function renderNoActivePlanStatusTail(statusData: StatusData): string;
261
291
  /**
262
292
  * Handle status command - delegates to service and formats output.
263
293
  * Kept for backward compatibility - thin adapter.
@@ -265,3 +295,4 @@ export declare function formatStatusMarkdown(status: StatusData): string;
265
295
  export declare function handleStatusCommand(directory: string, agents: Record<string, AgentDefinition>, sessionId?: string, options?: {
266
296
  backgroundSubagents?: boolean;
267
297
  }): Promise<string>;
298
+ export {};
@@ -0,0 +1,49 @@
1
+ /** Post-resolution SQLite snapshot import/readiness lifecycle (#2481). */
2
+ import type { SnapshotData } from './snapshot-writer.js';
3
+ type ReadinessState = 'running' | 'succeeded' | 'failed' | 'timed_out' | 'closing';
4
+ interface ReadinessEntry {
5
+ attemptId: number;
6
+ generation: number;
7
+ state: ReadinessState;
8
+ settled: boolean;
9
+ underlying: Promise<void>;
10
+ error?: string;
11
+ }
12
+ export interface SnapshotCoordinationStatus {
13
+ state: ReadinessState | 'idle';
14
+ attemptId?: number;
15
+ generation?: number;
16
+ settled: boolean;
17
+ error?: string;
18
+ }
19
+ /**
20
+ * Held while reset-session removes the authoritative snapshot and its legacy
21
+ * projection. Callers must release it after the destructive portion is done.
22
+ */
23
+ export interface SnapshotCoordinationResetGuard {
24
+ release(): void;
25
+ closeError?: Error;
26
+ /** True when the prior initializer did not settle before the reset deadline. */
27
+ priorUnsettled?: boolean;
28
+ }
29
+ export declare function startSnapshotCoordinationInitialization(directory: string): Promise<void>;
30
+ export declare function ensureSnapshotCoordinationReady(directory: string): Promise<void>;
31
+ export declare function retrySnapshotCoordinationInitialization(directory: string): Promise<void>;
32
+ export declare function getSnapshotCoordinationStatus(directory: string): SnapshotCoordinationStatus;
33
+ /**
34
+ * Prevent any fresh initializer from observing state while reset-session
35
+ * deletes the SQLite authority and legacy projection. The guard deliberately
36
+ * survives a prior initialization failure: reset remains best-effort, but a
37
+ * concurrent initializer cannot race through the destructive window.
38
+ */
39
+ export declare function beginSnapshotCoordinationReset(directory: string): Promise<SnapshotCoordinationResetGuard>;
40
+ export declare function closeSnapshotCoordinationInitialization(directory: string): Promise<void>;
41
+ export declare function markSnapshotCoordinationClosing(directory: string): void;
42
+ export declare const _snapshotCoordinationInternals: {
43
+ entries: Map<string, ReadinessEntry>;
44
+ initialize: (directory: string) => Promise<void>;
45
+ renameLegacySnapshot: (from: string, to: string) => void;
46
+ writeProjection: (directory: string, snapshot: SnapshotData) => Promise<void>;
47
+ timeoutMs: number;
48
+ };
49
+ export {};
@@ -29,6 +29,8 @@ export declare function deserializeAgentSession(s: SerializedAgentSession): Agen
29
29
  * NEVER throws - always returns null on any error.
30
30
  */
31
31
  export declare function readSnapshot(directory: string): Promise<SnapshotData | null>;
32
+ /** Strict single-candidate reader used by the SQLite import boundary. */
33
+ export declare function readSnapshotFileStrict(directory: string, relativePath: string): Promise<SnapshotData>;
32
34
  /**
33
35
  * Rehydrate swarmState from a SnapshotData object.
34
36
  * Clears existing maps first, then populates from snapshot.
@@ -0,0 +1,42 @@
1
+ /** SQLite row mapping for durable session snapshots (#2481). */
2
+ import type { SnapshotData } from './snapshot-writer.js';
3
+ /** Test-only seam for interleaving a foreign writer after the first snapshot read. */
4
+ export declare const _snapshotStoreInternals: {
5
+ afterSnapshotMetaRead: () => void;
6
+ };
7
+ interface DeletedSessionRowPayload {
8
+ ownerToken?: string;
9
+ reason: 'ended' | 'stale';
10
+ }
11
+ export interface SnapshotWriteOptions {
12
+ /** Do not let rehydrated foreign sessions overwrite their durable owners. */
13
+ onlyLocallyOwnedSessions?: boolean;
14
+ }
15
+ /**
16
+ * Mark a session as local for snapshot writes and reaping. Rehydration never
17
+ * calls this. Only a host invocation for the exact session may opt into
18
+ * takeover, which lets a restarted host resume its own session without letting
19
+ * a passive foreign rehydration overwrite a live peer.
20
+ */
21
+ export declare function claimSnapshotSessionOwnership(sessionId: string, canTakeOver?: boolean): string;
22
+ export declare function isSnapshotSessionOwnedLocally(sessionId: string): boolean;
23
+ export declare function releaseSnapshotSessionOwnership(sessionId: string): void;
24
+ export declare function clearSnapshotSessionOwnerships(): void;
25
+ export declare function writeSnapshotRows(directory: string, snapshot: SnapshotData, options?: SnapshotWriteOptions): void;
26
+ export declare function importSnapshotRowsOnce(directory: string, snapshot: SnapshotData, sourceDigest: string, source?: string): 'imported' | 'already_imported' | 'state_exists';
27
+ export declare function readSnapshotRows(directory: string): SnapshotData | null;
28
+ /**
29
+ * Confirm whether the authoritative durable row is genuinely stale before a
30
+ * local stale sweep is allowed to tombstone it.
31
+ *
32
+ * This re-reads SQLite rather than trusting the caller's in-memory copy so a
33
+ * peer process with a frozen snapshot cannot delete a still-fresh live row.
34
+ * Missing rows are treated as safe-to-evict: there is no durable authority left
35
+ * to protect.
36
+ */
37
+ export declare function isSnapshotSessionAuthoritativelyStale(directory: string, sessionId: string, staleDurationMs: number, now?: number): boolean;
38
+ /** Remove the complete authoritative snapshot as one FULL transaction. */
39
+ export declare function clearSnapshotRows(directory: string): number;
40
+ /** Tombstone the session-keyed rows removed by a host lifecycle event. */
41
+ export declare function deleteSnapshotSessionRows(directory: string, sessionId: string, reason?: DeletedSessionRowPayload['reason']): number;
42
+ export {};
@@ -1,11 +1,13 @@
1
1
  /**
2
2
  * Session snapshot writer for OpenCode Swarm plugin.
3
- * Serializes swarmState to .swarm/session/state.json using atomic write (temp-file + rename).
3
+ * Persists swarmState as independently keyed SQLite coordination rows and a
4
+ * non-authoritative, versioned file projection.
4
5
  */
5
6
  import { rename as fsRename } from 'node:fs/promises';
6
7
  import { TASK_WORKFLOW_SCHEMA_MARKER } from '../gate-evidence.js';
7
8
  import type { AgentSessionState, DelegationEntry, ToolAggregate } from '../state';
8
9
  import { swarmState } from '../state';
10
+ export declare const SNAPSHOT_PROJECTION_FILE = "session/state.sqlite-projection.json";
9
11
  /**
10
12
  * Windows can transiently fail a rename with EEXIST/EBUSY/EPERM while another
11
13
  * process (an external snapshot reader, an AV scanner) briefly holds the
@@ -144,6 +146,7 @@ export declare function serializeAgentSession(s: AgentSessionState): SerializedA
144
146
  * Silently swallows errors (non-fatal — never crash the plugin).
145
147
  */
146
148
  export declare function writeSnapshot(directory: string, state: typeof swarmState): Promise<void>;
149
+ export declare function writeSnapshotProjection(directory: string, snapshot: SnapshotData): Promise<void>;
147
150
  /**
148
151
  * Create a snapshot writer hook suitable for use in tool.execute.after.
149
152
  * Writes state immediately on every call. Concurrent calls are serialised so
package/dist/state.d.ts CHANGED
@@ -568,6 +568,14 @@ export interface AgentSessionState {
568
568
  resumeModelAdvisoryDone?: boolean;
569
569
  /** One-shot guard: the config-vs-UI model advisory has fired for this session (#1896). */
570
570
  configModelAdvisoryDone?: boolean;
571
+ /**
572
+ * One-shot guard: the first-run non-architect advisory has fired for this
573
+ * session (#2493 K3 UX-3). Keyed by sessionID only — "session starts on a
574
+ * non-architect agent" is operationalized as the first user message
575
+ * arriving on a non-architect agent (the OpenCode plugin v1 shape has no
576
+ * session-start hook).
577
+ */
578
+ nonArchitectAdvisoryDone?: boolean;
571
579
  }
572
580
  export type NonTransientErrorCategory = 'shell_parse_error' | 'command_not_found' | 'sandbox_wrapper_failure' | 'general_permanent';
573
581
  export interface NonTransientCircuitState {
@@ -1003,9 +1011,10 @@ export declare function isReviewerScopeGenerationCurrent(input: {
1003
1011
  *
1004
1012
  * @param staleDurationMs - Age threshold in ms (default 2h)
1005
1013
  * @param now - Current time in ms (injectable for deterministic tests)
1014
+ * @param directory - Optional project root whose locally-owned durable rows are tombstoned
1006
1015
  * @returns The list of evicted session IDs
1007
1016
  */
1008
- export declare function sweepStaleSessions(staleDurationMs?: number, now?: number): string[];
1017
+ export declare function sweepStaleSessions(staleDurationMs?: number, now?: number, directory?: string): string[];
1009
1018
  /**
1010
1019
  * Opportunistic, cooldown-guarded wrapper around sweepStaleSessions, intended
1011
1020
  * to be called from a frequently-hit code path (per-tool-call accounting in
@@ -1024,9 +1033,10 @@ export declare function sweepStaleSessions(staleDurationMs?: number, now?: numbe
1024
1033
  *
1025
1034
  * @param staleDurationMs - Age threshold in ms (default 2h)
1026
1035
  * @param now - Current time in ms (injectable for deterministic tests)
1036
+ * @param directory - Optional project root whose durable rows are tombstoned
1027
1037
  * @returns Evicted session IDs ([] when the cooldown blocks this run)
1028
1038
  */
1029
- export declare function maybeSweepStaleSessions(staleDurationMs?: number, now?: number): string[];
1039
+ export declare function maybeSweepStaleSessions(staleDurationMs?: number, now?: number, directory?: string): string[];
1030
1040
  /**
1031
1041
  * Start a new agent session with initialized guardrail state.
1032
1042
  * Also removes any stale sessions older than staleDurationMs.
@@ -1042,8 +1052,9 @@ export declare function startAgentSession(sessionId: string, agentName: string,
1042
1052
  * teardown) to prevent unbounded Map growth. Double-calls are safe: Map.delete is
1043
1053
  * a no-op for missing keys (FR-010).
1044
1054
  * @param sessionId - The session identifier to remove
1055
+ * @param directory - Optional project root whose durable snapshot row must be tombstoned
1045
1056
  */
1046
- export declare function endAgentSession(sessionId: string): void;
1057
+ export declare function endAgentSession(sessionId: string, directory?: string): void;
1047
1058
  /**
1048
1059
  * Get an agent session state by session ID.
1049
1060
  * @param sessionId - The session identifier
@@ -12,6 +12,7 @@
12
12
  */
13
13
  import { extractFileSymbols } from '../../lang/symbol-graph';
14
14
  import { extractDartSymbols, extractGoSymbols, extractPhpSymbols, extractPythonSymbols, extractRubySymbols, extractRustSymbols, extractTSSymbols } from '../symbols';
15
+ import { type ImportBinding, type ParsedImport } from './fallback-scanner';
15
16
  import { extractFileOntology } from './ontology';
16
17
  import { safeRealpathSync } from './safe-realpath';
17
18
  import type { BuildWorkspaceGraphOptions, GraphEdge, GraphExtractorInputWitness, GraphNode, RepoGraph, RepoGraphDiagnostics, SymbolEdge } from './types';
@@ -96,31 +97,6 @@ export declare function addEdge(graph: RepoGraph, edge: GraphEdge): void;
96
97
  * @returns Resolved absolute path or null if unresolvable
97
98
  */
98
99
  export declare function resolveModuleSpecifier(workspaceRoot: string, sourceFile: string, specifier: string): string | null;
99
- /**
100
- * A parsed import with its specifier and type.
101
- */
102
- /**
103
- * A single imported binding: the symbol's *exported* name in the target file
104
- * and the *local* name it is bound to in the importing file (differs when an
105
- * `as` alias or default import is used). Used to attribute call-site usage back
106
- * to the correct exported symbol.
107
- */
108
- interface ImportBinding {
109
- imported: string;
110
- local: string;
111
- }
112
- interface ParsedImport {
113
- /** The module specifier (e.g., './foo', 'lodash') */
114
- specifier: string;
115
- /** The type of import */
116
- importType: 'default' | 'named' | 'namespace' | 'require' | 'sideeffect' | 'type';
117
- /** Named imported symbols when statically detectable */
118
- importedSymbols: string[];
119
- /** Alias-aware imported→local bindings for usage attribution */
120
- bindings: ImportBinding[];
121
- /** True for `export { x } from '...'` re-exports (symbols are re-exposed). */
122
- reExport: boolean;
123
- }
124
100
  /**
125
101
  * Strip line (`//…`) and block (`/* … *\/`) comments from JS/TS source while
126
102
  * preserving string, template-literal, and regex-literal contents (DD-C010).
@@ -13,7 +13,7 @@ export declare function getCachedGraph(workspace: string): RepoGraph | undefined
13
13
  * Cache a graph and mark it clean. Omitting mtime clears any previous mtime so
14
14
  * an old optimistic-concurrency witness cannot survive a new graph value.
15
15
  */
16
- export declare function setCachedGraph(workspace: string, graph: RepoGraph, mtime?: number): void;
16
+ export declare function setCachedGraph(workspace: string, graph: RepoGraph, mtime?: number, ino?: number | string, size?: number): void;
17
17
  /** Mark a workspace's cached state dirty, preserving its graph and mtime. */
18
18
  export declare function markDirty(workspace: string): void;
19
19
  /** Return whether the workspace's cached state is dirty. */
@@ -22,3 +22,7 @@ export declare function isDirty(workspace: string): boolean;
22
22
  export declare function clearCache(workspace: string): void;
23
23
  /** Return the graph-file mtime captured with the cached graph, if present. */
24
24
  export declare function getCachedMtime(workspace: string): number | undefined;
25
+ /** Return the graph-file inode/file-id captured with the cached graph. */
26
+ export declare function getCachedIno(workspace: string): string | undefined;
27
+ /** Return the graph-file byte size captured with the cached graph. */
28
+ export declare function getCachedSize(workspace: string): number | undefined;
@@ -0,0 +1,71 @@
1
+ import type { GraphEdge, GraphNode } from './types';
2
+ export interface ImportBinding {
3
+ imported: string;
4
+ local: string;
5
+ }
6
+ export interface ParsedImport {
7
+ specifier: string;
8
+ importType: GraphEdge['importType'];
9
+ importedSymbols: string[];
10
+ bindings: ImportBinding[];
11
+ reExport: boolean;
12
+ }
13
+ interface FileStat {
14
+ size: number;
15
+ mtime: Date;
16
+ mtimeMs: number;
17
+ }
18
+ interface OntologyInput {
19
+ moduleName: string;
20
+ filePath: string;
21
+ content: string;
22
+ language: string;
23
+ exports: string[];
24
+ imports: string[];
25
+ hasManifest?: (relDir: string) => boolean;
26
+ }
27
+ export interface FallbackScannerDependencies {
28
+ statFile: (filePath: string) => FileStat;
29
+ readFile: (filePath: string) => string;
30
+ isBinaryContent: (content: string) => boolean;
31
+ extractExports: (filePath: string, absoluteRoot: string) => {
32
+ exports: string[];
33
+ exportLines: Record<string, number>;
34
+ };
35
+ parseImports: (content: string, filePath: string, absoluteRoot: string) => ParsedImport[];
36
+ stripComments: (content: string) => string;
37
+ toModuleName: (filePath: string, absoluteRoot: string) => string;
38
+ getLanguage: (filePath: string) => string;
39
+ extractOntology: (input: OntologyInput) => GraphNode['ontology'];
40
+ resolveSpecifier: (absoluteRoot: string, filePath: string, specifier: string) => string | null;
41
+ usedSymbolsForImport: (parsedImport: ParsedImport, strippedContent: string) => string[] | undefined;
42
+ isScannableSourcePath: (filePath: string) => boolean;
43
+ }
44
+ export type FallbackScanOutcome = {
45
+ status: 'scanned';
46
+ node: GraphNode & Required<Pick<GraphNode, 'sizeBytes' | 'mtimeMs'>>;
47
+ edges: GraphEdge[];
48
+ } | {
49
+ status: 'skipped';
50
+ reason: 'oversized' | 'unreadable' | 'binary' | 'malformed';
51
+ moduleName: string;
52
+ language?: string;
53
+ sizeBytes?: number;
54
+ mtimeMs?: number;
55
+ };
56
+ export interface FallbackScanOptions {
57
+ filePath: string;
58
+ absoluteRoot: string;
59
+ maxFileSize: number;
60
+ hasManifest?: (relDir: string) => boolean;
61
+ dependencies: FallbackScannerDependencies;
62
+ }
63
+ /**
64
+ * Bounded, fail-open boundary for the legacy parser-based file scanner.
65
+ *
66
+ * All filesystem access happens before parser work, with the size cap enforced
67
+ * before content is read. Language extraction and resolution stay injectable so
68
+ * builder tests can replace them without process-wide module mocks.
69
+ */
70
+ export declare function runFallbackScan({ filePath, absoluteRoot, maxFileSize, hasManifest, dependencies, }: FallbackScanOptions): FallbackScanOutcome;
71
+ export {};
@@ -25,6 +25,8 @@
25
25
  * statement's placeholder count equals its argument count exactly and
26
26
  * no-placeholder statements are issued as `db.run(sql)` with no array.
27
27
  */
28
+ import type { Database } from 'bun:sqlite';
29
+ import { unlinkSync } from 'node:fs';
28
30
  import type { GraphNode, RepoGraph } from './types';
29
31
  /** Filename of the derived index inside `.swarm/`. */
30
32
  export declare const REPO_MEMORY_FILENAME = "repo-memory.sqlite";
@@ -34,6 +36,7 @@ export declare const REPO_MEMORY_FILENAME = "repo-memory.sqlite";
34
36
  * validateSymlinkBoundary.
35
37
  */
36
38
  export declare function getRepoMemoryPath(workspace: string): string;
39
+ declare function cacheHandle(storePath: string, db: Database): void;
37
40
  /**
38
41
  * Close the cached connection for a workspace. Called by the `/swarm close`
39
42
  * clean stage before unlinking the store (Windows holds a WAL-mode file open,
@@ -55,6 +58,7 @@ export declare function closeAllRepoMemory(): void;
55
58
  * otherwise.
56
59
  */
57
60
  export declare function deleteRepoMemory(workspace: string): void;
61
+ declare function removeRepoMemoryFiles(workspace: string): boolean;
58
62
  /** Whether a SQLite driver is resolvable in this runtime. */
59
63
  export declare function isIndexedStorageAvailable(): boolean;
60
64
  /**
@@ -74,6 +78,12 @@ export declare function resolveGraphStorageMode(workspace: string): 'json' | 'in
74
78
  */
75
79
  export declare const _internals: {
76
80
  isIndexedStorageAvailable: typeof isIndexedStorageAvailable;
81
+ removeRepoMemoryFiles: typeof removeRepoMemoryFiles;
82
+ unlinkSync: typeof unlinkSync;
83
+ cacheHandle: typeof cacheHandle;
84
+ maxOpenHandles: number;
85
+ openHandleCount: () => number;
86
+ hasOpenHandle: (workspace: string) => boolean;
77
87
  };
78
88
  /**
79
89
  * Replace the whole index from `graph` in one transaction.
@@ -134,3 +144,4 @@ export declare function queryNodeByFile(workspace: string, file: string): GraphN
134
144
  * `maxDepth = 0` blast radius early-returns, query.ts:613-621).
135
145
  */
136
146
  export declare function loadSubgraphForFiles(workspace: string, files: string[], depth: number): RepoGraph | null;
147
+ export {};
@@ -22,7 +22,13 @@ export declare const _internals: {
22
22
  fsRename: typeof fsPromises.rename;
23
23
  retryDelayMs: number;
24
24
  writeFingerprint: typeof writeFingerprint;
25
+ cacheArtifactMatches: typeof cacheArtifactMatches;
25
26
  };
27
+ declare function cacheArtifactMatches(cachedMtime: number | undefined, cachedIno: string | undefined, cachedSize: number | undefined, stats: {
28
+ mtimeMs: number;
29
+ ino: number;
30
+ size: number;
31
+ }): boolean;
26
32
  /**
27
33
  * Get the validated path for the repo-graph.json file.
28
34
  * Resolves symlinks via realpath before validation to prevent
@@ -78,3 +84,4 @@ export declare function loadOrCreateGraph(workspace: string): Promise<RepoGraph>
78
84
  * @throws Error if save fails
79
85
  */
80
86
  export declare function saveIfDirty(workspace: string, freshnessOptions?: FreshnessOptions): Promise<void>;
87
+ export {};
@@ -1,14 +1,9 @@
1
1
  /**
2
- * Durable Epic Mode session state (Capability C).
2
+ * Durable Epic Mode session state.
3
3
  *
4
- * Persists per-session Epic Mode activation state under
5
- * `<projectRoot>/.swarm/epic-state.json` so toggling survives process
6
- * restarts. Mirrors the pattern in `src/turbo/lean/state.ts` (atomic
7
- * `tmp + rename`, per-directory `stateUnreadableMap` for fail-closed
8
- * semantics, sessions-keyed shape) — without modifying that file.
9
- *
10
- * Dependency direction is one-way: this module imports nothing from
11
- * `src/turbo/lean/`. The shape is parallel but independent.
4
+ * The authoritative store is the per-project SQLite coordination DB, with one
5
+ * row per session. `.swarm/epic-state.json` remains a compatibility
6
+ * projection and import source during the cutover.
12
7
  */
13
8
  /** Top-level state for a single session. */
14
9
  export interface EpicSessionState {
@@ -49,17 +44,6 @@ export declare function isEpicModeActive(directory: string, sessionID: string):
49
44
  /**
50
45
  * True iff epic mode is currently active for ANY session in the project.
51
46
  *
52
- * Use this when a code path needs to know "is the project running under
53
- * Epic Mode right now" without caring which session toggled it. The
54
- * session-scoped `isEpicModeActive` answers "did THIS session toggle it" —
55
- * a different question with a different answer.
56
- *
57
- * The architect's session enables Epic via `/swarm epic on`; sub-agents
58
- * (coders, reviewers) dispatched through the `Task` tool run in their own
59
- * sessions and have no record of that toggle. Asking the project-scoped
60
- * check is the only correct way to honor Epic Mode from those flows.
61
- * Rule 2's auto-commit (centralized in Phase 5) is the canonical caller.
62
- *
63
47
  * Fail-closed: returns `false` on unreadable state, matching the rest of
64
48
  * this module's defaults.
65
49
  */