opencode-swarm 7.128.0 → 7.129.1

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 (39) hide show
  1. package/dist/cli/{curation-policy-82czah39.js → curation-policy-vn1ybh31.js} +2 -2
  2. package/dist/cli/{curator-x5dzf1p7.js → curator-2nhjd2mn.js} +13 -13
  3. package/dist/cli/{curator-drift-24bdacdc.js → curator-drift-y1wm4atk.js} +1 -1
  4. package/dist/cli/{curator-llm-factory-rz4cbq28.js → curator-llm-factory-xbstvmpx.js} +13 -13
  5. package/dist/cli/{evidence-summary-service-thx1c3me.js → evidence-summary-service-hf7qq777.js} +2 -2
  6. package/dist/cli/{guardrail-explain-fwvxteqe.js → guardrail-explain-87wprr65.js} +14 -14
  7. package/dist/cli/{hive-promoter-z8gc80zq.js → hive-promoter-va29r2p0.js} +13 -13
  8. package/dist/cli/{index-nmedh7bw.js → index-3yd6bbnp.js} +14 -14
  9. package/dist/cli/{index-gn62e04k.js → index-5fnc76da.js} +1 -1
  10. package/dist/cli/{index-hv2p03f3.js → index-6w02qz7t.js} +250 -5
  11. package/dist/cli/{index-23zsx7dm.js → index-g4mnf3p5.js} +1 -1
  12. package/dist/cli/{index-npycj2tr.js → index-gczs3jy7.js} +41086 -40944
  13. package/dist/cli/{index-1mwdhq2p.js → index-kj86tyrs.js} +1 -1
  14. package/dist/cli/{index-edv27z4p.js → index-kxw2sx1d.js} +3 -1
  15. package/dist/cli/{index-kk1scggc.js → index-kzvwb2se.js} +1 -1
  16. package/dist/cli/{index-ff3j65em.js → index-m8vrw3pt.js} +4 -4
  17. package/dist/cli/{index-3ntrn97w.js → index-pgyp3tta.js} +1 -1
  18. package/dist/cli/{index-2445sx3d.js → index-s80bsjkj.js} +13 -4
  19. package/dist/cli/{index-rczj39pc.js → index-ty0xttaz.js} +1 -1
  20. package/dist/cli/{index-72envp1b.js → index-w2kp2zvf.js} +3 -3
  21. package/dist/cli/{index-ns62nv6t.js → index-waqvy9a5.js} +2 -2
  22. package/dist/cli/{index-c4mcheyz.js → index-wy5jy3m9.js} +3 -3
  23. package/dist/cli/{index-ecxwhwz7.js → index-y2pfmd0z.js} +1 -1
  24. package/dist/cli/index.js +13 -13
  25. package/dist/cli/{knowledge-escalator-b3k4b8pk.js → knowledge-escalator-5ytt2y9n.js} +3 -3
  26. package/dist/cli/{knowledge-events-4z5rkefv.js → knowledge-events-qnyfrsfv.js} +1 -1
  27. package/dist/cli/{knowledge-store-c0t16yr4.js → knowledge-store-yeybvcqw.js} +1 -1
  28. package/dist/cli/{knowledge-validator-cs33ws57.js → knowledge-validator-g2c4mbwa.js} +4 -4
  29. package/dist/cli/{pending-delegations-a1bbpp8b.js → pending-delegations-37t4xecr.js} +2 -2
  30. package/dist/cli/{pr-subscriptions-bxpqde8w.js → pr-subscriptions-zqbmctwz.js} +2 -2
  31. package/dist/cli/{scan-cursor-rgnarf67.js → scan-cursor-c5mcce5r.js} +2 -2
  32. package/dist/cli/{skill-generator-e8c2r816.js → skill-generator-c77e0y98.js} +5 -5
  33. package/dist/config/index.d.ts +1 -1
  34. package/dist/config/loader-recovery.d.ts +95 -0
  35. package/dist/config/loader.d.ts +26 -1
  36. package/dist/config/sanitize-malformed-values.d.ts +53 -0
  37. package/dist/index.d.ts +6 -0
  38. package/dist/index.js +19 -19
  39. package/package.json +1 -1
@@ -608,7 +608,7 @@ async function applyKnowledgeVerdictFeedback(directory, options) {
608
608
  deltas.push({ id, delta });
609
609
  }
610
610
  if (deltas.length > 0) {
611
- const { bumpKnowledgeConfidenceBatch } = await import("./knowledge-store-c0t16yr4.js");
611
+ const { bumpKnowledgeConfidenceBatch } = await import("./knowledge-store-yeybvcqw.js");
612
612
  await bumpKnowledgeConfidenceBatch(directory, deltas, options?.floorOptions);
613
613
  }
614
614
  return {
@@ -1,12 +1,13 @@
1
1
  // @bun
2
2
  import {
3
3
  _internals,
4
+ getSafeDefaultConfigLoadResult,
4
5
  loadAgentPrompt,
5
6
  loadPluginConfig,
6
7
  loadPluginConfigWithMeta,
7
8
  loadPluginConfigWithMetaAsync,
8
9
  resolveWorktreeIsolationConfig
9
- } from "./index-hv2p03f3.js";
10
+ } from "./index-6w02qz7t.js";
10
11
  import {
11
12
  ApprovalEvidenceSchema,
12
13
  BaseEvidenceSchema,
@@ -83,6 +84,7 @@ export {
83
84
  loadAgentPrompt,
84
85
  isSubagent,
85
86
  isQAAgent,
87
+ getSafeDefaultConfigLoadResult,
86
88
  _internals,
87
89
  WorktreeIsolationConfigSchema,
88
90
  TurboConfigSchema,
@@ -36,7 +36,7 @@ import {
36
36
  import {
37
37
  readSwarmFileAsync,
38
38
  validateSwarmPath
39
- } from "./index-2445sx3d.js";
39
+ } from "./index-s80bsjkj.js";
40
40
  import {
41
41
  criticalWarn,
42
42
  error,
@@ -6,13 +6,13 @@ import {
6
6
  resolveSwarmKnowledgePath,
7
7
  transactKnowledge,
8
8
  wordBigrams
9
- } from "./index-72envp1b.js";
9
+ } from "./index-w2kp2zvf.js";
10
10
  import {
11
11
  countEntryContradictionsInWindow,
12
12
  countEntryViolationsInWindow,
13
13
  readKnowledgeEvents,
14
14
  recordKnowledgeEvent
15
- } from "./index-1mwdhq2p.js";
15
+ } from "./index-kj86tyrs.js";
16
16
  import {
17
17
  init_knowledge_types,
18
18
  isActiveStatus
@@ -190,11 +190,11 @@ async function maybeQuarantineOnContradiction(directory, entryId, threshold, win
190
190
  alreadyInactive: true
191
191
  };
192
192
  }
193
- const { quarantineEntry } = await import("./knowledge-validator-cs33ws57.js");
193
+ const { quarantineEntry } = await import("./knowledge-validator-g2c4mbwa.js");
194
194
  let policyConfig;
195
195
  try {
196
196
  const { KnowledgeConfigSchema } = await import("./schema-2x7wsb0n.js");
197
- const { loadPluginConfigWithMeta } = await import("./index-edv27z4p.js");
197
+ const { loadPluginConfigWithMeta } = await import("./index-kxw2sx1d.js");
198
198
  const { config: loadedConfig } = loadPluginConfigWithMeta(directory);
199
199
  policyConfig = KnowledgeConfigSchema.parse(loadedConfig.knowledge ?? {});
200
200
  } catch {
@@ -4,7 +4,7 @@ import {
4
4
  } from "./index-rtry5xyf.js";
5
5
  import {
6
6
  readKnowledgeEvents
7
- } from "./index-1mwdhq2p.js";
7
+ } from "./index-kj86tyrs.js";
8
8
  import {
9
9
  isLinked,
10
10
  readLinkPointer,
@@ -140,8 +140,9 @@ async function readSwarmFileAsync(directory, filename, cache) {
140
140
  cache.set(key, promise);
141
141
  return promise;
142
142
  }
143
- const maxAttempts = 5;
144
- const retryDelayMs = 10;
143
+ const ENOENT_MAX_ATTEMPTS = 5;
144
+ const ENOENT_RETRY_DELAY_MS = 10;
145
+ const maxAttempts = 6;
145
146
  for (let attempt = 0;attempt < maxAttempts; attempt++) {
146
147
  try {
147
148
  const resolvedPath = _internals.validateSwarmPath(directory, filename);
@@ -150,10 +151,18 @@ async function readSwarmFileAsync(directory, filename, cache) {
150
151
  return await file.text();
151
152
  });
152
153
  } catch (err) {
153
- const isNotFound = err?.code === "ENOENT";
154
- if (!isNotFound || attempt === maxAttempts - 1) {
154
+ const code = err?.code;
155
+ if (code === "ENOENT") {
156
+ if (attempt >= ENOENT_MAX_ATTEMPTS - 1)
157
+ return null;
158
+ await new Promise((resolve2) => setTimeout(resolve2, ENOENT_RETRY_DELAY_MS));
159
+ continue;
160
+ }
161
+ const isAvRetryable = code === "EBUSY" || code === "EPERM" || code === "EACCES";
162
+ if (!isAvRetryable || attempt === maxAttempts - 1) {
155
163
  return null;
156
164
  }
165
+ const retryDelayMs = 10 * 2 ** attempt;
157
166
  await new Promise((resolve2) => setTimeout(resolve2, retryDelayMs));
158
167
  }
159
168
  }
@@ -12,7 +12,7 @@ import {
12
12
  detectPosixWrites,
13
13
  detectWindowsWrites,
14
14
  resolveWriteTargets
15
- } from "./index-npycj2tr.js";
15
+ } from "./index-gczs3jy7.js";
16
16
  import {
17
17
  checkFileAuthority,
18
18
  classifyFile,
@@ -650,7 +650,7 @@ async function applyConfidenceFloorAction(directory, touched, options) {
650
650
  const recovered = touched.filter((e) => e.confidence > CONFIDENCE_FLOOR + FLOOR_EPSILON && e.confidence_floor_demoted);
651
651
  if (atFloor.length === 0 && recovered.length === 0)
652
652
  return;
653
- const { readKnowledgeCounterRollups, effectiveRetrievalOutcomes } = await import("./knowledge-events-4z5rkefv.js");
653
+ const { readKnowledgeCounterRollups, effectiveRetrievalOutcomes } = await import("./knowledge-events-qnyfrsfv.js");
654
654
  const rollups = await readKnowledgeCounterRollups(directory);
655
655
  const flagIds = new Set;
656
656
  for (const e of atFloor) {
@@ -717,11 +717,11 @@ async function applyConfidenceFloorAction(directory, touched, options) {
717
717
  });
718
718
  }
719
719
  if (action === "quarantine" && toQuarantine.length > 0) {
720
- const { quarantineEntry } = await import("./knowledge-validator-cs33ws57.js");
720
+ const { quarantineEntry } = await import("./knowledge-validator-g2c4mbwa.js");
721
721
  const { KnowledgeConfigSchema } = await import("./schema-2x7wsb0n.js");
722
722
  let config;
723
723
  try {
724
- const { loadPluginConfigWithMeta } = await import("./index-edv27z4p.js");
724
+ const { loadPluginConfigWithMeta } = await import("./index-kxw2sx1d.js");
725
725
  const { config: loadedConfig } = loadPluginConfigWithMeta(directory);
726
726
  config = KnowledgeConfigSchema.parse(loadedConfig.knowledge ?? {});
727
727
  } catch {
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  import {
3
3
  authorizeCuration
4
- } from "./index-3ntrn97w.js";
4
+ } from "./index-pgyp3tta.js";
5
5
  import {
6
6
  findNearDuplicate,
7
7
  inferTags,
@@ -9,7 +9,7 @@ import {
9
9
  resolveSwarmKnowledgePath,
10
10
  resolveSwarmRejectedPath,
11
11
  transactKnowledge
12
- } from "./index-72envp1b.js";
12
+ } from "./index-w2kp2zvf.js";
13
13
  import {
14
14
  resolveKnowledgeStoreDir
15
15
  } from "./index-q27bajqb.js";
@@ -2,18 +2,18 @@
2
2
  import {
3
3
  ALLOWED_SKILL_PATH_PREFIXES,
4
4
  validateSkillPath
5
- } from "./index-ns62nv6t.js";
5
+ } from "./index-waqvy9a5.js";
6
6
  import {
7
7
  computeOutcomeSignal,
8
8
  readKnowledge,
9
9
  resolveHiveKnowledgePath,
10
10
  resolveSwarmKnowledgePath,
11
11
  transactKnowledge
12
- } from "./index-72envp1b.js";
12
+ } from "./index-w2kp2zvf.js";
13
13
  import {
14
14
  effectiveRetrievalOutcomes,
15
15
  readKnowledgeCounterRollups
16
- } from "./index-1mwdhq2p.js";
16
+ } from "./index-kj86tyrs.js";
17
17
  import {
18
18
  init_knowledge_types,
19
19
  isActiveStatus
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  import {
3
3
  validateSwarmPath
4
- } from "./index-2445sx3d.js";
4
+ } from "./index-s80bsjkj.js";
5
5
  import {
6
6
  init_logger,
7
7
  warn
package/dist/cli/index.js CHANGED
@@ -7,28 +7,28 @@ import {
7
7
  getPluginLockFilePaths,
8
8
  package_default,
9
9
  resolveCommand
10
- } from "./index-npycj2tr.js";
10
+ } from "./index-gczs3jy7.js";
11
11
  import"./index-v4n224r1.js";
12
12
  import"./index-cpssctv1.js";
13
- import"./index-kk1scggc.js";
13
+ import"./index-kzvwb2se.js";
14
14
  import"./index-4905hd2m.js";
15
15
  import"./index-134d35c1.js";
16
16
  import"./index-6n2jpz7x.js";
17
- import"./index-c4mcheyz.js";
18
- import"./index-ff3j65em.js";
19
- import"./index-gn62e04k.js";
17
+ import"./index-wy5jy3m9.js";
18
+ import"./index-m8vrw3pt.js";
19
+ import"./index-5fnc76da.js";
20
20
  import"./index-vxv732ex.js";
21
21
  import"./index-c8s9a3zh.js";
22
22
  import"./index-9ss2m4rs.js";
23
- import"./index-23zsx7dm.js";
24
- import"./index-ns62nv6t.js";
25
- import"./index-3ntrn97w.js";
23
+ import"./index-g4mnf3p5.js";
24
+ import"./index-waqvy9a5.js";
25
+ import"./index-pgyp3tta.js";
26
26
  import"./index-rtry5xyf.js";
27
- import"./index-72envp1b.js";
28
- import"./index-1mwdhq2p.js";
27
+ import"./index-w2kp2zvf.js";
28
+ import"./index-kj86tyrs.js";
29
29
  import"./index-ae75rja9.js";
30
30
  import"./index-q27bajqb.js";
31
- import"./index-hv2p03f3.js";
31
+ import"./index-6w02qz7t.js";
32
32
  import"./index-k5jrywpr.js";
33
33
  import"./index-n832052r.js";
34
34
  import {
@@ -43,8 +43,8 @@ import"./index-2tn5h2zp.js";
43
43
  import"./index-1kz6da87.js";
44
44
  import"./index-w9cb5zwh.js";
45
45
  import"./index-4rhhvd1a.js";
46
- import"./index-ecxwhwz7.js";
47
- import"./index-2445sx3d.js";
46
+ import"./index-y2pfmd0z.js";
47
+ import"./index-s80bsjkj.js";
48
48
  import"./index-z6xqpmqg.js";
49
49
  import"./index-zjygnfay.js";
50
50
  import"./index-zgwm4ryv.js";
@@ -8,9 +8,9 @@ import {
8
8
  maybeEscalateOnViolation,
9
9
  maybeQuarantineOnContradiction,
10
10
  readRecentEscalations
11
- } from "./index-ff3j65em.js";
12
- import"./index-72envp1b.js";
13
- import"./index-1mwdhq2p.js";
11
+ } from "./index-m8vrw3pt.js";
12
+ import"./index-w2kp2zvf.js";
13
+ import"./index-kj86tyrs.js";
14
14
  import"./index-ae75rja9.js";
15
15
  import"./index-q27bajqb.js";
16
16
  import"./index-bk5tah7q.js";
@@ -26,7 +26,7 @@ import {
26
26
  resolveKnowledgeCounterBaselinePath,
27
27
  resolveKnowledgeEventsPath,
28
28
  resolveLegacyApplicationLogPath
29
- } from "./index-1mwdhq2p.js";
29
+ } from "./index-kj86tyrs.js";
30
30
  import"./index-ae75rja9.js";
31
31
  import"./index-q27bajqb.js";
32
32
  import"./index-zgwm4ryv.js";
@@ -40,7 +40,7 @@ import {
40
40
  transactKnowledge,
41
41
  transactKnowledgeWithCas,
42
42
  wordBigrams
43
- } from "./index-72envp1b.js";
43
+ } from "./index-w2kp2zvf.js";
44
44
  import {
45
45
  resolveHiveDataDir
46
46
  } from "./index-ae75rja9.js";
@@ -23,11 +23,11 @@ import {
23
23
  validateLesson,
24
24
  validateSkillCandidatePath,
25
25
  validateSkillPath
26
- } from "./index-ns62nv6t.js";
27
- import"./index-3ntrn97w.js";
26
+ } from "./index-waqvy9a5.js";
27
+ import"./index-pgyp3tta.js";
28
28
  import"./index-rtry5xyf.js";
29
- import"./index-72envp1b.js";
30
- import"./index-1mwdhq2p.js";
29
+ import"./index-w2kp2zvf.js";
30
+ import"./index-kj86tyrs.js";
31
31
  import"./index-ae75rja9.js";
32
32
  import"./index-q27bajqb.js";
33
33
  import"./index-bk5tah7q.js";
@@ -9,8 +9,8 @@ import {
9
9
  readDelegations,
10
10
  recordPendingDelegation,
11
11
  sweepStaleDelegations
12
- } from "./index-ecxwhwz7.js";
13
- import"./index-2445sx3d.js";
12
+ } from "./index-y2pfmd0z.js";
13
+ import"./index-s80bsjkj.js";
14
14
  import"./index-z6xqpmqg.js";
15
15
  import"./index-zjygnfay.js";
16
16
  import"./index-zgwm4ryv.js";
@@ -9,8 +9,8 @@ import {
9
9
  sweepStale,
10
10
  unsubscribe,
11
11
  updateSnapshot
12
- } from "./index-23zsx7dm.js";
13
- import"./index-2445sx3d.js";
12
+ } from "./index-g4mnf3p5.js";
13
+ import"./index-s80bsjkj.js";
14
14
  import"./index-z6xqpmqg.js";
15
15
  import"./index-zjygnfay.js";
16
16
  import"./index-zgwm4ryv.js";
@@ -4,8 +4,8 @@ import {
4
4
  alreadyCuratedThisGeneration,
5
5
  claimNextScanBatch,
6
6
  getScanStatus
7
- } from "./index-gn62e04k.js";
8
- import"./index-72envp1b.js";
7
+ } from "./index-5fnc76da.js";
8
+ import"./index-w2kp2zvf.js";
9
9
  import"./index-ae75rja9.js";
10
10
  import"./index-q27bajqb.js";
11
11
  import"./index-bk5tah7q.js";
@@ -33,12 +33,12 @@ import {
33
33
  sanitizeSlug,
34
34
  selectCandidateEntries,
35
35
  writeEvalStub
36
- } from "./index-c4mcheyz.js";
37
- import"./index-ns62nv6t.js";
38
- import"./index-3ntrn97w.js";
36
+ } from "./index-wy5jy3m9.js";
37
+ import"./index-waqvy9a5.js";
38
+ import"./index-pgyp3tta.js";
39
39
  import"./index-rtry5xyf.js";
40
- import"./index-72envp1b.js";
41
- import"./index-1mwdhq2p.js";
40
+ import"./index-w2kp2zvf.js";
41
+ import"./index-kj86tyrs.js";
42
42
  import"./index-ae75rja9.js";
43
43
  import"./index-q27bajqb.js";
44
44
  import"./index-bk5tah7q.js";
@@ -3,7 +3,7 @@ export { ALL_AGENT_NAMES, ALL_SUBAGENT_NAMES, DEFAULT_MODELS, isQAAgent, isSubag
3
3
  export type { ApprovalEvidence, BaseEvidence, DiffEvidence, Evidence, EvidenceBundle, EvidenceType, EvidenceVerdict, NoteEvidence, ReviewEvidence, TestEvidence, } from './evidence-schema';
4
4
  export { ApprovalEvidenceSchema, BaseEvidenceSchema, DiffEvidenceSchema, EVIDENCE_MAX_JSON_BYTES, EVIDENCE_MAX_PATCH_BYTES, EVIDENCE_MAX_TASK_BYTES, EvidenceBundleSchema, EvidenceSchema, EvidenceTypeSchema, EvidenceVerdictSchema, NoteEvidenceSchema, ReviewEvidenceSchema, TestEvidenceSchema, } from './evidence-schema';
5
5
  export type { ConfigBuildResult, ConfigLoadResult, ConfigRecovery, } from './loader';
6
- export { loadAgentPrompt, loadPluginConfig, loadPluginConfigWithMeta, loadPluginConfigWithMetaAsync, } from './loader';
6
+ export { getSafeDefaultConfigLoadResult, loadAgentPrompt, loadPluginConfig, loadPluginConfigWithMeta, loadPluginConfigWithMetaAsync, } from './loader';
7
7
  import { loadPluginConfigWithMeta } from './loader';
8
8
  /**
9
9
  * Test-only dependency-injection seam — see `gitignore-warning.ts:_internals`
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Config loader recovery persistence module.
3
+ *
4
+ * Persists recovery metadata emitted by the config loader so that:
5
+ * - `/swarm config doctor` can surface stale recovery artifacts
6
+ * (left by a prior process that crashed before cleanup).
7
+ * - Post-init flush (via `flushPendingLoaderRecovery`) can record
8
+ * recovery warnings without blocking plugin init.
9
+ * - Stale artifacts from older loads are cleaned up atomically
10
+ * when a newer load completes successfully (SC-002.3).
11
+ *
12
+ * Conflict resolution: every completed load writes a recovery artifact
13
+ * tagged with the tuple `{loadStartedAt, pid, inProcessCounter}`. When
14
+ * an artifact already exists, the new load wins iff its tuple is
15
+ * numerically greater than the existing one (component-wise comparison).
16
+ * This prevents a slower or earlier process from overwriting a newer
17
+ * recovery result.
18
+ *
19
+ * Artifact format (JSON):
20
+ * ```json
21
+ * {
22
+ * "loadStartedAt": number,
23
+ * "pid": number,
24
+ * "inProcessCounter": number,
25
+ * "sources": string[],
26
+ * "fingerprint": string,
27
+ * "warnings": RecoveryWarning[]
28
+ * }
29
+ * ```
30
+ *
31
+ * Lives under `src/config/` alongside `loader.ts` so the loader can
32
+ * import it without cross-module dependency violations.
33
+ */
34
+ import * as fsPromises from 'node:fs/promises';
35
+ import { bunWrite } from '../utils/bun-compat.js';
36
+ import type { RecoveryWarning } from './sanitize-malformed-values.js';
37
+ /** Shape of the on-disk recovery artifact. */
38
+ export interface LoaderRecoveryArtifact {
39
+ /** Date.now() when the config load started. */
40
+ loadStartedAt: number;
41
+ /** process.pid of the loading process. */
42
+ pid: number;
43
+ /** Monotonic per-process counter for same-process disambiguation. */
44
+ inProcessCounter: number;
45
+ /** Sorted source paths that contributed to the config merge. */
46
+ sources: string[];
47
+ /** SHA-256 fingerprint of the merged raw config. */
48
+ fingerprint: string;
49
+ /** Recovery warnings from the load (empty for clean loads). */
50
+ warnings: RecoveryWarning[];
51
+ }
52
+ /**
53
+ * Input shape accepted by the public API.
54
+ * Matches `LoadPluginConfigWithRecoveryResult.pendingPersistence`
55
+ * from `loader.ts`.
56
+ */
57
+ export type PendingLoaderRecoveryData = Omit<LoaderRecoveryArtifact, 'warnings'> & {
58
+ warnings: RecoveryWarning[];
59
+ };
60
+ /**
61
+ * Test-only dependency-injection seam — replaces `fsPromises.readFile`
62
+ * and `bunWrite` so tests can exercise failure paths without
63
+ * `mock.module` leakage (AGENTS.md §7).
64
+ */
65
+ export declare const _internals: {
66
+ readFile: typeof fsPromises.readFile;
67
+ write: typeof bunWrite;
68
+ };
69
+ /**
70
+ * Persist loader recovery data to `<directory>/.swarm/advisories/loader-recovery.json`.
71
+ *
72
+ * Every completed load atomically writes the artifact under deterministic
73
+ * conflict resolution: the new load wins iff its `{loadStartedAt, pid,
74
+ * inProcessCounter}` tuple is numerically greater than the existing artifact's.
75
+ * Clean loads (no recovery warnings) write `warnings: []`, which serves as
76
+ * the SC-002.3 stale-artifact cleanup signal.
77
+ *
78
+ * Failures (filesystem errors, permission issues) are logged via
79
+ * `advisoryWarn` and never thrown — this is best-effort persistence.
80
+ *
81
+ * @param directory - Project root directory (the `.swarm/` parent).
82
+ * @param data - Recovery data from the loader's `pendingPersistence`.
83
+ */
84
+ export declare function persistLoaderRecovery(directory: string, data: PendingLoaderRecoveryData): Promise<void>;
85
+ /**
86
+ * Synchronous wrapper that defers `persistLoaderRecovery` via `queueMicrotask`.
87
+ *
88
+ * This is designed for the post-init flush path (task 1.5) where the caller
89
+ * must not await the write — the write is fire-and-forget, with errors
90
+ * routed to `advisoryWarn` inside `persistLoaderRecovery`.
91
+ *
92
+ * @param directory - Project root directory (the `.swarm/` parent).
93
+ * @param pendingData - Recovery data from the loader's `pendingPersistence`.
94
+ */
95
+ export declare function flushPendingLoaderRecovery(directory: string, pendingData: PendingLoaderRecoveryData): void;
@@ -24,10 +24,14 @@ export declare function formatZodIssues(error: z.ZodError): string;
24
24
  * the remaining configuration was preserved.
25
25
  * 'user_only' – project config was discarded (failed validation and
26
26
  * targeted recovery); user config alone was used.
27
+ * 'sanitized_values' – merged and user configs both failed, but recursive
28
+ * malformed-value recovery (step 7b, issue #1690)
29
+ * dropped the smallest invalid leaves/sections so the
30
+ * remaining valid configuration could load.
27
31
  * 'guardrails_defaults'– neither merged nor user config was recoverable;
28
32
  * fell back to fail-secure guardrails-only defaults.
29
33
  */
30
- export type ConfigRecovery = 'none' | 'stripped_keys' | 'user_only' | 'guardrails_defaults';
34
+ export type ConfigRecovery = 'none' | 'stripped_keys' | 'user_only' | 'sanitized_values' | 'guardrails_defaults';
31
35
  /** Full result from the shared config-build core. */
32
36
  export type ConfigBuildResult = {
33
37
  config: PluginConfig;
@@ -71,6 +75,27 @@ export declare function loadPluginConfig(directory: string): PluginConfig;
71
75
  * exactly once, no double-read.
72
76
  */
73
77
  export declare function loadPluginConfigWithMeta(directory: string): ConfigLoadResult;
78
+ /**
79
+ * Safe-default `ConfigLoadResult` for init-path timeout / error fallback.
80
+ *
81
+ * Produces the same shape `loadPluginConfigWithMeta[Async]` returns when no
82
+ * config file exists on disk: empty config + guardrails enabled + no recovery.
83
+ * Used by `src/index.ts` when the parallelized config read times out or fails
84
+ * (Invariant 1 — init must remain bounded). A parity test in
85
+ * `tests/unit/config/loader-safe-default.test.ts` asserts this matches the
86
+ * classification fields the loader returns for a missing config file.
87
+ *
88
+ * Classification fields:
89
+ * - `loadedFromFile: false` — on timeout we cannot know whether a file
90
+ * existed (the `stat` itself may have stalled); `false` is the safe
91
+ * choice that avoids the guardrails-disabled warning gated by this
92
+ * flag at `src/index.ts` (the only init-path consumer).
93
+ * - `configHadErrors: false` — we did not observe a corrupt/oversized
94
+ * config, only a slow one; fail-closed consumers (e.g. the Full-Auto
95
+ * `locked` activation guard) treat this as "config defaults", which
96
+ * matches the runtime behavior of the safe-default `PluginConfig`.
97
+ */
98
+ export declare function getSafeDefaultConfigLoadResult(): ConfigLoadResult;
74
99
  /**
75
100
  * Async variant of `loadPluginConfigWithMeta`. Used by the plugin entry
76
101
  * (issue #704) so initialization does not perform synchronous fs reads.
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Fixed-point recovery helper for malformed config values.
3
+ *
4
+ * Given a Zod schema and a raw config object, this module iteratively
5
+ * removes malformed fields/sections until the config validates cleanly.
6
+ * It uses ONLY `safeParse` + `issue.path`/`issue.code`/`issue.keys` as
7
+ * signals — no schema introspection (`_def`, `.shape`, `instanceof` along
8
+ * paths), making it robust across Zod versions (v3 and v4+).
9
+ *
10
+ * Algorithm (SME-designed fixed-point):
11
+ * 1. Fast path: if `safeParse` succeeds, return the original reference
12
+ * (no clone cost on the happy path).
13
+ * 2. Deep-clone the input exactly once.
14
+ * 3. Loop: parse → build leaf drop-set from issue paths → remove deepest
15
+ * leaves first → re-parse. If no new leaves found but fresh issues
16
+ * remain, escalate to nearest non-removed ancestor. If still stuck,
17
+ * drop entire implicated top-level sections.
18
+ * 4. Terminate when parse succeeds or fuel is exhausted.
19
+ * 5. Emit ancestor-suppressed, deterministically-ordered warnings.
20
+ *
21
+ * This is a PURE function — no side effects, no I/O, no logging.
22
+ */
23
+ import type { z } from 'zod';
24
+ /** Dotted path identifying the dropped unit, e.g. "council.enabled" or "pr_monitor". */
25
+ export interface RecoveryWarning {
26
+ section: string;
27
+ /** Currently always 'warn'; reserved for future severity levels. */
28
+ severity: 'warn';
29
+ /** Human-readable description of what was dropped and why. */
30
+ message: string;
31
+ /** Full Zod error path if available (for debugging / downstream use). */
32
+ path?: string;
33
+ }
34
+ export interface SanitizeResult {
35
+ /** The recovered config object. Keys omitted here will be filled by Zod defaults
36
+ * at parse time — callers should re-parse this through the schema. */
37
+ config: Record<string, unknown>;
38
+ /** Warnings for every field or section that was dropped during recovery. */
39
+ recoveryWarnings: RecoveryWarning[];
40
+ }
41
+ /**
42
+ * Attempt to recover a malformed config by iteratively dropping invalid
43
+ * values until the config validates. This is a generic helper that works
44
+ * with any Zod schema and avoids all schema introspection.
45
+ *
46
+ * The returned `config` is the cleaned raw config — callers should pass it
47
+ * through `schema.parse()` to get fully typed output with defaults applied.
48
+ *
49
+ * @param schema - The Zod schema to validate against.
50
+ * @param rawConfig - The raw parsed-config object (not yet Zod-validated).
51
+ * @returns The cleaned config plus any warnings emitted during recovery.
52
+ */
53
+ export declare function sanitizeMalformedValues(schema: z.ZodTypeAny, rawConfig: Record<string, unknown>): SanitizeResult;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,8 @@
1
1
  import type { Plugin } from '@opencode-ai/plugin';
2
+ import { loadPluginConfigWithMetaAsync } from './config';
2
3
  import { createRepoGraphBuilderHook } from './hooks';
4
+ import { loadSnapshot } from './session/snapshot-reader.js';
5
+ import { ensureSwarmGitExcluded } from './utils/gitignore-warning';
3
6
  /**
4
7
  * FIFO-cap a session-keyed Map to at most `max` entries, evicting oldest first.
5
8
  * Values tracked by these maps are plain data (timestamps/usage snapshots), never
@@ -18,6 +21,9 @@ declare function schedulePostResolutionTasks(tasks: readonly PostResolutionTask[
18
21
  export declare function overrideIndexInternalsForTest(overrides: {
19
22
  createRepoGraphBuilderHook?: typeof createRepoGraphBuilderHook;
20
23
  schedulePostResolutionTasks?: typeof schedulePostResolutionTasks;
24
+ loadPluginConfigWithMetaAsync?: typeof loadPluginConfigWithMetaAsync;
25
+ loadSnapshot?: typeof loadSnapshot;
26
+ ensureSwarmGitExcluded?: typeof ensureSwarmGitExcluded;
21
27
  }): () => void;
22
28
  export declare function schedulePostResolutionTasksForTest(tasks: readonly PostResolutionTask[]): void;
23
29
  declare const _default: {