opencode-swarm 7.38.0 → 7.40.0

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.
package/dist/index.js CHANGED
@@ -48,7 +48,7 @@ var package_default;
48
48
  var init_package = __esm(() => {
49
49
  package_default = {
50
50
  name: "opencode-swarm",
51
- version: "7.38.0",
51
+ version: "7.40.0",
52
52
  description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
53
53
  main: "dist/index.js",
54
54
  types: "dist/index.d.ts",
@@ -15581,6 +15581,13 @@ var init_schema = __esm(() => {
15581
15581
  redaction: exports_external.object({
15582
15582
  rejectDurableSecrets: exports_external.boolean().default(true)
15583
15583
  }).default({ rejectDurableSecrets: true }),
15584
+ maintenance: exports_external.object({
15585
+ lowUtilityMaxConfidence: exports_external.number().min(0).max(1).default(0.45),
15586
+ lowUtilityMinAgeDays: exports_external.number().int().min(1).max(3650).default(30)
15587
+ }).default({
15588
+ lowUtilityMaxConfidence: 0.45,
15589
+ lowUtilityMinAgeDays: 30
15590
+ }),
15584
15591
  hardDelete: exports_external.boolean().default(false)
15585
15592
  });
15586
15593
  CuratorConfigSchema = exports_external.object({
@@ -40120,7 +40127,8 @@ async function buildParallelExecutionGuidance(directory, sessionID, session) {
40120
40127
  const profile = plan.execution_profile;
40121
40128
  const enabled = profile?.parallelization_enabled === true;
40122
40129
  const maxConcurrent = profile?.max_concurrent_tasks ?? 1;
40123
- if (!enabled || maxConcurrent <= 1)
40130
+ const effectiveMaxConcurrent = session?.maxConcurrencyOverride ?? maxConcurrent;
40131
+ if (!enabled || effectiveMaxConcurrent <= 1)
40124
40132
  return null;
40125
40133
  if (hasActiveLeanTurbo(sessionID)) {
40126
40134
  return "[NEXT] Lean Turbo is active; use lean_turbo_run_phase and Lean Turbo lane guidance instead of standard execution-profile slot filling.";
@@ -40149,9 +40157,9 @@ async function buildParallelExecutionGuidance(directory, sessionID, session) {
40149
40157
  if (ACTIVE_PARALLEL_TASK_STATES.has(state))
40150
40158
  occupied.add(taskId);
40151
40159
  }
40152
- const availableSlots = Math.max(0, maxConcurrent - occupied.size);
40160
+ const availableSlots = Math.max(0, effectiveMaxConcurrent - occupied.size);
40153
40161
  if (availableSlots <= 0) {
40154
- return `[PARALLEL EXECUTION PROFILE] parallelization_enabled=true max_concurrent_tasks=${maxConcurrent}; all standard execution slots are occupied. Continue current active task gates before starting more coder work.`;
40162
+ return `[PARALLEL EXECUTION PROFILE] parallelization_enabled=true max_concurrent_tasks=${effectiveMaxConcurrent}; all standard execution slots are occupied. Continue current active task gates before starting more coder work.`;
40155
40163
  }
40156
40164
  const eligible = tasks.filter((task) => {
40157
40165
  const taskId = task.id;
@@ -40163,9 +40171,9 @@ async function buildParallelExecutionGuidance(directory, sessionID, session) {
40163
40171
  return task.depends.every((dep) => completed.has(dep));
40164
40172
  }).map((task) => task.id).slice(0, availableSlots);
40165
40173
  if (eligible.length === 0) {
40166
- return `[PARALLEL EXECUTION PROFILE] parallelization_enabled=true max_concurrent_tasks=${maxConcurrent}; no dependency-ready pending tasks are available for a new coder slot. Continue the current task/gate.`;
40174
+ return `[PARALLEL EXECUTION PROFILE] parallelization_enabled=true max_concurrent_tasks=${effectiveMaxConcurrent}; no dependency-ready pending tasks are available for a new coder slot. Continue the current task/gate.`;
40167
40175
  }
40168
- return `[PARALLEL EXECUTION PROFILE] parallelization_enabled=true max_concurrent_tasks=${maxConcurrent}; ${occupied.size} slot(s) occupied. Eligible now: ${eligible.join(", ")}. [NEXT] dispatch up to ${availableSlots} eligible coder task(s) before waiting; preserve ONE task per coder call and call declare_scope for each task.`;
40176
+ return `[PARALLEL EXECUTION PROFILE] parallelization_enabled=true max_concurrent_tasks=${effectiveMaxConcurrent}; ${occupied.size} slot(s) occupied. Eligible now: ${eligible.join(", ")}. [NEXT] dispatch up to ${availableSlots} eligible coder task(s) before waiting; preserve ONE task per coder call and call declare_scope for each task.`;
40169
40177
  }
40170
40178
  function isParallelGuidancePhaseComplete(phase) {
40171
40179
  return phase.status === "complete" || phase.status === "completed" || phase.status === "closed";
@@ -41006,6 +41014,7 @@ function startAgentSession(sessionId, agentName, staleDurationMs = 7200000, dire
41006
41014
  turboStrategy: undefined,
41007
41015
  leanTurboActive: false,
41008
41016
  leanTurboCurrentPhase: undefined,
41017
+ maxConcurrencyOverride: undefined,
41009
41018
  qaGateSessionOverrides: {},
41010
41019
  fullAutoMode: false,
41011
41020
  fullAutoInteractionCount: 0,
@@ -60234,6 +60243,110 @@ var init_close = __esm(() => {
60234
60243
  ];
60235
60244
  });
60236
60245
 
60246
+ // src/commands/concurrency.ts
60247
+ async function handleConcurrencyCommand(directory, args2, sessionID) {
60248
+ if (!sessionID || sessionID.trim() === "") {
60249
+ return "Error: No active session context. Concurrency requires an active session. Use /swarm concurrency from within an OpenCode session, or start a session first.";
60250
+ }
60251
+ const session = getAgentSession(sessionID);
60252
+ if (!session) {
60253
+ return "Error: No active session. Concurrency requires an active session to operate.";
60254
+ }
60255
+ const arg0 = args2[0]?.toLowerCase();
60256
+ const arg1 = args2[1];
60257
+ const plan = await loadPlanJsonOnly(directory).catch(() => null);
60258
+ const hasPlan = plan !== null && plan !== undefined;
60259
+ if (arg0 === undefined) {
60260
+ return [
60261
+ "Concurrency commands:",
60262
+ " /swarm concurrency set <N|preset> — Set session concurrency override (1-64 or min/medium/max)",
60263
+ " /swarm concurrency status — Show effective concurrency",
60264
+ " /swarm concurrency reset — Clear the override"
60265
+ ].join(`
60266
+ `);
60267
+ }
60268
+ if (arg0 === "status") {
60269
+ return buildStatusMessage(session, plan);
60270
+ }
60271
+ if (!hasPlan) {
60272
+ if (arg0 === "set") {
60273
+ return "No active plan. Concurrency override requires an active plan.";
60274
+ }
60275
+ }
60276
+ if (arg0 === "reset") {
60277
+ session.maxConcurrencyOverride = undefined;
60278
+ return "Concurrency override cleared";
60279
+ }
60280
+ if (arg0 === "set") {
60281
+ if (arg1 === undefined) {
60282
+ return "Error: /swarm concurrency set requires a value. Usage: /swarm concurrency set <N|preset>";
60283
+ }
60284
+ return handleSetCommand(session, arg1);
60285
+ }
60286
+ return [
60287
+ `Unknown concurrency subcommand: ${arg0}`,
60288
+ "Usage: /swarm concurrency <set|status|reset>"
60289
+ ].join(`
60290
+ `);
60291
+ }
60292
+ function handleSetCommand(session, value) {
60293
+ const normalizedValue = value.toLowerCase();
60294
+ if (normalizedValue in PRESETS) {
60295
+ const presetConcurrency = PRESETS[normalizedValue];
60296
+ session.maxConcurrencyOverride = presetConcurrency;
60297
+ return `Concurrency override set to ${presetConcurrency} (${normalizedValue})`;
60298
+ }
60299
+ const numericValue = Number(value);
60300
+ if (Number.isNaN(numericValue)) {
60301
+ return `Invalid concurrency value: ${value}. Must be a number (1-64) or a preset (min, medium, max).`;
60302
+ }
60303
+ if (!Number.isInteger(numericValue)) {
60304
+ return `Invalid concurrency value: ${value}. Must be a number (1-64) or a preset (min, medium, max).`;
60305
+ }
60306
+ if (numericValue < MIN_CONCURRENCY || numericValue > MAX_CONCURRENCY) {
60307
+ return `Concurrency value ${value} is out of range. Must be between ${MIN_CONCURRENCY} and ${MAX_CONCURRENCY}.`;
60308
+ }
60309
+ session.maxConcurrencyOverride = numericValue;
60310
+ return `Concurrency override set to ${numericValue}`;
60311
+ }
60312
+ function buildStatusMessage(session, plan) {
60313
+ const overrideActive = session.maxConcurrencyOverride !== undefined;
60314
+ const configuredOverride = session.maxConcurrencyOverride ?? "absent";
60315
+ const hasPlan = plan !== null && plan !== undefined;
60316
+ const planBaseline = hasPlan ? plan.execution_profile?.max_concurrent_tasks ?? 1 : 1;
60317
+ const parallelizationEnabled = hasPlan ? plan.execution_profile?.parallelization_enabled ?? false : false;
60318
+ const operationalEffective = !parallelizationEnabled ? 1 : session.maxConcurrencyOverride ?? planBaseline;
60319
+ let description;
60320
+ if (!hasPlan) {
60321
+ description = "No active plan";
60322
+ } else if (!parallelizationEnabled) {
60323
+ description = "Parallelization disabled (always 1)";
60324
+ } else if (overrideActive) {
60325
+ description = `Override active (${session.maxConcurrencyOverride})`;
60326
+ } else {
60327
+ description = `Plan baseline (${planBaseline})`;
60328
+ }
60329
+ return [
60330
+ `Concurrency: ${description}`,
60331
+ ` override_active: ${overrideActive}`,
60332
+ ` configured_override: ${configuredOverride}`,
60333
+ ` plan_baseline: ${planBaseline}`,
60334
+ ` operational_effective: ${operationalEffective}`,
60335
+ ` parallelization_enabled: ${parallelizationEnabled}`
60336
+ ].join(`
60337
+ `);
60338
+ }
60339
+ var PRESETS, MIN_CONCURRENCY = 1, MAX_CONCURRENCY = 64;
60340
+ var init_concurrency = __esm(() => {
60341
+ init_manager();
60342
+ init_state();
60343
+ PRESETS = {
60344
+ min: 1,
60345
+ medium: 3,
60346
+ max: 8
60347
+ };
60348
+ });
60349
+
60237
60350
  // src/commands/config.ts
60238
60351
  import * as os7 from "node:os";
60239
60352
  import * as path28 from "node:path";
@@ -65915,7 +66028,10 @@ function serializeAgentSession(s) {
65915
66028
  fullAutoDeadlockCount: s.fullAutoDeadlockCount ?? 0,
65916
66029
  fullAutoLastQuestionHash: s.fullAutoLastQuestionHash ?? null,
65917
66030
  sessionRehydratedAt: s.sessionRehydratedAt ?? 0,
65918
- ...Object.keys(stageBCompletion).length > 0 && { stageBCompletion }
66031
+ ...Object.keys(stageBCompletion).length > 0 && { stageBCompletion },
66032
+ ...s.maxConcurrencyOverride !== undefined && {
66033
+ maxConcurrencyOverride: s.maxConcurrencyOverride
66034
+ }
65919
66035
  };
65920
66036
  }
65921
66037
  async function writeSnapshot(directory, state) {
@@ -66788,6 +66904,10 @@ function resolveMemoryConfig(input) {
66788
66904
  redaction: {
66789
66905
  ...DEFAULT_MEMORY_CONFIG.redaction,
66790
66906
  ...input?.redaction ?? {}
66907
+ },
66908
+ maintenance: {
66909
+ ...DEFAULT_MEMORY_CONFIG.maintenance,
66910
+ ...input?.maintenance ?? {}
66791
66911
  }
66792
66912
  };
66793
66913
  }
@@ -66819,6 +66939,10 @@ var init_config3 = __esm(() => {
66819
66939
  redaction: {
66820
66940
  rejectDurableSecrets: true
66821
66941
  },
66942
+ maintenance: {
66943
+ lowUtilityMaxConfidence: 0.45,
66944
+ lowUtilityMinAgeDays: 30
66945
+ },
66822
66946
  hardDelete: false
66823
66947
  };
66824
66948
  DURABLE_MEMORY_KINDS = new Set([
@@ -67231,6 +67355,167 @@ var init_curator_decision_helpers = __esm(() => {
67231
67355
  init_schema2();
67232
67356
  });
67233
67357
 
67358
+ // src/memory/maintenance.ts
67359
+ async function buildMemoryMaintenanceReport(provider, options = {}) {
67360
+ const now = options.now ?? new Date;
67361
+ const limit = Math.max(1, Math.trunc(options.limit ?? 20));
67362
+ const memories = await provider.list({
67363
+ includeExpired: true,
67364
+ includeInactive: true
67365
+ });
67366
+ const proposals = await loadMaintenanceProposals(provider, limit);
67367
+ const recallUsage = provider.listRecallUsage ? await provider.listRecallUsage() : [];
67368
+ const usageByMemory = summarizeRecallByMemory(recallUsage);
67369
+ const usageByRole = summarizeRecallByRole(recallUsage);
67370
+ const activeMemories = memories.filter((memory) => isActiveMemory(memory, now));
67371
+ const deletedMemories = memories.filter((memory) => memory.metadata.deleted === true);
67372
+ const expiredScratchMemories = memories.filter((memory) => memory.kind === "scratch" && isExpired(memory, now));
67373
+ const supersededMemories = memories.filter((memory) => Boolean(memory.supersededBy));
67374
+ const lowUtilityMemories = activeMemories.filter((memory) => isLowUtility(memory, usageByMemory, now, {
67375
+ maxConfidence: options.lowUtilityMaxConfidence ?? DEFAULT_LOW_UTILITY_MAX_CONFIDENCE,
67376
+ minAgeDays: options.lowUtilityMinAgeDays ?? DEFAULT_LOW_UTILITY_MIN_AGE_DAYS
67377
+ })).sort(memorySort);
67378
+ const neverRecalledMemories = activeMemories.filter((memory) => !usageByMemory.has(memory.id)).sort(memorySort);
67379
+ const rejectedProposalReasons = proposals.filter((proposal) => proposal.status === "rejected").sort(proposalSort);
67380
+ const pendingProposals = proposals.filter((proposal) => proposal.status === "pending").sort(proposalSort);
67381
+ return {
67382
+ generatedAt: now.toISOString(),
67383
+ totalMemories: memories.length,
67384
+ activeMemories: activeMemories.length,
67385
+ deletedMemories: deletedMemories.slice(0, limit),
67386
+ expiredScratchMemories: expiredScratchMemories.slice(0, limit),
67387
+ supersededMemories: supersededMemories.slice(0, limit),
67388
+ supersededChains: buildSupersededChains(memories).slice(0, limit),
67389
+ lowUtilityMemories: lowUtilityMemories.slice(0, limit),
67390
+ neverRecalledMemories: neverRecalledMemories.slice(0, limit),
67391
+ mostRecalledMemories: Array.from(usageByMemory.values()).sort((a, b) => b.count - a.count || b.lastRecalledAt.localeCompare(a.lastRecalledAt) || a.memoryId.localeCompare(b.memoryId)).slice(0, limit),
67392
+ recallByAgentRole: Array.from(usageByRole.values()).sort((a, b) => b.count - a.count || a.agentRole.localeCompare(b.agentRole)).slice(0, limit),
67393
+ rejectedProposalReasons: rejectedProposalReasons.slice(0, limit),
67394
+ pendingProposals: pendingProposals.slice(0, limit),
67395
+ recallEventCount: recallUsage.length
67396
+ };
67397
+ }
67398
+ function shouldCompactMemory(memory, now = new Date) {
67399
+ if (memory.metadata.deleted === true)
67400
+ return "deleted";
67401
+ if (memory.supersededBy)
67402
+ return "superseded";
67403
+ if (memory.kind === "scratch" && isExpired(memory, now)) {
67404
+ return "expired_scratch";
67405
+ }
67406
+ return null;
67407
+ }
67408
+ function isActiveMemory(memory, now) {
67409
+ return memory.metadata.deleted !== true && !memory.supersededBy && !isExpired(memory, now);
67410
+ }
67411
+ function isLowUtility(memory, usageByMemory, now, options) {
67412
+ if (usageByMemory.has(memory.id))
67413
+ return false;
67414
+ const updated = Date.parse(memory.updatedAt);
67415
+ const ageDays = Number.isFinite(updated) ? (now.getTime() - updated) / (24 * 60 * 60 * 1000) : 0;
67416
+ return memory.confidence <= options.maxConfidence || ageDays >= options.minAgeDays;
67417
+ }
67418
+ function summarizeRecallByMemory(usageEvents) {
67419
+ const byMemory = new Map;
67420
+ for (const event of usageEvents) {
67421
+ event.memoryIds.forEach((memoryId, index) => {
67422
+ const role = event.agentRole ?? "unknown";
67423
+ const existing = byMemory.get(memoryId) ?? {
67424
+ memoryId,
67425
+ count: 0,
67426
+ lastRecalledAt: event.timestamp,
67427
+ agentRoles: {},
67428
+ averageScore: 0,
67429
+ scoreTotal: 0,
67430
+ scoreCount: 0
67431
+ };
67432
+ existing.count++;
67433
+ existing.lastRecalledAt = event.timestamp > existing.lastRecalledAt ? event.timestamp : existing.lastRecalledAt;
67434
+ existing.agentRoles[role] = (existing.agentRoles[role] ?? 0) + 1;
67435
+ const score = event.scores[index];
67436
+ if (typeof score === "number" && Number.isFinite(score)) {
67437
+ existing.scoreTotal += score;
67438
+ existing.scoreCount++;
67439
+ existing.averageScore = existing.scoreTotal / existing.scoreCount;
67440
+ }
67441
+ byMemory.set(memoryId, existing);
67442
+ });
67443
+ }
67444
+ return new Map(Array.from(byMemory, ([memoryId, value]) => [
67445
+ memoryId,
67446
+ {
67447
+ memoryId,
67448
+ count: value.count,
67449
+ lastRecalledAt: value.lastRecalledAt,
67450
+ agentRoles: value.agentRoles,
67451
+ averageScore: value.averageScore
67452
+ }
67453
+ ]));
67454
+ }
67455
+ async function loadMaintenanceProposals(provider, limit) {
67456
+ if (!provider.listProposals)
67457
+ return [];
67458
+ const [pending, rejected, recent] = await Promise.all([
67459
+ provider.listProposals({ status: "pending", limit }),
67460
+ provider.listProposals({ status: "rejected", limit }),
67461
+ provider.listProposals({ limit: Math.max(limit * 4, 100) })
67462
+ ]);
67463
+ const byId = new Map;
67464
+ for (const proposal of [...pending, ...rejected, ...recent]) {
67465
+ byId.set(proposal.id, proposal);
67466
+ }
67467
+ return Array.from(byId.values());
67468
+ }
67469
+ function summarizeRecallByRole(usageEvents) {
67470
+ const byRole = new Map;
67471
+ for (const event of usageEvents) {
67472
+ const role = event.agentRole ?? "unknown";
67473
+ const existing = byRole.get(role) ?? {
67474
+ agentRole: role,
67475
+ count: 0,
67476
+ memoryIds: {}
67477
+ };
67478
+ existing.count++;
67479
+ for (const memoryId of event.memoryIds) {
67480
+ existing.memoryIds[memoryId] = (existing.memoryIds[memoryId] ?? 0) + 1;
67481
+ }
67482
+ byRole.set(role, existing);
67483
+ }
67484
+ return byRole;
67485
+ }
67486
+ function buildSupersededChains(memories) {
67487
+ const byId = new Map(memories.map((memory) => [memory.id, memory]));
67488
+ const supersededIds = new Set(memories.filter((memory) => memory.supersededBy).map((memory) => memory.id));
67489
+ const roots = memories.filter((memory) => memory.supersededBy && !(memory.supersedes ?? []).some((id) => supersededIds.has(id)));
67490
+ return roots.map((root) => {
67491
+ const chain = [root.id];
67492
+ const seen = new Set(chain);
67493
+ let cursor = root;
67494
+ while (cursor?.supersededBy && !seen.has(cursor.supersededBy)) {
67495
+ chain.push(cursor.supersededBy);
67496
+ seen.add(cursor.supersededBy);
67497
+ cursor = byId.get(cursor.supersededBy);
67498
+ }
67499
+ return {
67500
+ rootId: root.id,
67501
+ chain,
67502
+ reason: typeof root.metadata.supersedeReason === "string" ? root.metadata.supersedeReason : undefined
67503
+ };
67504
+ });
67505
+ }
67506
+ function memorySort(a, b) {
67507
+ return b.updatedAt.localeCompare(a.updatedAt) || a.id.localeCompare(b.id);
67508
+ }
67509
+ function proposalSort(a, b) {
67510
+ const aTime = a.reviewedAt ?? a.createdAt;
67511
+ const bTime = b.reviewedAt ?? b.createdAt;
67512
+ return bTime.localeCompare(aTime) || a.id.localeCompare(b.id);
67513
+ }
67514
+ var DEFAULT_LOW_UTILITY_MAX_CONFIDENCE = 0.45, DEFAULT_LOW_UTILITY_MIN_AGE_DAYS = 30;
67515
+ var init_maintenance = __esm(() => {
67516
+ init_schema2();
67517
+ });
67518
+
67234
67519
  // src/memory/role-profiles.ts
67235
67520
  function resolveMemoryRecallProfile(agentRole) {
67236
67521
  const role = normalizeMemoryAgentRole(agentRole);
@@ -67618,16 +67903,21 @@ class LocalJsonlMemoryProvider {
67618
67903
  }
67619
67904
  async recordRecallUsage(event) {
67620
67905
  await this.initialize();
67621
- await this.audit("recall", event.bundleId, JSON.stringify({
67622
- query: event.query,
67623
- scopes: event.scopes,
67624
- kinds: event.kinds,
67625
- memoryIds: event.memoryIds,
67626
- scores: event.scores,
67627
- tokenEstimate: event.tokenEstimate,
67628
- agentRole: event.agentRole,
67629
- runId: event.runId
67630
- }));
67906
+ await this.audit("recall", event.bundleId, undefined, event);
67907
+ }
67908
+ async listRecallUsage(filter = {}) {
67909
+ await this.initialize();
67910
+ const events = await readAuditEvents(this.pathFor("audit"));
67911
+ const usage = [];
67912
+ for (const event of events) {
67913
+ if (event.operation !== "recall")
67914
+ continue;
67915
+ const parsed = parseRecallUsageEvent(event);
67916
+ if (parsed)
67917
+ usage.push(parsed);
67918
+ }
67919
+ usage.sort((a, b) => b.timestamp.localeCompare(a.timestamp));
67920
+ return usage.slice(0, filter.limit ?? usage.length);
67631
67921
  }
67632
67922
  async list(filter = {}) {
67633
67923
  await this.initialize();
@@ -67647,7 +67937,9 @@ class LocalJsonlMemoryProvider {
67647
67937
  return !Number.isFinite(expires) || expires > now;
67648
67938
  });
67649
67939
  }
67650
- records = records.filter((record3) => !record3.supersededBy && record3.metadata.deleted !== true);
67940
+ if (!filter.includeInactive) {
67941
+ records = records.filter((record3) => !record3.supersededBy && record3.metadata.deleted !== true);
67942
+ }
67651
67943
  records.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
67652
67944
  return records.slice(0, filter.limit ?? records.length);
67653
67945
  }
@@ -67759,6 +68051,41 @@ class LocalJsonlMemoryProvider {
67759
68051
  await writeJsonlAtomic(this.pathFor("memories"), Array.from(this.memories.values()));
67760
68052
  await this.audit("compact", "memories");
67761
68053
  }
68054
+ async compactMaintenance(options = {}) {
68055
+ await this.initialize();
68056
+ const now = options.now ? new Date(options.now) : new Date;
68057
+ const kept = [];
68058
+ const result = {
68059
+ dryRun: options.dryRun !== false,
68060
+ removedDeleted: 0,
68061
+ removedSuperseded: 0,
68062
+ removedExpiredScratch: 0,
68063
+ remaining: 0
68064
+ };
68065
+ for (const memory of this.memories.values()) {
68066
+ const compactReason = shouldCompactMemory(memory, now);
68067
+ if (compactReason === "deleted") {
68068
+ result.removedDeleted++;
68069
+ continue;
68070
+ }
68071
+ if (compactReason === "superseded") {
68072
+ result.removedSuperseded++;
68073
+ continue;
68074
+ }
68075
+ if (compactReason === "expired_scratch") {
68076
+ result.removedExpiredScratch++;
68077
+ continue;
68078
+ }
68079
+ kept.push(memory);
68080
+ }
68081
+ result.remaining = kept.length;
68082
+ if (result.dryRun)
68083
+ return result;
68084
+ this.memories = new Map(kept.map((memory) => [memory.id, memory]));
68085
+ await writeJsonlAtomic(this.pathFor("memories"), kept);
68086
+ await this.audit("compact", "memories", "removed deleted, superseded, and expired scratch memories", result);
68087
+ return result;
68088
+ }
67762
68089
  async audit(operation, targetId, reason, eventJson) {
67763
68090
  const event = {
67764
68091
  id: randomUUID4(),
@@ -67837,6 +68164,46 @@ async function readJsonl(filePath) {
67837
68164
  }
67838
68165
  return records;
67839
68166
  }
68167
+ async function readAuditEvents(filePath) {
68168
+ const values = await readJsonl(filePath);
68169
+ const events = [];
68170
+ for (const value of values) {
68171
+ if (!value || typeof value !== "object")
68172
+ continue;
68173
+ const candidate = value;
68174
+ if (typeof candidate.id !== "string" || typeof candidate.operation !== "string" || typeof candidate.targetId !== "string" || typeof candidate.timestamp !== "string") {
68175
+ continue;
68176
+ }
68177
+ events.push(candidate);
68178
+ }
68179
+ return events;
68180
+ }
68181
+ function parseRecallUsageEvent(event) {
68182
+ const raw = event.eventJson ?? event.reason;
68183
+ if (typeof raw !== "string" && (!raw || typeof raw !== "object")) {
68184
+ return null;
68185
+ }
68186
+ try {
68187
+ const parsed = typeof raw === "string" ? JSON.parse(raw) : raw;
68188
+ if (!Array.isArray(parsed.memoryIds) || typeof parsed.query !== "string") {
68189
+ return null;
68190
+ }
68191
+ return {
68192
+ bundleId: typeof parsed.bundleId === "string" ? parsed.bundleId : event.targetId,
68193
+ query: parsed.query,
68194
+ scopes: Array.isArray(parsed.scopes) ? parsed.scopes : [],
68195
+ kinds: Array.isArray(parsed.kinds) ? parsed.kinds : undefined,
68196
+ memoryIds: parsed.memoryIds.filter((memoryId) => typeof memoryId === "string"),
68197
+ scores: Array.isArray(parsed.scores) ? parsed.scores.filter((score) => typeof score === "number" && Number.isFinite(score)) : [],
68198
+ tokenEstimate: typeof parsed.tokenEstimate === "number" ? parsed.tokenEstimate : 0,
68199
+ agentRole: typeof parsed.agentRole === "string" ? parsed.agentRole : undefined,
68200
+ runId: typeof parsed.runId === "string" ? parsed.runId : undefined,
68201
+ timestamp: typeof parsed.timestamp === "string" ? parsed.timestamp : event.timestamp
68202
+ };
68203
+ } catch {
68204
+ return null;
68205
+ }
68206
+ }
67840
68207
  async function appendJsonl(filePath, value) {
67841
68208
  await mkdir9(path39.dirname(filePath), { recursive: true });
67842
68209
  await appendFile5(filePath, `${JSON.stringify(value)}
@@ -67856,6 +68223,7 @@ var init_local_jsonl_provider = __esm(() => {
67856
68223
  init_config3();
67857
68224
  init_curator_decision_helpers();
67858
68225
  init_errors6();
68226
+ init_maintenance();
67859
68227
  init_schema2();
67860
68228
  init_scoring();
67861
68229
  });
@@ -68187,6 +68555,10 @@ class SQLiteMemoryProvider {
68187
68555
  redaction: {
68188
68556
  ...DEFAULT_MEMORY_CONFIG.redaction,
68189
68557
  ...config3.redaction ?? {}
68558
+ },
68559
+ maintenance: {
68560
+ ...DEFAULT_MEMORY_CONFIG.maintenance,
68561
+ ...config3.maintenance ?? {}
68190
68562
  }
68191
68563
  };
68192
68564
  }
@@ -68292,6 +68664,26 @@ class SQLiteMemoryProvider {
68292
68664
  ) VALUES (?, ?, ?, ?)`, [randomUUID5(), event.bundleId, event.timestamp, JSON.stringify(event)]);
68293
68665
  await this.event("recall", event.bundleId, JSON.stringify(event));
68294
68666
  }
68667
+ async listRecallUsage(filter = {}) {
68668
+ await this.initialize();
68669
+ const rows = typeof filter.limit === "number" ? this.requireDb().query(`SELECT usage_json
68670
+ FROM memory_recall_usage
68671
+ ORDER BY timestamp DESC
68672
+ LIMIT ?`).all(Math.max(1, Math.trunc(filter.limit))) : this.requireDb().query(`SELECT usage_json
68673
+ FROM memory_recall_usage
68674
+ ORDER BY timestamp DESC
68675
+ `).all();
68676
+ const events = [];
68677
+ for (const row of rows) {
68678
+ try {
68679
+ const parsed = JSON.parse(row.usage_json);
68680
+ if (Array.isArray(parsed.memoryIds) && typeof parsed.query === "string") {
68681
+ events.push(parsed);
68682
+ }
68683
+ } catch {}
68684
+ }
68685
+ return events;
68686
+ }
68295
68687
  async list(filter = {}) {
68296
68688
  await this.initialize();
68297
68689
  let records = Array.from(this.memories.values());
@@ -68310,7 +68702,9 @@ class SQLiteMemoryProvider {
68310
68702
  return !Number.isFinite(expires) || expires > now;
68311
68703
  });
68312
68704
  }
68313
- records = records.filter((record3) => !record3.supersededBy && record3.metadata.deleted !== true);
68705
+ if (!filter.includeInactive) {
68706
+ records = records.filter((record3) => !record3.supersededBy && record3.metadata.deleted !== true);
68707
+ }
68314
68708
  records.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
68315
68709
  return records.slice(0, filter.limit ?? records.length);
68316
68710
  }
@@ -68391,6 +68785,52 @@ class SQLiteMemoryProvider {
68391
68785
  proposals: proposals.length
68392
68786
  };
68393
68787
  }
68788
+ async compactMaintenance(options = {}) {
68789
+ await this.initialize();
68790
+ const now = options.now ? new Date(options.now) : new Date;
68791
+ const kept = [];
68792
+ const removeIds = [];
68793
+ const result = {
68794
+ dryRun: options.dryRun !== false,
68795
+ removedDeleted: 0,
68796
+ removedSuperseded: 0,
68797
+ removedExpiredScratch: 0,
68798
+ remaining: 0
68799
+ };
68800
+ for (const memory of this.memories.values()) {
68801
+ const compactReason = shouldCompactMemory(memory, now);
68802
+ if (compactReason === "deleted") {
68803
+ result.removedDeleted++;
68804
+ removeIds.push(memory.id);
68805
+ continue;
68806
+ }
68807
+ if (compactReason === "superseded") {
68808
+ result.removedSuperseded++;
68809
+ removeIds.push(memory.id);
68810
+ continue;
68811
+ }
68812
+ if (compactReason === "expired_scratch") {
68813
+ result.removedExpiredScratch++;
68814
+ removeIds.push(memory.id);
68815
+ continue;
68816
+ }
68817
+ kept.push(memory);
68818
+ }
68819
+ result.remaining = kept.length;
68820
+ if (result.dryRun)
68821
+ return result;
68822
+ const db = this.requireDb();
68823
+ const compact = db.transaction(() => {
68824
+ for (const id of removeIds) {
68825
+ db.run("DELETE FROM memory_items WHERE id = ?", [id]);
68826
+ this.deleteMemoryFts(id);
68827
+ }
68828
+ this.insertEvent("compact", "memory_items", "removed deleted, superseded, and expired scratch memories", JSON.stringify(result));
68829
+ });
68830
+ compact();
68831
+ this.memories = new Map(kept.map((memory) => [memory.id, memory]));
68832
+ return result;
68833
+ }
68394
68834
  hasMigration(name2) {
68395
68835
  const row = this.requireDb().query("SELECT version, name FROM schema_migrations WHERE name = ? LIMIT 1").get(name2);
68396
68836
  return Boolean(row);
@@ -68867,6 +69307,7 @@ var init_sqlite_provider = __esm(() => {
68867
69307
  init_curator_decision_helpers();
68868
69308
  init_errors6();
68869
69309
  init_jsonl_migration();
69310
+ init_maintenance();
68870
69311
  init_schema2();
68871
69312
  init_scoring();
68872
69313
  FTS_INDEX_COLUMNS = [
@@ -70282,6 +70723,7 @@ var init_memory = __esm(() => {
70282
70723
  init_injector();
70283
70724
  init_jsonl_migration();
70284
70725
  init_local_jsonl_provider();
70726
+ init_maintenance();
70285
70727
  init_prompt_block();
70286
70728
  init_recall_planner();
70287
70729
  init_redaction();
@@ -70300,6 +70742,10 @@ async function handleMemoryCommand(_directory, _args) {
70300
70742
  "## Swarm Memory",
70301
70743
  "",
70302
70744
  "- `/swarm memory status` - show provider, SQLite path, JSONL files, and last migration report",
70745
+ "- `/swarm memory pending` - show pending proposals and recent rejection reasons",
70746
+ "- `/swarm memory recall-log` - summarize recall usage by agent role and memory ID",
70747
+ "- `/swarm memory stale` - list expired scratch, superseded, deleted, and low-utility memories",
70748
+ "- `/swarm memory compact` - dry-run compaction; pass `--confirm` to remove deleted, superseded, and expired scratch records",
70303
70749
  "- `/swarm memory export` - export current memory and proposals to `.swarm/memory/export/*.jsonl`",
70304
70750
  "- `/swarm memory import` - import `.swarm/memory/{memories,proposals}.jsonl` into SQLite",
70305
70751
  "- `/swarm memory migrate` - run the one-time legacy JSONL to SQLite migration",
@@ -70321,6 +70767,7 @@ async function handleMemoryStatusCommand(directory, _args) {
70321
70767
  `- Storage: \`${storageDir}\``,
70322
70768
  `- SQLite path: \`${sqlitePath}\``,
70323
70769
  `- SQLite database exists: \`${existsSync25(sqlitePath)}\``,
70770
+ `- Automatic destructive cleanup: \`disabled\``,
70324
70771
  "",
70325
70772
  "### Legacy JSONL"
70326
70773
  ];
@@ -70345,6 +70792,119 @@ async function handleMemoryStatusCommand(directory, _args) {
70345
70792
  return lines.join(`
70346
70793
  `);
70347
70794
  }
70795
+ async function handleMemoryPendingCommand(directory, args2) {
70796
+ const parsed = parseMaintenanceArgs(args2, {
70797
+ usage: "Usage: /swarm memory pending [--limit <n>]",
70798
+ allowConfirm: false
70799
+ });
70800
+ if ("error" in parsed)
70801
+ return parsed.error;
70802
+ const config3 = resolveCommandMemoryConfig(directory);
70803
+ const provider = createMaintenanceProvider(directory, config3);
70804
+ try {
70805
+ await provider.initialize?.();
70806
+ const report = await buildMemoryMaintenanceReport(provider, {
70807
+ ...maintenanceReportOptions(config3, parsed.limit)
70808
+ });
70809
+ const lines = [
70810
+ "## Swarm Memory Pending",
70811
+ "",
70812
+ `- Pending proposals shown: \`${report.pendingProposals.length}\``,
70813
+ `- Rejected proposal reasons shown: \`${report.rejectedProposalReasons.length}\``
70814
+ ];
70815
+ appendProposalLines(lines, "Pending proposals", report.pendingProposals);
70816
+ appendProposalLines(lines, "Rejected proposal reasons", report.rejectedProposalReasons);
70817
+ return lines.join(`
70818
+ `);
70819
+ } finally {
70820
+ await provider.close?.();
70821
+ }
70822
+ }
70823
+ async function handleMemoryRecallLogCommand(directory, args2) {
70824
+ const parsed = parseMaintenanceArgs(args2, {
70825
+ usage: "Usage: /swarm memory recall-log [--limit <n>]",
70826
+ allowConfirm: false
70827
+ });
70828
+ if ("error" in parsed)
70829
+ return parsed.error;
70830
+ const config3 = resolveCommandMemoryConfig(directory);
70831
+ const provider = createMaintenanceProvider(directory, config3);
70832
+ try {
70833
+ await provider.initialize?.();
70834
+ const report = await buildMemoryMaintenanceReport(provider, {
70835
+ ...maintenanceReportOptions(config3, parsed.limit)
70836
+ });
70837
+ const lines = [
70838
+ "## Swarm Memory Recall Log",
70839
+ "",
70840
+ `- Recall events scanned: \`${report.recallEventCount}\``,
70841
+ `- Most-recalled memories shown: \`${report.mostRecalledMemories.length}\``,
70842
+ `- Never-recalled memories shown: \`${report.neverRecalledMemories.length}\``
70843
+ ];
70844
+ appendRecallRoleLines(lines, report.recallByAgentRole);
70845
+ appendRecallMemoryLines(lines, report.mostRecalledMemories);
70846
+ appendMemoryLines(lines, "Never-recalled memories", report.neverRecalledMemories);
70847
+ return lines.join(`
70848
+ `);
70849
+ } finally {
70850
+ await provider.close?.();
70851
+ }
70852
+ }
70853
+ async function handleMemoryStaleCommand(directory, args2) {
70854
+ const parsed = parseMaintenanceArgs(args2, {
70855
+ usage: "Usage: /swarm memory stale [--limit <n>]",
70856
+ allowConfirm: false
70857
+ });
70858
+ if ("error" in parsed)
70859
+ return parsed.error;
70860
+ const config3 = resolveCommandMemoryConfig(directory);
70861
+ const provider = createMaintenanceProvider(directory, config3);
70862
+ try {
70863
+ await provider.initialize?.();
70864
+ const report = await buildMemoryMaintenanceReport(provider, {
70865
+ ...maintenanceReportOptions(config3, parsed.limit)
70866
+ });
70867
+ const lines = [
70868
+ "## Swarm Memory Stale",
70869
+ "",
70870
+ `- Active memories: \`${report.activeMemories}\``,
70871
+ `- Expired scratch memories shown: \`${report.expiredScratchMemories.length}\``,
70872
+ `- Deleted tombstones shown: \`${report.deletedMemories.length}\``,
70873
+ `- Superseded memories shown: \`${report.supersededMemories.length}\``,
70874
+ `- Low-utility memories shown: \`${report.lowUtilityMemories.length}\``
70875
+ ];
70876
+ appendMemoryLines(lines, "Expired scratch memories", report.expiredScratchMemories);
70877
+ appendMemoryLines(lines, "Deleted tombstones", report.deletedMemories);
70878
+ appendSupersededChains(lines, report);
70879
+ appendMemoryLines(lines, "Low-utility memories", report.lowUtilityMemories);
70880
+ return lines.join(`
70881
+ `);
70882
+ } finally {
70883
+ await provider.close?.();
70884
+ }
70885
+ }
70886
+ async function handleMemoryCompactCommand(directory, args2) {
70887
+ const parsed = parseMaintenanceArgs(args2, {
70888
+ usage: "Usage: /swarm memory compact [--confirm]",
70889
+ allowConfirm: true,
70890
+ allowLimit: false
70891
+ });
70892
+ if ("error" in parsed)
70893
+ return parsed.error;
70894
+ const provider = createMaintenanceProvider(directory, resolveCommandMemoryConfig(directory));
70895
+ try {
70896
+ await provider.initialize?.();
70897
+ if (!provider.compactMaintenance) {
70898
+ return "Memory provider does not support compaction.";
70899
+ }
70900
+ const result = await provider.compactMaintenance({
70901
+ dryRun: !parsed.confirm
70902
+ });
70903
+ return formatCompactResult(result, parsed.confirm);
70904
+ } finally {
70905
+ await provider.close?.();
70906
+ }
70907
+ }
70348
70908
  async function handleMemoryMigrateCommand(directory, _args) {
70349
70909
  const config3 = {
70350
70910
  ...resolveCommandMemoryConfig(directory),
@@ -70401,6 +70961,16 @@ async function handleMemoryExportCommand(directory, _args) {
70401
70961
  await provider.close?.();
70402
70962
  }
70403
70963
  }
70964
+ function createMaintenanceProvider(directory, config3) {
70965
+ return createConfiguredMemoryProvider(directory, config3);
70966
+ }
70967
+ function maintenanceReportOptions(config3, limit) {
70968
+ return {
70969
+ limit,
70970
+ lowUtilityMaxConfidence: config3.maintenance.lowUtilityMaxConfidence,
70971
+ lowUtilityMinAgeDays: config3.maintenance.lowUtilityMinAgeDays
70972
+ };
70973
+ }
70404
70974
  async function handleMemoryEvaluateCommand(directory, args2) {
70405
70975
  const parsed = parseEvaluateArgs(directory, args2);
70406
70976
  if ("error" in parsed)
@@ -70459,6 +71029,28 @@ function parseEvaluateArgs(directory, args2) {
70459
71029
  }
70460
71030
  return { json: json3, fixtureDirectory };
70461
71031
  }
71032
+ function parseMaintenanceArgs(args2, options) {
71033
+ let limit = 20;
71034
+ let confirm = false;
71035
+ const allowLimit = options.allowLimit ?? true;
71036
+ for (let i2 = 0;i2 < args2.length; i2++) {
71037
+ const arg = args2[i2];
71038
+ if (arg === "--confirm" && options.allowConfirm) {
71039
+ confirm = true;
71040
+ continue;
71041
+ }
71042
+ if (arg === "--limit" && allowLimit) {
71043
+ const next = args2[i2 + 1];
71044
+ if (!next || !/^\d+$/.test(next))
71045
+ return { error: options.usage };
71046
+ limit = Math.min(100, Math.max(1, Number(next)));
71047
+ i2++;
71048
+ continue;
71049
+ }
71050
+ return { error: options.usage };
71051
+ }
71052
+ return { limit, confirm };
71053
+ }
70462
71054
  function resolvePackageRootFromModule(modulePath) {
70463
71055
  const moduleDir = path45.dirname(modulePath);
70464
71056
  const leaf = path45.basename(moduleDir);
@@ -70509,6 +71101,80 @@ function appendInvalidRows(lines, invalidRows) {
70509
71101
  lines.push(`- ... ${invalidRows.length - 20} more`);
70510
71102
  }
70511
71103
  }
71104
+ function appendProposalLines(lines, title, proposals) {
71105
+ lines.push("", `### ${title}`);
71106
+ if (proposals.length === 0) {
71107
+ lines.push("- none");
71108
+ return;
71109
+ }
71110
+ for (const proposal of proposals) {
71111
+ const reason = proposal.status === "rejected" ? ` - ${proposal.rejectionReason ?? "no reason recorded"}` : "";
71112
+ lines.push(`- \`${proposal.id}\` ${proposal.operation} ${proposal.targetMemoryId ?? proposal.proposedRecord?.id ?? "new"} (${proposal.status})${reason}`);
71113
+ }
71114
+ }
71115
+ function appendMemoryLines(lines, title, memories) {
71116
+ lines.push("", `### ${title}`);
71117
+ if (memories.length === 0) {
71118
+ lines.push("- none");
71119
+ return;
71120
+ }
71121
+ for (const memory of memories) {
71122
+ lines.push(`- \`${memory.id}\` ${memory.kind} confidence=${memory.confidence.toFixed(2)} updated=${memory.updatedAt} - ${truncate(memory.text, 100)}`);
71123
+ }
71124
+ }
71125
+ function appendRecallRoleLines(lines, roles) {
71126
+ lines.push("", "### Recall by agent role");
71127
+ if (roles.length === 0) {
71128
+ lines.push("- none");
71129
+ return;
71130
+ }
71131
+ for (const role of roles) {
71132
+ const memoryCount = Object.keys(role.memoryIds).length;
71133
+ lines.push(`- \`${role.agentRole}\`: ${role.count} recall event(s), ${memoryCount} memory ID(s)`);
71134
+ }
71135
+ }
71136
+ function appendRecallMemoryLines(lines, memories) {
71137
+ lines.push("", "### Most-recalled memories");
71138
+ if (memories.length === 0) {
71139
+ lines.push("- none");
71140
+ return;
71141
+ }
71142
+ for (const memory of memories) {
71143
+ lines.push(`- \`${memory.memoryId}\`: ${memory.count} hit(s), last=${memory.lastRecalledAt}, avgScore=${memory.averageScore.toFixed(3)}`);
71144
+ }
71145
+ }
71146
+ function appendSupersededChains(lines, report) {
71147
+ lines.push("", "### Superseded chains");
71148
+ if (report.supersededChains.length === 0) {
71149
+ lines.push("- none");
71150
+ return;
71151
+ }
71152
+ for (const chain of report.supersededChains) {
71153
+ const reason = chain.reason ? ` - ${chain.reason}` : "";
71154
+ lines.push(`- ${chain.chain.map((id) => `\`${id}\``).join(" -> ")}${reason}`);
71155
+ }
71156
+ }
71157
+ function formatCompactResult(result, confirmed) {
71158
+ const lines = [
71159
+ "## Swarm Memory Compact",
71160
+ "",
71161
+ `- Mode: \`${confirmed ? "confirmed" : "dry-run"}\``,
71162
+ `- Deleted tombstones: \`${result.removedDeleted}\``,
71163
+ `- Superseded records: \`${result.removedSuperseded}\``,
71164
+ `- Expired scratch records: \`${result.removedExpiredScratch}\``,
71165
+ `- Remaining memories: \`${result.remaining}\``
71166
+ ];
71167
+ if (!confirmed) {
71168
+ lines.push("", "No records were removed. Re-run `/swarm memory compact --confirm` to apply this compaction.");
71169
+ }
71170
+ return lines.join(`
71171
+ `);
71172
+ }
71173
+ function truncate(value, maxLength) {
71174
+ if (value.length <= maxLength)
71175
+ return value;
71176
+ return `${value.slice(0, maxLength - 3)}...`;
71177
+ }
70512
71178
  var PACKAGE_ROOT;
70513
71179
  var init_memory2 = __esm(() => {
70514
71180
  init_loader();
@@ -78502,7 +79168,7 @@ async function handleTurboCommand(directory, args2, sessionID) {
78502
79168
  const arg0 = args2[0]?.toLowerCase();
78503
79169
  const arg1 = args2[1]?.toLowerCase();
78504
79170
  if (arg0 === "status") {
78505
- return buildStatusMessage(session, directory, sessionID);
79171
+ return buildStatusMessage2(session, directory, sessionID);
78506
79172
  }
78507
79173
  const isTurboOn = session.turboMode;
78508
79174
  const isLeanActive = session.leanTurboActive === true;
@@ -78633,7 +79299,7 @@ function enableLeanTurbo(session, directory, sessionID) {
78633
79299
  `Full-Auto: ${fullAutoActive ? "active" : "inactive"})`
78634
79300
  ].join(" ");
78635
79301
  }
78636
- function buildStatusMessage(session, directory, sessionID) {
79302
+ function buildStatusMessage2(session, directory, sessionID) {
78637
79303
  if (!session.turboMode) {
78638
79304
  return "Turbo: off";
78639
79305
  }
@@ -78893,7 +79559,7 @@ function classifySwarmCommandToolUse(resolved) {
78893
79559
  return { allowed: true };
78894
79560
  return {
78895
79561
  allowed: false,
78896
- message: "Use `/swarm memory status`, `/swarm memory export`, or `/swarm memory evaluate --json` through swarm_command. Memory import and migrate are intentionally excluded from chat-tool execution."
79562
+ message: "Use `/swarm memory status`, `/swarm memory pending`, `/swarm memory recall-log`, `/swarm memory stale`, `/swarm memory export`, or `/swarm memory evaluate --json` through swarm_command. Memory import, migrate, and compact are intentionally excluded from chat-tool execution."
78897
79563
  };
78898
79564
  }
78899
79565
  if (canonicalKey === "memory evaluate") {
@@ -78906,6 +79572,17 @@ function classifySwarmCommandToolUse(resolved) {
78906
79572
  message: "Usage through swarm_command: `/swarm memory evaluate --json`. Custom fixture directories are only available through direct user command execution."
78907
79573
  };
78908
79574
  }
79575
+ if (canonicalKey === "memory pending" || canonicalKey === "memory recall-log" || canonicalKey === "memory stale") {
79576
+ if (args2.length === 0)
79577
+ return { allowed: true };
79578
+ if (args2.length === 2 && args2[0] === "--limit" && /^\d+$/.test(args2[1])) {
79579
+ return { allowed: true };
79580
+ }
79581
+ return {
79582
+ allowed: false,
79583
+ message: `Usage through swarm_command: \`/swarm ${canonicalKey}\` or ` + `\`/swarm ${canonicalKey} --limit <n>\`.`
79584
+ };
79585
+ }
78909
79586
  if (canonicalKey === "retrieve") {
78910
79587
  if (args2.length !== 1 || !SUMMARY_ID_PATTERN.test(args2[0])) {
78911
79588
  return {
@@ -78957,7 +79634,7 @@ function classifySwarmCommandChatFallbackUse(resolved) {
78957
79634
  message: "/swarm config doctor --fix is not available through chat fallback because it can modify configuration files. Run the CLI command directly when you intend to apply fixes."
78958
79635
  };
78959
79636
  }
78960
- if (canonicalKey === "knowledge migrate" || canonicalKey === "knowledge quarantine" || canonicalKey === "knowledge restore" || canonicalKey === "memory import" || canonicalKey === "memory migrate") {
79637
+ if (canonicalKey === "knowledge migrate" || canonicalKey === "knowledge quarantine" || canonicalKey === "knowledge restore" || canonicalKey === "memory import" || canonicalKey === "memory migrate" || canonicalKey === "memory compact") {
78961
79638
  return {
78962
79639
  allowed: false,
78963
79640
  message: `/swarm ${canonicalKey} is not available through chat fallback because it mutates .swarm state. ` + "Run the CLI command directly after confirming the intended state change."
@@ -78990,6 +79667,10 @@ var init_tool_policy = __esm(() => {
78990
79667
  "knowledge",
78991
79668
  "memory",
78992
79669
  "memory status",
79670
+ "memory pending",
79671
+ "memory recall-log",
79672
+ "memory compact",
79673
+ "memory stale",
78993
79674
  "memory export",
78994
79675
  "memory evaluate",
78995
79676
  "memory import",
@@ -79016,6 +79697,9 @@ var init_tool_policy = __esm(() => {
79016
79697
  "knowledge",
79017
79698
  "memory",
79018
79699
  "memory status",
79700
+ "memory pending",
79701
+ "memory recall-log",
79702
+ "memory stale",
79019
79703
  "memory export",
79020
79704
  "memory evaluate",
79021
79705
  "sync-plan",
@@ -79028,7 +79712,8 @@ var init_tool_policy = __esm(() => {
79028
79712
  "rollback",
79029
79713
  "checkpoint",
79030
79714
  "memory import",
79031
- "memory migrate"
79715
+ "memory migrate",
79716
+ "memory compact"
79032
79717
  ]);
79033
79718
  NO_ARGS = new Set([
79034
79719
  "agents",
@@ -79081,7 +79766,6 @@ __export(exports_commands, {
79081
79766
  handleMemoryMigrateCommand: () => handleMemoryMigrateCommand,
79082
79767
  handleMemoryImportCommand: () => handleMemoryImportCommand,
79083
79768
  handleMemoryExportCommand: () => handleMemoryExportCommand,
79084
- handleMemoryEvaluateCommand: () => handleMemoryEvaluateCommand,
79085
79769
  handleMemoryCommand: () => handleMemoryCommand,
79086
79770
  handleKnowledgeRestoreCommand: () => handleKnowledgeRestoreCommand,
79087
79771
  handleKnowledgeQuarantineCommand: () => handleKnowledgeQuarantineCommand,
@@ -79101,6 +79785,7 @@ __export(exports_commands, {
79101
79785
  handleCurateCommand: () => handleCurateCommand,
79102
79786
  handleCouncilCommand: () => handleCouncilCommand,
79103
79787
  handleConfigCommand: () => handleConfigCommand,
79788
+ handleConcurrencyCommand: () => handleConcurrencyCommand,
79104
79789
  handleCloseCommand: () => handleCloseCommand,
79105
79790
  handleClarifyCommand: () => handleClarifyCommand,
79106
79791
  handleCheckpointCommand: () => handleCheckpointCommand,
@@ -79347,6 +80032,7 @@ var init_commands = __esm(() => {
79347
80032
  init_close();
79348
80033
  init_command_dispatch();
79349
80034
  init_command_names();
80035
+ init_concurrency();
79350
80036
  init_config2();
79351
80037
  init_council();
79352
80038
  init_curate();
@@ -79567,6 +80253,7 @@ var init_registry = __esm(() => {
79567
80253
  init_benchmark();
79568
80254
  init_checkpoint2();
79569
80255
  init_close();
80256
+ init_concurrency();
79570
80257
  init_config2();
79571
80258
  init_council();
79572
80259
  init_curate();
@@ -79811,6 +80498,23 @@ var init_registry = __esm(() => {
79811
80498
  aliasOf: "finalize",
79812
80499
  deprecated: true
79813
80500
  },
80501
+ concurrency: {
80502
+ handler: (ctx) => handleConcurrencyCommand(ctx.directory, ctx.args, ctx.sessionID),
80503
+ description: "Manage runtime concurrency override for plan execution [set|status|reset]",
80504
+ args: "set <N|preset>, status, reset",
80505
+ details: `Sets, queries, or clears a session-scoped concurrency override for max_concurrent_tasks during plan execution.
80506
+ When set, the override takes precedence over the plan's locked execution_profile.max_concurrent_tasks.
80507
+ ` + `The override is session-scoped — it does not modify the plan and is cleared on session reset.
80508
+ ` + `
80509
+ Subcommands:
80510
+ ` + ` concurrency set <N> — Set session concurrency to N (1-64)
80511
+ ` + ` concurrency set <preset> — Set to preset: min (1), medium (3), max (8)
80512
+ ` + ` concurrency status — Show effective concurrency (override, plan baseline, operational effective)
80513
+ ` + ` concurrency reset — Clear the session concurrency override
80514
+ ` + `
80515
+ ` + "Session-scoped — resets on new session.",
80516
+ category: "utility"
80517
+ },
79814
80518
  simulate: {
79815
80519
  handler: (ctx) => handleSimulateCommand(ctx.directory, ctx.args),
79816
80520
  description: "Dry-run hidden coupling analysis with configurable thresholds",
@@ -80004,6 +80708,34 @@ Subcommands:
80004
80708
  args: "",
80005
80709
  category: "diagnostics"
80006
80710
  },
80711
+ "memory pending": {
80712
+ handler: (ctx) => handleMemoryPendingCommand(ctx.directory, ctx.args),
80713
+ description: "Show pending Swarm memory proposals and rejection reasons",
80714
+ subcommandOf: "memory",
80715
+ args: "--limit <n>",
80716
+ category: "diagnostics"
80717
+ },
80718
+ "memory recall-log": {
80719
+ handler: (ctx) => handleMemoryRecallLogCommand(ctx.directory, ctx.args),
80720
+ description: "Summarize Swarm memory recall usage",
80721
+ subcommandOf: "memory",
80722
+ args: "--limit <n>",
80723
+ category: "diagnostics"
80724
+ },
80725
+ "memory compact": {
80726
+ handler: (ctx) => handleMemoryCompactCommand(ctx.directory, ctx.args),
80727
+ description: "Compact deleted, superseded, and expired scratch memories",
80728
+ subcommandOf: "memory",
80729
+ args: "--confirm",
80730
+ category: "utility"
80731
+ },
80732
+ "memory stale": {
80733
+ handler: (ctx) => handleMemoryStaleCommand(ctx.directory, ctx.args),
80734
+ description: "List stale and low-utility Swarm memories",
80735
+ subcommandOf: "memory",
80736
+ args: "--limit <n>",
80737
+ category: "diagnostics"
80738
+ },
80007
80739
  "memory export": {
80008
80740
  handler: (ctx) => handleMemoryExportCommand(ctx.directory, ctx.args),
80009
80741
  description: "Export current Swarm memory to JSONL files",
@@ -103304,6 +104036,7 @@ function deserializeAgentSession(s) {
103304
104036
  fullAutoInteractionCount: s.fullAutoInteractionCount ?? 0,
103305
104037
  fullAutoDeadlockCount: s.fullAutoDeadlockCount ?? 0,
103306
104038
  fullAutoLastQuestionHash: s.fullAutoLastQuestionHash ?? null,
104039
+ maxConcurrencyOverride: typeof s.maxConcurrencyOverride === "number" ? Math.min(64, Math.max(1, s.maxConcurrencyOverride)) : undefined,
103307
104040
  prmPatternCounts: new Map,
103308
104041
  prmEscalationLevel: 0,
103309
104042
  prmLastPatternDetected: null,
@@ -124027,7 +124760,7 @@ async function initializeOpenCodeSwarm(ctx) {
124027
124760
  ...opencodeConfig.command || {},
124028
124761
  swarm: {
124029
124762
  template: "/swarm $ARGUMENTS",
124030
- description: "Swarm management commands: /swarm [status|show-plan|plan|agents|history|config|help|evidence|handoff|archive|diagnose|diagnosis|preflight|sync-plan|benchmark|export|reset|rollback|retrieve|clarify|analyze|specify|brainstorm|council|pr-review|issue|qa-gates|dark-matter|knowledge|memory|curate|turbo|full-auto|write-retro|reset-session|simulate|promote|checkpoint|acknowledge-spec-drift|doctor tools|finalize|close]"
124763
+ description: "Swarm management commands: /swarm [status|show-plan|plan|agents|history|config|help|evidence|handoff|archive|diagnose|diagnosis|preflight|sync-plan|benchmark|export|reset|rollback|retrieve|clarify|analyze|specify|brainstorm|council|pr-review|issue|qa-gates|dark-matter|knowledge|memory|curate|concurrency|turbo|full-auto|write-retro|reset-session|simulate|promote|checkpoint|acknowledge-spec-drift|doctor tools|finalize|close]"
124031
124764
  },
124032
124765
  "swarm-status": {
124033
124766
  template: "/swarm status",
@@ -124157,10 +124890,6 @@ async function initializeOpenCodeSwarm(ctx) {
124157
124890
  template: "/swarm memory export",
124158
124891
  description: "Use /swarm memory export to write current memory to JSONL"
124159
124892
  },
124160
- "swarm-memory-evaluate": {
124161
- template: "/swarm memory evaluate --json",
124162
- description: "Use /swarm memory evaluate --json to generate the recall evaluation report"
124163
- },
124164
124893
  "swarm-memory-import": {
124165
124894
  template: "/swarm memory import",
124166
124895
  description: "Use /swarm memory import to import legacy JSONL into SQLite"
@@ -124173,6 +124902,10 @@ async function initializeOpenCodeSwarm(ctx) {
124173
124902
  template: "/swarm curate",
124174
124903
  description: "Use /swarm curate to curate knowledge artifacts and entries"
124175
124904
  },
124905
+ "swarm-concurrency": {
124906
+ template: "/swarm concurrency $ARGUMENTS",
124907
+ description: "Use /swarm concurrency to manage runtime concurrency override for plan execution"
124908
+ },
124176
124909
  "swarm-turbo": {
124177
124910
  template: "/swarm turbo",
124178
124911
  description: "Use /swarm turbo to enable turbo mode for faster execution"