arcane-cli 0.23.0 → 0.24.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.
|
@@ -58,6 +58,48 @@ Assign a default power level per agent × per repo. Human approval and commit go
|
|
|
58
58
|
|
|
59
59
|
---
|
|
60
60
|
|
|
61
|
+
## Solo-Operator Delegation Records (No Roster)
|
|
62
|
+
|
|
63
|
+
The Per-Repo Power Level Matrix above assumes an installed agent roster (`.arcane/agents.yaml`) — each
|
|
64
|
+
agent has a slug and a per-repo power level, and that's where standing authority lives. A repo with **no
|
|
65
|
+
roster installed at all** has nowhere in that model to record a delegation, so one tends to get granted
|
|
66
|
+
ad hoc — free prose in whatever document is at hand — and then forgotten, since nothing lists it.
|
|
67
|
+
|
|
68
|
+
For exactly this case, record the grant explicitly instead, in `.arcane/delegations.json`:
|
|
69
|
+
|
|
70
|
+
```json
|
|
71
|
+
{
|
|
72
|
+
"delegations": [
|
|
73
|
+
{
|
|
74
|
+
"id": "short-identifier",
|
|
75
|
+
"grantedBy": "operator (name)",
|
|
76
|
+
"grantedAt": "YYYY-MM-DD",
|
|
77
|
+
"scope": "What this delegation covers — be specific, not 'everything'",
|
|
78
|
+
"permittedActions": ["create-session-branches", "commit", "push", "..."],
|
|
79
|
+
"excludedActions": ["platform-settings-mutations", "..."],
|
|
80
|
+
"status": "active",
|
|
81
|
+
"revocation": "Edit or remove this entry and commit."
|
|
82
|
+
}
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
- **Explicit:** a structured, git-tracked file — not prose buried in an unrelated document.
|
|
88
|
+
- **Listable:** `spell doctor` reads this file (when present) and reports every active delegation's
|
|
89
|
+
scope and exclusion list. A missing file is a silent pass — a repo with no ad hoc grants has nothing
|
|
90
|
+
to report.
|
|
91
|
+
- **Revocable per repo:** revocation is the git-native act of editing or removing the entry and
|
|
92
|
+
committing — set `status` to `"revoked"` or delete the entry outright.
|
|
93
|
+
- **Grants no new authority.** This mechanism does not permit anything `agent-policies.md` didn't
|
|
94
|
+
already allow in principle (human execution required absent an explicit grant) — it only makes an
|
|
95
|
+
existing kind of ad hoc grant explicit and discoverable instead of buried.
|
|
96
|
+
- **No scaffold is shipped.** A delegation record is inherently repo-specific and starts empty for a
|
|
97
|
+
fresh install — there is nothing generic to seed.
|
|
98
|
+
- **Does not replace the roster-based matrix.** A repo with an installed roster still uses per-agent
|
|
99
|
+
power levels for standing authority; this is the parallel, lighter-weight path for repos without one.
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
61
103
|
## Agent-to-Agent Topology
|
|
62
104
|
|
|
63
105
|
Spawn rights are configured per agent. Use a small number of orchestrators; keep most agents as leaf nodes that cannot spawn subagents.
|
package/dist/index.js
CHANGED
|
@@ -4065,6 +4065,38 @@ async function checkPushPolicy(targetDir) {
|
|
|
4065
4065
|
message: `declared "blocked" but not enforced \u2014 ${missing.join("; ")}. The manifest claims a protection this repository does not have.`
|
|
4066
4066
|
};
|
|
4067
4067
|
}
|
|
4068
|
+
async function checkDelegations(targetDir) {
|
|
4069
|
+
const name = "Standing delegations (T13)";
|
|
4070
|
+
const filePath = join11(targetDir, ".arcane", "delegations.json");
|
|
4071
|
+
let raw;
|
|
4072
|
+
try {
|
|
4073
|
+
raw = await readFile6(filePath, "utf8");
|
|
4074
|
+
} catch {
|
|
4075
|
+
return { name, passed: true, blocking: false, message: "no delegations recorded" };
|
|
4076
|
+
}
|
|
4077
|
+
let parsed;
|
|
4078
|
+
try {
|
|
4079
|
+
parsed = JSON.parse(raw);
|
|
4080
|
+
} catch {
|
|
4081
|
+
return {
|
|
4082
|
+
name,
|
|
4083
|
+
passed: false,
|
|
4084
|
+
blocking: false,
|
|
4085
|
+
message: `.arcane/delegations.json exists but contains invalid JSON`
|
|
4086
|
+
};
|
|
4087
|
+
}
|
|
4088
|
+
const active = (parsed.delegations ?? []).filter((d) => d.status === "active");
|
|
4089
|
+
if (active.length === 0) {
|
|
4090
|
+
return { name, passed: true, blocking: false, message: "no active delegations" };
|
|
4091
|
+
}
|
|
4092
|
+
const summary = active.map((d) => `${d.id} (scope: ${d.scope}; excludes: ${d.excludedActions.length} action(s))`).join("; ");
|
|
4093
|
+
return {
|
|
4094
|
+
name,
|
|
4095
|
+
passed: true,
|
|
4096
|
+
blocking: false,
|
|
4097
|
+
message: `${active.length} active: ${summary}`
|
|
4098
|
+
};
|
|
4099
|
+
}
|
|
4068
4100
|
async function checkPlatformBranchPolicy(targetDir) {
|
|
4069
4101
|
const name = "Platform branch/merge policy (T11)";
|
|
4070
4102
|
const targets = await pushTargets(targetDir);
|
|
@@ -4117,7 +4149,8 @@ async function runDoctor(targetDir, options = {}, assetsDir) {
|
|
|
4117
4149
|
Promise.resolve(checkIncidentReleaseGate()),
|
|
4118
4150
|
checkPullRebase(targetDir),
|
|
4119
4151
|
checkPushPolicy(targetDir),
|
|
4120
|
-
checkPlatformBranchPolicy(targetDir)
|
|
4152
|
+
checkPlatformBranchPolicy(targetDir),
|
|
4153
|
+
checkDelegations(targetDir)
|
|
4121
4154
|
]);
|
|
4122
4155
|
const sessionResults = await checkSessionContinuity(targetDir);
|
|
4123
4156
|
results.push(...sessionResults);
|