opencode-swarm 7.54.0 → 7.56.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/background/completion-observer.d.ts +33 -0
- package/dist/background/pending-delegations.d.ts +88 -0
- package/dist/background/task-envelope.d.ts +43 -0
- package/dist/cli/index.js +136 -17
- package/dist/config/schema.d.ts +4 -0
- package/dist/index.js +2280 -1941
- package/dist/services/skill-generator.d.ts +2 -1
- package/dist/services/skill-improver.d.ts +6 -0
- package/package.json +1 -1
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Background subagent completion OBSERVER (issue #1151, PR 2 Stage A).
|
|
3
|
+
*
|
|
4
|
+
* Registers as a swarm `event` hook to watch for the upstream background-completion signal:
|
|
5
|
+
* a message part with `synthetic === true` whose text is a task envelope with
|
|
6
|
+
* `state="completed"` or `state="error"`. When such a part correlates to a durable pending
|
|
7
|
+
* background-delegation record, it is logged (debug-gated) as the empirical confirmation
|
|
8
|
+
* instrument operators use to verify the runtime signal in a real environment.
|
|
9
|
+
*
|
|
10
|
+
* Stage A is strictly READ-ONLY: this observer NEVER advances workflow gates, records gate
|
|
11
|
+
* evidence, or mutates the durable store. Gate-affecting completion ingestion is Stage B,
|
|
12
|
+
* gated on runtime confirmation produced by exactly this observer.
|
|
13
|
+
*
|
|
14
|
+
* The `synthetic` flag is the trust gate (set by OpenCode, not the model/user). Non-synthetic
|
|
15
|
+
* text that merely looks like an envelope is ignored. The observer is fail-open: any error is
|
|
16
|
+
* swallowed so it can never block event delivery or plugin load (Invariant 1/10).
|
|
17
|
+
*/
|
|
18
|
+
interface ObserverConfig {
|
|
19
|
+
enabled: boolean;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Build the Stage A completion observer. Returns an `event` handler suitable for the
|
|
23
|
+
* OpenCode plugin `event` hook. No-op (cheap early return) when the feature is disabled.
|
|
24
|
+
*/
|
|
25
|
+
export declare function createBackgroundCompletionObserver(opts: {
|
|
26
|
+
config: ObserverConfig;
|
|
27
|
+
directory: string;
|
|
28
|
+
}): {
|
|
29
|
+
event: (input: {
|
|
30
|
+
event: unknown;
|
|
31
|
+
}) => Promise<void>;
|
|
32
|
+
};
|
|
33
|
+
export {};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Durable pending background-delegation store (issue #1151, PR 2 Stage A).
|
|
3
|
+
*
|
|
4
|
+
* Append-only JSONL event log under project-root `.swarm/background-delegations.jsonl`.
|
|
5
|
+
* Each line is a full record snapshot; readers fold to the latest snapshot per
|
|
6
|
+
* `correlationId`. This tracks background swarm `Task` dispatches so a later (Stage B)
|
|
7
|
+
* trusted completion can be correlated to a real dispatch. The stale sweep bounds the
|
|
8
|
+
* number of permanently-running (unresolved) entries by transitioning them to `stale`, so
|
|
9
|
+
* the folded in-memory view stays bounded by distinct correlationIds. Note: the on-disk
|
|
10
|
+
* log itself is append-only and is NOT compacted in Stage A — each dispatch leaves a small,
|
|
11
|
+
* fixed number of lines; on-disk compaction of dropped/stale records is a future stage.
|
|
12
|
+
*
|
|
13
|
+
* Stage A scope: dispatch records a `pending` snapshot and the stale sweep records
|
|
14
|
+
* `stale` snapshots. There is NO gate advancement and NO completion mutation here — the
|
|
15
|
+
* completion observer (Stage A) is read-only. Gate-affecting completion ingestion is
|
|
16
|
+
* Stage B, gated on runtime confirmation of the upstream completion signal.
|
|
17
|
+
*
|
|
18
|
+
* Concurrency: all writes (append, sweep) run under a single project-scoped lock via
|
|
19
|
+
* `withEvidenceLock`, so concurrent dispatches/sweeps cannot interleave appends. Reads are
|
|
20
|
+
* lock-free (line-oriented; partial trailing lines are skipped defensively).
|
|
21
|
+
*
|
|
22
|
+
* Containment: the path is validated with `validateSwarmPath`, so it can never escape
|
|
23
|
+
* `.swarm/` (Invariant 4).
|
|
24
|
+
*/
|
|
25
|
+
export declare const BACKGROUND_DELEGATIONS_FILE = "background-delegations.jsonl";
|
|
26
|
+
export type BackgroundDelegationStatus = 'pending' | 'completed' | 'error' | 'stale';
|
|
27
|
+
export interface BackgroundDelegationRecord {
|
|
28
|
+
schemaVersion: 1;
|
|
29
|
+
/** Subagent session id from the dispatch envelope — the correlation key. */
|
|
30
|
+
correlationId: string;
|
|
31
|
+
/** Structured jobId from dispatch metadata when available, else null. */
|
|
32
|
+
jobId: string | null;
|
|
33
|
+
/** Subagent session id (== correlationId; kept explicit for clarity/forward-compat). */
|
|
34
|
+
subagentSessionId: string;
|
|
35
|
+
/** Parent (dispatching) session id. */
|
|
36
|
+
parentSessionId: string;
|
|
37
|
+
/** Tool callID of the dispatching Task call. */
|
|
38
|
+
callID: string;
|
|
39
|
+
/** Canonical swarm role (e.g. "reviewer", "test_engineer"). */
|
|
40
|
+
normalizedAgent: string;
|
|
41
|
+
/** Raw, possibly swarm-prefixed agent name (e.g. "mega_reviewer"). */
|
|
42
|
+
swarmPrefixedAgent: string;
|
|
43
|
+
/** Plan/evidence task id resolved at dispatch, or null. */
|
|
44
|
+
planTaskId: string | null;
|
|
45
|
+
evidenceTaskId: string | null;
|
|
46
|
+
status: BackgroundDelegationStatus;
|
|
47
|
+
createdAt: number;
|
|
48
|
+
updatedAt: number;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Read and fold the store to the latest snapshot per correlationId. Lock-free and
|
|
52
|
+
* defensive: a missing file yields an empty list, and malformed/partial lines are skipped
|
|
53
|
+
* (never throws). Records are returned in first-seen correlationId order.
|
|
54
|
+
*
|
|
55
|
+
* Cost: O(lines on disk) per call — a full read + parse + fold with no in-memory cache.
|
|
56
|
+
* This is intentionally simple and acceptable at Stage A volumes (a swarm has few concurrent
|
|
57
|
+
* background delegations, and the on-disk log is small). If sustained high-throughput
|
|
58
|
+
* background load ever makes this hot, a future stage should add a stat-invalidated in-memory
|
|
59
|
+
* cache and/or JSONL compaction (the same future-compaction work noted in the module header).
|
|
60
|
+
*/
|
|
61
|
+
export declare function readDelegations(directory: string): BackgroundDelegationRecord[];
|
|
62
|
+
/** Returns the folded record for a correlationId, or null. Lock-free read. */
|
|
63
|
+
export declare function findByCorrelationId(directory: string, correlationId: string): BackgroundDelegationRecord | null;
|
|
64
|
+
export interface RecordPendingInput {
|
|
65
|
+
correlationId: string;
|
|
66
|
+
jobId: string | null;
|
|
67
|
+
subagentSessionId: string;
|
|
68
|
+
parentSessionId: string;
|
|
69
|
+
callID: string;
|
|
70
|
+
normalizedAgent: string;
|
|
71
|
+
swarmPrefixedAgent: string;
|
|
72
|
+
planTaskId: string | null;
|
|
73
|
+
evidenceTaskId: string | null;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Record a `pending` background delegation. Runs the stale sweep first (lazy maintenance,
|
|
77
|
+
* no plugin-init cost), then appends the pending snapshot — all under one lock acquisition
|
|
78
|
+
* so concurrent dispatches cannot interleave. Best-effort: returns null on lock timeout or
|
|
79
|
+
* write failure (Stage A has no gate effects, so a missed record is non-fatal).
|
|
80
|
+
*/
|
|
81
|
+
export declare function recordPendingDelegation(directory: string, input: RecordPendingInput, options?: {
|
|
82
|
+
staleTimeoutMs?: number;
|
|
83
|
+
}): Promise<BackgroundDelegationRecord | null>;
|
|
84
|
+
/**
|
|
85
|
+
* Public stale sweep: acquires the store lock and marks overdue pendings as `stale`.
|
|
86
|
+
* Best-effort; returns the number swept (0 on lock timeout / error).
|
|
87
|
+
*/
|
|
88
|
+
export declare function sweepStaleDelegations(directory: string, timeoutMs: number): Promise<number>;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Background subagent task-envelope parsing (issue #1151, PR 2 Stage A).
|
|
3
|
+
*
|
|
4
|
+
* OpenCode background subagents (v1.16.2) render task dispatch/completion as a stable
|
|
5
|
+
* XML-ish envelope via the upstream `renderOutput`:
|
|
6
|
+
*
|
|
7
|
+
* <task id="<subagentSessionID>" state="running|completed|error">
|
|
8
|
+
* <summary>...</summary>
|
|
9
|
+
* <task_result>...</task_result> (or <task_error> for state="error")
|
|
10
|
+
* </task>
|
|
11
|
+
*
|
|
12
|
+
* - The dispatch tool result carries `state="running"` and the subagent session id.
|
|
13
|
+
* - The deferred completion arrives as a synthetic parent message part whose text is the
|
|
14
|
+
* same envelope with `state="completed"` or `state="error"`.
|
|
15
|
+
*
|
|
16
|
+
* These parsers are intentionally pure and defensive — they never throw — so they can be
|
|
17
|
+
* used both at dispatch (tool.execute.after output) and at completion observation time.
|
|
18
|
+
*/
|
|
19
|
+
export type TaskEnvelopeState = 'running' | 'completed' | 'error';
|
|
20
|
+
export interface TaskEnvelope {
|
|
21
|
+
/** The subagent session id from `<task id="...">` — the cross-event correlation key. */
|
|
22
|
+
sessionId: string;
|
|
23
|
+
state: TaskEnvelopeState;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Parse a task envelope from arbitrary text. Returns null when the text does not contain
|
|
27
|
+
* a well-formed opening `<task id="..." state="...">` tag. Never throws.
|
|
28
|
+
*/
|
|
29
|
+
export declare function parseTaskEnvelope(text: unknown): TaskEnvelope | null;
|
|
30
|
+
/**
|
|
31
|
+
* Extract the subagent session id and (optional) jobId from a background `Task` dispatch
|
|
32
|
+
* result (the `tool.execute.after` output object `{ title, output, metadata }`).
|
|
33
|
+
*
|
|
34
|
+
* - `subagentSessionId` is parsed from the rendered `output` envelope `<task id="...">`.
|
|
35
|
+
* - `jobId` is read defensively from `metadata.jobId` (the installed plugin SDK types this
|
|
36
|
+
* field as `any`; upstream sets `{ background: true, jobId }`). Absent → null.
|
|
37
|
+
*
|
|
38
|
+
* Both are best-effort; either may be null.
|
|
39
|
+
*/
|
|
40
|
+
export declare function extractDispatchIds(output: unknown): {
|
|
41
|
+
subagentSessionId: string | null;
|
|
42
|
+
jobId: string | null;
|
|
43
|
+
};
|
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.56.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",
|
|
@@ -17302,7 +17302,9 @@ var init_schema = __esm(() => {
|
|
|
17302
17302
|
delegation_tracker: exports_external.boolean().default(false),
|
|
17303
17303
|
agent_awareness_max_chars: exports_external.number().min(50).max(2000).default(300),
|
|
17304
17304
|
delegation_gate: exports_external.boolean().default(true),
|
|
17305
|
-
delegation_max_chars: exports_external.number().min(500).max(20000).default(4000)
|
|
17305
|
+
delegation_max_chars: exports_external.number().min(500).max(20000).default(4000),
|
|
17306
|
+
background_subagents: exports_external.boolean().default(false),
|
|
17307
|
+
background_pending_timeout_minutes: exports_external.number().int().min(1).max(1440).default(30)
|
|
17306
17308
|
});
|
|
17307
17309
|
ScoringWeightsSchema = exports_external.object({
|
|
17308
17310
|
phase: exports_external.number().min(0).max(5).default(1),
|
|
@@ -36809,7 +36811,7 @@ function clusterEntries(entries) {
|
|
|
36809
36811
|
function uniqueStrings(arr) {
|
|
36810
36812
|
return [...new Set(arr.filter((s) => typeof s === "string" && s.length > 0))];
|
|
36811
36813
|
}
|
|
36812
|
-
function renderSkillMarkdown(cluster, mode = "active") {
|
|
36814
|
+
function renderSkillMarkdown(cluster, mode = "active", generatedAt = new Date().toISOString()) {
|
|
36813
36815
|
const description = cluster.title.length > 200 ? `${cluster.title.slice(0, 197)}\u2026` : cluster.title;
|
|
36814
36816
|
const ids = cluster.entries.map((e) => ` - ${e.id}`).join(`
|
|
36815
36817
|
`);
|
|
@@ -36819,6 +36821,9 @@ function renderSkillMarkdown(cluster, mode = "active") {
|
|
|
36819
36821
|
lines.push(`description: ${escapeYaml(description)}`);
|
|
36820
36822
|
lines.push("generated_from_knowledge:");
|
|
36821
36823
|
lines.push(ids);
|
|
36824
|
+
lines.push("source_knowledge_ids:");
|
|
36825
|
+
lines.push(ids);
|
|
36826
|
+
lines.push(`generated_at: ${generatedAt}`);
|
|
36822
36827
|
lines.push(`confidence: ${cluster.avgConfidence.toFixed(2)}`);
|
|
36823
36828
|
lines.push(`status: ${mode === "active" ? "active" : "draft"}`);
|
|
36824
36829
|
lines.push("---");
|
|
@@ -37007,6 +37012,62 @@ async function stampSourceEntries(directory, slug, ids) {
|
|
|
37007
37012
|
if (touchedHive)
|
|
37008
37013
|
await rewriteKnowledge(hivePath, hive);
|
|
37009
37014
|
}
|
|
37015
|
+
function parseDraftFrontmatter(content) {
|
|
37016
|
+
const stripped = content.charCodeAt(0) === 65279 ? content.slice(1) : content;
|
|
37017
|
+
const openFence = stripped.match(/^---[ \t]*\r?\n/);
|
|
37018
|
+
if (!openFence)
|
|
37019
|
+
return null;
|
|
37020
|
+
const fenceLen = openFence[0].length;
|
|
37021
|
+
const closeFence = stripped.slice(fenceLen).match(/\n---[ \t]*(\r?\n|$)/);
|
|
37022
|
+
if (!closeFence)
|
|
37023
|
+
return null;
|
|
37024
|
+
const closeStart = fenceLen + (closeFence.index ?? 0);
|
|
37025
|
+
const body = stripped.slice(fenceLen, closeStart).replace(/\r\n/g, `
|
|
37026
|
+
`);
|
|
37027
|
+
const lines = body.split(`
|
|
37028
|
+
`);
|
|
37029
|
+
const out = {
|
|
37030
|
+
sourceKnowledgeIds: []
|
|
37031
|
+
};
|
|
37032
|
+
let inLegacyIdsList = false;
|
|
37033
|
+
let inSourceIdsList = false;
|
|
37034
|
+
for (const raw of lines) {
|
|
37035
|
+
const line = raw;
|
|
37036
|
+
if (inLegacyIdsList || inSourceIdsList) {
|
|
37037
|
+
const m = line.match(/^\s+-\s+(\S{1,64})\s*$/);
|
|
37038
|
+
if (m) {
|
|
37039
|
+
out.sourceKnowledgeIds.push(m[1]);
|
|
37040
|
+
continue;
|
|
37041
|
+
}
|
|
37042
|
+
inLegacyIdsList = false;
|
|
37043
|
+
inSourceIdsList = false;
|
|
37044
|
+
}
|
|
37045
|
+
const nm = line.match(/^name:\s*(\S+)\s*$/);
|
|
37046
|
+
if (nm) {
|
|
37047
|
+
out.name = nm[1];
|
|
37048
|
+
continue;
|
|
37049
|
+
}
|
|
37050
|
+
const st = line.match(/^status:\s*(\S+)\s*$/);
|
|
37051
|
+
if (st) {
|
|
37052
|
+
out.status = st[1];
|
|
37053
|
+
continue;
|
|
37054
|
+
}
|
|
37055
|
+
const ga = line.match(/^generated_at:\s*(\S+)\s*$/);
|
|
37056
|
+
if (ga) {
|
|
37057
|
+
out.generatedAt = ga[1];
|
|
37058
|
+
continue;
|
|
37059
|
+
}
|
|
37060
|
+
if (/^generated_from_knowledge:\s*$/.test(line)) {
|
|
37061
|
+
inLegacyIdsList = true;
|
|
37062
|
+
continue;
|
|
37063
|
+
}
|
|
37064
|
+
if (/^source_knowledge_ids:\s*$/.test(line)) {
|
|
37065
|
+
out.sourceKnowledgeIds = [];
|
|
37066
|
+
inSourceIdsList = true;
|
|
37067
|
+
}
|
|
37068
|
+
}
|
|
37069
|
+
return out;
|
|
37070
|
+
}
|
|
37010
37071
|
async function listSkills(directory) {
|
|
37011
37072
|
const result = {
|
|
37012
37073
|
proposals: [],
|
|
@@ -38336,7 +38397,7 @@ var init_skill_improver_quota = __esm(() => {
|
|
|
38336
38397
|
|
|
38337
38398
|
// src/services/skill-improver.ts
|
|
38338
38399
|
import { existsSync as existsSync12 } from "fs";
|
|
38339
|
-
import { mkdir as mkdir7, rename as rename5, writeFile as writeFile6 } from "fs/promises";
|
|
38400
|
+
import { mkdir as mkdir7, readFile as readFile7, rename as rename5, writeFile as writeFile6 } from "fs/promises";
|
|
38340
38401
|
import * as path18 from "path";
|
|
38341
38402
|
function timestampSlug(d) {
|
|
38342
38403
|
return d.toISOString().replace(/[:.]/g, "-");
|
|
@@ -38353,15 +38414,63 @@ async function gatherInventory(directory) {
|
|
|
38353
38414
|
const hive = existsSync12(hivePath) ? await readKnowledge(hivePath) : [];
|
|
38354
38415
|
const archived = [...swarm, ...hive].filter((e) => e.status === "archived").length;
|
|
38355
38416
|
const skills = await listSkills(directory);
|
|
38417
|
+
const knowledgeById = new Map([...swarm, ...hive].map((entry) => [entry.id, entry]));
|
|
38418
|
+
const staleActiveSkills = [];
|
|
38419
|
+
let metadataReadable = 0;
|
|
38420
|
+
for (const skill of skills.active) {
|
|
38421
|
+
let content;
|
|
38422
|
+
try {
|
|
38423
|
+
content = await readFile7(skill.path, "utf-8");
|
|
38424
|
+
} catch {
|
|
38425
|
+
continue;
|
|
38426
|
+
}
|
|
38427
|
+
const fm = parseDraftFrontmatter(content);
|
|
38428
|
+
if (!fm)
|
|
38429
|
+
continue;
|
|
38430
|
+
metadataReadable += 1;
|
|
38431
|
+
const reasons = [];
|
|
38432
|
+
if (fm.sourceKnowledgeIds.length === 0) {
|
|
38433
|
+
reasons.push("missing_source_knowledge_ids");
|
|
38434
|
+
}
|
|
38435
|
+
if (!fm.generatedAt) {
|
|
38436
|
+
reasons.push("missing_generated_at");
|
|
38437
|
+
} else {
|
|
38438
|
+
const generatedAtMs = Date.parse(fm.generatedAt);
|
|
38439
|
+
if (!Number.isFinite(generatedAtMs)) {
|
|
38440
|
+
reasons.push("invalid_generated_at");
|
|
38441
|
+
} else {
|
|
38442
|
+
for (const id of fm.sourceKnowledgeIds) {
|
|
38443
|
+
const source = knowledgeById.get(id);
|
|
38444
|
+
if (!source) {
|
|
38445
|
+
reasons.push(`missing_source:${id}`);
|
|
38446
|
+
continue;
|
|
38447
|
+
}
|
|
38448
|
+
const updatedAtMs = Date.parse(source.updated_at);
|
|
38449
|
+
if (Number.isFinite(updatedAtMs) && updatedAtMs > generatedAtMs) {
|
|
38450
|
+
reasons.push(`updated_after_generation:${id}`);
|
|
38451
|
+
}
|
|
38452
|
+
}
|
|
38453
|
+
}
|
|
38454
|
+
}
|
|
38455
|
+
if (reasons.length > 0) {
|
|
38456
|
+
staleActiveSkills.push({
|
|
38457
|
+
slug: skill.slug,
|
|
38458
|
+
reasons: reasons.slice(0, 6)
|
|
38459
|
+
});
|
|
38460
|
+
}
|
|
38461
|
+
}
|
|
38356
38462
|
const matureCandidates = swarm.concat(hive).filter((e) => e.status !== "archived" && e.confidence >= 0.85 && !e.generated_skill_slug && (e.confirmed_by ?? []).length >= 2);
|
|
38357
38463
|
return {
|
|
38358
38464
|
knowledge: { swarm: swarm.length, hive: hive.length, archived },
|
|
38359
38465
|
skills: {
|
|
38360
38466
|
proposals: skills.proposals.length,
|
|
38361
|
-
active: skills.active.length
|
|
38467
|
+
active: skills.active.length,
|
|
38468
|
+
stale: staleActiveSkills.length,
|
|
38469
|
+
metadataReadable
|
|
38362
38470
|
},
|
|
38363
38471
|
highConfidenceClusters: matureCandidates.length,
|
|
38364
|
-
matureCandidates
|
|
38472
|
+
matureCandidates,
|
|
38473
|
+
staleActiveSkills
|
|
38365
38474
|
};
|
|
38366
38475
|
}
|
|
38367
38476
|
function buildSystemPrompt(targets, cfg) {
|
|
@@ -38385,10 +38494,16 @@ hive_entries: ${inv.knowledge.hive}
|
|
|
38385
38494
|
archived: ${inv.knowledge.archived}
|
|
38386
38495
|
draft_skills: ${inv.skills.proposals}
|
|
38387
38496
|
active_skills: ${inv.skills.active}
|
|
38497
|
+
active_skills_with_readable_metadata: ${inv.skills.metadataReadable}
|
|
38498
|
+
stale_active_skills: ${inv.skills.stale}
|
|
38388
38499
|
mature_uncompiled_clusters: ${inv.highConfidenceClusters}
|
|
38389
38500
|
|
|
38390
38501
|
TOP MATURE CANDIDATES (first 25):
|
|
38391
38502
|
${matureRows || "(none)"}
|
|
38503
|
+
|
|
38504
|
+
STALE ACTIVE SKILLS (first 10):
|
|
38505
|
+
${inv.staleActiveSkills.slice(0, 10).map((s) => `- ${s.slug} | ${s.reasons.join(", ")}`).join(`
|
|
38506
|
+
`) || "(none)"}
|
|
38392
38507
|
`;
|
|
38393
38508
|
}
|
|
38394
38509
|
function isAbortError(err) {
|
|
@@ -38417,7 +38532,11 @@ function buildDeterministicProposal(args) {
|
|
|
38417
38532
|
lines.push("## Inventory snapshot");
|
|
38418
38533
|
lines.push(`- Knowledge entries: swarm=${args.inventory.knowledge.swarm}, hive=${args.inventory.knowledge.hive}, archived=${args.inventory.knowledge.archived}`);
|
|
38419
38534
|
lines.push(`- Generated skills: proposals=${args.inventory.skills.proposals}, active=${args.inventory.skills.active}`);
|
|
38535
|
+
lines.push(`- Active skills with readable metadata: ${args.inventory.skills.metadataReadable} (stale=${args.inventory.skills.stale})`);
|
|
38420
38536
|
lines.push(`- High-confidence un-skill'd clusters: ${args.inventory.highConfidenceClusters}`);
|
|
38537
|
+
if (args.inventory.staleActiveSkills.length > 0) {
|
|
38538
|
+
lines.push(`- Stale active skills: ${args.inventory.staleActiveSkills.map((s) => s.slug).join(", ")}`);
|
|
38539
|
+
}
|
|
38421
38540
|
lines.push("");
|
|
38422
38541
|
lines.push("## Recommendations");
|
|
38423
38542
|
if (args.inventory.highConfidenceClusters > 0) {
|
|
@@ -39912,7 +40031,7 @@ var init_curate = __esm(() => {
|
|
|
39912
40031
|
// src/tools/co-change-analyzer.ts
|
|
39913
40032
|
import * as child_process3 from "child_process";
|
|
39914
40033
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
39915
|
-
import { readdir, readFile as
|
|
40034
|
+
import { readdir, readFile as readFile8, stat as stat2 } from "fs/promises";
|
|
39916
40035
|
import * as path21 from "path";
|
|
39917
40036
|
import { promisify } from "util";
|
|
39918
40037
|
function getExecFileAsync() {
|
|
@@ -40039,7 +40158,7 @@ async function getStaticEdges(directory) {
|
|
|
40039
40158
|
const sourceFiles = await scanSourceFiles(directory);
|
|
40040
40159
|
for (const sourceFile of sourceFiles) {
|
|
40041
40160
|
try {
|
|
40042
|
-
const content = await
|
|
40161
|
+
const content = await readFile8(sourceFile, "utf-8");
|
|
40043
40162
|
const importRegex = /(?:import|require)\s*(?:\(?\s*['"`]|.*?from\s+['"`])([^'"`]+)['"`]/g;
|
|
40044
40163
|
for (let match = importRegex.exec(content);match !== null; match = importRegex.exec(content)) {
|
|
40045
40164
|
const importPath = match[1].trim();
|
|
@@ -40823,11 +40942,11 @@ var init_version_check = __esm(() => {
|
|
|
40823
40942
|
|
|
40824
40943
|
// src/services/knowledge-diagnostics.ts
|
|
40825
40944
|
import { existsSync as existsSync14 } from "fs";
|
|
40826
|
-
import { readFile as
|
|
40945
|
+
import { readFile as readFile9 } from "fs/promises";
|
|
40827
40946
|
async function readRawLines(filePath) {
|
|
40828
40947
|
if (!existsSync14(filePath))
|
|
40829
40948
|
return { entries: [], corrupt: 0 };
|
|
40830
|
-
const content = await
|
|
40949
|
+
const content = await readFile9(filePath, "utf-8");
|
|
40831
40950
|
const entries = [];
|
|
40832
40951
|
let corrupt = 0;
|
|
40833
40952
|
for (const line of content.split(`
|
|
@@ -46047,7 +46166,7 @@ var KNOWLEDGE_SCHEMA_VERSION = 2;
|
|
|
46047
46166
|
// src/hooks/knowledge-migrator.ts
|
|
46048
46167
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
46049
46168
|
import { existsSync as existsSync19, readFileSync as readFileSync13 } from "fs";
|
|
46050
|
-
import { mkdir as mkdir8, readFile as
|
|
46169
|
+
import { mkdir as mkdir8, readFile as readFile10, writeFile as writeFile7 } from "fs/promises";
|
|
46051
46170
|
import * as path29 from "path";
|
|
46052
46171
|
async function migrateKnowledgeToExternal(_directory, _config) {
|
|
46053
46172
|
return {
|
|
@@ -46080,7 +46199,7 @@ async function migrateContextToKnowledge(directory, config3) {
|
|
|
46080
46199
|
skippedReason: "no-context-file"
|
|
46081
46200
|
};
|
|
46082
46201
|
}
|
|
46083
|
-
const contextContent = await
|
|
46202
|
+
const contextContent = await readFile10(contextPath, "utf-8");
|
|
46084
46203
|
if (contextContent.trim().length === 0) {
|
|
46085
46204
|
return {
|
|
46086
46205
|
migrated: false,
|
|
@@ -47329,7 +47448,7 @@ import { existsSync as existsSync20 } from "fs";
|
|
|
47329
47448
|
import {
|
|
47330
47449
|
appendFile as appendFile5,
|
|
47331
47450
|
mkdir as mkdir9,
|
|
47332
|
-
readFile as
|
|
47451
|
+
readFile as readFile11,
|
|
47333
47452
|
rename as rename6,
|
|
47334
47453
|
writeFile as writeFile8
|
|
47335
47454
|
} from "fs/promises";
|
|
@@ -47678,7 +47797,7 @@ function validateLoadedProposals(values, config3) {
|
|
|
47678
47797
|
async function readJsonl(filePath) {
|
|
47679
47798
|
if (!existsSync20(filePath))
|
|
47680
47799
|
return [];
|
|
47681
|
-
const content = await
|
|
47800
|
+
const content = await readFile11(filePath, "utf-8");
|
|
47682
47801
|
const records = [];
|
|
47683
47802
|
for (const line of content.split(`
|
|
47684
47803
|
`)) {
|
|
@@ -47763,7 +47882,7 @@ var init_prompt_block = __esm(() => {
|
|
|
47763
47882
|
|
|
47764
47883
|
// src/memory/jsonl-migration.ts
|
|
47765
47884
|
import { existsSync as existsSync21 } from "fs";
|
|
47766
|
-
import { copyFile, mkdir as mkdir10, readFile as
|
|
47885
|
+
import { copyFile, mkdir as mkdir10, readFile as readFile12, stat as stat3, writeFile as writeFile9 } from "fs/promises";
|
|
47767
47886
|
import * as path31 from "path";
|
|
47768
47887
|
function resolveMemoryStorageDir(rootDirectory, config3 = {}) {
|
|
47769
47888
|
const resolved = resolveConfig(config3);
|
|
@@ -47827,7 +47946,7 @@ async function readMigrationReport(rootDirectory, config3 = {}) {
|
|
|
47827
47946
|
if (!existsSync21(reportPath))
|
|
47828
47947
|
return null;
|
|
47829
47948
|
try {
|
|
47830
|
-
return JSON.parse(await
|
|
47949
|
+
return JSON.parse(await readFile12(reportPath, "utf-8"));
|
|
47831
47950
|
} catch {
|
|
47832
47951
|
return null;
|
|
47833
47952
|
}
|
|
@@ -47928,7 +48047,7 @@ async function readJsonlRows(filePath) {
|
|
|
47928
48047
|
if (!existsSync21(filePath)) {
|
|
47929
48048
|
return { rows: [], invalidRows: [], totalRows: 0 };
|
|
47930
48049
|
}
|
|
47931
|
-
const content = await
|
|
48050
|
+
const content = await readFile12(filePath, "utf-8");
|
|
47932
48051
|
const rows = [];
|
|
47933
48052
|
const invalidRows = [];
|
|
47934
48053
|
let totalRows = 0;
|
package/dist/config/schema.d.ts
CHANGED
|
@@ -93,6 +93,8 @@ export declare const HooksConfigSchema: z.ZodObject<{
|
|
|
93
93
|
agent_awareness_max_chars: z.ZodDefault<z.ZodNumber>;
|
|
94
94
|
delegation_gate: z.ZodDefault<z.ZodBoolean>;
|
|
95
95
|
delegation_max_chars: z.ZodDefault<z.ZodNumber>;
|
|
96
|
+
background_subagents: z.ZodDefault<z.ZodBoolean>;
|
|
97
|
+
background_pending_timeout_minutes: z.ZodDefault<z.ZodNumber>;
|
|
96
98
|
}, z.core.$strip>;
|
|
97
99
|
export type HooksConfig = z.infer<typeof HooksConfigSchema>;
|
|
98
100
|
export declare const ScoringWeightsSchema: z.ZodObject<{
|
|
@@ -958,6 +960,8 @@ export declare const PluginConfigSchema: z.ZodObject<{
|
|
|
958
960
|
agent_awareness_max_chars: z.ZodDefault<z.ZodNumber>;
|
|
959
961
|
delegation_gate: z.ZodDefault<z.ZodBoolean>;
|
|
960
962
|
delegation_max_chars: z.ZodDefault<z.ZodNumber>;
|
|
963
|
+
background_subagents: z.ZodDefault<z.ZodBoolean>;
|
|
964
|
+
background_pending_timeout_minutes: z.ZodDefault<z.ZodNumber>;
|
|
961
965
|
}, z.core.$strip>>;
|
|
962
966
|
gates: z.ZodOptional<z.ZodObject<{
|
|
963
967
|
syntax_check: z.ZodDefault<z.ZodObject<{
|