@azure-id/orc 1.9.2 → 2.1.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/CHANGELOG.md +722 -0
- package/README-id.md +56 -42
- package/README.md +58 -41
- package/bin/build-agents.js +125 -29
- package/bin/clear-logs.js +620 -0
- package/bin/cli.js +1873 -180
- package/bin/fix.js +459 -0
- package/bin/gotcha-import.js +1081 -0
- package/bin/gotcha.js +1566 -0
- package/bin/graph-query.js +1 -1
- package/bin/graph.js +717 -717
- package/bin/habit.js +1538 -0
- package/bin/mockrun-catalog.js +284 -276
- package/bin/onboarding-content.js +2 -1
- package/bin/pricing.json +28 -21
- package/bin/run-undo.js +398 -0
- package/bin/trace-write.js +869 -0
- package/bin/verify-contracts.js +627 -100
- package/bin/verify-package.js +68 -10
- package/bin/webui/api.js +151 -6
- package/bin/webui/app.html +239 -232
- package/bin/webui/css/00-tokens.css +110 -92
- package/bin/webui/css/04-motion.css +87 -0
- package/bin/webui/css/06-responsive.css +203 -178
- package/bin/webui/css/panels/behaviour.css +205 -0
- package/bin/webui/css/panels/hookui.css +79 -0
- package/bin/webui/fixtures/behaviour.js +562 -0
- package/bin/webui/fixtures/extra.js +9 -9
- package/bin/webui/fixtures/flow.js +81 -81
- package/bin/webui/fixtures/hookui.js +506 -431
- package/bin/webui/fixtures/index.js +66 -3
- package/bin/webui/fixtures/knowledge.js +9 -3
- package/bin/webui/fixtures/maintenance.js +123 -42
- package/bin/webui/fixtures/rules.js +1007 -1002
- package/bin/webui/fixtures/settings.js +6 -7
- package/bin/webui/fixtures/stats.js +25 -6
- package/bin/webui/fixtures/wait.js +98 -97
- package/bin/webui/i18n/en/behaviour.json +156 -0
- package/bin/webui/i18n/en/hookui.json +290 -194
- package/bin/webui/i18n/en/maintenance.json +71 -52
- package/bin/webui/i18n/en/nav.json +25 -24
- package/bin/webui/i18n/en/settings.json +60 -60
- package/bin/webui/i18n/en/tour.json +37 -35
- package/bin/webui/i18n/id/behaviour.json +156 -0
- package/bin/webui/i18n/id/hookui.json +290 -194
- package/bin/webui/i18n/id/maintenance.json +71 -52
- package/bin/webui/i18n/id/nav.json +25 -24
- package/bin/webui/i18n/id/settings.json +60 -60
- package/bin/webui/i18n/id/tour.json +37 -35
- package/bin/webui/js/01-i18n.js +155 -154
- package/bin/webui/js/05-banners.js +181 -172
- package/bin/webui/js/06-edit.js +193 -183
- package/bin/webui/js/90-tour.js +498 -494
- package/bin/webui/js/91-shortcuts.js +126 -126
- package/bin/webui/js/99-boot.js +121 -118
- package/bin/webui/js/panels/behaviour.js +1087 -0
- package/bin/webui/js/panels/hookui.js +2196 -1691
- package/bin/webui/js/panels/maintenance.js +336 -235
- package/bin/webui/js/panels/settings.js +726 -719
- package/mock-run/INDEX.md +110 -107
- package/mock-run/extra-slots.md +1 -1
- package/mock-run/gotcha-import.md +118 -0
- package/mock-run/habits.md +129 -0
- package/mock-run/orc-aftermath.md +392 -392
- package/mock-run/orc-budget.md +29 -33
- package/mock-run/orc-cli.md +200 -200
- package/mock-run/orc-explain.md +86 -86
- package/mock-run/orc-extra.md +389 -392
- package/mock-run/orc-fix.md +87 -0
- package/mock-run/orc-pattern.md +112 -112
- package/mock-run/orc-quick.md +6 -1
- package/mock-run/orc.md +157 -157
- package/package.json +1 -1
- package/templates/agents/MODEL-MAPPING.md +37 -34
- package/templates/agents/orc-advisor-opus-5-xhigh.md +1 -7
- package/templates/agents/orc-analyze-mini-opus-5-med.md +1 -6
- package/templates/agents/orc-analyze-mini-sonnet-5-high.md +2 -5
- package/templates/agents/{orc-claude-writer-opus-4-8-high.md → orc-claude-writer-opus-5-low.md} +48 -53
- package/templates/agents/orc-context-combiner-opus-5-high.md +1 -11
- package/templates/agents/orc-executor-haiku-4-5.md +14 -6
- package/templates/agents/orc-executor-opus-4-7-high.md +14 -6
- package/templates/agents/orc-executor-opus-4-7-med.md +14 -6
- package/templates/agents/orc-executor-opus-4-8-high.md +14 -6
- package/templates/agents/orc-executor-opus-5-high.md +14 -6
- package/templates/agents/orc-executor-opus-5-low.md +14 -6
- package/templates/agents/orc-executor-opus-5-med.md +14 -6
- package/templates/agents/orc-executor-sonnet-4-6-high.md +14 -6
- package/templates/agents/orc-executor-sonnet-4-6-med.md +14 -6
- package/templates/agents/orc-executor-sonnet-5-high.md +15 -7
- package/templates/agents/orc-executor-sonnet-5-low.md +155 -0
- package/templates/agents/orc-executor-sonnet-5-med.md +155 -0
- package/templates/agents/orc-graph-noter-sonnet-4-6-med.md +1 -10
- package/templates/agents/orc-judge-opus-5-xhigh.md +5 -9
- package/templates/agents/orc-learn-writer-opus-5-low.md +1 -7
- package/templates/agents/orc-pattern-codifier-opus-5-med.md +1 -8
- package/templates/agents/orc-pattern-codifier-sonnet-5-high.md +58 -63
- package/templates/agents/orc-planner-mini-opus-5-med.md +1 -4
- package/templates/agents/orc-planner-mini-sonnet-5-high.md +2 -3
- package/templates/agents/orc-planner-opus-5-med.md +1 -4
- package/templates/agents/orc-recon-opus-5-low.md +1 -8
- package/templates/agents/orc-recon-sonnet-4-6-med.md +1 -8
- package/templates/agents/orc-retro-opus-5-med.md +6 -8
- package/templates/agents/orc-retro-sonnet-5-high.md +7 -8
- package/templates/agents/orc-reviewer-opus-5-low.md +96 -0
- package/templates/agents/orc-scout-opus-5-low.md +1 -6
- package/templates/agents/orc-scout-sonnet-4-6-high.md +35 -39
- package/templates/agents/orc-system-analyst-opus-5-high.md +1 -6
- package/templates/agents/orc-test-author-opus-5-med.md +4 -5
- package/templates/agents/orc-trace-writer-haiku-4-5.md +3 -7
- package/templates/agents/orc-verifier-opus-5-med.md +16 -8
- package/templates/agents/{orc-wiki-scanner-opus-4-8-high.md → orc-wiki-scanner-opus-5-low.md} +74 -79
- package/templates/agents/orc-wiki-scanner-sonnet-5-high.md +97 -106
- package/templates/commands/orc-analyze.md +13 -21
- package/templates/commands/orc-fast.md +10 -15
- package/templates/commands/orc-fix.md +18 -0
- package/templates/commands/orc-poly.md +12 -21
- package/templates/commands/orc-pr-driver.md +11 -30
- package/templates/commands/orc-pr-setup.md +10 -31
- package/templates/commands/orc-route.md +11 -41
- package/templates/commands/orc-test.md +5 -60
- package/templates/commands/orc-wiki.md +64 -64
- package/templates/hooks/README.md +109 -7
- package/templates/hooks/orc-session-hook.js +339 -0
- package/templates/hooks/orc-statusline-render.js +317 -23
- package/templates/hooks/orc-statusline.js +165 -50
- package/templates/hooks/orc-subagent-line.js +23 -5
- package/templates/hooks/orc-weather-fetch.js +123 -0
- package/templates/skills/_shared/README.md +9 -0
- package/templates/skills/_shared/code-graph.md +47 -55
- package/templates/skills/_shared/config-precedence.md +3 -1
- package/templates/skills/_shared/extra-dispatch.md +78 -93
- package/templates/skills/_shared/gotchas.md +248 -177
- package/templates/skills/_shared/habits.md +101 -0
- package/templates/skills/_shared/lane-contract.md +84 -0
- package/templates/skills/_shared/opus5-only.md +14 -14
- package/templates/skills/_shared/phases/README.md +142 -83
- package/templates/skills/_shared/phases/analyst-gates.md +10 -21
- package/templates/skills/_shared/phases/execution.md +8 -14
- package/templates/skills/_shared/phases/house-rules.md +27 -32
- package/templates/skills/_shared/phases/intake.md +127 -133
- package/templates/skills/_shared/phases/mock-example.md +46 -56
- package/templates/skills/_shared/phases/plan-handoff.md +91 -97
- package/templates/skills/_shared/phases/planning.md +7 -17
- package/templates/skills/_shared/phases/preflight.md +19 -42
- package/templates/skills/_shared/phases/review.md +24 -28
- package/templates/skills/_shared/phases/rules.md +18 -42
- package/templates/skills/_shared/phases/scoring.md +55 -65
- package/templates/skills/_shared/phases/security-checklist.md +46 -50
- package/templates/skills/_shared/phases/security.md +45 -55
- package/templates/skills/_shared/phases/ship.md +6 -15
- package/templates/skills/_shared/phases/stop-resume.md +2 -5
- package/templates/skills/_shared/phases/summary.md +73 -48
- package/templates/skills/_shared/phases/testgen.md +41 -51
- package/templates/skills/_shared/phases/trace-verbs.md +447 -0
- package/templates/skills/_shared/phases/trace.md +66 -297
- package/templates/skills/_shared/phases/verify.md +62 -70
- package/templates/skills/_shared/phases/wave-grouping.md +128 -133
- package/templates/skills/_shared/phases/wiki-consult.md +10 -6
- package/templates/skills/_shared/read-ladder.md +2 -55
- package/templates/skills/_shared/return-validation.md +17 -70
- package/templates/skills/_shared/review-slice.md +106 -0
- package/templates/skills/_shared/smoke-gate.md +46 -28
- package/templates/skills/_shared/wait.md +1 -0
- package/templates/skills/context-combiner/SKILL.md +15 -44
- package/templates/skills/orc/README.md +2 -2
- package/templates/skills/orc/SKILL.md +35 -63
- package/templates/skills/orc/config.md +25 -27
- package/templates/skills/orc/examples/full-run-mock.md +2 -1
- package/templates/skills/orc/references/effort-and-mode.md +17 -17
- package/templates/skills/orc/references/pattern-gate.md +89 -89
- package/templates/skills/orc/references/phases/intake.md +41 -47
- package/templates/skills/orc/references/phases/integration.md +13 -19
- package/templates/skills/orc/references/preflight-report.md +11 -12
- package/templates/skills/orc/references/ultra-mode.md +9 -7
- package/templates/skills/orc/schemas/checkpoint.md +122 -122
- package/templates/skills/orc/subskills/orc-execution/SKILL.md +27 -73
- package/templates/skills/orc/subskills/orc-execution/core.md +12 -99
- package/templates/skills/orc/subskills/orc-execution/subagent.md +14 -13
- package/templates/skills/orc/subskills/orc-review-verify/SKILL.md +12 -53
- package/templates/skills/orc/subskills/orc-review-verify/core.md +52 -135
- package/templates/skills/orc/subskills/orc-review-verify/subagent.md +7 -7
- package/templates/skills/orc/subskills/orc-testgen/SKILL.md +11 -22
- package/templates/skills/orc/subskills/orc-testgen/core.md +20 -59
- package/templates/skills/orc/subskills/orc-testgen/subagent.md +7 -7
- package/templates/skills/orc-advisor/SKILL.md +56 -60
- package/templates/skills/orc-analyze/SKILL.md +33 -67
- package/templates/skills/orc-analyze/schemas/report-audit.md +2 -1
- package/templates/skills/orc-analyze/schemas/report-prose.md +2 -1
- package/templates/skills/orc-analyze-mini/SKILL.md +35 -70
- package/templates/skills/orc-claude/SKILL.md +14 -14
- package/templates/skills/orc-claude/examples/claude-run-mock.md +65 -65
- package/templates/skills/orc-diy/README.md +31 -0
- package/templates/skills/orc-diy/SKILL.md +27 -78
- package/templates/skills/orc-diy/references/blocks/pattern.md +18 -18
- package/templates/skills/orc-fast/SKILL.md +49 -75
- package/templates/skills/orc-fix/SKILL.md +110 -0
- package/templates/skills/orc-judge/SKILL.md +77 -82
- package/templates/skills/orc-mini/SKILL.md +64 -112
- package/templates/skills/orc-mini/examples/mini-run-mock.md +4 -2
- package/templates/skills/orc-pattern/SKILL.md +27 -48
- package/templates/skills/orc-poly/SKILL.md +32 -61
- package/templates/skills/orc-pr-driver/SKILL.md +25 -51
- package/templates/skills/orc-pr-driver/references/green-gate.md +113 -105
- package/templates/skills/orc-pr-setup/SKILL.md +20 -45
- package/templates/skills/orc-quick/README.md +44 -3
- package/templates/skills/orc-quick/SKILL.md +77 -108
- package/templates/skills/orc-quick/references/dispatch-gate.md +18 -6
- package/templates/skills/orc-quick/references/gh-mode.md +50 -1
- package/templates/skills/orc-quick/references/look.md +3 -1
- package/templates/skills/orc-retro/SKILL.md +20 -19
- package/templates/skills/orc-retro/examples/retro-mock.md +17 -17
- package/templates/skills/orc-route/SKILL.md +25 -45
- package/templates/skills/orc-test/SKILL.md +16 -37
- package/templates/skills/orc-verify/SKILL.md +14 -32
- package/templates/skills/orc-wait/SKILL.md +156 -163
- package/templates/skills/orc-wiki/README.md +325 -325
- package/templates/skills/orc-wiki/SKILL.md +195 -195
- package/templates/skills/orc-wiki/examples/wiki-run-mock.md +37 -37
- package/templates/skills/orc-wiki/references/extra.md +2 -2
- package/templates/skills/orc-wiki/references/partial-refresh.md +276 -271
- package/templates/skills/orc-wiki/references/phases/phase-0.md +2 -7
- package/templates/skills/orc-wiki/references/phases/phase-1.md +1 -6
- package/templates/skills/orc-wiki/references/phases/phase-2.md +4 -9
- package/templates/skills/orc-wiki/references/phases/phase-3.md +1 -6
- package/templates/skills/orc-wiki/references/phases/phase-3c.md +4 -8
- package/templates/agents/orc-claude-writer-opus-5-med.md +0 -55
- package/templates/agents/orc-reviewer-opus-5-med.md +0 -60
- package/templates/agents/orc-wiki-scanner-opus-5-med.md +0 -81
package/bin/webui/js/06-edit.js
CHANGED
|
@@ -1,183 +1,193 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/* 06-edit.js — orc ui client
|
|
3
|
-
editSet, editBar, applyEdits — the staged-write machinery Settings AND Flow
|
|
4
|
-
both use. Nothing is written until Apply; the CLI is still the only writer and
|
|
5
|
-
the only validator.
|
|
6
|
-
|
|
7
|
-
Loaded by app.html in the order its numeric prefix names. Classic
|
|
8
|
-
script, no import/export: an ES module import carries no query string,
|
|
9
|
-
and every static request here needs the per-launch session token. */
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
/* ============================================================ staged edits == */
|
|
13
|
-
//
|
|
14
|
-
// WRITES ARE BATCHED (v0.44.1). Every control used to commit on the spot: one
|
|
15
|
-
// click, one `orc config set`, one full re-render of the panel. Changing four
|
|
16
|
-
// keys meant four subprocesses and four re-renders, and each one scrolled the
|
|
17
|
-
// list out from under you — so a routine "set these five things" was a fight.
|
|
18
|
-
//
|
|
19
|
-
// Nothing is written until Apply now. Edits accumulate here, the affected rows
|
|
20
|
-
// mark themselves, and an edit bar at the bottom says how many are pending.
|
|
21
|
-
// The CLI is still the only writer and still the only validator; what changed
|
|
22
|
-
// is WHEN it is called, never by whom.
|
|
23
|
-
//
|
|
24
|
-
// An entry is `{kind: "set", value}` or `{kind: "reset"}` — a per-key reset is
|
|
25
|
-
// `orc config reset <key>` (it REMOVES the key from the file), which is not the
|
|
26
|
-
// same write as setting it to its default value, so it cannot be flattened into
|
|
27
|
-
// one.
|
|
28
|
-
function editSet(onChange) {
|
|
29
|
-
const map = new Map();
|
|
30
|
-
const api = {
|
|
31
|
-
map,
|
|
32
|
-
get size() {
|
|
33
|
-
return map.size;
|
|
34
|
-
},
|
|
35
|
-
// Staging a value back to what it already was CLEARS the edit rather than
|
|
36
|
-
// recording a no-op — otherwise "cancel" and "set it back by hand" would
|
|
37
|
-
// leave the bar claiming an unsaved change that would write nothing.
|
|
38
|
-
set(key, value, original) {
|
|
39
|
-
if (String(value) === String(original)) map.delete(key);
|
|
40
|
-
else map.set(key, { kind: "set", value: String(value), original: String(original) });
|
|
41
|
-
onChange(api);
|
|
42
|
-
},
|
|
43
|
-
reset(key) {
|
|
44
|
-
map.set(key, { kind: "reset" });
|
|
45
|
-
onChange(api);
|
|
46
|
-
},
|
|
47
|
-
// An ACTION entry (v0.49.2): a route and a body, staged like any other
|
|
48
|
-
// edit, applied by `applyActions`. `label` is what the pending list names —
|
|
49
|
-
// a count is not a change list.
|
|
50
|
-
action(key, route, body, label) {
|
|
51
|
-
map.set(key, { kind: "action", route, body, value: label });
|
|
52
|
-
onChange(api);
|
|
53
|
-
},
|
|
54
|
-
drop(key) {
|
|
55
|
-
map.delete(key);
|
|
56
|
-
onChange(api);
|
|
57
|
-
},
|
|
58
|
-
clear() {
|
|
59
|
-
map.clear();
|
|
60
|
-
onChange(api);
|
|
61
|
-
},
|
|
62
|
-
entries() {
|
|
63
|
-
return [...map.entries()];
|
|
64
|
-
},
|
|
65
|
-
};
|
|
66
|
-
return api;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// The bar. Apply is disabled with nothing pending; Reset is always offered
|
|
70
|
-
// (it is a write in its own right, not an undo); **Cancel appears only when
|
|
71
|
-
// there is something to cancel** — a permanently visible Cancel next to a
|
|
72
|
-
// disabled Apply reads as though the panel is broken.
|
|
73
|
-
function editBar(edits, { onApply, onReset, onCancel, resetLabel }) {
|
|
74
|
-
const bar = el("div", "edit-bar");
|
|
75
|
-
const summary = el("div", "edit-summary");
|
|
76
|
-
const actions = el("div", "edit-actions");
|
|
77
|
-
|
|
78
|
-
const apply = el("button", "btn btn-sm btn-primary", t("edits.apply"));
|
|
79
|
-
apply.type = "button";
|
|
80
|
-
apply.addEventListener("click", () => onApply(apply));
|
|
81
|
-
|
|
82
|
-
const reset = el("button", "btn btn-sm btn-ghost", resetLabel || t("edits.reset"));
|
|
83
|
-
reset.type = "button";
|
|
84
|
-
reset.addEventListener("click", onReset);
|
|
85
|
-
|
|
86
|
-
const cancel = el("button", "btn btn-sm btn-ghost", t("edits.cancel"));
|
|
87
|
-
cancel.type = "button";
|
|
88
|
-
cancel.addEventListener("click", onCancel);
|
|
89
|
-
|
|
90
|
-
bar.paint = () => {
|
|
91
|
-
const n = edits.size;
|
|
92
|
-
bar.classList.toggle("edit-bar-dirty", n > 0);
|
|
93
|
-
apply.disabled = n === 0;
|
|
94
|
-
apply.textContent = n ? t("edits.applyN", { n }) : t("edits.apply");
|
|
95
|
-
// The pending list is named, never counted: "3 changes" is not consent for
|
|
96
|
-
// three writes you can no longer see.
|
|
97
|
-
summary.replaceChildren();
|
|
98
|
-
if (!n) {
|
|
99
|
-
summary.append(el("span", "note", t("edits.none")));
|
|
100
|
-
} else {
|
|
101
|
-
summary.append(el("span", "note", t("edits.pending")));
|
|
102
|
-
const list = el("div", "edit-list");
|
|
103
|
-
for (const [key, e] of edits.entries()) {
|
|
104
|
-
const item = el("span", "edit-chip");
|
|
105
|
-
// Key names and values are CLI data — never translated.
|
|
106
|
-
item.append(el("span", "edit-key", key));
|
|
107
|
-
item.append(document.createTextNode(e.kind === "reset" ? " → " + t("edits.toDefault") : " → " + e.value));
|
|
108
|
-
list.append(item);
|
|
109
|
-
}
|
|
110
|
-
summary.append(list);
|
|
111
|
-
}
|
|
112
|
-
actions.replaceChildren();
|
|
113
|
-
actions.append(apply, reset);
|
|
114
|
-
if (n) actions.append(cancel);
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
bar.append(summary, actions);
|
|
118
|
-
bar.paint();
|
|
119
|
-
return bar;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Apply runs the staged writes ONE AT A TIME, in the order they were staged —
|
|
123
|
-
// the same sequence a terminal user would type, which matters because settings
|
|
124
|
-
// can shadow each other. A failure does not abort the rest: the remaining
|
|
125
|
-
// writes are independent, and stopping halfway would leave a state nobody
|
|
126
|
-
// chose. Every failure is reported by key.
|
|
127
|
-
async function applyEdits(edits, routes, button) {
|
|
128
|
-
const list = edits.entries();
|
|
129
|
-
if (!list.length) return { ok: true, failed: [] };
|
|
130
|
-
const label = button && button.textContent;
|
|
131
|
-
if (button) {
|
|
132
|
-
button.disabled = true;
|
|
133
|
-
button.textContent = t("edits.applying");
|
|
134
|
-
}
|
|
135
|
-
const failed = [];
|
|
136
|
-
for (const [key, e] of list) {
|
|
137
|
-
try {
|
|
138
|
-
const r = e.kind === "reset" ? await post(routes.reset, { key }) : await post(routes.set, { key, value: e.value });
|
|
139
|
-
if (!r.ok) failed.push(`${key}: ${(r.output || r.command || "").trim().split("\n")[0]}`);
|
|
140
|
-
} catch (err) {
|
|
141
|
-
failed.push(`${key}: ${err.message}`);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
if (button) {
|
|
145
|
-
button.disabled = false;
|
|
146
|
-
if (label) button.textContent = label;
|
|
147
|
-
}
|
|
148
|
-
if (failed.length) toast(t("edits.someFailed", { n: failed.length }), "bad", failed.join("\n"));
|
|
149
|
-
else toast(t("edits.applied", { n: list.length }), "ok");
|
|
150
|
-
return { ok: !failed.length, failed };
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// The same batching, for a panel whose edits are not key/value pairs (v0.49.2).
|
|
154
|
-
// The house-rule ledger stages ADDs, REMOVEs, TOGGLEs and MOVEs — four routes,
|
|
155
|
-
// four body shapes — so the entry carries its own `route` and `body` and this
|
|
156
|
-
// runs them one at a time in staged order. Every other rule of `applyEdits`
|
|
157
|
-
// holds exactly: a refused write NEVER aborts the rest, and every failure is
|
|
158
|
-
// reported by the key it was staged under.
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
}
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
/* 06-edit.js — orc ui client
|
|
3
|
+
editSet, editBar, applyEdits — the staged-write machinery Settings AND Flow
|
|
4
|
+
both use. Nothing is written until Apply; the CLI is still the only writer and
|
|
5
|
+
the only validator.
|
|
6
|
+
|
|
7
|
+
Loaded by app.html in the order its numeric prefix names. Classic
|
|
8
|
+
script, no import/export: an ES module import carries no query string,
|
|
9
|
+
and every static request here needs the per-launch session token. */
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
/* ============================================================ staged edits == */
|
|
13
|
+
//
|
|
14
|
+
// WRITES ARE BATCHED (v0.44.1). Every control used to commit on the spot: one
|
|
15
|
+
// click, one `orc config set`, one full re-render of the panel. Changing four
|
|
16
|
+
// keys meant four subprocesses and four re-renders, and each one scrolled the
|
|
17
|
+
// list out from under you — so a routine "set these five things" was a fight.
|
|
18
|
+
//
|
|
19
|
+
// Nothing is written until Apply now. Edits accumulate here, the affected rows
|
|
20
|
+
// mark themselves, and an edit bar at the bottom says how many are pending.
|
|
21
|
+
// The CLI is still the only writer and still the only validator; what changed
|
|
22
|
+
// is WHEN it is called, never by whom.
|
|
23
|
+
//
|
|
24
|
+
// An entry is `{kind: "set", value}` or `{kind: "reset"}` — a per-key reset is
|
|
25
|
+
// `orc config reset <key>` (it REMOVES the key from the file), which is not the
|
|
26
|
+
// same write as setting it to its default value, so it cannot be flattened into
|
|
27
|
+
// one.
|
|
28
|
+
function editSet(onChange) {
|
|
29
|
+
const map = new Map();
|
|
30
|
+
const api = {
|
|
31
|
+
map,
|
|
32
|
+
get size() {
|
|
33
|
+
return map.size;
|
|
34
|
+
},
|
|
35
|
+
// Staging a value back to what it already was CLEARS the edit rather than
|
|
36
|
+
// recording a no-op — otherwise "cancel" and "set it back by hand" would
|
|
37
|
+
// leave the bar claiming an unsaved change that would write nothing.
|
|
38
|
+
set(key, value, original) {
|
|
39
|
+
if (String(value) === String(original)) map.delete(key);
|
|
40
|
+
else map.set(key, { kind: "set", value: String(value), original: String(original) });
|
|
41
|
+
onChange(api);
|
|
42
|
+
},
|
|
43
|
+
reset(key) {
|
|
44
|
+
map.set(key, { kind: "reset" });
|
|
45
|
+
onChange(api);
|
|
46
|
+
},
|
|
47
|
+
// An ACTION entry (v0.49.2): a route and a body, staged like any other
|
|
48
|
+
// edit, applied by `applyActions`. `label` is what the pending list names —
|
|
49
|
+
// a count is not a change list.
|
|
50
|
+
action(key, route, body, label) {
|
|
51
|
+
map.set(key, { kind: "action", route, body, value: label });
|
|
52
|
+
onChange(api);
|
|
53
|
+
},
|
|
54
|
+
drop(key) {
|
|
55
|
+
map.delete(key);
|
|
56
|
+
onChange(api);
|
|
57
|
+
},
|
|
58
|
+
clear() {
|
|
59
|
+
map.clear();
|
|
60
|
+
onChange(api);
|
|
61
|
+
},
|
|
62
|
+
entries() {
|
|
63
|
+
return [...map.entries()];
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
return api;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// The bar. Apply is disabled with nothing pending; Reset is always offered
|
|
70
|
+
// (it is a write in its own right, not an undo); **Cancel appears only when
|
|
71
|
+
// there is something to cancel** — a permanently visible Cancel next to a
|
|
72
|
+
// disabled Apply reads as though the panel is broken.
|
|
73
|
+
function editBar(edits, { onApply, onReset, onCancel, resetLabel }) {
|
|
74
|
+
const bar = el("div", "edit-bar");
|
|
75
|
+
const summary = el("div", "edit-summary");
|
|
76
|
+
const actions = el("div", "edit-actions");
|
|
77
|
+
|
|
78
|
+
const apply = el("button", "btn btn-sm btn-primary", t("edits.apply"));
|
|
79
|
+
apply.type = "button";
|
|
80
|
+
apply.addEventListener("click", () => onApply(apply));
|
|
81
|
+
|
|
82
|
+
const reset = el("button", "btn btn-sm btn-ghost", resetLabel || t("edits.reset"));
|
|
83
|
+
reset.type = "button";
|
|
84
|
+
reset.addEventListener("click", onReset);
|
|
85
|
+
|
|
86
|
+
const cancel = el("button", "btn btn-sm btn-ghost", t("edits.cancel"));
|
|
87
|
+
cancel.type = "button";
|
|
88
|
+
cancel.addEventListener("click", onCancel);
|
|
89
|
+
|
|
90
|
+
bar.paint = () => {
|
|
91
|
+
const n = edits.size;
|
|
92
|
+
bar.classList.toggle("edit-bar-dirty", n > 0);
|
|
93
|
+
apply.disabled = n === 0;
|
|
94
|
+
apply.textContent = n ? t("edits.applyN", { n }) : t("edits.apply");
|
|
95
|
+
// The pending list is named, never counted: "3 changes" is not consent for
|
|
96
|
+
// three writes you can no longer see.
|
|
97
|
+
summary.replaceChildren();
|
|
98
|
+
if (!n) {
|
|
99
|
+
summary.append(el("span", "note", t("edits.none")));
|
|
100
|
+
} else {
|
|
101
|
+
summary.append(el("span", "note", t("edits.pending")));
|
|
102
|
+
const list = el("div", "edit-list");
|
|
103
|
+
for (const [key, e] of edits.entries()) {
|
|
104
|
+
const item = el("span", "edit-chip");
|
|
105
|
+
// Key names and values are CLI data — never translated.
|
|
106
|
+
item.append(el("span", "edit-key", key));
|
|
107
|
+
item.append(document.createTextNode(e.kind === "reset" ? " → " + t("edits.toDefault") : " → " + e.value));
|
|
108
|
+
list.append(item);
|
|
109
|
+
}
|
|
110
|
+
summary.append(list);
|
|
111
|
+
}
|
|
112
|
+
actions.replaceChildren();
|
|
113
|
+
actions.append(apply, reset);
|
|
114
|
+
if (n) actions.append(cancel);
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
bar.append(summary, actions);
|
|
118
|
+
bar.paint();
|
|
119
|
+
return bar;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Apply runs the staged writes ONE AT A TIME, in the order they were staged —
|
|
123
|
+
// the same sequence a terminal user would type, which matters because settings
|
|
124
|
+
// can shadow each other. A failure does not abort the rest: the remaining
|
|
125
|
+
// writes are independent, and stopping halfway would leave a state nobody
|
|
126
|
+
// chose. Every failure is reported by key.
|
|
127
|
+
async function applyEdits(edits, routes, button) {
|
|
128
|
+
const list = edits.entries();
|
|
129
|
+
if (!list.length) return { ok: true, failed: [] };
|
|
130
|
+
const label = button && button.textContent;
|
|
131
|
+
if (button) {
|
|
132
|
+
button.disabled = true;
|
|
133
|
+
button.textContent = t("edits.applying");
|
|
134
|
+
}
|
|
135
|
+
const failed = [];
|
|
136
|
+
for (const [key, e] of list) {
|
|
137
|
+
try {
|
|
138
|
+
const r = e.kind === "reset" ? await post(routes.reset, { key }) : await post(routes.set, { key, value: e.value });
|
|
139
|
+
if (!r.ok) failed.push(`${key}: ${(r.output || r.command || "").trim().split("\n")[0]}`);
|
|
140
|
+
} catch (err) {
|
|
141
|
+
failed.push(`${key}: ${err.message}`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
if (button) {
|
|
145
|
+
button.disabled = false;
|
|
146
|
+
if (label) button.textContent = label;
|
|
147
|
+
}
|
|
148
|
+
if (failed.length) toast(t("edits.someFailed", { n: failed.length }), "bad", failed.join("\n"));
|
|
149
|
+
else toast(t("edits.applied", { n: list.length }), "ok");
|
|
150
|
+
return { ok: !failed.length, failed };
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// The same batching, for a panel whose edits are not key/value pairs (v0.49.2).
|
|
154
|
+
// The house-rule ledger stages ADDs, REMOVEs, TOGGLEs and MOVEs — four routes,
|
|
155
|
+
// four body shapes — so the entry carries its own `route` and `body` and this
|
|
156
|
+
// runs them one at a time in staged order. Every other rule of `applyEdits`
|
|
157
|
+
// holds exactly: a refused write NEVER aborts the rest, and every failure is
|
|
158
|
+
// reported by the key it was staged under.
|
|
159
|
+
// `opts.stopOnFail` is the exception: POSITIONAL writes (the hook board) were
|
|
160
|
+
// each computed assuming every earlier one succeeded, so after a refusal the
|
|
161
|
+
// rest would hit the wrong part. It stops at the first failure; the panel
|
|
162
|
+
// passes `opts.stoppedText(n)` to name the n writes that were NOT sent.
|
|
163
|
+
async function applyActions(edits, button, opts) {
|
|
164
|
+
const o = opts || {};
|
|
165
|
+
const list = edits.entries();
|
|
166
|
+
if (!list.length) return { ok: true, failed: [] };
|
|
167
|
+
const label = button && button.textContent;
|
|
168
|
+
if (button) {
|
|
169
|
+
button.disabled = true;
|
|
170
|
+
button.textContent = t("edits.applying");
|
|
171
|
+
}
|
|
172
|
+
const failed = [];
|
|
173
|
+
for (const [key, e] of list) {
|
|
174
|
+
try {
|
|
175
|
+
const r = await post(e.route, e.body);
|
|
176
|
+
if (!r.ok) failed.push(`${key}: ${(r.output || r.command || "").trim().split("\n")[0]}`);
|
|
177
|
+
} catch (err) {
|
|
178
|
+
failed.push(`${key}: ${err.message}`);
|
|
179
|
+
}
|
|
180
|
+
if (o.stopOnFail && failed.length) {
|
|
181
|
+
const left = list.length - list.findIndex((x) => x[0] === key) - 1;
|
|
182
|
+
if (left > 0) failed.push(o.stoppedText ? o.stoppedText(left) : String(left));
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
if (button) {
|
|
187
|
+
button.disabled = false;
|
|
188
|
+
if (label) button.textContent = label;
|
|
189
|
+
}
|
|
190
|
+
if (failed.length) toast(t("edits.someFailed", { n: o.stopOnFail ? 1 : failed.length }), "bad", failed.join("\n"));
|
|
191
|
+
else toast(t("edits.applied", { n: list.length }), "ok");
|
|
192
|
+
return { ok: !failed.length, failed };
|
|
193
|
+
}
|