opencode-swarm 7.51.5 → 7.52.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/cli/index.js +12 -3
- package/dist/config/schema.d.ts +24 -1
- package/dist/context-map/capsule-builder.d.ts +128 -0
- package/dist/context-map/capsule-persistence.d.ts +66 -0
- package/dist/context-map/file-summary.d.ts +100 -0
- package/dist/context-map/persistence.d.ts +79 -0
- package/dist/context-map/post-agent-update.d.ts +116 -0
- package/dist/context-map/telemetry.d.ts +119 -0
- package/dist/council/types.d.ts +2 -0
- package/dist/hooks/context-capsule-inject.d.ts +78 -0
- package/dist/hooks/index.d.ts +1 -0
- package/dist/index.js +2379 -1327
- package/dist/state.d.ts +6 -0
- package/dist/summaries/schema.d.ts +2 -2
- package/dist/tools/convene-council.d.ts +2 -1
- package/dist/tools/submit-phase-council-verdicts.d.ts +2 -1
- package/dist/tools/write-final-council-evidence.d.ts +1 -1
- package/dist/types/context-capsule.d.ts +115 -0
- package/dist/types/context-map.d.ts +124 -0
- package/package.json +3 -2
package/dist/cli/index.js
CHANGED
|
@@ -52,7 +52,7 @@ var package_default;
|
|
|
52
52
|
var init_package = __esm(() => {
|
|
53
53
|
package_default = {
|
|
54
54
|
name: "opencode-swarm",
|
|
55
|
-
version: "7.
|
|
55
|
+
version: "7.52.0",
|
|
56
56
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
57
57
|
main: "dist/index.js",
|
|
58
58
|
types: "dist/index.d.ts",
|
|
@@ -100,7 +100,8 @@ var init_package = __esm(() => {
|
|
|
100
100
|
dev: "bun run build && opencode",
|
|
101
101
|
"package:smoke": "node scripts/package-smoke.mjs",
|
|
102
102
|
prepare: "bun run build",
|
|
103
|
-
"repro:704": "node scripts/repro-704.mjs"
|
|
103
|
+
"repro:704": "node scripts/repro-704.mjs",
|
|
104
|
+
"repro:1144": "bun scripts/repro-1144.mjs"
|
|
104
105
|
},
|
|
105
106
|
dependencies: {
|
|
106
107
|
"@opencode-ai/plugin": "^1.1.53",
|
|
@@ -17274,7 +17275,7 @@ function getCanonicalAgentRole(agentName, generatedAgentNames) {
|
|
|
17274
17275
|
function stripKnownSwarmPrefix(agentName) {
|
|
17275
17276
|
return getCanonicalAgentRole(agentName);
|
|
17276
17277
|
}
|
|
17277
|
-
var SEPARATORS, CANONICAL_ROLES_LONGEST_FIRST, CANONICAL_ROLES_SET, AgentOverrideConfigSchema, SwarmConfigSchema, HooksConfigSchema, ScoringWeightsSchema, DecisionDecaySchema, TokenRatiosSchema, ScoringConfigSchema, ContextBudgetConfigSchema, EvidenceConfigSchema, GateFeatureSchema, PlaceholderScanConfigSchema, QualityBudgetConfigSchema, GateConfigSchema, PipelineConfigSchema, PhaseCompleteConfigSchema, SummaryConfigSchema, ReviewPassesConfigSchema, AdversarialDetectionConfigSchema, AdversarialTestingConfigSchemaBase, AdversarialTestingConfigSchema, IntegrationAnalysisConfigSchema, DocsConfigSchema, DesignDocsConfigSchema, UIReviewConfigSchema, CompactionAdvisoryConfigSchema, LintConfigSchema, SecretscanConfigSchema, GuardrailsProfileSchema, DEFAULT_AGENT_PROFILES, DEFAULT_ARCHITECT_PROFILE, GuardrailsConfigSchema, WatchdogConfigSchema, SelfReviewConfigSchema, ToolFilterConfigSchema, PlanCursorConfigSchema, CheckpointConfigSchema, AutomationModeSchema, AutomationCapabilitiesSchema, AutomationConfigSchemaBase, AutomationConfigSchema, KnowledgeConfigSchema, MemoryConfigSchema, CuratorConfigSchema, ArchitecturalSupervisionConfigSchema, KnowledgeApplicationConfigSchema, SkillImproverConfigSchema, SpecWriterConfigSchema, SlopDetectorConfigSchema, IncrementalVerifyConfigSchema, CompactionConfigSchema, PrmConfigSchema, AgentAuthorityRuleSchema, AuthorityConfigSchema, GeneralCouncilMemberConfigSchema, GeneralCouncilConfigSchema, CouncilConfigSchema, ParallelizationConfigSchema, LeanTurboConfigSchema, StandardTurboConfigSchema, LeanTurboStrategyConfigSchema, TurboConfigSchema, PluginConfigSchema;
|
|
17278
|
+
var SEPARATORS, CANONICAL_ROLES_LONGEST_FIRST, CANONICAL_ROLES_SET, AgentOverrideConfigSchema, SwarmConfigSchema, HooksConfigSchema, ScoringWeightsSchema, DecisionDecaySchema, TokenRatiosSchema, ScoringConfigSchema, ContextBudgetConfigSchema, EvidenceConfigSchema, GateFeatureSchema, PlaceholderScanConfigSchema, QualityBudgetConfigSchema, GateConfigSchema, PipelineConfigSchema, PhaseCompleteConfigSchema, SummaryConfigSchema, ReviewPassesConfigSchema, AdversarialDetectionConfigSchema, AdversarialTestingConfigSchemaBase, AdversarialTestingConfigSchema, IntegrationAnalysisConfigSchema, DocsConfigSchema, DesignDocsConfigSchema, UIReviewConfigSchema, CompactionAdvisoryConfigSchema, LintConfigSchema, SecretscanConfigSchema, GuardrailsProfileSchema, DEFAULT_AGENT_PROFILES, DEFAULT_ARCHITECT_PROFILE, GuardrailsConfigSchema, WatchdogConfigSchema, SelfReviewConfigSchema, ToolFilterConfigSchema, PlanCursorConfigSchema, ContextMapConfigSchema, CheckpointConfigSchema, AutomationModeSchema, AutomationCapabilitiesSchema, AutomationConfigSchemaBase, AutomationConfigSchema, KnowledgeConfigSchema, MemoryConfigSchema, CuratorConfigSchema, ArchitecturalSupervisionConfigSchema, KnowledgeApplicationConfigSchema, SkillImproverConfigSchema, SpecWriterConfigSchema, SlopDetectorConfigSchema, IncrementalVerifyConfigSchema, CompactionConfigSchema, PrmConfigSchema, AgentAuthorityRuleSchema, AuthorityConfigSchema, GeneralCouncilMemberConfigSchema, GeneralCouncilConfigSchema, CouncilConfigSchema, ParallelizationConfigSchema, LeanTurboConfigSchema, StandardTurboConfigSchema, LeanTurboStrategyConfigSchema, TurboConfigSchema, PluginConfigSchema;
|
|
17278
17279
|
var init_schema = __esm(() => {
|
|
17279
17280
|
init_zod();
|
|
17280
17281
|
init_constants();
|
|
@@ -17677,6 +17678,13 @@ var init_schema = __esm(() => {
|
|
|
17677
17678
|
max_tokens: exports_external.number().min(500).max(4000).default(1500),
|
|
17678
17679
|
lookahead_tasks: exports_external.number().min(0).max(5).default(2)
|
|
17679
17680
|
});
|
|
17681
|
+
ContextMapConfigSchema = exports_external.object({
|
|
17682
|
+
enabled: exports_external.boolean().default(false),
|
|
17683
|
+
mode: exports_external.enum(["conservative", "balanced", "aggressive"]).default("balanced"),
|
|
17684
|
+
max_capsule_tokens: exports_external.number().int().positive().default(2000),
|
|
17685
|
+
invalidate_on_hash_change: exports_external.boolean().default(true),
|
|
17686
|
+
agent_profiles: exports_external.record(exports_external.string(), exports_external.string()).default({})
|
|
17687
|
+
});
|
|
17680
17688
|
CheckpointConfigSchema = exports_external.object({
|
|
17681
17689
|
enabled: exports_external.boolean().default(true),
|
|
17682
17690
|
auto_checkpoint_threshold: exports_external.number().int().min(1).max(20).default(3),
|
|
@@ -17995,6 +18003,7 @@ var init_schema = __esm(() => {
|
|
|
17995
18003
|
tool_filter: ToolFilterConfigSchema.optional(),
|
|
17996
18004
|
authority: AuthorityConfigSchema.optional(),
|
|
17997
18005
|
plan_cursor: PlanCursorConfigSchema.optional(),
|
|
18006
|
+
context_map: ContextMapConfigSchema.optional(),
|
|
17998
18007
|
evidence: EvidenceConfigSchema.optional(),
|
|
17999
18008
|
summaries: SummaryConfigSchema.optional(),
|
|
18000
18009
|
review_passes: ReviewPassesConfigSchema.optional(),
|
package/dist/config/schema.d.ts
CHANGED
|
@@ -439,6 +439,18 @@ export declare const PlanCursorConfigSchema: z.ZodObject<{
|
|
|
439
439
|
lookahead_tasks: z.ZodDefault<z.ZodNumber>;
|
|
440
440
|
}, z.core.$strip>;
|
|
441
441
|
export type PlanCursorConfig = z.infer<typeof PlanCursorConfigSchema>;
|
|
442
|
+
export declare const ContextMapConfigSchema: z.ZodObject<{
|
|
443
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
444
|
+
mode: z.ZodDefault<z.ZodEnum<{
|
|
445
|
+
conservative: "conservative";
|
|
446
|
+
balanced: "balanced";
|
|
447
|
+
aggressive: "aggressive";
|
|
448
|
+
}>>;
|
|
449
|
+
max_capsule_tokens: z.ZodDefault<z.ZodNumber>;
|
|
450
|
+
invalidate_on_hash_change: z.ZodDefault<z.ZodBoolean>;
|
|
451
|
+
agent_profiles: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
452
|
+
}, z.core.$strip>;
|
|
453
|
+
export type ContextMapConfig = z.infer<typeof ContextMapConfigSchema>;
|
|
442
454
|
export declare const CheckpointConfigSchema: z.ZodObject<{
|
|
443
455
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
444
456
|
auto_checkpoint_threshold: z.ZodDefault<z.ZodNumber>;
|
|
@@ -928,8 +940,8 @@ export declare const PluginConfigSchema: z.ZodObject<{
|
|
|
928
940
|
}, z.core.$strip>>;
|
|
929
941
|
qa_retry_limit: z.ZodDefault<z.ZodNumber>;
|
|
930
942
|
execution_mode: z.ZodDefault<z.ZodEnum<{
|
|
931
|
-
strict: "strict";
|
|
932
943
|
balanced: "balanced";
|
|
944
|
+
strict: "strict";
|
|
933
945
|
fast: "fast";
|
|
934
946
|
}>>;
|
|
935
947
|
inject_phase_reminders: z.ZodDefault<z.ZodBoolean>;
|
|
@@ -1081,6 +1093,17 @@ export declare const PluginConfigSchema: z.ZodObject<{
|
|
|
1081
1093
|
max_tokens: z.ZodDefault<z.ZodNumber>;
|
|
1082
1094
|
lookahead_tasks: z.ZodDefault<z.ZodNumber>;
|
|
1083
1095
|
}, z.core.$strip>>;
|
|
1096
|
+
context_map: z.ZodOptional<z.ZodObject<{
|
|
1097
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
1098
|
+
mode: z.ZodDefault<z.ZodEnum<{
|
|
1099
|
+
conservative: "conservative";
|
|
1100
|
+
balanced: "balanced";
|
|
1101
|
+
aggressive: "aggressive";
|
|
1102
|
+
}>>;
|
|
1103
|
+
max_capsule_tokens: z.ZodDefault<z.ZodNumber>;
|
|
1104
|
+
invalidate_on_hash_change: z.ZodDefault<z.ZodBoolean>;
|
|
1105
|
+
agent_profiles: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
1106
|
+
}, z.core.$strip>>;
|
|
1084
1107
|
evidence: z.ZodOptional<z.ZodObject<{
|
|
1085
1108
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
1086
1109
|
max_age_days: z.ZodDefault<z.ZodNumber>;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context Capsule Builder
|
|
3
|
+
*
|
|
4
|
+
* Constructs role-specific Context Capsules that are injected into delegated
|
|
5
|
+
* agent system messages. Uses the Context Map to populate file summaries,
|
|
6
|
+
* builds a per-file read policy based on staleness, and formats the capsule
|
|
7
|
+
* as a structured markdown document.
|
|
8
|
+
*
|
|
9
|
+
* Each agent role (coder, reviewer, critic, test_engineer, sme) has a
|
|
10
|
+
* dedicated profile that controls which sections are included and how many
|
|
11
|
+
* files appear in the capsule.
|
|
12
|
+
*
|
|
13
|
+
* Uses the `_internals` DI seam pattern so tests can override filesystem
|
|
14
|
+
* and analysis dependencies without `mock.module` (which leaks across
|
|
15
|
+
* files in Bun's shared test-runner process).
|
|
16
|
+
*
|
|
17
|
+
* All functions accept an explicit `directory` parameter (Invariant 4).
|
|
18
|
+
* No `process.cwd()` usage. Never throws — returns best-effort capsules.
|
|
19
|
+
* No `bun:` imports — Node-ESM-loadable (Invariant 2).
|
|
20
|
+
*/
|
|
21
|
+
import * as fs from 'node:fs';
|
|
22
|
+
import type { AgentRole, CapsuleDelegationReason, CapsuleMetadata, ContextCapsule, ReadPolicyEntry, RoleProfile } from '../types/context-capsule';
|
|
23
|
+
import type { ContextMap } from '../types/context-map';
|
|
24
|
+
import { extractFileSummary, isFileStale } from './file-summary';
|
|
25
|
+
import { computeContentHash, createEmptyContextMap, loadContextMap } from './persistence';
|
|
26
|
+
/**
|
|
27
|
+
* Reuse shared token estimator with capsule-specific floor of 1.
|
|
28
|
+
* The base estimator returns 0 for empty strings; capsules need at least 1
|
|
29
|
+
* token to avoid degenerate budget calculations.
|
|
30
|
+
*/
|
|
31
|
+
export declare function estimateTokens(content: string): number;
|
|
32
|
+
/**
|
|
33
|
+
* Test-only dependency-injection seam. Production code calls through this
|
|
34
|
+
* object so tests can replace the underlying implementations without
|
|
35
|
+
* `mock.module` (which leaks across files in Bun's shared test-runner process).
|
|
36
|
+
* Mutating this local object is file-scoped and trivially restorable
|
|
37
|
+
* via `afterEach`.
|
|
38
|
+
*/
|
|
39
|
+
export declare const _internals: {
|
|
40
|
+
readonly loadContextMap: typeof loadContextMap;
|
|
41
|
+
readonly createEmptyContextMap: typeof createEmptyContextMap;
|
|
42
|
+
readonly computeContentHash: typeof computeContentHash;
|
|
43
|
+
readonly isFileStale: typeof isFileStale;
|
|
44
|
+
readonly extractFileSummary: typeof extractFileSummary;
|
|
45
|
+
readonly estimateTokens: typeof estimateTokens;
|
|
46
|
+
readonly readFileSync: typeof fs.readFileSync;
|
|
47
|
+
readonly existsSync: typeof fs.existsSync;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Parameters for building a context capsule.
|
|
51
|
+
* Defined inline — not part of the public API surface.
|
|
52
|
+
*/
|
|
53
|
+
interface BuildCapsuleParams {
|
|
54
|
+
/** Task ID this capsule is for (e.g. "1.1", "2.3") */
|
|
55
|
+
task_id: string;
|
|
56
|
+
/** Which agent role receives this capsule */
|
|
57
|
+
agent_role: AgentRole;
|
|
58
|
+
/** Why this capsule was generated */
|
|
59
|
+
delegation_reason: CapsuleDelegationReason;
|
|
60
|
+
/** Files relevant to this task */
|
|
61
|
+
files_in_scope: string[];
|
|
62
|
+
/** What the task aims to accomplish */
|
|
63
|
+
task_goal: string;
|
|
64
|
+
/** Prior rejection reason, if this capsule is for a fix iteration */
|
|
65
|
+
prior_rejection?: string;
|
|
66
|
+
/** What needs to be fixed, if applicable */
|
|
67
|
+
required_fix?: string;
|
|
68
|
+
/** Repository facts relevant to this task */
|
|
69
|
+
relevant_facts?: string[];
|
|
70
|
+
/** Review checklist items, included for reviewer capsules */
|
|
71
|
+
review_checklist?: string[];
|
|
72
|
+
/** Coverage targets, included for test_engineer capsules */
|
|
73
|
+
coverage_targets?: string[];
|
|
74
|
+
/** Project root directory */
|
|
75
|
+
directory: string;
|
|
76
|
+
/** Maximum token budget for the capsule content (default 2000) */
|
|
77
|
+
max_capsule_tokens?: number;
|
|
78
|
+
/** Capsule mode: conservative (more files, less pruning), balanced (default), aggressive (fewer files, more pruning) */
|
|
79
|
+
mode?: 'conservative' | 'balanced' | 'aggressive';
|
|
80
|
+
/** Whether content hash changes invalidate cached file summaries. Default: true. */
|
|
81
|
+
invalidate_on_hash_change?: boolean;
|
|
82
|
+
/** Custom agent profile overrides — maps role names to strategy names */
|
|
83
|
+
agent_profiles?: Record<string, string>;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Default capsule construction profiles for each agent role.
|
|
87
|
+
* Controls strategy, max file count, and which optional sections are included.
|
|
88
|
+
*/
|
|
89
|
+
export declare const DEFAULT_ROLE_PROFILES: Record<AgentRole, RoleProfile>;
|
|
90
|
+
/**
|
|
91
|
+
* Build a per-file read policy that tells the consuming agent whether to
|
|
92
|
+
* trust cached summaries or read the original source.
|
|
93
|
+
*
|
|
94
|
+
* For each file:
|
|
95
|
+
* - Not in map → read original (no cached data exists)
|
|
96
|
+
* - In map but stale (content hash changed) → read original
|
|
97
|
+
* - In map and fresh → trust summary
|
|
98
|
+
*
|
|
99
|
+
* When `contentCache` is provided, the file contents read during staleness
|
|
100
|
+
* checking are stored in the map so callers can reuse them without re-reading
|
|
101
|
+
* the filesystem (avoids the redundant double-read in buildCapsule).
|
|
102
|
+
*
|
|
103
|
+
* @param files - Relative file paths to build policy for
|
|
104
|
+
* @param map - The loaded Context Map
|
|
105
|
+
* @param directory - Project root directory for file resolution
|
|
106
|
+
* @param invalidateOnHashChange - Whether content hash changes invalidate entries
|
|
107
|
+
* @param contentCache - Optional output map populated with `filePath → content`
|
|
108
|
+
* @returns Array of read policy entries, one per file
|
|
109
|
+
*/
|
|
110
|
+
export declare function buildReadPolicy(files: string[], map: ContextMap, directory: string, invalidateOnHashChange?: boolean, contentCache?: Map<string, string | undefined>): ReadPolicyEntry[];
|
|
111
|
+
/**
|
|
112
|
+
* Build a role-specific Context Capsule for a delegated agent.
|
|
113
|
+
*
|
|
114
|
+
* Loads the context map, applies the role profile to determine which
|
|
115
|
+
* sections to include, builds a per-file read policy, and formats
|
|
116
|
+
* everything as a structured markdown document.
|
|
117
|
+
*
|
|
118
|
+
* Never throws — returns a best-effort capsule even if the context map
|
|
119
|
+
* is missing or corrupt.
|
|
120
|
+
*
|
|
121
|
+
* @param params - Build parameters including task ID, role, files, and directory
|
|
122
|
+
* @returns The constructed capsule and diagnostic metadata
|
|
123
|
+
*/
|
|
124
|
+
export declare function buildCapsule(params: BuildCapsuleParams): {
|
|
125
|
+
capsule: ContextCapsule;
|
|
126
|
+
metadata: CapsuleMetadata;
|
|
127
|
+
};
|
|
128
|
+
export {};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capsule persistence module — handles saving, loading, deleting, and
|
|
3
|
+
* listing Context Capsules stored at `.swarm/capsules/{task_id}.json`.
|
|
4
|
+
*
|
|
5
|
+
* All functions are synchronous for simplicity and reliability. The module
|
|
6
|
+
* uses the `_internals` DI seam pattern so tests can override filesystem
|
|
7
|
+
* operations without `mock.module` (which leaks across files in Bun's
|
|
8
|
+
* shared test-runner process).
|
|
9
|
+
*
|
|
10
|
+
* State lives exclusively under `.swarm/` (Invariant 4). No `process.cwd()`
|
|
11
|
+
* usage — every function accepts an explicit `directory` parameter.
|
|
12
|
+
*
|
|
13
|
+
* No `bun:` imports — this module is Node-ESM-loadable (Invariant 2).
|
|
14
|
+
*
|
|
15
|
+
* No imports from capsule-builder to avoid circular dependencies.
|
|
16
|
+
*/
|
|
17
|
+
import * as fs from 'node:fs';
|
|
18
|
+
import type { CapsuleMetadata, ContextCapsule } from '../types/context-capsule';
|
|
19
|
+
/**
|
|
20
|
+
* Test-only dependency-injection seam. Production code calls through this
|
|
21
|
+
* object so tests can replace the underlying implementations without
|
|
22
|
+
* `mock.module` (which leaks across files in Bun's shared test-runner process).
|
|
23
|
+
* Mutating this local object is file-scoped and trivially restorable
|
|
24
|
+
* via `afterEach`.
|
|
25
|
+
*/
|
|
26
|
+
export declare const _internals: {
|
|
27
|
+
readonly writeFileSync: typeof fs.writeFileSync;
|
|
28
|
+
readonly readFileSync: typeof fs.readFileSync;
|
|
29
|
+
readonly existsSync: typeof fs.existsSync;
|
|
30
|
+
readonly mkdirSync: typeof fs.mkdirSync;
|
|
31
|
+
readonly readdirSync: typeof fs.readdirSync;
|
|
32
|
+
readonly unlinkSync: typeof fs.unlinkSync;
|
|
33
|
+
readonly renameSync: typeof fs.renameSync;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Save a capsule to `.swarm/capsules/{task_id}.json` using an atomic
|
|
37
|
+
* temp-then-rename write pattern to avoid partial-write corruption.
|
|
38
|
+
*
|
|
39
|
+
* Creates the `.swarm/capsules/` directory if it does not exist.
|
|
40
|
+
*
|
|
41
|
+
* Returns {@link CapsuleMetadata} with diagnostics. On error, returns
|
|
42
|
+
* metadata with `success: false` — never throws.
|
|
43
|
+
*/
|
|
44
|
+
export declare function saveCapsule(capsule: ContextCapsule, directory: string): CapsuleMetadata;
|
|
45
|
+
/**
|
|
46
|
+
* Load a capsule from `.swarm/capsules/{task_id}.json`.
|
|
47
|
+
*
|
|
48
|
+
* Returns the parsed {@link ContextCapsule}, or `null` if the file
|
|
49
|
+
* doesn't exist or the JSON is invalid. Never throws.
|
|
50
|
+
*/
|
|
51
|
+
export declare function loadCapsule(taskId: string, directory: string): ContextCapsule | null;
|
|
52
|
+
/**
|
|
53
|
+
* Delete a capsule from `.swarm/capsules/{task_id}.json`.
|
|
54
|
+
*
|
|
55
|
+
* Returns `true` if the file was deleted, `false` if it didn't exist.
|
|
56
|
+
* Never throws.
|
|
57
|
+
*/
|
|
58
|
+
export declare function deleteCapsule(taskId: string, directory: string): boolean;
|
|
59
|
+
/**
|
|
60
|
+
* List all saved capsule task IDs in `.swarm/capsules/`.
|
|
61
|
+
*
|
|
62
|
+
* Returns an array of task IDs derived from filenames (stripping the
|
|
63
|
+
* `.json` extension). Returns an empty array if the directory doesn't
|
|
64
|
+
* exist. Never throws.
|
|
65
|
+
*/
|
|
66
|
+
export declare function listCapsules(directory: string): string[];
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File Summary Population Module
|
|
3
|
+
*
|
|
4
|
+
* Incrementally builds FileContextEntry records as agents interact with files.
|
|
5
|
+
* Uses lightweight regex-based analysis (no external tool calls) to extract
|
|
6
|
+
* exports, imports, language, and purpose summaries from source content.
|
|
7
|
+
*
|
|
8
|
+
* All functions are synchronous and bounded — no filesystem scans,
|
|
9
|
+
* no subprocess calls, no network requests. This module is designed
|
|
10
|
+
* to be fast enough to call on every file an agent touches.
|
|
11
|
+
*/
|
|
12
|
+
import type { FileContextEntry } from '../types/context-map';
|
|
13
|
+
/**
|
|
14
|
+
* Detect the programming language of a file from its extension.
|
|
15
|
+
*
|
|
16
|
+
* @param filePath - Relative or absolute file path
|
|
17
|
+
* @returns Language identifier string, or undefined if the extension is unrecognized
|
|
18
|
+
*/
|
|
19
|
+
export declare function detectLanguage(filePath: string): string | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* Matches named ESM exports: "export function foo", "export class Bar", etc.
|
|
22
|
+
* Capture group 1: the exported symbol name.
|
|
23
|
+
*/
|
|
24
|
+
export declare const RE_EXPORT_NAMED: RegExp;
|
|
25
|
+
/**
|
|
26
|
+
* Matches brace-delimited ESM re-exports: "export { foo, bar }".
|
|
27
|
+
* Capture group 1: the comma-separated symbol list inside braces.
|
|
28
|
+
*/
|
|
29
|
+
export declare const RE_EXPORT_BRACE: RegExp;
|
|
30
|
+
/**
|
|
31
|
+
* Matches ESM import statements: "import ... from '...'".
|
|
32
|
+
* Capture group 1: the module specifier (source path).
|
|
33
|
+
*/
|
|
34
|
+
export declare const RE_IMPORT_FROM: RegExp;
|
|
35
|
+
/**
|
|
36
|
+
* Matches CommonJS require calls: "require('...')".
|
|
37
|
+
* Capture group 1: the module specifier.
|
|
38
|
+
*/
|
|
39
|
+
export declare const RE_IMPORT_REQUIRE: RegExp;
|
|
40
|
+
/**
|
|
41
|
+
* Matches the first JSDoc or block comment in a file.
|
|
42
|
+
* Capture group 1: the comment body (between slash-star and star-slash).
|
|
43
|
+
*/
|
|
44
|
+
export declare const RE_FIRST_COMMENT: RegExp;
|
|
45
|
+
/**
|
|
46
|
+
* Maximum number of key symbols to retain per file entry.
|
|
47
|
+
*/
|
|
48
|
+
export declare const MAX_KEY_SYMBOLS = 10;
|
|
49
|
+
/**
|
|
50
|
+
* Maximum character length for purpose summaries.
|
|
51
|
+
*/
|
|
52
|
+
export declare const MAX_PURPOSE_LENGTH = 200;
|
|
53
|
+
/**
|
|
54
|
+
* Build a complete FileContextEntry from file content.
|
|
55
|
+
*
|
|
56
|
+
* Computes content hash, detects language, extracts exports/imports,
|
|
57
|
+
* generates a purpose summary from the first JSDoc comment, and
|
|
58
|
+
* identifies key symbols from export names.
|
|
59
|
+
*
|
|
60
|
+
* When an existing entry is provided, mutable fields (hash, language,
|
|
61
|
+
* purpose, exports, imports, summary, mtime) are refreshed while
|
|
62
|
+
* accumulated fields (invariants, risks, tests, last_seen_task_ids)
|
|
63
|
+
* are preserved.
|
|
64
|
+
*
|
|
65
|
+
* @param filePath - Relative file path within the project
|
|
66
|
+
* @param content - Full file content as a string
|
|
67
|
+
* @param absolutePath - Optional absolute path for filesystem stat (avoids process.cwd() resolution)
|
|
68
|
+
* @param existingEntry - Optional previous entry to merge with
|
|
69
|
+
* @returns A complete FileContextEntry
|
|
70
|
+
*/
|
|
71
|
+
export declare function extractFileSummary(filePath: string, content: string, absolutePath?: string, existingEntry?: FileContextEntry): FileContextEntry;
|
|
72
|
+
/**
|
|
73
|
+
* Populate FileContextEntry records for multiple files at once.
|
|
74
|
+
*
|
|
75
|
+
* For each file path, reads content from directory + path, calls
|
|
76
|
+
* extractFileSummary, and collects the result. Skips files that
|
|
77
|
+
* don't exist or can't be read.
|
|
78
|
+
*
|
|
79
|
+
* When an existing map is provided, entries are merged: new extractions
|
|
80
|
+
* take precedence for mutable fields while accumulated fields from
|
|
81
|
+
* existing entries are preserved.
|
|
82
|
+
*
|
|
83
|
+
* @param filePaths - Array of relative file paths to populate
|
|
84
|
+
* @param directory - Project root directory to resolve file paths against
|
|
85
|
+
* @param existingMap - Optional map of previously populated entries to merge with
|
|
86
|
+
* @returns Record mapping file paths to their FileContextEntry instances
|
|
87
|
+
*/
|
|
88
|
+
export declare function batchPopulateSummaries(filePaths: string[], directory: string, existingMap?: Record<string, FileContextEntry>): Record<string, FileContextEntry>;
|
|
89
|
+
/**
|
|
90
|
+
* Check whether a stored context map entry is stale relative to current content.
|
|
91
|
+
*
|
|
92
|
+
* Compares the stored content_hash against a fresh SHA-256 hash of the
|
|
93
|
+
* provided current content. Returns true if the hashes differ, indicating
|
|
94
|
+
* the file has been modified since the entry was last populated.
|
|
95
|
+
*
|
|
96
|
+
* @param entry - The stored FileContextEntry to check
|
|
97
|
+
* @param currentContent - The current file content to compare against
|
|
98
|
+
* @returns true if the entry is stale (hashes differ), false if still current
|
|
99
|
+
*/
|
|
100
|
+
export declare function isFileStale(entry: FileContextEntry, currentContent: string): boolean;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context Map persistence module — handles reading, writing, and invalidating
|
|
3
|
+
* the durable Context Map stored at `.swarm/context-map.json`.
|
|
4
|
+
*
|
|
5
|
+
* All functions are synchronous for simplicity and reliability. The module
|
|
6
|
+
* uses the `_internals` DI seam pattern so tests can override filesystem
|
|
7
|
+
* and crypto operations without `mock.module` (which leaks across files in
|
|
8
|
+
* Bun's shared test-runner process).
|
|
9
|
+
*
|
|
10
|
+
* State lives exclusively under `.swarm/` (Invariant 4). No `process.cwd()`
|
|
11
|
+
* usage — every function accepts an explicit `directory` parameter.
|
|
12
|
+
*
|
|
13
|
+
* No `bun:` imports — this module is Node-ESM-loadable (Invariant 2).
|
|
14
|
+
*/
|
|
15
|
+
import * as crypto from 'node:crypto';
|
|
16
|
+
import * as fs from 'node:fs';
|
|
17
|
+
import type { ContentHash, ContextMap, ContextMapStaleEntry, DecisionEntry, TaskContextSummary } from '../types/context-map';
|
|
18
|
+
/**
|
|
19
|
+
* Test-only dependency-injection seam. Production code calls through this
|
|
20
|
+
* object so tests can replace the underlying implementations without
|
|
21
|
+
* `mock.module` (which leaks across files in Bun's shared test-runner process).
|
|
22
|
+
* Mutating this local object is file-scoped and trivially restorable
|
|
23
|
+
* via `afterEach`.
|
|
24
|
+
*/
|
|
25
|
+
export declare const _internals: {
|
|
26
|
+
readonly readFileSync: typeof fs.readFileSync;
|
|
27
|
+
readonly writeFileSync: typeof fs.writeFileSync;
|
|
28
|
+
readonly mkdirSync: typeof fs.mkdirSync;
|
|
29
|
+
readonly renameSync: typeof fs.renameSync;
|
|
30
|
+
readonly existsSync: typeof fs.existsSync;
|
|
31
|
+
readonly statSync: fs.StatSyncFn;
|
|
32
|
+
readonly createHash: typeof crypto.createHash;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Compute a SHA-256 content hash for the given string content.
|
|
36
|
+
* Returns the hash as a 64-character lowercase hex string.
|
|
37
|
+
*/
|
|
38
|
+
export declare function computeContentHash(content: string): ContentHash;
|
|
39
|
+
/**
|
|
40
|
+
* Create a new empty ContextMap with sensible defaults.
|
|
41
|
+
* The `repo_fingerprint` is left empty and populated by the caller later.
|
|
42
|
+
*/
|
|
43
|
+
export declare function createEmptyContextMap(): ContextMap;
|
|
44
|
+
/**
|
|
45
|
+
* Load the Context Map from `.swarm/context-map.json` in the given directory.
|
|
46
|
+
* Returns `null` if the file doesn't exist or cannot be parsed (corrupt file).
|
|
47
|
+
* Never throws.
|
|
48
|
+
*/
|
|
49
|
+
export declare function loadContextMap(directory: string): ContextMap | null;
|
|
50
|
+
/**
|
|
51
|
+
* Save the Context Map to `.swarm/context-map.json` using an atomic
|
|
52
|
+
* temp-then-rename write pattern to avoid partial-write corruption.
|
|
53
|
+
*
|
|
54
|
+
* Updates `generated_at` to the current timestamp before writing.
|
|
55
|
+
* Creates the `.swarm/` directory if it does not exist.
|
|
56
|
+
*/
|
|
57
|
+
export declare function saveContextMap(map: ContextMap, directory: string): void;
|
|
58
|
+
/**
|
|
59
|
+
* Scan all file entries in the context map and detect which ones have
|
|
60
|
+
* changed or been deleted since the map was last generated.
|
|
61
|
+
*
|
|
62
|
+
* Uses an mtime pre-check before computing the expensive SHA-256 hash —
|
|
63
|
+
* only files with a modified timestamp undergo hashing.
|
|
64
|
+
*
|
|
65
|
+
* Returns the list of stale entries. Files that don't exist on disk or
|
|
66
|
+
* whose content hash differs from the stored hash are included.
|
|
67
|
+
* This function is read-only and does NOT modify the input map.
|
|
68
|
+
*/
|
|
69
|
+
export declare function markStaleEntries(map: ContextMap, directory: string): ContextMapStaleEntry[];
|
|
70
|
+
/**
|
|
71
|
+
* Add or update a task history entry in the context map.
|
|
72
|
+
* Returns a new ContextMap with the entry added/updated (input is not mutated).
|
|
73
|
+
*/
|
|
74
|
+
export declare function appendTaskHistory(map: ContextMap, summary: TaskContextSummary): ContextMap;
|
|
75
|
+
/**
|
|
76
|
+
* Append an architectural decision to the context map's decisions array.
|
|
77
|
+
* Returns a new ContextMap with the decision appended (input is not mutated).
|
|
78
|
+
*/
|
|
79
|
+
export declare function appendDecision(map: ContextMap, decision: DecisionEntry): ContextMap;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Post-Agent Context Map Update Module
|
|
3
|
+
*
|
|
4
|
+
* After an agent completes a task, this module updates the Context Map with
|
|
5
|
+
* the task's results — files touched, implementation summary,
|
|
6
|
+
* rejection/review findings, and decisions made. This is the "write-back"
|
|
7
|
+
* half of the context map lifecycle.
|
|
8
|
+
*
|
|
9
|
+
* All functions use the `_internals` DI seam pattern so tests can override
|
|
10
|
+
* dependencies without `mock.module` (which leaks across files in Bun's
|
|
11
|
+
* shared test-runner process).
|
|
12
|
+
*
|
|
13
|
+
* State lives exclusively under `.swarm/` (Invariant 4). No `process.cwd()`
|
|
14
|
+
* usage — every function accepts an explicit `directory` parameter.
|
|
15
|
+
*
|
|
16
|
+
* No `bun:` imports — this module is Node-ESM-loadable (Invariant 2).
|
|
17
|
+
*/
|
|
18
|
+
import * as fs from 'node:fs';
|
|
19
|
+
import type { ContextMap } from '../types/context-map';
|
|
20
|
+
import { extractFileSummary } from './file-summary';
|
|
21
|
+
import { appendDecision, appendTaskHistory, createEmptyContextMap, loadContextMap, saveContextMap } from './persistence';
|
|
22
|
+
/**
|
|
23
|
+
* Parameters for updating the Context Map after an agent completes a task.
|
|
24
|
+
* Captures all relevant context from the agent's work session so that
|
|
25
|
+
* future agents can understand what happened without re-reading evidence files.
|
|
26
|
+
*/
|
|
27
|
+
export interface PostAgentUpdateParams {
|
|
28
|
+
/** Task ID (e.g. "1.1", "2.3") */
|
|
29
|
+
task_id: string;
|
|
30
|
+
/** Agent role that completed (coder, reviewer, etc.) */
|
|
31
|
+
agent_role: string;
|
|
32
|
+
/** Files the agent touched/modified */
|
|
33
|
+
files_touched: string[];
|
|
34
|
+
/** Brief summary of what the agent did */
|
|
35
|
+
implementation_summary: string;
|
|
36
|
+
/** Task goal description */
|
|
37
|
+
task_goal: string;
|
|
38
|
+
/** Final status of the task */
|
|
39
|
+
final_status: 'completed' | 'failed' | 'blocked' | 'cancelled';
|
|
40
|
+
/** Reviewer rejection reasons (if any) */
|
|
41
|
+
rejection_reasons?: string[];
|
|
42
|
+
/** Review findings (if any) */
|
|
43
|
+
review_findings?: string[];
|
|
44
|
+
/** Decisions made during this task */
|
|
45
|
+
decisions?: Array<{
|
|
46
|
+
decision: string;
|
|
47
|
+
rationale: string;
|
|
48
|
+
}>;
|
|
49
|
+
/** Project root directory */
|
|
50
|
+
directory: string;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Test-only dependency-injection seam. Production code calls through this
|
|
54
|
+
* object so tests can replace the underlying implementations without
|
|
55
|
+
* `mock.module` (which leaks across files in Bun's shared test-runner process).
|
|
56
|
+
* Mutating this local object is file-scoped and trivially restorable
|
|
57
|
+
* via `afterEach`.
|
|
58
|
+
*/
|
|
59
|
+
export declare const _internals: {
|
|
60
|
+
loadContextMap: typeof loadContextMap;
|
|
61
|
+
saveContextMap: typeof saveContextMap;
|
|
62
|
+
createEmptyContextMap: typeof createEmptyContextMap;
|
|
63
|
+
extractFileSummary: typeof extractFileSummary;
|
|
64
|
+
existsSync: typeof fs.existsSync;
|
|
65
|
+
readFileSync: typeof fs.readFileSync;
|
|
66
|
+
readdirSync: typeof fs.readdirSync;
|
|
67
|
+
realpathSync: typeof fs.realpathSync;
|
|
68
|
+
appendTaskHistory: typeof appendTaskHistory;
|
|
69
|
+
appendDecision: typeof appendDecision;
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* Extract reviewer/critic findings from .swarm/evidence/ files for a task.
|
|
73
|
+
*
|
|
74
|
+
* Looks for reviewer and test-engineer evidence files under
|
|
75
|
+
* `.swarm/evidence/{taskId}/`, parses them, and returns consolidated
|
|
76
|
+
* rejection reasons and findings.
|
|
77
|
+
*
|
|
78
|
+
* Tries both `test-engineer.json` and `test_engineer.json` filenames to
|
|
79
|
+
* handle naming inconsistencies across the repo.
|
|
80
|
+
*
|
|
81
|
+
* Evidence files may contain:
|
|
82
|
+
* - `verdict`: string (e.g. "APPROVED", "approved", "pass", "REJECTED") —
|
|
83
|
+
* non-approval verdicts are collected as rejection reasons. Case-insensitive.
|
|
84
|
+
* - `issues`: array of objects with a `message`, `detail`, or `description`
|
|
85
|
+
* string field — each is collected as a finding.
|
|
86
|
+
* - `findings`: array of objects with a `message`, `detail`, or `description`
|
|
87
|
+
* string field — also collected as findings.
|
|
88
|
+
*
|
|
89
|
+
* Never throws — returns empty arrays on any error (missing directory,
|
|
90
|
+
* unreadable files, malformed JSON, etc.).
|
|
91
|
+
*
|
|
92
|
+
* @param taskId - Task ID (e.g. "1.1", "2.3")
|
|
93
|
+
* @param directory - Project root directory
|
|
94
|
+
* @returns Consolidated rejection reasons and review findings from evidence
|
|
95
|
+
*/
|
|
96
|
+
export declare function extractEvidenceFindings(taskId: string, directory: string): {
|
|
97
|
+
rejection_reasons: string[];
|
|
98
|
+
review_findings: string[];
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* Update the Context Map after an agent completes a task.
|
|
102
|
+
*
|
|
103
|
+
* This is the "write-back" half of the context map lifecycle. It:
|
|
104
|
+
* 1. Loads the existing context map (or creates an empty one)
|
|
105
|
+
* 2. Refreshes file summaries for all touched files, preserving accumulated data
|
|
106
|
+
* 3. Appends a TaskContextSummary entry for the completed task
|
|
107
|
+
* 4. Appends any architectural decisions made during the task
|
|
108
|
+
* 5. Saves the updated map and returns it
|
|
109
|
+
*
|
|
110
|
+
* Never throws — on any error, returns the best-effort context map
|
|
111
|
+
* (either the existing one or a fresh empty one).
|
|
112
|
+
*
|
|
113
|
+
* @param params - Parameters describing the completed task and its results
|
|
114
|
+
* @returns The updated ContextMap
|
|
115
|
+
*/
|
|
116
|
+
export declare function updateContextMapAfterAgent(params: PostAgentUpdateParams): ContextMap;
|