opencode-swarm 7.130.2 → 7.132.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/README.md +2 -2
- package/dist/cli/{config-doctor-489wej17.js → config-doctor-3rssa871.js} +2 -2
- package/dist/cli/{curation-policy-aaz0hap6.js → curation-policy-3914h3g9.js} +2 -2
- package/dist/cli/{curator-s2ynewsr.js → curator-1e77dq6x.js} +13 -13
- package/dist/cli/{curator-llm-factory-mxjcctn8.js → curator-llm-factory-41c17ybs.js} +13 -13
- package/dist/cli/{evidence-summary-service-hf7qq777.js → evidence-summary-service-jfagmvrh.js} +1 -1
- package/dist/cli/{guardrail-explain-s85kv81r.js → guardrail-explain-624brj1y.js} +14 -14
- package/dist/cli/{guardrail-log-2cejc33f.js → guardrail-log-vfka4tcn.js} +3 -3
- package/dist/cli/{hive-promoter-qdgxajht.js → hive-promoter-mw5prfy2.js} +13 -13
- package/dist/cli/{index-kzvwb2se.js → index-03zyn94g.js} +110 -85
- package/dist/cli/{index-xa29259t.js → index-2dtwjx39.js} +1 -1
- package/dist/cli/{index-5xxgeksy.js → index-5x3g1q91.js} +50 -2
- package/dist/cli/{index-zft4hp35.js → index-64z5dvam.js} +1 -1
- package/dist/cli/{index-ts9wh1ba.js → index-6mcx76j9.js} +60 -8
- package/dist/cli/{index-etdgtk3m.js → index-8w3sp149.js} +3502 -1947
- package/dist/cli/{index-6fqj8fcp.js → index-99tq1zd5.js} +2 -2
- package/dist/cli/{index-jvyn76xe.js → index-e630fw43.js} +3 -3
- package/dist/cli/{index-nr5pr54q.js → index-exs5bt14.js} +1 -1
- package/dist/cli/{index-hjar4crm.js → index-fegng5pv.js} +1 -1
- package/dist/cli/{index-jxha73tm.js → index-nsxchdx0.js} +1 -1
- package/dist/cli/{index-3rnkyb60.js → index-ppkp20fp.js} +5 -5
- package/dist/cli/{index-p6qgjkbt.js → index-q0ysv66x.js} +9 -1
- package/dist/cli/{index-jvwkxz8q.js → index-qg1cj1ev.js} +15 -15
- package/dist/cli/{index-s8h2cedv.js → index-sbq3gbjs.js} +1 -1
- package/dist/cli/{index-wy3q73j2.js → index-zah4qws8.js} +18 -14
- package/dist/cli/{index-agte9w1e.js → index-zrh07ykv.js} +2 -2
- package/dist/cli/index.js +13 -13
- package/dist/cli/{knowledge-escalator-1ypz0266.js → knowledge-escalator-5hv2dwhz.js} +3 -3
- package/dist/cli/{knowledge-events-yvcczmja.js → knowledge-events-434663dp.js} +1 -1
- package/dist/cli/{knowledge-store-h8bp9eje.js → knowledge-store-73ykq5j3.js} +3 -1
- package/dist/cli/{knowledge-validator-sz9v1fdq.js → knowledge-validator-tnadtt1h.js} +4 -4
- package/dist/cli/{scan-cursor-k9zyt374.js → scan-cursor-e33n9pej.js} +2 -2
- package/dist/cli/{schema-fkpn2r1s.js → schema-1kwmcayk.js} +5 -1
- package/dist/cli/{skill-generator-a6a9jxfd.js → skill-generator-k111qfdw.js} +5 -5
- package/dist/commands/consolidate.d.ts +14 -0
- package/dist/commands/curate.d.ts +2 -0
- package/dist/commands/promote.d.ts +25 -0
- package/dist/commands/registry.d.ts +2 -2
- package/dist/config/schema.d.ts +101 -0
- package/dist/consensus/contracts.d.ts +479 -0
- package/dist/consensus/corpus.d.ts +261 -0
- package/dist/consensus/miner.d.ts +200 -0
- package/dist/consensus/public-api.d.ts +42 -0
- package/dist/consensus/store.d.ts +119 -0
- package/dist/evidence/immutable-store.d.ts +86 -0
- package/dist/evidence/manager.d.ts +31 -1
- package/dist/hooks/actionability-predicate.d.ts +36 -0
- package/dist/hooks/curator.d.ts +3 -0
- package/dist/hooks/hive-policy.d.ts +11 -0
- package/dist/hooks/hive-promoter.d.ts +27 -1
- package/dist/hooks/knowledge-dedup-sweep.d.ts +145 -0
- package/dist/hooks/knowledge-injector.d.ts +4 -0
- package/dist/hooks/knowledge-store.d.ts +26 -0
- package/dist/hooks/knowledge-types.d.ts +6 -0
- package/dist/hooks/knowledge-validator.d.ts +10 -14
- package/dist/hooks/micro-reflector.d.ts +106 -2
- package/dist/hooks/realtime-learning-nudge.d.ts +19 -0
- package/dist/index.js +464 -456
- package/dist/knowledge/entry-merge.d.ts +112 -0
- package/dist/knowledge/family-migration.d.ts +6 -2
- package/dist/learning/admission.d.ts +154 -0
- package/dist/learning/candidate-queue.d.ts +178 -0
- package/dist/learning/fingerprint.d.ts +56 -0
- package/dist/learning/prm-pattern-support.d.ts +124 -0
- package/dist/learning/provenance.d.ts +86 -0
- package/dist/parallel/index.d.ts +0 -2
- package/dist/plan/parallel-verdict.d.ts +94 -0
- package/dist/prm/index.d.ts +46 -1
- package/dist/services/recommendation-ledger.d.ts +266 -0
- package/dist/services/skill-improver.d.ts +4 -0
- package/dist/services/status-service.d.ts +27 -0
- package/dist/services/trajectory-cluster.d.ts +65 -2
- package/dist/tools/consensus-mine.d.ts +172 -0
- package/dist/tools/index.d.ts +2 -0
- package/dist/tools/knowledge-add.d.ts +34 -0
- package/dist/tools/lean-turbo-run-phase.d.ts +7 -0
- package/dist/tools/manifest.d.ts +2 -0
- package/dist/tools/plan-conflict-check.d.ts +61 -0
- package/dist/tools/tool-metadata.d.ts +8 -0
- package/dist/turbo/lean/recovery.d.ts +90 -0
- package/dist/turbo/lean/runner.d.ts +16 -1
- package/dist/worktree/merge.d.ts +5 -0
- package/package.json +1 -1
- package/dist/parallel/dependency-graph.d.ts +0 -34
- package/dist/parallel/meta-indexer.d.ts +0 -32
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
* Read-only over the knowledge store; writes only proposal markdown (never
|
|
17
17
|
* active skills). Fail-open.
|
|
18
18
|
*/
|
|
19
|
+
import { checkRecommendations, recordEmittedRecommendations } from './recommendation-ledger.js';
|
|
19
20
|
/** Trajectories scanned per macro pass (the plan's N=200 window). */
|
|
20
21
|
export declare const MACRO_TRAJECTORY_WINDOW = 200;
|
|
21
22
|
/** A motif must recur across at least this many distinct tasks to propose. */
|
|
@@ -36,11 +37,31 @@ export declare function gatherFailureMotifs(directory: string, opts?: {
|
|
|
36
37
|
window?: number;
|
|
37
38
|
minTasks?: number;
|
|
38
39
|
}): Promise<FailureMotif[]>;
|
|
40
|
+
/**
|
|
41
|
+
* The recommendation a failure motif asserts, in cross-producer form
|
|
42
|
+
* (issue #1821 AC21).
|
|
43
|
+
*
|
|
44
|
+
* The agent role is folded into the *statement* rather than carried as a scope
|
|
45
|
+
* key so this statement can collide with an equivalent lesson proposed by the
|
|
46
|
+
* curator or the consensus miner — the whole point of a shared identity. The
|
|
47
|
+
* motif signature's constituents (tool, failure kind) are what actually vary
|
|
48
|
+
* between motifs, so two distinct motifs never produce the same statement.
|
|
49
|
+
*/
|
|
50
|
+
declare function motifStatement(motif: FailureMotif): string;
|
|
39
51
|
/** Render a draft SKILL.md proposal body for a motif (with full provenance). */
|
|
40
|
-
export declare function buildMotifProposal(motif: FailureMotif
|
|
52
|
+
export declare function buildMotifProposal(motif: FailureMotif, options?: {
|
|
53
|
+
fingerprint?: string;
|
|
54
|
+
producedAt?: string;
|
|
55
|
+
}): string;
|
|
41
56
|
export interface MotifProposalResult {
|
|
42
57
|
motifs: number;
|
|
43
58
|
proposalsWritten: string[];
|
|
59
|
+
/**
|
|
60
|
+
* #1821 AC21: motifs whose recommendation was already emitted — by an earlier
|
|
61
|
+
* improver run, the curator sweep, or the consensus miner — and were therefore
|
|
62
|
+
* not re-proposed.
|
|
63
|
+
*/
|
|
64
|
+
duplicatesSuppressed: number;
|
|
44
65
|
}
|
|
45
66
|
/**
|
|
46
67
|
* Run the macro motif pass and write one proposal per recurring motif. Returns
|
|
@@ -50,6 +71,8 @@ export declare function writeMotifProposals(directory: string, opts?: {
|
|
|
50
71
|
window?: number;
|
|
51
72
|
minTasks?: number;
|
|
52
73
|
maxProposals?: number;
|
|
74
|
+
/** Recorded in the ledger entry's provenance write origin. */
|
|
75
|
+
sessionId?: string;
|
|
53
76
|
}): Promise<MotifProposalResult>;
|
|
54
77
|
/** Minimum number of steps in a trajectory for it to qualify as a workflow. */
|
|
55
78
|
export declare const SUCCESS_SEQUENCE_MIN_STEPS = 3;
|
|
@@ -66,16 +89,56 @@ export interface SuccessMotif {
|
|
|
66
89
|
export interface SuccessMotifProposalResult {
|
|
67
90
|
motifs: number;
|
|
68
91
|
proposalsWritten: string[];
|
|
92
|
+
/** #1821 AC21: see `MotifProposalResult.duplicatesSuppressed`. */
|
|
93
|
+
duplicatesSuppressed: number;
|
|
69
94
|
}
|
|
70
95
|
export declare function gatherSuccessMotifs(directory: string, opts?: {
|
|
71
96
|
window?: number;
|
|
72
97
|
minTasks?: number;
|
|
73
98
|
minSteps?: number;
|
|
74
99
|
}): Promise<SuccessMotif[]>;
|
|
75
|
-
|
|
100
|
+
/**
|
|
101
|
+
* The recommendation a success motif asserts, in cross-producer form
|
|
102
|
+
* (issue #1821 AC21). Same agent-in-statement rationale as `motifStatement`.
|
|
103
|
+
*
|
|
104
|
+
* The rendered sequence MUST mirror `sequenceSignature` (`tool:action` per
|
|
105
|
+
* step), not just the tool names: two motifs that share a tool chain but differ
|
|
106
|
+
* in actions have different signatures, different slugs, and different proposal
|
|
107
|
+
* files, so a tool-only statement would collapse two genuinely different
|
|
108
|
+
* workflows onto one cross key and suppress the second.
|
|
109
|
+
*/
|
|
110
|
+
declare function workflowStatement(motif: SuccessMotif): string;
|
|
111
|
+
export declare function buildWorkflowProposal(motif: SuccessMotif, options?: {
|
|
112
|
+
fingerprint?: string;
|
|
113
|
+
producedAt?: string;
|
|
114
|
+
}): string;
|
|
76
115
|
export declare function writeSuccessMotifProposals(directory: string, opts?: {
|
|
77
116
|
window?: number;
|
|
78
117
|
minTasks?: number;
|
|
79
118
|
minSteps?: number;
|
|
80
119
|
maxProposals?: number;
|
|
120
|
+
/** Recorded in the ledger entry's provenance write origin. */
|
|
121
|
+
sessionId?: string;
|
|
81
122
|
}): Promise<SuccessMotifProposalResult>;
|
|
123
|
+
/**
|
|
124
|
+
* DI seam (AGENTS.md invariant 7). `now` pins the shared `producedAt` that the
|
|
125
|
+
* ledger entry and the proposal frontmatter both carry; the two ledger functions
|
|
126
|
+
* let a test exercise the suppressed / degraded branches without touching the
|
|
127
|
+
* real ledger. Restore each entry in `afterEach`.
|
|
128
|
+
*/
|
|
129
|
+
export declare const _internals: {
|
|
130
|
+
now: () => Date;
|
|
131
|
+
checkRecommendations: typeof checkRecommendations;
|
|
132
|
+
recordEmittedRecommendations: typeof recordEmittedRecommendations;
|
|
133
|
+
};
|
|
134
|
+
/**
|
|
135
|
+
* Pure-function seam for tests (writing-tests SKILL.md, Tier 0). The two
|
|
136
|
+
* statement builders define the cross-producer identity of a motif, so a test
|
|
137
|
+
* asserting cross-producer suppression must derive the competing statement from
|
|
138
|
+
* them rather than hardcode a copy that can silently drift.
|
|
139
|
+
*/
|
|
140
|
+
export declare const _test_exports: {
|
|
141
|
+
motifStatement: typeof motifStatement;
|
|
142
|
+
workflowStatement: typeof workflowStatement;
|
|
143
|
+
};
|
|
144
|
+
export {};
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `consensus_mine` — run the consensus miner and persist its report.
|
|
3
|
+
*
|
|
4
|
+
* The tool is a thin, fully-wired shell around `src/consensus/`: it resolves the
|
|
5
|
+
* effective consensus config, assembles a `ConsensusMineRequest` from the
|
|
6
|
+
* caller's overrides, optionally supplies an LLM dispatcher, delegates to
|
|
7
|
+
* `mineAndStoreConsensusV1`, applies report retention, and renders a bounded
|
|
8
|
+
* summary.
|
|
9
|
+
*
|
|
10
|
+
* It is NOT write-minimal, and the description the model reads says so. The
|
|
11
|
+
* complete list of effects, none of which touches a project file:
|
|
12
|
+
*
|
|
13
|
+
* 1. **Its own report** under `.swarm/evolution/consensus/<reportId>.json`.
|
|
14
|
+
* 2. **Deletions of its own prior reports.** `pruneConsensusReports` runs
|
|
15
|
+
* unconditionally after every mine and `consensus.report_retention` defaults
|
|
16
|
+
* to 50, so the steady state of a long-lived project is that each run
|
|
17
|
+
* `unlink`s the oldest report. Only `report_retention: 0` disables it.
|
|
18
|
+
* 3. **The shared dedup ledger** (issue #1821 AC21). It gains one entry per
|
|
19
|
+
* emitted proposal EXCEPT where it already carries that recommendation's
|
|
20
|
+
* cross key — those are counted as `duplicate_recommendation_count` instead.
|
|
21
|
+
* The append is a whole-file rewrite with FIFO eviction at
|
|
22
|
+
* `MAX_RECOMMENDATION_LEDGER_ENTRIES`, and eviction is by position, not by
|
|
23
|
+
* producer: a miner append can evict the CURATOR's or the IMPROVER's oldest
|
|
24
|
+
* entries. The ledger normally lives at
|
|
25
|
+
* `.swarm/learning/recommendation-ledger.jsonl`, but its root is
|
|
26
|
+
* `resolveKnowledgeStoreDir`, so under a knowledge-link pointer it lands in
|
|
27
|
+
* the shared cohort root rather than this project's `.swarm/`.
|
|
28
|
+
* 4. **Lock sentinels.** The report goes through `withEvidenceLock`, whose
|
|
29
|
+
* sentinel is an empty `<sha256>.lock` file under this project's
|
|
30
|
+
* `.swarm/locks/`; `proper-lockfile` removes its own lock directory but
|
|
31
|
+
* NOTHING removes that sentinel, so each distinct report id leaves one behind
|
|
32
|
+
* permanently. The ledger goes through `transactFile`, which locks the
|
|
33
|
+
* ledger's own containing directory and therefore produces
|
|
34
|
+
* `<resolveKnowledgeStoreDir(directory)>/learning.lock` — outside this
|
|
35
|
+
* project's `.swarm/` entirely whenever a knowledge link is active.
|
|
36
|
+
* 5. **A pending memory proposal per emitted proposal**, but only when
|
|
37
|
+
* `memory.enabled` is `true` (it defaults to `false`,
|
|
38
|
+
* `src/config/schema.ts`). This is issue #1821 AC22 — "use existing
|
|
39
|
+
* proposal/MemoryRecord paths, not another inbox" — so the mirror goes
|
|
40
|
+
* through the same `MemoryGateway.propose` path `swarm_memory_propose` uses,
|
|
41
|
+
* which creates a *pending proposal* requiring curator review and never a
|
|
42
|
+
* durable memory record.
|
|
43
|
+
* 6. **Up to `MAX_LLM_SUMMARIES` (20) `session.create` + `session.prompt`
|
|
44
|
+
* calls** whenever `consensus.llm_summarization_enabled` (default `true`)
|
|
45
|
+
* finds a wired OpenCode client.
|
|
46
|
+
*
|
|
47
|
+
* Effects 2-6 were absent from the tool description for four review rounds
|
|
48
|
+
* while it claimed "its only writes are its own immutable report and one entry
|
|
49
|
+
* in the shared recommendation dedup ledger". That string is read by a model as
|
|
50
|
+
* fact and was the premise of the Full-Auto auto-allow in
|
|
51
|
+
* `src/full-auto/policy.ts`; both now state the list above.
|
|
52
|
+
*
|
|
53
|
+
* What the tool does NOT do is mutate any of the evidence it reads. That is a
|
|
54
|
+
* chosen property, not a free one:
|
|
55
|
+
* `loadEvidence` upgrades a legacy flat retrospective in place by default, so
|
|
56
|
+
* `src/consensus/corpus.ts` binds it with `{ migrate: false }`. Without that, a
|
|
57
|
+
* mining run would rewrite evidence bundles — and remap their legacy
|
|
58
|
+
* `task_complexity` values — while advertising itself as read-only.
|
|
59
|
+
*
|
|
60
|
+
* It activates no skill, writes no knowledge entry, admits no durable memory
|
|
61
|
+
* record, and touches no project file — which is why it is classified as a
|
|
62
|
+
* **pathless write-like** tool in `src/full-auto/policy.ts` alongside
|
|
63
|
+
* `write_retro` and `knowledge_add`, and why it is absent from
|
|
64
|
+
* `WRITE_TOOL_NAMES` (`src/config/constants.ts`), whose members are the tools
|
|
65
|
+
* that write PROJECT FILE CONTENTS and are therefore subject to the scope guard.
|
|
66
|
+
* The knowledge-link redirection in effects 3 and 5 does not change that
|
|
67
|
+
* classification: `knowledge_add` and `knowledge_remove` are in the same
|
|
68
|
+
* auto-allow set and have the same redirection, and it comes from operator
|
|
69
|
+
* configuration rather than from anything the caller passed.
|
|
70
|
+
*
|
|
71
|
+
* `ctx.directory` is injected by `createSwarmTool`; there is no `process.cwd()`
|
|
72
|
+
* anywhere in this file (AGENTS.md invariant 4).
|
|
73
|
+
*/
|
|
74
|
+
import type { MemoryConfig } from '../config/schema';
|
|
75
|
+
import type { ConsensusAttributeV1, ConsensusReportV1 } from '../consensus/contracts';
|
|
76
|
+
import { createMemoryGateway } from '../memory';
|
|
77
|
+
import { type RecommendationCandidate } from '../services/recommendation-ledger';
|
|
78
|
+
import { createSwarmTool } from './create-tool';
|
|
79
|
+
/**
|
|
80
|
+
* Reconcile the summary counters with what the inline echo actually shows.
|
|
81
|
+
*
|
|
82
|
+
* These are two different orderings and they do not line up. Restatements are
|
|
83
|
+
* spent on the top `MAX_LLM_SUMMARIES` attributes by CONFIDENCE
|
|
84
|
+
* (`src/consensus/miner.ts`), while the echo below is the first
|
|
85
|
+
* `MAX_INLINE_ATTRIBUTES` in canonical SIGNAL order. With confidence inverted
|
|
86
|
+
* relative to signal order, a report can print `summarized_count: 20` while zero
|
|
87
|
+
* `llm_summary` values are visible — which is exactly what "the count always
|
|
88
|
+
* agrees with the values echoed alongside it" used to claim was impossible.
|
|
89
|
+
* `hidden` is what makes the discrepancy legible instead of mysterious.
|
|
90
|
+
*/
|
|
91
|
+
declare function countSummaries(attributes: readonly ConsensusAttributeV1[], inlineLimit: number): {
|
|
92
|
+
total: number;
|
|
93
|
+
hidden: number;
|
|
94
|
+
};
|
|
95
|
+
/**
|
|
96
|
+
* Describe the miner's emissions to the cross-producer dedup ledger
|
|
97
|
+
* (issue #1821 AC21).
|
|
98
|
+
*
|
|
99
|
+
* The statement is the proposal's `intent` — the sentence the miner actually
|
|
100
|
+
* emits — not the internal attribute statement its own `lrec_` fingerprint is
|
|
101
|
+
* built from: only the intent survives onto the persisted report, and it is the
|
|
102
|
+
* text a human reads as "the recommendation". `scopeKeys` stays empty for the
|
|
103
|
+
* same reason the curator's new-knowledge recommendations carry none: content
|
|
104
|
+
* alone is the identity of a freshly-minted lesson, and that is exactly where
|
|
105
|
+
* another producer can legitimately be proposing the same thing.
|
|
106
|
+
*/
|
|
107
|
+
declare function buildMinerRecommendationCandidates(report: Pick<ConsensusReportV1, 'proposals' | 'generatedAt'>, sessionId?: string): RecommendationCandidate[];
|
|
108
|
+
/**
|
|
109
|
+
* What the AC22 memory mirror actually did, reported rather than assumed.
|
|
110
|
+
*
|
|
111
|
+
* `attempted` is 0 whenever `enabled` is false, so a reader can tell "memory is
|
|
112
|
+
* off" from "memory is on and nothing was proposed". `failed` and `error` exist
|
|
113
|
+
* because the mirror is deliberately fail-open — the report is already durably
|
|
114
|
+
* written by the time it runs, and losing the whole mine to a memory-store
|
|
115
|
+
* problem would be worse than losing the mirror — but a fail-open path that
|
|
116
|
+
* reports nothing is exactly the defect `recommendation_ledger.degraded` was
|
|
117
|
+
* added to close.
|
|
118
|
+
*/
|
|
119
|
+
type MemoryMirrorResult = {
|
|
120
|
+
enabled: boolean;
|
|
121
|
+
attempted: number;
|
|
122
|
+
proposed: number;
|
|
123
|
+
rejected: number;
|
|
124
|
+
failed: number;
|
|
125
|
+
error?: string;
|
|
126
|
+
};
|
|
127
|
+
/**
|
|
128
|
+
* Issue #1821 AC22: mirror each emitted proposal into the EXISTING memory
|
|
129
|
+
* proposal path rather than leaving the consensus report as a write-only inbox.
|
|
130
|
+
*
|
|
131
|
+
* `MemoryGateway.propose` is the same entry point `swarm_memory_propose` uses
|
|
132
|
+
* (`src/tools/swarm-memory-propose.ts`), including its `dispose()` in a
|
|
133
|
+
* `finally`. It creates a PENDING proposal — curator review is still required,
|
|
134
|
+
* nothing durable is admitted — which is why the tool's proposals-only guarantee
|
|
135
|
+
* survives the mirror.
|
|
136
|
+
*
|
|
137
|
+
* Fail-open by design and per-proposal: one rejected or throwing proposal must
|
|
138
|
+
* not discard the ones that succeeded, and none of it can unwrite the report.
|
|
139
|
+
* Every outcome is counted and returned, so the tool's response says what
|
|
140
|
+
* happened instead of implying success.
|
|
141
|
+
*/
|
|
142
|
+
declare function mirrorProposalsToMemory(options: {
|
|
143
|
+
directory: string;
|
|
144
|
+
memoryConfig: MemoryConfig | undefined;
|
|
145
|
+
report: Pick<ConsensusReportV1, 'proposals' | 'reportId'>;
|
|
146
|
+
sessionId?: string;
|
|
147
|
+
}): Promise<MemoryMirrorResult>;
|
|
148
|
+
/**
|
|
149
|
+
* DI seam (AGENTS.md invariant 7). Lets a test drive the AC22 mirror's
|
|
150
|
+
* failure and rejection branches without a real provider and without
|
|
151
|
+
* `mock.module`. Restore each entry in `afterEach`.
|
|
152
|
+
*/
|
|
153
|
+
export declare const _internals: {
|
|
154
|
+
createMemoryGateway: typeof createMemoryGateway;
|
|
155
|
+
};
|
|
156
|
+
/**
|
|
157
|
+
* Pure-function seam for tests (writing-tests SKILL.md, Tier 0). Exported so a
|
|
158
|
+
* cross-producer dedup test can build the miner's ledger candidates through the
|
|
159
|
+
* same code the tool runs instead of restating the mapping, and so the
|
|
160
|
+
* summary-counter reconciliation can be asserted at the ordering that produces
|
|
161
|
+
* it — 20 summarized attributes with none visible — rather than only at the
|
|
162
|
+
* degenerate all-zero case a dispatcher-less run reaches.
|
|
163
|
+
*/
|
|
164
|
+
export declare const _test_exports: {
|
|
165
|
+
buildMinerRecommendationCandidates: typeof buildMinerRecommendationCandidates;
|
|
166
|
+
countSummaries: typeof countSummaries;
|
|
167
|
+
mirrorProposalsToMemory: typeof mirrorProposalsToMemory;
|
|
168
|
+
MAX_INLINE_ATTRIBUTES: number;
|
|
169
|
+
MIRRORED_PROPOSAL_KIND: "todo";
|
|
170
|
+
};
|
|
171
|
+
export declare const consensus_mine: ReturnType<typeof createSwarmTool>;
|
|
172
|
+
export {};
|
package/dist/tools/index.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export { checkpoint } from './checkpoint';
|
|
|
10
10
|
export { co_change_analyzer } from './co-change-analyzer';
|
|
11
11
|
export { completion_verify } from './completion-verify';
|
|
12
12
|
export { complexity_hotspots } from './complexity-hotspots';
|
|
13
|
+
export { consensus_mine } from './consensus-mine';
|
|
13
14
|
export { context_status } from './context-status';
|
|
14
15
|
export { submit_council_verdicts } from './convene-council';
|
|
15
16
|
export { convene_general_council } from './convene-general-council';
|
|
@@ -48,6 +49,7 @@ export { parse_lane_candidates } from './parse-lane-candidates';
|
|
|
48
49
|
export { phase_complete } from './phase-complete';
|
|
49
50
|
export { pkg_audit } from './pkg-audit';
|
|
50
51
|
export { type PlaceholderFinding, type PlaceholderScanInput, type PlaceholderScanResult, placeholder_scan, placeholderScan, } from './placeholder-scan';
|
|
52
|
+
export { plan_conflict_check } from './plan-conflict-check';
|
|
51
53
|
export { pr_workflow_status } from './pr-workflow-status';
|
|
52
54
|
export { type PreCheckBatchInput, type PreCheckBatchResult, pre_check_batch, runPreCheckBatch, type ToolResult, } from './pre-check-batch';
|
|
53
55
|
export { executePreparePrFeedbackScope, prepare_pr_feedback_scope, } from './prepare-pr-feedback-scope';
|
|
@@ -1,2 +1,36 @@
|
|
|
1
1
|
import { createSwarmTool } from './create-tool.js';
|
|
2
|
+
/**
|
|
3
|
+
* Merge caller-supplied tags with the tags inferred from the lesson.
|
|
4
|
+
*
|
|
5
|
+
* Caller tags come FIRST so that when the combined list exceeds the cap,
|
|
6
|
+
* truncation drops inferred tags before it drops user intent. `dedupeCapped`
|
|
7
|
+
* is case-insensitive (first casing wins), so an inferred tag the caller
|
|
8
|
+
* already supplied collapses into the caller's casing instead of duplicating.
|
|
9
|
+
*
|
|
10
|
+
* Hoisted to module scope and exposed via `_test_exports` so this call site is
|
|
11
|
+
* observable on its own: the store write boundary normalizes the same fields,
|
|
12
|
+
* which would otherwise mask a regression here (issue #1821 Lane 0b).
|
|
13
|
+
*/
|
|
14
|
+
declare function mergeLessonTags(tagsInput: unknown, lesson: string): string[];
|
|
15
|
+
/**
|
|
16
|
+
* Normalize one optional v3 actionability array from untrusted tool input.
|
|
17
|
+
*
|
|
18
|
+
* The `undefined` return is load-bearing: `validateActionableFields` and
|
|
19
|
+
* `validateActionability` distinguish an ABSENT field from an empty one, and
|
|
20
|
+
* JSON.stringify drops an `undefined` value so the persisted record keeps that
|
|
21
|
+
* distinction. Only the inner filter+cap is `dedupeCapped` (#1821 Lane 0b).
|
|
22
|
+
*/
|
|
23
|
+
declare function strArray(v: unknown): string[] | undefined;
|
|
2
24
|
export declare const knowledge_add: ReturnType<typeof createSwarmTool>;
|
|
25
|
+
/**
|
|
26
|
+
* Tier-0 test seam (issue #1821 Lane 0b). These are pure functions with no I/O.
|
|
27
|
+
* They are exported so the call-site normalization can be asserted directly:
|
|
28
|
+
* the store write boundary normalizes the same fields with the same semantics,
|
|
29
|
+
* so an assertion made against a PERSISTED entry cannot distinguish "call site
|
|
30
|
+
* fixed" from "call site reverted".
|
|
31
|
+
*/
|
|
32
|
+
export declare const _test_exports: {
|
|
33
|
+
mergeLessonTags: typeof mergeLessonTags;
|
|
34
|
+
strArray: typeof strArray;
|
|
35
|
+
};
|
|
36
|
+
export {};
|
|
@@ -6,6 +6,7 @@ import type { ToolDefinition } from '@opencode-ai/plugin/tool';
|
|
|
6
6
|
import { loadPluginConfigWithMeta as loadPluginConfigWithMeta_import } from '../config';
|
|
7
7
|
import type { LaneResult, MergeBackFailureInfo } from '../turbo/lean/runner';
|
|
8
8
|
import { LeanTurboRunner as LeanTurboRunner_import } from '../turbo/lean/runner';
|
|
9
|
+
import type { LeanTurboDegradedTask } from '../turbo/lean/state';
|
|
9
10
|
/**
|
|
10
11
|
* Arguments for the lean_turbo_run_phase tool
|
|
11
12
|
*/
|
|
@@ -21,6 +22,12 @@ export interface LeanTurboRunPhaseResult {
|
|
|
21
22
|
success: boolean;
|
|
22
23
|
lanes?: LaneResult[];
|
|
23
24
|
degradedTasks?: string[];
|
|
25
|
+
/**
|
|
26
|
+
* #1657: full degraded-task details (reason/files/requiredMode), additive
|
|
27
|
+
* alongside `degradedTasks`. Lets the architect see per-task degradation
|
|
28
|
+
* reasons in the tool result without reading /swarm status separately.
|
|
29
|
+
*/
|
|
30
|
+
degradedDetails?: LeanTurboDegradedTask[];
|
|
24
31
|
serializedTasks?: string[];
|
|
25
32
|
mergeBackFailures?: MergeBackFailureInfo[];
|
|
26
33
|
reason?: string;
|
package/dist/tools/manifest.d.ts
CHANGED
|
@@ -53,6 +53,7 @@ export declare const TOOL_MANIFEST: {
|
|
|
53
53
|
checkpoint: () => ToolDefinition;
|
|
54
54
|
pkg_audit: () => ToolDefinition;
|
|
55
55
|
parse_lane_candidates: () => ToolDefinition;
|
|
56
|
+
plan_conflict_check: () => ToolDefinition;
|
|
56
57
|
prepare_pr_feedback_scope: () => ToolDefinition;
|
|
57
58
|
write_pr_review_artifact: () => ToolDefinition;
|
|
58
59
|
write_pr_review_trigger_eval: () => ToolDefinition;
|
|
@@ -79,6 +80,7 @@ export declare const TOOL_MANIFEST: {
|
|
|
79
80
|
doc_scan: () => ToolDefinition;
|
|
80
81
|
doc_extract: () => ToolDefinition;
|
|
81
82
|
curator_analyze: () => ToolDefinition;
|
|
83
|
+
consensus_mine: () => ToolDefinition;
|
|
82
84
|
knowledge_add: () => ToolDefinition;
|
|
83
85
|
knowledge_recall: () => ToolDefinition;
|
|
84
86
|
knowledge_remove: () => ToolDefinition;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `plan_conflict_check` tool (#1656 — v8 parallel-first execution prerequisite).
|
|
3
|
+
*
|
|
4
|
+
* Read-only advisory: compute a pairwise file-conflict matrix for N proposed
|
|
5
|
+
* parallel task groups using declared scopes (and optional git co-change),
|
|
6
|
+
* returning a verdict and suggested serialization order.
|
|
7
|
+
*
|
|
8
|
+
* READ-ONLY CONTRACT (issue #1656 acceptance): this tool writes NOTHING — not
|
|
9
|
+
* to `.swarm/`, not to the source tree. It calls no other tools. The only I/O
|
|
10
|
+
* is reading `.swarm/plan.json` (via `loadPlanJsonOnly`) and
|
|
11
|
+
* `.swarm/scopes/scope-<taskId>.json` (via `readTaskScopes` inside
|
|
12
|
+
* `computeParallelVerdict`), plus an optional `git log` (only when the caller
|
|
13
|
+
* opts in via `use_cochange: true`).
|
|
14
|
+
*
|
|
15
|
+
* Why this tool exists alongside the gate: the gate (`delegation-gate.ts`)
|
|
16
|
+
* independently recomputes the verdict INLINE at coder-dispatch time via the
|
|
17
|
+
* same shared `computeParallelVerdict` helper. The tool gives the architect a
|
|
18
|
+
* way to inspect the conflict matrix BEFORE attempting parallel dispatch, so it
|
|
19
|
+
* can choose disjoint task groups and understand why the gate will (or won't)
|
|
20
|
+
* permit parallelism. Single source of truth (the helper), two call sites.
|
|
21
|
+
*/
|
|
22
|
+
import type { tool } from '@opencode-ai/plugin';
|
|
23
|
+
import { z } from 'zod';
|
|
24
|
+
export declare const plan_conflict_check_args: {
|
|
25
|
+
task_ids: z.ZodArray<z.ZodString>;
|
|
26
|
+
use_cochange: z.ZodOptional<z.ZodBoolean>;
|
|
27
|
+
phase_id: z.ZodOptional<z.ZodString>;
|
|
28
|
+
};
|
|
29
|
+
export interface PlanConflictCheckResult {
|
|
30
|
+
/** Summary verdict. `all_disjoint` ⇒ safe to parallelize. */
|
|
31
|
+
verdict: 'all_disjoint' | 'conflicts_present' | 'unknown_scopes';
|
|
32
|
+
/** Pairwise results. */
|
|
33
|
+
pairs: Array<{
|
|
34
|
+
a: string;
|
|
35
|
+
b: string;
|
|
36
|
+
verdict: 'conflict' | 'disjoint' | 'unknown';
|
|
37
|
+
evidence: string[];
|
|
38
|
+
}>;
|
|
39
|
+
/** Suggested serialization order (topological sort over the conflict graph). */
|
|
40
|
+
suggested_serial_order: string[];
|
|
41
|
+
/** Tasks whose declared scope could not be resolved. */
|
|
42
|
+
unknown_scope_tasks: string[];
|
|
43
|
+
/** Whether co-change signal was used. */
|
|
44
|
+
used_cochange: boolean;
|
|
45
|
+
/** Diagnostic: did plan.json load successfully? */
|
|
46
|
+
plan_loaded: boolean;
|
|
47
|
+
/** Task ids requested by the caller but absent from the loaded plan. */
|
|
48
|
+
unknown_to_plan?: string[];
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Pure executor (no createSwarmTool wrapper) so it is directly unit-testable.
|
|
52
|
+
*
|
|
53
|
+
* Reads `.swarm/plan.json` (to confirm the task ids exist) and
|
|
54
|
+
* `.swarm/scopes/scope-*.json` (via `computeParallelVerdict`). Writes nothing.
|
|
55
|
+
*/
|
|
56
|
+
export declare function executePlanConflictCheck(args: {
|
|
57
|
+
task_ids: string[];
|
|
58
|
+
use_cochange?: boolean;
|
|
59
|
+
phase_id?: string;
|
|
60
|
+
}, directory: string): Promise<PlanConflictCheckResult>;
|
|
61
|
+
export declare const plan_conflict_check: ReturnType<typeof tool>;
|
|
@@ -196,6 +196,10 @@ export declare const TOOL_METADATA: {
|
|
|
196
196
|
description: string;
|
|
197
197
|
agents: "architect"[];
|
|
198
198
|
};
|
|
199
|
+
plan_conflict_check: {
|
|
200
|
+
description: string;
|
|
201
|
+
agents: "architect"[];
|
|
202
|
+
};
|
|
199
203
|
write_pr_review_trigger_eval: {
|
|
200
204
|
description: string;
|
|
201
205
|
agents: "architect"[];
|
|
@@ -320,6 +324,10 @@ export declare const TOOL_METADATA: {
|
|
|
320
324
|
description: string;
|
|
321
325
|
agents: "architect"[];
|
|
322
326
|
};
|
|
327
|
+
consensus_mine: {
|
|
328
|
+
description: string;
|
|
329
|
+
agents: ("architect" | "curator_phase" | "curator_postmortem")[];
|
|
330
|
+
};
|
|
323
331
|
knowledge_add: {
|
|
324
332
|
description: string;
|
|
325
333
|
agents: ("coder" | "architect")[];
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Durable merge-back conflict recovery records (#1657).
|
|
3
|
+
*
|
|
4
|
+
* When a lean-turbo lane's merge-back fails (conflict / partial / error), the
|
|
5
|
+
* runner preserves the lane's worktree + branch for manual recovery but —
|
|
6
|
+
* before this module — that information lived only in:
|
|
7
|
+
* - the in-memory `LeanTurboLane` state (lost when the session ends), and
|
|
8
|
+
* - a scrolled-away log line.
|
|
9
|
+
*
|
|
10
|
+
* Problem #1: `cleanupOrphanedBranches` (`src/worktree/merge.ts`) force-deletes
|
|
11
|
+
* any lane branch whose session isn't active, including a branch just preserved
|
|
12
|
+
* for recovery. The only copy of unmerged lane work could be deleted by routine
|
|
13
|
+
* init-time cleanup before a human ever sees the recovery message.
|
|
14
|
+
*
|
|
15
|
+
* Problem #2: `/swarm status` had no concept of preserved worktrees, so the
|
|
16
|
+
* architect was blind to pending recovery work unless it re-read the tool
|
|
17
|
+
* result inline.
|
|
18
|
+
*
|
|
19
|
+
* This module writes a durable record under `.swarm/recovery/` on every
|
|
20
|
+
* merge-back failure, lets `cleanupOrphanedBranches` EXEMPT recovery branches
|
|
21
|
+
* (fail-safe on read error), and lets `/swarm status` surface them. Records are
|
|
22
|
+
* auto-cleared when the lane later merges back successfully (no accumulation).
|
|
23
|
+
*
|
|
24
|
+
* Records live ONLY under `.swarm/recovery/` (AGENTS.md invariant 4 — `.swarm/`
|
|
25
|
+
* containment). They are intentionally NOT part of the plan ledger or
|
|
26
|
+
* turbo-state: recovery is a side-channel safety net, not authoritative plan
|
|
27
|
+
* or run state.
|
|
28
|
+
*/
|
|
29
|
+
/**
|
|
30
|
+
* A durable merge-back recovery record. Mirrors `MergeBackFailureInfo` plus
|
|
31
|
+
* the session/bookkeeping fields needed for orphan-cleanup exemption and
|
|
32
|
+
* status surfacing.
|
|
33
|
+
*/
|
|
34
|
+
export interface RecoveryRecord {
|
|
35
|
+
/** Lane identifier (e.g. "lane-1"). */
|
|
36
|
+
laneId: string;
|
|
37
|
+
/** Session that created the record (for scoping/status). */
|
|
38
|
+
sessionId: string;
|
|
39
|
+
/** Lane branch preserved for recovery (e.g. "swarm-lane/<sid>/<laneId>"). */
|
|
40
|
+
branchName?: string;
|
|
41
|
+
/** Lane worktree filesystem path preserved for recovery. */
|
|
42
|
+
worktreePath: string;
|
|
43
|
+
/** Merge-back failure class. */
|
|
44
|
+
status: 'failed' | 'partial' | 'conflict';
|
|
45
|
+
/** Human-readable reason for the merge-back failure. */
|
|
46
|
+
reason: string;
|
|
47
|
+
/** Conflict files (when status === 'conflict'). */
|
|
48
|
+
conflictFiles?: string[];
|
|
49
|
+
/** Epoch ms when the record was written. */
|
|
50
|
+
recordedAt: number;
|
|
51
|
+
/** Portable human guidance for inspecting the preserved worktree. */
|
|
52
|
+
replayHint: string;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Write a recovery record atomically (temp file + rename, mirroring the
|
|
56
|
+
* `turbo-state.json` pattern in `src/turbo/lean/state.ts`). Best-effort:
|
|
57
|
+
* swallows errors so a recovery-write failure can never break the merge-back
|
|
58
|
+
* path that called it.
|
|
59
|
+
*/
|
|
60
|
+
export declare function writeRecoveryRecord(directory: string, record: Omit<RecoveryRecord, 'recordedAt'> & {
|
|
61
|
+
recordedAt?: number;
|
|
62
|
+
}): void;
|
|
63
|
+
/**
|
|
64
|
+
* List all recovery records under `.swarm/recovery/`. Tolerates malformed
|
|
65
|
+
* files (skips + continues). Returns `[]` if the directory is absent or
|
|
66
|
+
* unreadable.
|
|
67
|
+
*/
|
|
68
|
+
export declare function listRecoveryRecords(directory: string): RecoveryRecord[];
|
|
69
|
+
/**
|
|
70
|
+
* Fast check: does any recovery record reference the given branch name?
|
|
71
|
+
* Used by `cleanupOrphanedBranches` to exempt recovery branches. Returns
|
|
72
|
+
* `false` on any read error (the caller decides fail-open vs fail-safe —
|
|
73
|
+
* see `cleanupOrphanedBranches`).
|
|
74
|
+
*/
|
|
75
|
+
export declare function hasRecoveryRecordForBranch(directory: string, branchName: string): boolean;
|
|
76
|
+
/**
|
|
77
|
+
* Remove the recovery record for a specific lane + session. Called on
|
|
78
|
+
* SUCCESSFUL merge-back so records don't accumulate (a record exists only
|
|
79
|
+
* while a lane is in a failed/preserved state). Best-effort.
|
|
80
|
+
*/
|
|
81
|
+
export declare function clearRecoveryRecord(directory: string, laneId: string, sessionId: string): void;
|
|
82
|
+
/**
|
|
83
|
+
* Did the recovery-directory read itself throw (vs simply being empty)?
|
|
84
|
+
* `cleanupOrphanedBranches` uses this to decide fail-safe behavior: on a
|
|
85
|
+
* genuine read error it skips ALL lane-branch deletions for that pass
|
|
86
|
+
* (recovery safety trumps orphan cleanliness). Returns `true` if the
|
|
87
|
+
* directory exists but could not be read, OR if any record file exists but
|
|
88
|
+
* is unreadable.
|
|
89
|
+
*/
|
|
90
|
+
export declare function recoveryReadErrored(directory: string): boolean;
|
|
@@ -25,7 +25,7 @@ import { type ModelOverride } from '../../utils/model-dispatch-fallback';
|
|
|
25
25
|
import { writeLaneEvidence, writePhaseEvidence } from './evidence';
|
|
26
26
|
import { attemptMergeBackFromDirty, getMergeStrategy, mergeLaneBranch, postMergeCleanup, startupOrphanRecovery } from './merge-back';
|
|
27
27
|
import { planLeanTurboLanes } from './planner';
|
|
28
|
-
import type { LeanTurboLane } from './state';
|
|
28
|
+
import type { LeanTurboDegradedTask, LeanTurboLane } from './state';
|
|
29
29
|
import { loadLeanTurboRunState, saveLeanTurboRunState } from './state';
|
|
30
30
|
import { assertCleanWorkingTree, provisionWorktree, removeLaneProfileFromDiskReal, removeWorktree } from './worktree';
|
|
31
31
|
/**
|
|
@@ -152,6 +152,12 @@ export interface LeanTurboPhaseResult {
|
|
|
152
152
|
lanes: LaneResult[];
|
|
153
153
|
/** Task IDs that were degraded (risk conditions) */
|
|
154
154
|
degradedTasks: string[];
|
|
155
|
+
/**
|
|
156
|
+
* #1657: full degraded-task details (reason/files/requiredMode) so the
|
|
157
|
+
* architect sees per-task degradation reasons in the tool result, not
|
|
158
|
+
* just task IDs. Additive alongside `degradedTasks` (kept for back-compat).
|
|
159
|
+
*/
|
|
160
|
+
degradedDetails?: LeanTurboDegradedTask[];
|
|
155
161
|
/**
|
|
156
162
|
* Task IDs excluded from parallel lanes due to lock conflicts.
|
|
157
163
|
* Caller must complete these via standard serial flow before phase can advance.
|
|
@@ -323,6 +329,15 @@ export declare class LeanTurboRunner {
|
|
|
323
329
|
* the serialized tasks set for standard serial fallback.
|
|
324
330
|
*/
|
|
325
331
|
private _processLane;
|
|
332
|
+
/**
|
|
333
|
+
* Persist a durable recovery record for a merge-back / dispatch failure (#1657).
|
|
334
|
+
*
|
|
335
|
+
* Wraps `writeRecoveryRecord` (best-effort, non-fatal) with this session's
|
|
336
|
+
* id and portable human recovery guidance. Called from every failure branch of
|
|
337
|
+
* `_sequentialWorktreeCleanup`. Records are auto-cleared on successful
|
|
338
|
+
* merge-back so they exist only while a lane is preserved.
|
|
339
|
+
*/
|
|
340
|
+
private _persistRecovery;
|
|
326
341
|
/**
|
|
327
342
|
* Sequential worktree cleanup for completed and failed worktree lanes.
|
|
328
343
|
*
|
package/dist/worktree/merge.d.ts
CHANGED
|
@@ -86,6 +86,11 @@ export interface OrphanCleanupResult {
|
|
|
86
86
|
branch: string;
|
|
87
87
|
error: string;
|
|
88
88
|
}>;
|
|
89
|
+
/** #1657: lane branches skipped because a recovery record references them. */
|
|
90
|
+
skippedRecoveryBranches: string[];
|
|
91
|
+
/** #1657: set when the recovery-directory read errored and ALL lane-branch
|
|
92
|
+
* deletions were skipped this pass (fail-safe). */
|
|
93
|
+
recoveryReadError?: boolean;
|
|
89
94
|
}
|
|
90
95
|
export interface StartupRecoveryResult {
|
|
91
96
|
prunedWorktrees: boolean;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-swarm",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.132.0",
|
|
4
4
|
"description": "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
export interface TaskNode {
|
|
2
|
-
id: string;
|
|
3
|
-
phase: number;
|
|
4
|
-
description: string;
|
|
5
|
-
depends: string[];
|
|
6
|
-
dependents: string[];
|
|
7
|
-
status: 'pending' | 'in_progress' | 'complete' | 'blocked';
|
|
8
|
-
}
|
|
9
|
-
export interface DependencyGraph {
|
|
10
|
-
tasks: Map<string, TaskNode>;
|
|
11
|
-
phases: Map<number, string[]>;
|
|
12
|
-
roots: string[];
|
|
13
|
-
leaves: string[];
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* Parse plan.json and build dependency graph
|
|
17
|
-
*/
|
|
18
|
-
export declare function parseDependencyGraph(planPath: string): DependencyGraph;
|
|
19
|
-
/**
|
|
20
|
-
* Get tasks that can run in parallel (no unresolved dependencies)
|
|
21
|
-
*/
|
|
22
|
-
export declare function getRunnableTasks(graph: DependencyGraph): string[];
|
|
23
|
-
/**
|
|
24
|
-
* Check if a task is blocked (has incomplete dependencies)
|
|
25
|
-
*/
|
|
26
|
-
export declare function isTaskBlocked(graph: DependencyGraph, taskId: string): boolean;
|
|
27
|
-
/**
|
|
28
|
-
* Get execution order (topological sort)
|
|
29
|
-
*/
|
|
30
|
-
export declare function getExecutionOrder(graph: DependencyGraph): string[];
|
|
31
|
-
/**
|
|
32
|
-
* Find all paths from root to a task
|
|
33
|
-
*/
|
|
34
|
-
export declare function getDependencyChain(graph: DependencyGraph, taskId: string): string[];
|