@azure-id/orc 1.9.1 → 1.9.2
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/CHANGELOG.md +69 -0
- package/README-id.md +38 -39
- package/README.md +36 -35
- package/bin/build-agents.js +109 -109
- package/bin/cli.js +35 -33
- package/bin/onboarding-content.js +4 -4
- package/bin/pricing.json +207 -200
- package/bin/verify-contracts.js +2 -2
- package/bin/verify-package.js +7 -7
- package/bin/webui/css/04-motion.css +162 -152
- package/bin/webui/css/panels/knowledge.css +563 -116
- package/bin/webui/fixtures/extra.js +2036 -2036
- package/bin/webui/fixtures/hookui.js +5 -5
- package/bin/webui/fixtures/settings.js +305 -305
- package/bin/webui/i18n/en/knowledge.json +117 -2
- package/bin/webui/i18n/id/knowledge.json +117 -2
- package/bin/webui/js/panels/knowledge.js +552 -7
- package/bin/webui/js/panels/overview.js +13 -4
- package/mock-run/context-combiner.md +100 -100
- package/mock-run/orc-budget.md +534 -534
- package/mock-run/orc-challenge-council.md +262 -262
- package/mock-run/orc-ultra.md +103 -103
- package/package.json +1 -1
- package/templates/agents/MODEL-MAPPING.md +43 -43
- package/templates/agents/orc-advisor-opus-5-xhigh.md +56 -56
- package/templates/agents/orc-analyze-mini-opus-5-med.md +60 -60
- package/templates/agents/orc-analyze-mini-sonnet-5-high.md +58 -58
- package/templates/agents/orc-challenge-advisor-opus-5-med.md +75 -75
- package/templates/agents/orc-challenge-contrarian-opus-5-high.md +110 -110
- package/templates/agents/orc-challenge-executor-opus-5-med.md +114 -114
- package/templates/agents/orc-challenge-expansionist-opus-5-med.md +112 -112
- package/templates/agents/orc-challenge-judge-opus-5-high.md +132 -132
- package/templates/agents/orc-challenge-outsider-opus-5-low.md +109 -109
- package/templates/agents/orc-challenge-principles-opus-5-high.md +109 -109
- package/templates/agents/orc-challenge-reader-opus-5-low.md +90 -90
- package/templates/agents/orc-claude-writer-opus-5-med.md +55 -55
- package/templates/agents/orc-context-combiner-opus-5-high.md +88 -88
- package/templates/agents/orc-doc-checker-opus-5-low.md +108 -108
- package/templates/agents/orc-doc-writer-opus-5-med.md +134 -134
- package/templates/agents/orc-executor-opus-5-high.md +2 -2
- package/templates/agents/orc-executor-opus-5-low.md +2 -2
- package/templates/agents/orc-executor-opus-5-med.md +2 -2
- package/templates/agents/orc-graph-noter-sonnet-4-6-med.md +1 -1
- package/templates/agents/orc-judge-opus-5-xhigh.md +85 -85
- package/templates/agents/orc-learn-writer-opus-5-low.md +73 -73
- package/templates/agents/orc-pattern-codifier-opus-5-med.md +65 -65
- package/templates/agents/orc-planner-mini-opus-5-med.md +4 -4
- package/templates/agents/orc-planner-mini-sonnet-5-high.md +1 -1
- package/templates/agents/orc-planner-opus-5-med.md +160 -160
- package/templates/agents/orc-recon-opus-5-low.md +3 -3
- package/templates/agents/orc-retro-opus-5-med.md +3 -3
- package/templates/agents/orc-reviewer-opus-5-med.md +60 -60
- package/templates/agents/orc-scout-opus-5-low.md +40 -40
- package/templates/agents/orc-system-analyst-opus-5-high.md +120 -120
- package/templates/agents/orc-test-author-opus-5-med.md +71 -71
- package/templates/agents/orc-test-designer-opus-5-high.md +158 -158
- package/templates/agents/orc-test-interpreter-opus-5-low.md +130 -130
- package/templates/agents/orc-verifier-opus-5-med.md +69 -69
- package/templates/agents/orc-wiki-scanner-opus-5-med.md +81 -81
- package/templates/commands/orc-ultra.md +17 -17
- package/templates/commands/orc-verify.md +11 -11
- package/templates/hooks/README.md +2 -2
- package/templates/hooks/orc-effort-guard.js +178 -178
- package/templates/hooks/orc-statusline.js +6 -6
- package/templates/skills/_shared/code-graph.md +1 -1
- package/templates/skills/_shared/config-precedence.md +198 -198
- package/templates/skills/_shared/extra-dispatch.md +1346 -1346
- package/templates/skills/_shared/opus5-only.md +8 -8
- package/templates/skills/_shared/phases/analyst-gates.md +136 -136
- package/templates/skills/_shared/phases/review.md +1 -1
- package/templates/skills/_shared/phases/trace.md +1 -1
- package/templates/skills/_shared/return-validation.md +1 -1
- package/templates/skills/context-combiner/SKILL.md +1 -1
- package/templates/skills/context-combiner/schemas/combined-report.md +78 -78
- package/templates/skills/orc/README.md +2 -2
- package/templates/skills/orc/SKILL.md +7 -7
- package/templates/skills/orc/config.md +9 -9
- package/templates/skills/orc/examples/full-run-mock.md +73 -73
- package/templates/skills/orc/references/effort-and-mode.md +222 -222
- package/templates/skills/orc/references/preflight-report.md +2 -2
- package/templates/skills/orc/references/ultra-mode.md +3 -3
- package/templates/skills/orc/subskills/orc-planner/SKILL.md +2 -2
- package/templates/skills/orc/subskills/orc-planner-mini/SKILL.md +121 -121
- package/templates/skills/orc/subskills/orc-review-verify/SKILL.md +76 -76
- package/templates/skills/orc/subskills/orc-testgen/SKILL.md +45 -45
- package/templates/skills/orc-analyze/SKILL.md +2 -2
- package/templates/skills/orc-analyze/examples/analyze-mock.md +42 -42
- package/templates/skills/orc-analyze/schemas/report-audit.md +83 -83
- package/templates/skills/orc-analyze/schemas/report-prose.md +63 -63
- package/templates/skills/orc-analyze/schemas/report-requirement.md +78 -78
- package/templates/skills/orc-challenge/README.md +142 -142
- package/templates/skills/orc-challenge/examples/council-full-roster.md +273 -273
- package/templates/skills/orc-challenge/references/council.md +315 -315
- package/templates/skills/orc-challenge/references/intake.md +171 -171
- package/templates/skills/orc-claude/SKILL.md +14 -14
- package/templates/skills/orc-diy/README.md +143 -143
- package/templates/skills/orc-diy/references/flow-schema.md +1 -1
- package/templates/skills/orc-doc/README.md +229 -229
- package/templates/skills/orc-doc/examples/orc-doc-prd-run.md +325 -325
- package/templates/skills/orc-doc/references/chunking.md +527 -527
- package/templates/skills/orc-fast/SKILL.md +1 -1
- package/templates/skills/orc-learn/SKILL.md +14 -14
- package/templates/skills/orc-learn/examples/learn-run-mock.md +61 -61
- package/templates/skills/orc-mini/SKILL.md +3 -3
- package/templates/skills/orc-verify/SKILL.md +15 -15
- package/templates/skills/orc-verify/examples/verify-mock.md +33 -33
- package/templates/skills/orc-wiki/references/extra.md +1 -1
|
@@ -1,178 +1,178 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
"use strict";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* ORC effort guard — a Claude Code PreToolUse hook.
|
|
6
|
-
*
|
|
7
|
-
* Blocks invocation of the full `orc` orchestrator skill unless the MAIN
|
|
8
|
-
* session is running at HIGH reasoning effort (Opus 5 / Fable 5 clear at
|
|
9
|
-
* medium+ — see the session-model bridge below). This is the one half of the
|
|
10
|
-
* "run ORC on Opus 4.8 high or better" rule hooks can enforce deterministically:
|
|
11
|
-
* Claude Code exposes `effort.level` (and $CLAUDE_EFFORT) to PreToolUse, but
|
|
12
|
-
* NOT the model id (only SessionStart may see the model, and cannot block).
|
|
13
|
-
* The model tier is surfaced separately by the statusline warning + the
|
|
14
|
-
* self-check inside skills/orc/SKILL.md.
|
|
15
|
-
*
|
|
16
|
-
* Wiring (installed by `orc init` into .claude/settings.json):
|
|
17
|
-
* hooks.PreToolUse[] { matcher: "Skill", hooks:[{ type:"command",
|
|
18
|
-
* command: 'node "<.claude>/hooks/orc-effort-guard.js"' }] }
|
|
19
|
-
*
|
|
20
|
-
* Contract: read PreToolUse JSON from stdin. Exit 0 = allow. Exit 2 = block
|
|
21
|
-
* the tool call and show stderr to Claude, which relays it to the user.
|
|
22
|
-
*
|
|
23
|
-
* Also surfaces a "newer orc version available" nudge here — this hook fires
|
|
24
|
-
* exactly when /orc is invoked, so it's the natural place to tell the user
|
|
25
|
-
* without them running `orc version`. On allow it emits a `systemMessage`
|
|
26
|
-
* (shown to the user, NOT added to model context → zero tokens); on block it
|
|
27
|
-
* appends the nudge to the block reason. Version check is cached 24h and
|
|
28
|
-
* fail-silent. (systemMessage handling may vary by Claude Code version — verify
|
|
29
|
-
* with /doctor if you don't see it; the statusline shows it regardless.)
|
|
30
|
-
*/
|
|
31
|
-
|
|
32
|
-
// Shared update-check helper (sibling file). Degrade gracefully if absent.
|
|
33
|
-
let updater = null;
|
|
34
|
-
try {
|
|
35
|
-
updater = require("./orc-update-lib.js");
|
|
36
|
-
} catch (_) {
|
|
37
|
-
updater = null;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Effort ladder: low < medium < high < xhigh < max. A tier that meets the bar
|
|
41
|
-
// meets it at that rung OR anything stronger — so "requires high" allows xhigh
|
|
42
|
-
// and max too (the bug this fixes: an xhigh/max session was hard-blocked).
|
|
43
|
-
const EFFORT_LADDER = ["low", "medium", "high", "xhigh", "max"];
|
|
44
|
-
const effortsAtOrAbove = (e) => {
|
|
45
|
-
const i = EFFORT_LADDER.indexOf(String(e).toLowerCase());
|
|
46
|
-
return i === -1 ? ["high", "xhigh", "max"] : EFFORT_LADDER.slice(i);
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
// Session-model bridge (written by orc-statusline.js). The guard can't see the
|
|
50
|
-
// model id itself, so it reads it here to grant the medium-effort allowance of
|
|
51
|
-
// the models that are strictly stronger than the Opus 4.8 baseline (Opus 5 and
|
|
52
|
-
// Fable 5). Fail-OPEN: missing / unreadable / stale → null, and the guard
|
|
53
|
-
// behaves exactly as it would without a bridge (never blocks on our own error).
|
|
54
|
-
// Stale = older than this window; a live session re-renders the statusline far
|
|
55
|
-
// more often, so a fresh file always exists during active use.
|
|
56
|
-
const BRIDGE_MAX_AGE_MS = 30 * 60 * 1000;
|
|
57
|
-
function readSessionModel(projectDir) {
|
|
58
|
-
try {
|
|
59
|
-
const fs = require("fs");
|
|
60
|
-
const path = require("path");
|
|
61
|
-
const p = path.join(projectDir, ".claude", "orc", "session-model.json");
|
|
62
|
-
const j = JSON.parse(fs.readFileSync(p, "utf8").replace(/^/, ""));
|
|
63
|
-
if (!j || typeof j.written_at !== "number") return null;
|
|
64
|
-
if (Date.now() - j.written_at > BRIDGE_MAX_AGE_MS) return null;
|
|
65
|
-
return String(j.model_id || "");
|
|
66
|
-
} catch (_) {
|
|
67
|
-
return null;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
// Models that clear /orc at medium effort — strictly stronger than the Opus 4.8
|
|
71
|
-
// baseline, so medium on them beats high on it. Opus 5 (v0.34.0) joins Fable 5.
|
|
72
|
-
// The `\b` after the 5 keeps 4.8 / 4.7 / 5-something-else correctly gated.
|
|
73
|
-
const isMediumOkModel = (id) =>
|
|
74
|
-
/(opus|fable)[\s._-]?5\b/.test(String(id || "").toLowerCase());
|
|
75
|
-
|
|
76
|
-
let raw = "";
|
|
77
|
-
process.stdin.on("data", (c) => (raw += c));
|
|
78
|
-
process.stdin.on("end", () => {
|
|
79
|
-
let data = {};
|
|
80
|
-
try {
|
|
81
|
-
data = JSON.parse(raw || "{}");
|
|
82
|
-
} catch (_) {
|
|
83
|
-
// Unparseable payload — never block on our own error.
|
|
84
|
-
process.exit(0);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const tool = data.tool_name || "";
|
|
88
|
-
const input = data.tool_input || {};
|
|
89
|
-
const skill = String(input.skill || input.name || "");
|
|
90
|
-
|
|
91
|
-
// Only gate the full orchestrator and the compiled DIY lane. orc-mini /
|
|
92
|
-
// orc-fast / orc-analyze / subskills pass — orc-fast is DESIGNED to run at
|
|
93
|
-
// Sonnet medium; never widen this match to include it.
|
|
94
|
-
const isOrc = tool === "Skill" && /^orc$/i.test(skill);
|
|
95
|
-
const isDiy = tool === "Skill" && /^orc-diy$/i.test(skill);
|
|
96
|
-
if (!isOrc && !isDiy) process.exit(0);
|
|
97
|
-
|
|
98
|
-
const effort = String(
|
|
99
|
-
(data.effort && data.effort.level) || process.env.CLAUDE_EFFORT || ""
|
|
100
|
-
).toLowerCase();
|
|
101
|
-
const installed = updater ? updater.installedVersion(__dirname) : null;
|
|
102
|
-
const projectDir = data.cwd || process.cwd();
|
|
103
|
-
|
|
104
|
-
// Baseline /orc: the session must be at high effort OR stronger (xhigh/max).
|
|
105
|
-
// Opus 5 and Fable 5 additionally clear at medium — strictly-capable models —
|
|
106
|
-
// detected through the session-model bridge (the guard can't see the model id
|
|
107
|
-
// itself; fail-open when the bridge is missing/stale, i.e. medium stays blocked).
|
|
108
|
-
let requiredEfforts = effortsAtOrAbove("high");
|
|
109
|
-
let requiredLabel =
|
|
110
|
-
"Opus 4.8 at high effort (Opus 5 / Fable 5 also clear at medium+)";
|
|
111
|
-
if (!isDiy && isMediumOkModel(readSessionModel(projectDir))) {
|
|
112
|
-
requiredEfforts = ["medium", ...requiredEfforts];
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// /orc-diy: the required tier is whatever the flow was COMPILED for — read
|
|
116
|
-
// it from flow.lock.json (written only by the `orc diy` CLI). Fail closed:
|
|
117
|
-
// no lock = no compiled flow = deterministic onboarding block. `compile` /
|
|
118
|
-
// `status` invocations pass at any effort (they just shell out to the CLI).
|
|
119
|
-
if (isDiy) {
|
|
120
|
-
if (/^\s*(compile|status)\b/i.test(String(input.args || ""))) process.exit(0);
|
|
121
|
-
const fs = require("fs");
|
|
122
|
-
const path = require("path");
|
|
123
|
-
let lock = null;
|
|
124
|
-
try {
|
|
125
|
-
lock = JSON.parse(
|
|
126
|
-
fs
|
|
127
|
-
.readFileSync(
|
|
128
|
-
path.join(projectDir, ".claude", "orc", "diy", "flow.lock.json"),
|
|
129
|
-
"utf8"
|
|
130
|
-
)
|
|
131
|
-
.replace(/^\uFEFF/, "")
|
|
132
|
-
);
|
|
133
|
-
} catch (_) {}
|
|
134
|
-
if (!lock || !lock.session_tier) {
|
|
135
|
-
process.stderr.write(
|
|
136
|
-
"\n⛔ /orc-diy blocked — no compiled flow in this project (fail-closed gate)." +
|
|
137
|
-
"\n Compose and build your flow in the terminal first:" +
|
|
138
|
-
"\n orc diy init (then shape it: orc diy set <key> <value>)" +
|
|
139
|
-
"\n orc diy compile" +
|
|
140
|
-
"\n Guide: .claude/skills/orc-diy/README.md — or use plain /orc for this request.\n"
|
|
141
|
-
);
|
|
142
|
-
process.exit(2);
|
|
143
|
-
}
|
|
144
|
-
// Effort half is DETERMINISTIC from the compiled slug's suffix (allow that
|
|
145
|
-
// effort or anything stronger); the model half is warn-only on the
|
|
146
|
-
// statusline (hooks can't block on model). Covers the full tier grid —
|
|
147
|
-
// sonnet-4-6 / opus-4-7 / opus-4-8 / fable-5 at med|high|xhigh|max.
|
|
148
|
-
const m = String(lock.session_tier).match(/-(med|high|xhigh|max)$/);
|
|
149
|
-
const slugEffort = m ? (m[1] === "med" ? "medium" : m[1]) : "high";
|
|
150
|
-
requiredEfforts = effortsAtOrAbove(slugEffort);
|
|
151
|
-
requiredLabel = `${lock.session_tier} (compiled session_tier — needs effort ${slugEffort}+)`;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
const decide = (nudge) => {
|
|
155
|
-
if (requiredEfforts.includes(effort)) {
|
|
156
|
-
// Requirement met — allow. Surface a version nudge if one exists.
|
|
157
|
-
if (nudge) {
|
|
158
|
-
try {
|
|
159
|
-
process.stdout.write(JSON.stringify({ systemMessage: nudge }));
|
|
160
|
-
} catch (_) {}
|
|
161
|
-
}
|
|
162
|
-
process.exit(0);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
process.stderr.write(
|
|
166
|
-
`\n⛔ ${isDiy ? "/orc-diy" : "ORC"} blocked — required effort not met` +
|
|
167
|
-
(effort ? ` (current effort: ${effort}).` : " (effort not detected).") +
|
|
168
|
-
`\n Switch this session to ${requiredLabel}, then re-run.` +
|
|
169
|
-
"\n Run the MAIN session at (or above) the required tier — subagents cannot" +
|
|
170
|
-
"\n exceed the main tier, so pinned agents silently downgrade below it.\n" +
|
|
171
|
-
(nudge ? "\n" + nudge + "\n" : "")
|
|
172
|
-
);
|
|
173
|
-
process.exit(2);
|
|
174
|
-
};
|
|
175
|
-
|
|
176
|
-
if (updater) updater.refreshAndNudge(installed, decide);
|
|
177
|
-
else decide(null);
|
|
178
|
-
});
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* ORC effort guard — a Claude Code PreToolUse hook.
|
|
6
|
+
*
|
|
7
|
+
* Blocks invocation of the full `orc` orchestrator skill unless the MAIN
|
|
8
|
+
* session is running at HIGH reasoning effort (Opus 5.5 / Fable 5 clear at
|
|
9
|
+
* medium+ — see the session-model bridge below). This is the one half of the
|
|
10
|
+
* "run ORC on Opus 4.8 high or better" rule hooks can enforce deterministically:
|
|
11
|
+
* Claude Code exposes `effort.level` (and $CLAUDE_EFFORT) to PreToolUse, but
|
|
12
|
+
* NOT the model id (only SessionStart may see the model, and cannot block).
|
|
13
|
+
* The model tier is surfaced separately by the statusline warning + the
|
|
14
|
+
* self-check inside skills/orc/SKILL.md.
|
|
15
|
+
*
|
|
16
|
+
* Wiring (installed by `orc init` into .claude/settings.json):
|
|
17
|
+
* hooks.PreToolUse[] { matcher: "Skill", hooks:[{ type:"command",
|
|
18
|
+
* command: 'node "<.claude>/hooks/orc-effort-guard.js"' }] }
|
|
19
|
+
*
|
|
20
|
+
* Contract: read PreToolUse JSON from stdin. Exit 0 = allow. Exit 2 = block
|
|
21
|
+
* the tool call and show stderr to Claude, which relays it to the user.
|
|
22
|
+
*
|
|
23
|
+
* Also surfaces a "newer orc version available" nudge here — this hook fires
|
|
24
|
+
* exactly when /orc is invoked, so it's the natural place to tell the user
|
|
25
|
+
* without them running `orc version`. On allow it emits a `systemMessage`
|
|
26
|
+
* (shown to the user, NOT added to model context → zero tokens); on block it
|
|
27
|
+
* appends the nudge to the block reason. Version check is cached 24h and
|
|
28
|
+
* fail-silent. (systemMessage handling may vary by Claude Code version — verify
|
|
29
|
+
* with /doctor if you don't see it; the statusline shows it regardless.)
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
// Shared update-check helper (sibling file). Degrade gracefully if absent.
|
|
33
|
+
let updater = null;
|
|
34
|
+
try {
|
|
35
|
+
updater = require("./orc-update-lib.js");
|
|
36
|
+
} catch (_) {
|
|
37
|
+
updater = null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Effort ladder: low < medium < high < xhigh < max. A tier that meets the bar
|
|
41
|
+
// meets it at that rung OR anything stronger — so "requires high" allows xhigh
|
|
42
|
+
// and max too (the bug this fixes: an xhigh/max session was hard-blocked).
|
|
43
|
+
const EFFORT_LADDER = ["low", "medium", "high", "xhigh", "max"];
|
|
44
|
+
const effortsAtOrAbove = (e) => {
|
|
45
|
+
const i = EFFORT_LADDER.indexOf(String(e).toLowerCase());
|
|
46
|
+
return i === -1 ? ["high", "xhigh", "max"] : EFFORT_LADDER.slice(i);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// Session-model bridge (written by orc-statusline.js). The guard can't see the
|
|
50
|
+
// model id itself, so it reads it here to grant the medium-effort allowance of
|
|
51
|
+
// the models that are strictly stronger than the Opus 4.8 baseline (Opus 5.5 and
|
|
52
|
+
// Fable 5). Fail-OPEN: missing / unreadable / stale → null, and the guard
|
|
53
|
+
// behaves exactly as it would without a bridge (never blocks on our own error).
|
|
54
|
+
// Stale = older than this window; a live session re-renders the statusline far
|
|
55
|
+
// more often, so a fresh file always exists during active use.
|
|
56
|
+
const BRIDGE_MAX_AGE_MS = 30 * 60 * 1000;
|
|
57
|
+
function readSessionModel(projectDir) {
|
|
58
|
+
try {
|
|
59
|
+
const fs = require("fs");
|
|
60
|
+
const path = require("path");
|
|
61
|
+
const p = path.join(projectDir, ".claude", "orc", "session-model.json");
|
|
62
|
+
const j = JSON.parse(fs.readFileSync(p, "utf8").replace(/^/, ""));
|
|
63
|
+
if (!j || typeof j.written_at !== "number") return null;
|
|
64
|
+
if (Date.now() - j.written_at > BRIDGE_MAX_AGE_MS) return null;
|
|
65
|
+
return String(j.model_id || "");
|
|
66
|
+
} catch (_) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// Models that clear /orc at medium effort — strictly stronger than the Opus 4.8
|
|
71
|
+
// baseline, so medium on them beats high on it. Opus 5.5 (v0.34.0) joins Fable 5.
|
|
72
|
+
// The `\b` after the 5 keeps 4.8 / 4.7 / 5-something-else correctly gated.
|
|
73
|
+
const isMediumOkModel = (id) =>
|
|
74
|
+
/(opus|fable)[\s._-]?5\b/.test(String(id || "").toLowerCase());
|
|
75
|
+
|
|
76
|
+
let raw = "";
|
|
77
|
+
process.stdin.on("data", (c) => (raw += c));
|
|
78
|
+
process.stdin.on("end", () => {
|
|
79
|
+
let data = {};
|
|
80
|
+
try {
|
|
81
|
+
data = JSON.parse(raw || "{}");
|
|
82
|
+
} catch (_) {
|
|
83
|
+
// Unparseable payload — never block on our own error.
|
|
84
|
+
process.exit(0);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const tool = data.tool_name || "";
|
|
88
|
+
const input = data.tool_input || {};
|
|
89
|
+
const skill = String(input.skill || input.name || "");
|
|
90
|
+
|
|
91
|
+
// Only gate the full orchestrator and the compiled DIY lane. orc-mini /
|
|
92
|
+
// orc-fast / orc-analyze / subskills pass — orc-fast is DESIGNED to run at
|
|
93
|
+
// Sonnet medium; never widen this match to include it.
|
|
94
|
+
const isOrc = tool === "Skill" && /^orc$/i.test(skill);
|
|
95
|
+
const isDiy = tool === "Skill" && /^orc-diy$/i.test(skill);
|
|
96
|
+
if (!isOrc && !isDiy) process.exit(0);
|
|
97
|
+
|
|
98
|
+
const effort = String(
|
|
99
|
+
(data.effort && data.effort.level) || process.env.CLAUDE_EFFORT || ""
|
|
100
|
+
).toLowerCase();
|
|
101
|
+
const installed = updater ? updater.installedVersion(__dirname) : null;
|
|
102
|
+
const projectDir = data.cwd || process.cwd();
|
|
103
|
+
|
|
104
|
+
// Baseline /orc: the session must be at high effort OR stronger (xhigh/max).
|
|
105
|
+
// Opus 5.5 and Fable 5 additionally clear at medium — strictly-capable models —
|
|
106
|
+
// detected through the session-model bridge (the guard can't see the model id
|
|
107
|
+
// itself; fail-open when the bridge is missing/stale, i.e. medium stays blocked).
|
|
108
|
+
let requiredEfforts = effortsAtOrAbove("high");
|
|
109
|
+
let requiredLabel =
|
|
110
|
+
"Opus 4.8 at high effort (Opus 5.5 / Fable 5 also clear at medium+)";
|
|
111
|
+
if (!isDiy && isMediumOkModel(readSessionModel(projectDir))) {
|
|
112
|
+
requiredEfforts = ["medium", ...requiredEfforts];
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// /orc-diy: the required tier is whatever the flow was COMPILED for — read
|
|
116
|
+
// it from flow.lock.json (written only by the `orc diy` CLI). Fail closed:
|
|
117
|
+
// no lock = no compiled flow = deterministic onboarding block. `compile` /
|
|
118
|
+
// `status` invocations pass at any effort (they just shell out to the CLI).
|
|
119
|
+
if (isDiy) {
|
|
120
|
+
if (/^\s*(compile|status)\b/i.test(String(input.args || ""))) process.exit(0);
|
|
121
|
+
const fs = require("fs");
|
|
122
|
+
const path = require("path");
|
|
123
|
+
let lock = null;
|
|
124
|
+
try {
|
|
125
|
+
lock = JSON.parse(
|
|
126
|
+
fs
|
|
127
|
+
.readFileSync(
|
|
128
|
+
path.join(projectDir, ".claude", "orc", "diy", "flow.lock.json"),
|
|
129
|
+
"utf8"
|
|
130
|
+
)
|
|
131
|
+
.replace(/^\uFEFF/, "")
|
|
132
|
+
);
|
|
133
|
+
} catch (_) {}
|
|
134
|
+
if (!lock || !lock.session_tier) {
|
|
135
|
+
process.stderr.write(
|
|
136
|
+
"\n⛔ /orc-diy blocked — no compiled flow in this project (fail-closed gate)." +
|
|
137
|
+
"\n Compose and build your flow in the terminal first:" +
|
|
138
|
+
"\n orc diy init (then shape it: orc diy set <key> <value>)" +
|
|
139
|
+
"\n orc diy compile" +
|
|
140
|
+
"\n Guide: .claude/skills/orc-diy/README.md — or use plain /orc for this request.\n"
|
|
141
|
+
);
|
|
142
|
+
process.exit(2);
|
|
143
|
+
}
|
|
144
|
+
// Effort half is DETERMINISTIC from the compiled slug's suffix (allow that
|
|
145
|
+
// effort or anything stronger); the model half is warn-only on the
|
|
146
|
+
// statusline (hooks can't block on model). Covers the full tier grid —
|
|
147
|
+
// sonnet-4-6 / opus-4-7 / opus-4-8 / fable-5 at med|high|xhigh|max.
|
|
148
|
+
const m = String(lock.session_tier).match(/-(med|high|xhigh|max)$/);
|
|
149
|
+
const slugEffort = m ? (m[1] === "med" ? "medium" : m[1]) : "high";
|
|
150
|
+
requiredEfforts = effortsAtOrAbove(slugEffort);
|
|
151
|
+
requiredLabel = `${lock.session_tier} (compiled session_tier — needs effort ${slugEffort}+)`;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const decide = (nudge) => {
|
|
155
|
+
if (requiredEfforts.includes(effort)) {
|
|
156
|
+
// Requirement met — allow. Surface a version nudge if one exists.
|
|
157
|
+
if (nudge) {
|
|
158
|
+
try {
|
|
159
|
+
process.stdout.write(JSON.stringify({ systemMessage: nudge }));
|
|
160
|
+
} catch (_) {}
|
|
161
|
+
}
|
|
162
|
+
process.exit(0);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
process.stderr.write(
|
|
166
|
+
`\n⛔ ${isDiy ? "/orc-diy" : "ORC"} blocked — required effort not met` +
|
|
167
|
+
(effort ? ` (current effort: ${effort}).` : " (effort not detected).") +
|
|
168
|
+
`\n Switch this session to ${requiredLabel}, then re-run.` +
|
|
169
|
+
"\n Run the MAIN session at (or above) the required tier — subagents cannot" +
|
|
170
|
+
"\n exceed the main tier, so pinned agents silently downgrade below it.\n" +
|
|
171
|
+
(nudge ? "\n" + nudge + "\n" : "")
|
|
172
|
+
);
|
|
173
|
+
process.exit(2);
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
if (updater) updater.refreshAndNudge(installed, decide);
|
|
177
|
+
else decide(null);
|
|
178
|
+
});
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
* ICON carries the verdict and the words carry the installed ORC version — but
|
|
25
25
|
* the degrade branch still names every reason, because a warning with no reason
|
|
26
26
|
* is an emoji:
|
|
27
|
-
* ✅ ORC v1.2.1 - Opus 5/high Opus 4.8 high (the baseline)
|
|
28
|
-
* 🚀 ORC v1.2.1 - Opus 5/high Opus 4.8 xhigh/max, or Opus 5 / Fable 5 medium…max
|
|
27
|
+
* ✅ ORC v1.2.1 - Opus 5.5/high Opus 4.8 high (the baseline)
|
|
28
|
+
* 🚀 ORC v1.2.1 - Opus 5.5/high Opus 4.8 xhigh/max, or Opus 5.5 / Fable 5 medium…max
|
|
29
29
|
* ⛔ ORC v1.2.1 - Sonnet 5/high (why) everything below (wrong model, sub-baseline effort, quota)
|
|
30
30
|
*
|
|
31
31
|
* The two lines, in full (v1.2.1):
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
* This is the ONLY place Claude Code exposes the live model id, so it also
|
|
53
53
|
* writes a fail-silent session-model bridge (.claude/orc/session-model.json)
|
|
54
54
|
* that the PreToolUse effort guard reads — the guard can't see the model id
|
|
55
|
-
* on its own, so the bridge is how the Opus 5 / Fable 5 medium-effort allowance
|
|
55
|
+
* on its own, so the bridge is how the Opus 5.5 / Fable 5 medium-effort allowance
|
|
56
56
|
* reaches it.
|
|
57
57
|
*
|
|
58
58
|
* Also appends a "newer orc version available" hint from the 24h update cache
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
* over that budget — ORC_STATUSLINE_SCAN_MS — and nothing in ORC ever sets it.
|
|
67
67
|
*/
|
|
68
68
|
|
|
69
|
-
// Opus 4.8 / Opus 5 / Fable 5 are matched by tolerant regexes below (accept
|
|
69
|
+
// Opus 4.8 / Opus 5.5 / Fable 5 are matched by tolerant regexes below (accept
|
|
70
70
|
// dated/suffixed ids and the display name), not strict strings. Effort ranks give
|
|
71
71
|
// the acceptance-matrix tiers (0 = unknown, never treated as a positive downgrade).
|
|
72
72
|
const EFFORT_RANK = { low: 1, medium: 2, high: 3, xhigh: 4, max: 5 };
|
|
@@ -526,7 +526,7 @@ process.stdin.on("end", () => {
|
|
|
526
526
|
// ── Session-model bridge (fail-silent) ─────────────────────────────────────
|
|
527
527
|
// The PreToolUse effort guard cannot see the model id; it can only read
|
|
528
528
|
// effort. Persist {model_id, effort, written_at} here so the guard can grant
|
|
529
|
-
// the Opus 5 / Fable 5 medium-effort allowance. The statusline re-renders constantly
|
|
529
|
+
// the Opus 5.5 / Fable 5 medium-effort allowance. The statusline re-renders constantly
|
|
530
530
|
// while a session is active, so written_at stays fresh; the guard treats a
|
|
531
531
|
// stale file (older than its freshness window) as absent and never blocks on
|
|
532
532
|
// it. Any error (no dir, read-only fs) is swallowed — this is a nicety, not a
|
|
@@ -674,7 +674,7 @@ process.stdin.on("end", () => {
|
|
|
674
674
|
const hay = `${model} ${display}`.toLowerCase();
|
|
675
675
|
const isOpus48 = /opus[\s._-]?4[\s._-]?8\b/.test(hay);
|
|
676
676
|
const isFable5 = /fable[\s._-]?5\b/.test(hay);
|
|
677
|
-
// Opus 5 (v0.34.0) — strictly above the baseline, so it boosts from medium up,
|
|
677
|
+
// Opus 5.5 (v0.34.0) — strictly above the baseline, so it boosts from medium up,
|
|
678
678
|
// exactly like Fable 5. The `\b` keeps opus 4.8 / 4.7 out of this branch.
|
|
679
679
|
const isOpus5 = /opus[\s._-]?5\b/.test(hay);
|
|
680
680
|
const modelKnown = model !== "" || (display !== "" && display !== "unknown");
|
|
@@ -294,7 +294,7 @@ false.
|
|
|
294
294
|
on every later turn (~100K tokens across a 6-task run).
|
|
295
295
|
4. `code_graph_notes: wave` → once per wave. `end` → once, at the end of the
|
|
296
296
|
run, for every path the run changed.
|
|
297
|
-
5. Under `opus5_only` there is no Opus 5 noter. Print
|
|
297
|
+
5. Under `opus5_only` there is no Opus 5.5 noter. Print
|
|
298
298
|
`graph notes: skipped (opus5_only)` once and dispatch nothing.
|
|
299
299
|
|
|
300
300
|
## 7. Slice injection — and when NOT to inject
|