cyberlegion 1.9.0 → 1.10.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/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.plugin/pins.json +1 -1
- package/CHANGELOG.md +6 -0
- package/dist/cli.mjs +64 -8
- package/dist/index.d.mts +10 -0
- package/dist/index.mjs +58 -8
- package/package.json +1 -1
- package/plugin.json +1 -1
- package/skills/dispatch-governance/SKILL.md +1 -1
- package/skills/dispatch-governance/scripts/cyberlegion.mjs +58 -58
- package/skills/init-cyberlegion/scripts/cyberlegion.mjs +58 -58
- package/skills/legate/SKILL.md +1 -1
- package/skills/legate/scripts/cyberlegion.mjs +58 -58
- package/skills/manage-inbox/SKILL.md +1 -1
- package/skills/manage-inbox/scripts/cyberlegion.mjs +58 -58
- package/skills/relay-governance/SKILL.md +1 -1
- package/skills/relay-governance/scripts/cyberlegion.mjs +58 -58
- package/skills/subagent-backend-governance/SKILL.md +1 -1
- package/skills/subagent-backend-governance/scripts/cyberlegion.mjs +58 -58
package/.plugin/pins.json
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# cyberlegion
|
|
2
2
|
|
|
3
|
+
## 1.10.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 7a1c849: A unit now records a worktree it works in but does not own as `sharedWorktree` (`root`, `branch`, `primaryRoot`, and `owner`, the id of the unit that owns it). `unit spawn --cwd` records the checkout its directory sits in, and `unit register` records a worktree another unit's record owns this way instead of taking it as its own `worktree`. `unit close` never removes, prunes, or releases a shared worktree, so closing such a unit can no longer remove another unit's worktree or release its lease. `unit who` gains a `shared` column and `unit show` a `shared` field (`sharedWorktree` in JSON), so a sweep can judge the unit by that checkout. Records without the field read as before.
|
|
8
|
+
|
|
3
9
|
## 1.9.0
|
|
4
10
|
|
|
5
11
|
### Minor Changes
|
package/dist/cli.mjs
CHANGED
|
@@ -10517,7 +10517,7 @@ function register(ctx, input) {
|
|
|
10517
10517
|
handle: input.handle ?? existing?.handle ?? id.slice(0, 6),
|
|
10518
10518
|
harness,
|
|
10519
10519
|
cwd: process.cwd(),
|
|
10520
|
-
|
|
10520
|
+
...checkoutFor(ctx.store, exec, id, existing),
|
|
10521
10521
|
pane: cur ? paneLocator(cur, exec, env) : null,
|
|
10522
10522
|
status: "active",
|
|
10523
10523
|
createdAt: existing?.createdAt ?? ts,
|
|
@@ -10584,24 +10584,71 @@ function writeStanding(ctx, id, input) {
|
|
|
10584
10584
|
saveAgent(ctx.store, rec);
|
|
10585
10585
|
return rec;
|
|
10586
10586
|
}
|
|
10587
|
-
/** The checkout the cwd sits in: its root, its branch, and the repository's primary
|
|
10588
|
-
* same `primaryRoot` spawn records, so a lookup by repository finds a unit in a linked
|
|
10589
|
-
* the repository's name rather than the worktree folder's. */
|
|
10590
|
-
function gitWorktree(exec) {
|
|
10591
|
-
const
|
|
10587
|
+
/** The checkout `dir` (else the cwd) sits in: its root, its branch, and the repository's primary
|
|
10588
|
+
* checkout — the same `primaryRoot` spawn records, so a lookup by repository finds a unit in a linked
|
|
10589
|
+
* worktree by the repository's name rather than the worktree folder's. */
|
|
10590
|
+
function gitWorktree(exec, dir) {
|
|
10591
|
+
const git = dir === void 0 ? exec : (cmd, args) => exec(cmd, cmd === "git" ? [
|
|
10592
|
+
"-C",
|
|
10593
|
+
dir,
|
|
10594
|
+
...args
|
|
10595
|
+
] : args);
|
|
10596
|
+
const root = git("git", ["rev-parse", "--show-toplevel"]);
|
|
10592
10597
|
if (!root) return null;
|
|
10593
|
-
const branch =
|
|
10598
|
+
const branch = git("git", [
|
|
10594
10599
|
"rev-parse",
|
|
10595
10600
|
"--abbrev-ref",
|
|
10596
10601
|
"HEAD"
|
|
10597
10602
|
]) ?? void 0;
|
|
10598
|
-
const primaryRoot = primaryRootHere(
|
|
10603
|
+
const primaryRoot = primaryRootHere(git);
|
|
10599
10604
|
return {
|
|
10600
10605
|
root,
|
|
10601
10606
|
...branch !== void 0 ? { branch } : {},
|
|
10602
10607
|
...primaryRoot !== void 0 ? { primaryRoot } : {}
|
|
10603
10608
|
};
|
|
10604
10609
|
}
|
|
10610
|
+
/** The id of the unit, other than `self`, whose record owns the worktree at `root`. */
|
|
10611
|
+
function ownerOf(store, root, self) {
|
|
10612
|
+
const at = resolve(root);
|
|
10613
|
+
return listAgents(store).find((a) => a.id !== self && a.worktree?.root && resolve(a.worktree.root) === at)?.id;
|
|
10614
|
+
}
|
|
10615
|
+
/** `checkout` as a shared reference, naming the unit that owns it when one does. */
|
|
10616
|
+
function asShared(store, checkout, self) {
|
|
10617
|
+
const owner = ownerOf(store, checkout.root, self);
|
|
10618
|
+
return {
|
|
10619
|
+
...checkout,
|
|
10620
|
+
...owner ? { owner } : {}
|
|
10621
|
+
};
|
|
10622
|
+
}
|
|
10623
|
+
/** The checkout a `--cwd` spawn opens into, as a shared reference — spawn created none, so the unit
|
|
10624
|
+
* owns none, whoever does. `undefined` when `dir` is in no git checkout. */
|
|
10625
|
+
function sharedCheckoutAt(store, exec, dir) {
|
|
10626
|
+
const checkout = gitWorktree(exec, dir);
|
|
10627
|
+
return checkout ? asShared(store, checkout) : void 0;
|
|
10628
|
+
}
|
|
10629
|
+
/**
|
|
10630
|
+
* Which checkout a registering session owns and which it only shares. An existing owned worktree is
|
|
10631
|
+
* kept. Otherwise the cwd's checkout is the session's own — unless another unit's record owns it, or
|
|
10632
|
+
* this unit already records it as shared (a `--cwd` spawn): then it is a shared reference, and the
|
|
10633
|
+
* session owns none, so its close can never remove another unit's worktree or release its lease.
|
|
10634
|
+
*/
|
|
10635
|
+
function checkoutFor(store, exec, id, existing) {
|
|
10636
|
+
const kept = existing?.sharedWorktree ? { sharedWorktree: existing.sharedWorktree } : {};
|
|
10637
|
+
if (existing?.worktree) return {
|
|
10638
|
+
worktree: keptWorktree(existing.worktree, exec),
|
|
10639
|
+
...kept
|
|
10640
|
+
};
|
|
10641
|
+
const here = gitWorktree(exec);
|
|
10642
|
+
if (!here) return {
|
|
10643
|
+
worktree: null,
|
|
10644
|
+
...kept
|
|
10645
|
+
};
|
|
10646
|
+
if (existing?.sharedWorktree || ownerOf(store, here.root, id)) return {
|
|
10647
|
+
worktree: null,
|
|
10648
|
+
sharedWorktree: asShared(store, here, id)
|
|
10649
|
+
};
|
|
10650
|
+
return { worktree: here };
|
|
10651
|
+
}
|
|
10605
10652
|
function primaryRootHere(exec) {
|
|
10606
10653
|
try {
|
|
10607
10654
|
return resolvePrimaryRoot(exec);
|
|
@@ -11852,6 +11899,7 @@ async function spawn(ctx, input) {
|
|
|
11852
11899
|
const from = callerPane(sessionAdapter, normalizedEnv);
|
|
11853
11900
|
let cwd;
|
|
11854
11901
|
let worktree;
|
|
11902
|
+
let sharedWorktree;
|
|
11855
11903
|
let base;
|
|
11856
11904
|
let reused;
|
|
11857
11905
|
let target;
|
|
@@ -11860,6 +11908,7 @@ async function spawn(ctx, input) {
|
|
|
11860
11908
|
cwd = resolve(input.cwd);
|
|
11861
11909
|
if (primaryRoot$1 !== void 0) assertDistinctFromPrimary(cwd, primaryRoot$1);
|
|
11862
11910
|
worktree = null;
|
|
11911
|
+
sharedWorktree = sharedCheckoutAt(ctx.store, exec, cwd);
|
|
11863
11912
|
const at = input.at ?? "tab";
|
|
11864
11913
|
target = sessionAdapter.open(exec, {
|
|
11865
11914
|
cwd,
|
|
@@ -11950,6 +11999,7 @@ async function spawn(ctx, input) {
|
|
|
11950
11999
|
harness,
|
|
11951
12000
|
cwd,
|
|
11952
12001
|
worktree,
|
|
12002
|
+
...sharedWorktree ? { sharedWorktree } : {},
|
|
11953
12003
|
pane: muxName === "tmux" || muxName === "herdr" ? {
|
|
11954
12004
|
mux: muxName,
|
|
11955
12005
|
id: target.id
|
|
@@ -14460,6 +14510,7 @@ function showUnit(ctx, ref) {
|
|
|
14460
14510
|
} : null,
|
|
14461
14511
|
cwd: rec.cwd,
|
|
14462
14512
|
worktree: rec.worktree ?? null,
|
|
14513
|
+
sharedWorktree: rec.sharedWorktree ?? null,
|
|
14463
14514
|
lastSeen: rec.lastSeen,
|
|
14464
14515
|
controls: controlsFor(ctx, rec, liveness)
|
|
14465
14516
|
};
|
|
@@ -14759,6 +14810,10 @@ function runWho(opts) {
|
|
|
14759
14810
|
{
|
|
14760
14811
|
key: "pane",
|
|
14761
14812
|
get: (a) => a.pane?.id ?? "-"
|
|
14813
|
+
},
|
|
14814
|
+
{
|
|
14815
|
+
key: "shared",
|
|
14816
|
+
get: (a) => a.sharedWorktree?.root ?? "-"
|
|
14762
14817
|
}
|
|
14763
14818
|
], `${agents.length} units`),
|
|
14764
14819
|
json: agents
|
|
@@ -14958,6 +15013,7 @@ withGlobals(unit.command("show")).description("show a unit's runtime: where it i
|
|
|
14958
15013
|
pane: view.pane ? `${view.pane.mux}:${view.pane.id}` : "-",
|
|
14959
15014
|
cwd: view.cwd,
|
|
14960
15015
|
worktree: view.worktree?.root ?? "-",
|
|
15016
|
+
shared: view.sharedWorktree?.root ?? "-",
|
|
14961
15017
|
lastSeen: view.lastSeen,
|
|
14962
15018
|
controls: view.controls.join(",") || "-"
|
|
14963
15019
|
}),
|
package/dist/index.d.mts
CHANGED
|
@@ -40,6 +40,16 @@ interface AgentRecord {
|
|
|
40
40
|
holder: string;
|
|
41
41
|
};
|
|
42
42
|
} | null;
|
|
43
|
+
/** A checkout the unit works in but does not own: a `--cwd` spawn into an existing checkout, or a
|
|
44
|
+
* session registered in a worktree another unit's record owns. `owner` is that unit's id, when one
|
|
45
|
+
* owned the root at the time of recording. Close never removes, prunes, or releases it — it is read
|
|
46
|
+
* only, so a sweep can judge the unit by the work there. Absent on records from before it existed. */
|
|
47
|
+
sharedWorktree?: {
|
|
48
|
+
root: string;
|
|
49
|
+
branch?: string;
|
|
50
|
+
primaryRoot?: string;
|
|
51
|
+
owner?: string;
|
|
52
|
+
};
|
|
43
53
|
/** Where this session lives, tagged with its multiplexer so `prune` runs the right liveness check.
|
|
44
54
|
* `null` for a session in no pane and for a standing record. `window`/`session` are tmux-only. */
|
|
45
55
|
pane?: {
|
package/dist/index.mjs
CHANGED
|
@@ -247,7 +247,7 @@ function register(ctx, input) {
|
|
|
247
247
|
handle: input.handle ?? existing?.handle ?? id.slice(0, 6),
|
|
248
248
|
harness,
|
|
249
249
|
cwd: process.cwd(),
|
|
250
|
-
|
|
250
|
+
...checkoutFor(ctx.store, exec, id, existing),
|
|
251
251
|
pane: cur ? paneLocator(cur, exec, env) : null,
|
|
252
252
|
status: "active",
|
|
253
253
|
createdAt: existing?.createdAt ?? ts,
|
|
@@ -279,24 +279,71 @@ function paneLocator(cur, exec, env) {
|
|
|
279
279
|
id: cur.pane
|
|
280
280
|
};
|
|
281
281
|
}
|
|
282
|
-
/** The checkout the cwd sits in: its root, its branch, and the repository's primary
|
|
283
|
-
* same `primaryRoot` spawn records, so a lookup by repository finds a unit in a linked
|
|
284
|
-
* the repository's name rather than the worktree folder's. */
|
|
285
|
-
function gitWorktree(exec) {
|
|
286
|
-
const
|
|
282
|
+
/** The checkout `dir` (else the cwd) sits in: its root, its branch, and the repository's primary
|
|
283
|
+
* checkout — the same `primaryRoot` spawn records, so a lookup by repository finds a unit in a linked
|
|
284
|
+
* worktree by the repository's name rather than the worktree folder's. */
|
|
285
|
+
function gitWorktree(exec, dir) {
|
|
286
|
+
const git = dir === void 0 ? exec : (cmd, args) => exec(cmd, cmd === "git" ? [
|
|
287
|
+
"-C",
|
|
288
|
+
dir,
|
|
289
|
+
...args
|
|
290
|
+
] : args);
|
|
291
|
+
const root = git("git", ["rev-parse", "--show-toplevel"]);
|
|
287
292
|
if (!root) return null;
|
|
288
|
-
const branch =
|
|
293
|
+
const branch = git("git", [
|
|
289
294
|
"rev-parse",
|
|
290
295
|
"--abbrev-ref",
|
|
291
296
|
"HEAD"
|
|
292
297
|
]) ?? void 0;
|
|
293
|
-
const primaryRoot = primaryRootHere(
|
|
298
|
+
const primaryRoot = primaryRootHere(git);
|
|
294
299
|
return {
|
|
295
300
|
root,
|
|
296
301
|
...branch !== void 0 ? { branch } : {},
|
|
297
302
|
...primaryRoot !== void 0 ? { primaryRoot } : {}
|
|
298
303
|
};
|
|
299
304
|
}
|
|
305
|
+
/** The id of the unit, other than `self`, whose record owns the worktree at `root`. */
|
|
306
|
+
function ownerOf(store, root, self) {
|
|
307
|
+
const at = resolve(root);
|
|
308
|
+
return listAgents(store).find((a) => a.id !== self && a.worktree?.root && resolve(a.worktree.root) === at)?.id;
|
|
309
|
+
}
|
|
310
|
+
/** `checkout` as a shared reference, naming the unit that owns it when one does. */
|
|
311
|
+
function asShared(store, checkout, self) {
|
|
312
|
+
const owner = ownerOf(store, checkout.root, self);
|
|
313
|
+
return {
|
|
314
|
+
...checkout,
|
|
315
|
+
...owner ? { owner } : {}
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
/** The checkout a `--cwd` spawn opens into, as a shared reference — spawn created none, so the unit
|
|
319
|
+
* owns none, whoever does. `undefined` when `dir` is in no git checkout. */
|
|
320
|
+
function sharedCheckoutAt(store, exec, dir) {
|
|
321
|
+
const checkout = gitWorktree(exec, dir);
|
|
322
|
+
return checkout ? asShared(store, checkout) : void 0;
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Which checkout a registering session owns and which it only shares. An existing owned worktree is
|
|
326
|
+
* kept. Otherwise the cwd's checkout is the session's own — unless another unit's record owns it, or
|
|
327
|
+
* this unit already records it as shared (a `--cwd` spawn): then it is a shared reference, and the
|
|
328
|
+
* session owns none, so its close can never remove another unit's worktree or release its lease.
|
|
329
|
+
*/
|
|
330
|
+
function checkoutFor(store, exec, id, existing) {
|
|
331
|
+
const kept = existing?.sharedWorktree ? { sharedWorktree: existing.sharedWorktree } : {};
|
|
332
|
+
if (existing?.worktree) return {
|
|
333
|
+
worktree: keptWorktree(existing.worktree, exec),
|
|
334
|
+
...kept
|
|
335
|
+
};
|
|
336
|
+
const here = gitWorktree(exec);
|
|
337
|
+
if (!here) return {
|
|
338
|
+
worktree: null,
|
|
339
|
+
...kept
|
|
340
|
+
};
|
|
341
|
+
if (existing?.sharedWorktree || ownerOf(store, here.root, id)) return {
|
|
342
|
+
worktree: null,
|
|
343
|
+
sharedWorktree: asShared(store, here, id)
|
|
344
|
+
};
|
|
345
|
+
return { worktree: here };
|
|
346
|
+
}
|
|
300
347
|
function primaryRootHere(exec) {
|
|
301
348
|
try {
|
|
302
349
|
return resolvePrimaryRoot$1(exec);
|
|
@@ -1282,6 +1329,7 @@ async function spawn(ctx, input) {
|
|
|
1282
1329
|
const from = callerPane(sessionAdapter, normalizedEnv);
|
|
1283
1330
|
let cwd;
|
|
1284
1331
|
let worktree;
|
|
1332
|
+
let sharedWorktree;
|
|
1285
1333
|
let base;
|
|
1286
1334
|
let reused;
|
|
1287
1335
|
let target;
|
|
@@ -1290,6 +1338,7 @@ async function spawn(ctx, input) {
|
|
|
1290
1338
|
cwd = resolve(input.cwd);
|
|
1291
1339
|
if (primaryRoot$1 !== void 0) assertDistinctFromPrimary$1(cwd, primaryRoot$1);
|
|
1292
1340
|
worktree = null;
|
|
1341
|
+
sharedWorktree = sharedCheckoutAt(ctx.store, exec, cwd);
|
|
1293
1342
|
const at = input.at ?? "tab";
|
|
1294
1343
|
target = sessionAdapter.open(exec, {
|
|
1295
1344
|
cwd,
|
|
@@ -1380,6 +1429,7 @@ async function spawn(ctx, input) {
|
|
|
1380
1429
|
harness,
|
|
1381
1430
|
cwd,
|
|
1382
1431
|
worktree,
|
|
1432
|
+
...sharedWorktree ? { sharedWorktree } : {},
|
|
1383
1433
|
pane: muxName === "tmux" || muxName === "herdr" ? {
|
|
1384
1434
|
mux: muxName,
|
|
1385
1435
|
id: target.id
|
package/package.json
CHANGED
package/plugin.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
|
|
3
3
|
"name": "cyberlegion",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.10.0",
|
|
5
5
|
"description": "Agent session spawning, messaging, and dispatch — the Legion and its Legate.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "unional"
|
|
@@ -17,7 +17,7 @@ satisfies verdict schema `V`.
|
|
|
17
17
|
> **Running the CLI.** Every `node scripts/cyberlegion.mjs …` command below runs the `cyberlegion` CLI
|
|
18
18
|
> this plugin ships. The path is relative to this skill's own directory, not the working directory.
|
|
19
19
|
> If you cannot resolve it, run the published CLI of the version that shipped this skill instead,
|
|
20
|
-
> with the same arguments: `npx -y cyberlegion@1.
|
|
20
|
+
> with the same arguments: `npx -y cyberlegion@1.10.0`.
|
|
21
21
|
|
|
22
22
|
## 1. Resolve the agent definition
|
|
23
23
|
|