arcane-cli 0.26.0 → 0.26.1
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/assets/.arcane/governance/git-conventions.md +11 -0
- package/dist/assets/.github/instructions/agent-output.instructions.md +7 -0
- package/dist/assets/.github/prompts/spell-commit-work.prompt.md +2 -0
- package/dist/assets/.mcp.json +10 -0
- package/dist/index.js +52 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -478,6 +478,17 @@ git branch -d <branch> # delete local branch (skip if branch
|
|
|
478
478
|
git push origin --delete <branch> # delete remote branch (safety net — --delete-source-branch true usually handles this; ignore 'does not exist' errors)
|
|
479
479
|
```
|
|
480
480
|
|
|
481
|
+
**MCP fail-fast / fallback rule:** one abnormal MCP tool failure — a hang, an idle-timeout abort, a
|
|
482
|
+
transport error, or an empty response where data is clearly expected — marks that MCP server **down
|
|
483
|
+
for the rest of the session**. Do not retry it blindly. All subsequent operations that would have used
|
|
484
|
+
it fall back to the documented CLI (`az repos pr` / `gh` / a direct REST call), and the downgrade is
|
|
485
|
+
reported in output so a human sees it happened. The known-issues rows below (`MCP vote_pull_request`,
|
|
486
|
+
`MCP create_pull_request`) are concrete instances of this general rule, not special cases of their own.
|
|
487
|
+
**Consumer hardening:** set a per-server `"timeout"` (milliseconds) in `.mcp.json` so a hang aborts on a
|
|
488
|
+
predictable schedule instead of running to the client's own default idle limit (as long as 30 minutes).
|
|
489
|
+
Origin: a real ops session lost roughly an hour to two consecutive 30-minute MCP hangs before the
|
|
490
|
+
documented `az` fallback was used (2026-08-14).
|
|
491
|
+
|
|
481
492
|
**Known issues:**
|
|
482
493
|
|
|
483
494
|
| Issue | Symptom | Fix |
|
|
@@ -81,6 +81,13 @@ When completing a PR via `az repos pr update`, do **not** pass `--squash true`.
|
|
|
81
81
|
az repos pr update --id <PR_ID> --org https://dev.azure.com/<org> --status completed --delete-source-branch true
|
|
82
82
|
```
|
|
83
83
|
|
|
84
|
+
## MCP Fail-Fast / Fallback
|
|
85
|
+
|
|
86
|
+
One abnormal MCP tool failure (hang, idle-timeout abort, transport error, empty response where data is
|
|
87
|
+
expected) marks that server down for the rest of the session — fall back to the documented CLI (`az
|
|
88
|
+
repos pr` / `gh` / REST), no blind retries, and report the downgrade in output. Full rule and origin
|
|
89
|
+
incident: `.arcane/governance/git-conventions.md` → Known issues.
|
|
90
|
+
|
|
84
91
|
## Branch Naming (Interactive Sessions)
|
|
85
92
|
|
|
86
93
|
Interactive tool session branches use:
|
|
@@ -152,6 +152,8 @@ Workflow:
|
|
|
152
152
|
|
|
153
153
|
a. Run `git push origin <branch>`.
|
|
154
154
|
|
|
155
|
+
a1. **MCP fail-fast / fallback.** If an MCP tool used anywhere in this step (e.g. `create_pull_request`) fails abnormally once — a hang, an idle-timeout abort, a transport error, or an empty response where data is clearly expected — treat that server as down for the rest of this session. Do not retry it blindly; fall back to the raw CLI paths below (`gh pr create` / `az repos pr create`) and report the downgrade. Full rule: `.arcane/governance/git-conventions.md` → Known issues.
|
|
156
|
+
|
|
155
157
|
b. **🛑 Mandatory pre-PR rebase (governance guard, applies to every path below).** Before invoking any PR-creation command — whether via `spell-create-pull-request`, raw `gh pr create`, raw `az repos pr create`, or an MCP `create_pull_request` tool — you MUST:
|
|
156
158
|
|
|
157
159
|
```bash
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "Example MCP server config. Replace or remove the example server below with your own. Set a per-server \"timeout\" (milliseconds) so a hung server aborts on a predictable schedule instead of running to the client's own default idle limit (as long as 30 minutes) -- see .arcane/governance/git-conventions.md's MCP fail-fast / fallback rule.",
|
|
3
|
+
"mcpServers": {
|
|
4
|
+
"example-server": {
|
|
5
|
+
"command": "npx",
|
|
6
|
+
"args": ["-y", "@example/mcp-server"],
|
|
7
|
+
"timeout": 30000
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -428,6 +428,15 @@ var COMPONENTS = [
|
|
|
428
428
|
skipExisting: true,
|
|
429
429
|
initOnly: true
|
|
430
430
|
},
|
|
431
|
+
// Optional MCP config scaffold (BC-22/I12). skipExisting: a repo's own
|
|
432
|
+
// .mcp.json is user-owned server config Arcane must never overwrite.
|
|
433
|
+
// Not initOnly -- useful to retrofit via `spell add` on an existing repo too.
|
|
434
|
+
{
|
|
435
|
+
name: "mcp-config-template",
|
|
436
|
+
description: "Example .mcp.json with a per-server timeout, companion to the MCP fail-fast rule",
|
|
437
|
+
files: [".mcp.json"],
|
|
438
|
+
skipExisting: true
|
|
439
|
+
},
|
|
431
440
|
{
|
|
432
441
|
name: "records-conventions",
|
|
433
442
|
description: "Supersession, tombstone, and retention conventions for records repositories",
|
|
@@ -4067,6 +4076,47 @@ async function checkPushPolicy(targetDir) {
|
|
|
4067
4076
|
message: `declared "blocked" but not enforced \u2014 ${missing.join("; ")}. The manifest claims a protection this repository does not have.`
|
|
4068
4077
|
};
|
|
4069
4078
|
}
|
|
4079
|
+
async function checkMcpConfig(targetDir) {
|
|
4080
|
+
const name = "MCP config (per-server timeout, I12)";
|
|
4081
|
+
const filePath = join11(targetDir, ".mcp.json");
|
|
4082
|
+
let raw;
|
|
4083
|
+
try {
|
|
4084
|
+
raw = await readFile6(filePath, "utf8");
|
|
4085
|
+
} catch {
|
|
4086
|
+
return { name, passed: true, blocking: false, message: "no .mcp.json \u2014 nothing to check" };
|
|
4087
|
+
}
|
|
4088
|
+
let parsed;
|
|
4089
|
+
try {
|
|
4090
|
+
parsed = JSON.parse(raw);
|
|
4091
|
+
} catch {
|
|
4092
|
+
return {
|
|
4093
|
+
name,
|
|
4094
|
+
passed: false,
|
|
4095
|
+
blocking: false,
|
|
4096
|
+
message: ".mcp.json exists but contains invalid JSON"
|
|
4097
|
+
};
|
|
4098
|
+
}
|
|
4099
|
+
const servers = parsed.mcpServers ?? {};
|
|
4100
|
+
const serverNames = Object.keys(servers);
|
|
4101
|
+
if (serverNames.length === 0) {
|
|
4102
|
+
return { name, passed: true, blocking: false, message: "no MCP servers configured" };
|
|
4103
|
+
}
|
|
4104
|
+
const missingTimeout = serverNames.filter((n) => typeof servers[n]?.timeout !== "number");
|
|
4105
|
+
if (missingTimeout.length > 0) {
|
|
4106
|
+
return {
|
|
4107
|
+
name,
|
|
4108
|
+
passed: false,
|
|
4109
|
+
blocking: false,
|
|
4110
|
+
message: `server(s) missing a "timeout": ${missingTimeout.join(", ")} \u2014 a hang runs to the client's own default idle limit (up to 30 min) instead of a predictable one`
|
|
4111
|
+
};
|
|
4112
|
+
}
|
|
4113
|
+
return {
|
|
4114
|
+
name,
|
|
4115
|
+
passed: true,
|
|
4116
|
+
blocking: false,
|
|
4117
|
+
message: `${serverNames.length} server(s) configured, all with a timeout set`
|
|
4118
|
+
};
|
|
4119
|
+
}
|
|
4070
4120
|
async function checkDelegations(targetDir) {
|
|
4071
4121
|
const name = "Standing delegations (T13)";
|
|
4072
4122
|
const filePath = join11(targetDir, ".arcane", "delegations.json");
|
|
@@ -4152,7 +4202,8 @@ async function runDoctor(targetDir, options = {}, assetsDir) {
|
|
|
4152
4202
|
checkPullRebase(targetDir),
|
|
4153
4203
|
checkPushPolicy(targetDir),
|
|
4154
4204
|
checkPlatformBranchPolicy(targetDir),
|
|
4155
|
-
checkDelegations(targetDir)
|
|
4205
|
+
checkDelegations(targetDir),
|
|
4206
|
+
checkMcpConfig(targetDir)
|
|
4156
4207
|
]);
|
|
4157
4208
|
const sessionResults = await checkSessionContinuity(targetDir);
|
|
4158
4209
|
results.push(...sessionResults);
|