@imfusion/web-ui 0.10.1-dev.41.g467e0e1a → 0.10.1-dev.45.ga6a3c86a
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 +4 -5
- package/README.md +4 -33
- package/dist/icons.js +1 -2
- package/dist/paths-B5Ht3ETc.js +26 -0
- package/dist/vite/local-web-ui-link.d.ts +15 -6
- package/dist/vite.js +33 -44
- package/dist/web-ui-cli.js +129 -161
- package/package.json +9 -7
- package/src/llms/install-templates/hooks/baseline-staleness.sh +2 -0
- package/src/llms/install-templates/hooks/stop.sh +5 -2
- package/src/llms/skills/imf-web-ui/SKILL.md +13 -15
- package/src/llms/skills/imf-web-ui-audit/SKILL.md +4 -1
- package/src/llms/skills/imf-web-ui-conventions/SKILL.md +23 -24
- package/src/llms/skills/imf-web-ui-conventions/templates/AUDIT_CHECKLIST.md +1 -0
- package/src/llms/skills/imf-web-ui-conventions/topics/tooling.md +22 -23
- package/src/llms/skills/imf-web-ui-setup/SKILL.md +3 -2
- package/src/llms/skills/imf-web-ui-update/SKILL.md +7 -0
- package/dist/paths-CZtwNknt.js +0 -132
package/dist/web-ui-cli.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import { chmodSync as
|
|
4
|
-
import { dirname as
|
|
5
|
-
import { Command as
|
|
6
|
-
import * as
|
|
7
|
-
var
|
|
2
|
+
import { n as e, r as t, t as n } from "./paths-B5Ht3ETc.js";
|
|
3
|
+
import { chmodSync as r, cpSync as i, existsSync as a, lstatSync as o, mkdirSync as s, readFileSync as c, readdirSync as l, readlinkSync as u, realpathSync as d, rmSync as f, symlinkSync as p, writeFileSync as m } from "node:fs";
|
|
4
|
+
import { dirname as h, relative as g, resolve as _ } from "node:path";
|
|
5
|
+
import { Command as ee, Option as te } from "commander";
|
|
6
|
+
import * as v from "@clack/prompts";
|
|
7
|
+
var y = {
|
|
8
8
|
harnesses: {
|
|
9
9
|
claude: {
|
|
10
10
|
label: "Claude Code",
|
|
@@ -24,91 +24,91 @@ var b = {
|
|
|
24
24
|
skillsDir: ".agents/skills",
|
|
25
25
|
linkDir: ".claude/skills",
|
|
26
26
|
versionMarker: ".imf-web-ui-skill-version.json"
|
|
27
|
-
},
|
|
28
|
-
function
|
|
29
|
-
let t = e.indexOf(
|
|
30
|
-
return t === -1 || n === -1 ? null : e.slice(t, n +
|
|
27
|
+
}, ne = `<!-- ${y.namespace}:begin`, b = `<!-- ${y.namespace}:end -->`, re = _(e, y.templatesDir, "AGENTS.md"), x = _(t, "AGENTS.md");
|
|
28
|
+
function S(e) {
|
|
29
|
+
let t = e.indexOf(ne), n = e.indexOf(b);
|
|
30
|
+
return t === -1 || n === -1 ? null : e.slice(t, n + b.length);
|
|
31
31
|
}
|
|
32
|
-
function
|
|
33
|
-
if (!
|
|
34
|
-
let e =
|
|
32
|
+
function ie() {
|
|
33
|
+
if (!a(x)) return "absent";
|
|
34
|
+
let e = S(c(re, "utf-8"));
|
|
35
35
|
if (!e) return "absent";
|
|
36
|
-
let t =
|
|
37
|
-
return r === t ? "unchanged" : (
|
|
36
|
+
let t = c(x, "utf-8"), n = S(t), r = n ? t.replace(n, e) : `${t.trimEnd()}\n\n${e}\n`;
|
|
37
|
+
return r === t ? "unchanged" : (m(x, r), n ? "updated" : "added");
|
|
38
38
|
}
|
|
39
39
|
//#endregion
|
|
40
40
|
//#region src/cli/skills.ts
|
|
41
|
-
var
|
|
41
|
+
var C = Object.keys(y.harnesses).filter((e) => e in y.harnesses), w = [...C, "all"];
|
|
42
42
|
function T(e) {
|
|
43
|
-
return e === "all" ?
|
|
43
|
+
return e === "all" ? C : [e];
|
|
44
44
|
}
|
|
45
45
|
function E(e) {
|
|
46
|
-
return `./${
|
|
46
|
+
return `./${g(t, e)}`;
|
|
47
47
|
}
|
|
48
|
-
var D =
|
|
49
|
-
if (typeof N != "object" || !N || !("version" in N) || typeof N.version != "string") throw Error(`${
|
|
48
|
+
var D = y.namespace, O = y.versionMarker, k = _(e, y.skillsSource), A = _(t, y.skillsDir), j = _(t, y.linkDir), M = class extends Error {}, N = JSON.parse(c(_(e, "package.json"), "utf-8"));
|
|
49
|
+
if (typeof N != "object" || !N || !("version" in N) || typeof N.version != "string") throw Error(`${_(e, "package.json")} has no string "version" field`);
|
|
50
50
|
var P = N.version;
|
|
51
51
|
function F(e) {
|
|
52
52
|
return e === D || e.startsWith(`${D}-`);
|
|
53
53
|
}
|
|
54
54
|
function I() {
|
|
55
|
-
return
|
|
55
|
+
return a(k) ? l(k, { withFileTypes: !0 }).filter((e) => e.isDirectory() && F(e.name)).map((e) => e.name).sort() : [];
|
|
56
56
|
}
|
|
57
|
-
function
|
|
58
|
-
let t =
|
|
59
|
-
if (!
|
|
57
|
+
function ae(e) {
|
|
58
|
+
let t = _(A, e, O);
|
|
59
|
+
if (!a(t)) return null;
|
|
60
60
|
try {
|
|
61
|
-
let e = JSON.parse(
|
|
61
|
+
let e = JSON.parse(c(t, "utf-8"));
|
|
62
62
|
if (typeof e != "object" || !e) return null;
|
|
63
63
|
let n = "harnesses" in e && Array.isArray(e.harnesses) ? e.harnesses : null;
|
|
64
|
-
return n ?
|
|
64
|
+
return n ? C.filter((e) => n.includes(e)) : null;
|
|
65
65
|
} catch {
|
|
66
66
|
return null;
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
function L(e) {
|
|
70
70
|
for (let t of e) {
|
|
71
|
-
let e =
|
|
71
|
+
let e = ae(t);
|
|
72
72
|
if (e && e.length > 0) return e;
|
|
73
73
|
}
|
|
74
74
|
return null;
|
|
75
75
|
}
|
|
76
76
|
function R(e, t, n) {
|
|
77
|
-
if (
|
|
77
|
+
if (a(e)) for (let r of l(e).filter(F)) t.has(r) || (f(_(e, r), {
|
|
78
78
|
recursive: !0,
|
|
79
79
|
force: !0
|
|
80
|
-
}),
|
|
80
|
+
}), v.log.info(`Removed skill: ${r} (${n})`));
|
|
81
81
|
}
|
|
82
|
-
function
|
|
83
|
-
return
|
|
82
|
+
function oe() {
|
|
83
|
+
return a(j) && a(A) && d(j) === d(A);
|
|
84
84
|
}
|
|
85
|
-
function
|
|
86
|
-
let t =
|
|
87
|
-
r?.isSymbolicLink() &&
|
|
85
|
+
function z(e) {
|
|
86
|
+
let t = _(j, e), n = g(j, _(A, e)), r = o(t, { throwIfNoEntry: !1 });
|
|
87
|
+
r?.isSymbolicLink() && u(t) === n || (r && f(t, {
|
|
88
88
|
recursive: !0,
|
|
89
89
|
force: !0
|
|
90
|
-
}),
|
|
90
|
+
}), s(j, { recursive: !0 }), p(n, t));
|
|
91
91
|
}
|
|
92
|
-
function
|
|
92
|
+
function se(e, t) {
|
|
93
93
|
try {
|
|
94
|
-
|
|
95
|
-
let
|
|
96
|
-
for (let
|
|
97
|
-
let e =
|
|
98
|
-
|
|
94
|
+
s(A, { recursive: !0 });
|
|
95
|
+
let r = [];
|
|
96
|
+
for (let n of e) {
|
|
97
|
+
let e = _(A, n);
|
|
98
|
+
f(e, {
|
|
99
99
|
recursive: !0,
|
|
100
100
|
force: !0
|
|
101
|
-
}),
|
|
102
|
-
let
|
|
103
|
-
|
|
101
|
+
}), i(_(k, n), e, { recursive: !0 });
|
|
102
|
+
let a = _(e, O);
|
|
103
|
+
m(a, JSON.stringify({
|
|
104
104
|
version: P,
|
|
105
105
|
harnesses: t
|
|
106
|
-
}, null, 2) + "\n"),
|
|
106
|
+
}, null, 2) + "\n"), r.push(a);
|
|
107
107
|
}
|
|
108
|
-
if (
|
|
108
|
+
if (n(r), R(A, new Set(e), "no longer in this bundle"), v.log.success(`Skills -> ${E(A)}/${D}*`), oe()) return;
|
|
109
109
|
if (t.includes("claude")) {
|
|
110
|
-
for (let t of e)
|
|
111
|
-
R(j, new Set(e), "no longer in this bundle"),
|
|
110
|
+
for (let t of e) z(t);
|
|
111
|
+
R(j, new Set(e), "no longer in this bundle"), v.log.success(`Claude Code -> ${E(j)}/${D}* (symlinks -> ${E(A)})`);
|
|
112
112
|
} else R(j, /* @__PURE__ */ new Set(), "claude not selected");
|
|
113
113
|
} catch (e) {
|
|
114
114
|
throw e instanceof Error ? new M(e.message) : e;
|
|
@@ -116,68 +116,68 @@ function fe(e, t) {
|
|
|
116
116
|
}
|
|
117
117
|
//#endregion
|
|
118
118
|
//#region src/cli/hooks.ts
|
|
119
|
-
var
|
|
120
|
-
function
|
|
121
|
-
if (typeof e != "object" || !e || Array.isArray(e)) throw new
|
|
119
|
+
var B = _(e, y.templatesDir), V = _(B, "hooks"), H = _(t, y.hooksDir), U = class extends Error {};
|
|
120
|
+
function ce(e, t) {
|
|
121
|
+
if (typeof e != "object" || !e || Array.isArray(e)) throw new U(`${t} is not a JSON object.`);
|
|
122
122
|
let n = { ...e };
|
|
123
123
|
if ("hooks" in n) {
|
|
124
|
-
if (typeof n.hooks != "object" || n.hooks === null || Array.isArray(n.hooks)) throw new
|
|
125
|
-
for (let [e, r] of Object.entries(n.hooks)) if (!Array.isArray(r)) throw new
|
|
124
|
+
if (typeof n.hooks != "object" || n.hooks === null || Array.isArray(n.hooks)) throw new U(`${t}: "hooks" is not a JSON object.`);
|
|
125
|
+
for (let [e, r] of Object.entries(n.hooks)) if (!Array.isArray(r)) throw new U(`${t}: "hooks.${e}" is not a JSON array.`);
|
|
126
126
|
}
|
|
127
127
|
return n;
|
|
128
128
|
}
|
|
129
|
-
function
|
|
129
|
+
function W(e) {
|
|
130
130
|
let t;
|
|
131
131
|
try {
|
|
132
|
-
t = JSON.parse(
|
|
132
|
+
t = JSON.parse(c(e, "utf-8"));
|
|
133
133
|
} catch {
|
|
134
|
-
throw new
|
|
134
|
+
throw new U(`${e} is not valid JSON.`);
|
|
135
135
|
}
|
|
136
|
-
return
|
|
136
|
+
return ce(t, e);
|
|
137
137
|
}
|
|
138
|
-
function
|
|
139
|
-
let e =
|
|
140
|
-
|
|
138
|
+
function le() {
|
|
139
|
+
let e = l(V).filter((e) => e.endsWith(".sh"));
|
|
140
|
+
s(H, { recursive: !0 });
|
|
141
141
|
for (let t of e) {
|
|
142
|
-
let e =
|
|
143
|
-
|
|
142
|
+
let e = _(H, t);
|
|
143
|
+
i(_(V, t), e, { force: !0 }), r(e, 493);
|
|
144
144
|
}
|
|
145
|
-
let t =
|
|
146
|
-
for (let e of t)
|
|
145
|
+
let t = l(H).filter((t) => t.endsWith(".sh") && !e.includes(t));
|
|
146
|
+
for (let e of t) f(_(H, e), { force: !0 });
|
|
147
147
|
return {
|
|
148
148
|
installed: e,
|
|
149
149
|
removed: t
|
|
150
150
|
};
|
|
151
151
|
}
|
|
152
|
-
var
|
|
153
|
-
function
|
|
152
|
+
var G = `${y.hooksDir}/`;
|
|
153
|
+
function K(e) {
|
|
154
154
|
if (typeof e != "string") return null;
|
|
155
|
-
let t = e.lastIndexOf(
|
|
155
|
+
let t = e.lastIndexOf(G);
|
|
156
156
|
if (t === -1) return null;
|
|
157
|
-
let n = /^([\w.-]+)["']?$/.exec(e.slice(t +
|
|
157
|
+
let n = /^([\w.-]+)["']?$/.exec(e.slice(t + G.length));
|
|
158
158
|
return n ? n[1] : null;
|
|
159
159
|
}
|
|
160
|
-
function K(e) {
|
|
161
|
-
return typeof e == "object" && !!e && "hooks" in e && Array.isArray(e.hooks);
|
|
162
|
-
}
|
|
163
160
|
function q(e) {
|
|
164
|
-
return
|
|
161
|
+
return typeof e == "object" && !!e && "hooks" in e && Array.isArray(e.hooks);
|
|
165
162
|
}
|
|
166
163
|
function J(e) {
|
|
167
|
-
return
|
|
164
|
+
return q(e) ? e.hooks : null;
|
|
168
165
|
}
|
|
169
166
|
function Y(e) {
|
|
170
|
-
|
|
171
|
-
|
|
167
|
+
return typeof e == "object" && e && "command" in e ? e.command : void 0;
|
|
168
|
+
}
|
|
169
|
+
function X(e) {
|
|
170
|
+
let t = J(e);
|
|
171
|
+
return t ? t.map((e) => K(Y(e))).filter((e) => e !== null) : [];
|
|
172
172
|
}
|
|
173
|
-
function
|
|
173
|
+
function ue(e, t, n) {
|
|
174
174
|
e.hooks ??= {};
|
|
175
175
|
let r = 0, i = 0, a = [];
|
|
176
176
|
for (let [r, o] of Object.entries(e.hooks)) {
|
|
177
177
|
let s = 0, c = o.map((e) => {
|
|
178
|
-
if (!
|
|
178
|
+
if (!q(e)) return e;
|
|
179
179
|
let t = e.hooks, r = t.filter((e) => {
|
|
180
|
-
let t =
|
|
180
|
+
let t = K(Y(e));
|
|
181
181
|
return t === null || n.includes(t);
|
|
182
182
|
});
|
|
183
183
|
return s += t.length - r.length, r.length === t.length ? e : {
|
|
@@ -185,7 +185,7 @@ function he(e, t, n) {
|
|
|
185
185
|
hooks: r
|
|
186
186
|
};
|
|
187
187
|
}).filter((e) => {
|
|
188
|
-
let t =
|
|
188
|
+
let t = J(e);
|
|
189
189
|
return t === null || t.length > 0;
|
|
190
190
|
});
|
|
191
191
|
s !== 0 && (i += s, c.length === 0 && !(r in t) ? a.push(r) : e.hooks[r] = c);
|
|
@@ -194,8 +194,8 @@ function he(e, t, n) {
|
|
|
194
194
|
for (let [n, i] of Object.entries(t)) {
|
|
195
195
|
e.hooks[n] ??= [];
|
|
196
196
|
for (let t of i) {
|
|
197
|
-
let i =
|
|
198
|
-
e.hooks[n].some((e) =>
|
|
197
|
+
let i = X(t);
|
|
198
|
+
e.hooks[n].some((e) => X(e).some((e) => i.includes(e))) || (e.hooks[n].push(t), r++);
|
|
199
199
|
}
|
|
200
200
|
}
|
|
201
201
|
return {
|
|
@@ -203,72 +203,72 @@ function he(e, t, n) {
|
|
|
203
203
|
removed: i
|
|
204
204
|
};
|
|
205
205
|
}
|
|
206
|
-
function
|
|
207
|
-
let
|
|
208
|
-
for (let
|
|
209
|
-
let
|
|
210
|
-
if (
|
|
211
|
-
let e =
|
|
212
|
-
|
|
206
|
+
function de(e) {
|
|
207
|
+
let r = /* @__PURE__ */ new Map(), i = /* @__PURE__ */ new Map();
|
|
208
|
+
for (let n of C) {
|
|
209
|
+
let o = _(t, y.harnesses[n].hookSettings);
|
|
210
|
+
if (a(o) && r.set(n, W(o)), e.includes(n)) {
|
|
211
|
+
let e = _(B, y.harnesses[n].hookTemplate);
|
|
212
|
+
i.set(n, W(e).hooks ?? {});
|
|
213
213
|
}
|
|
214
214
|
}
|
|
215
|
-
let { installed:
|
|
216
|
-
|
|
217
|
-
for (let
|
|
218
|
-
let
|
|
219
|
-
if (!
|
|
220
|
-
let
|
|
215
|
+
let { installed: o, removed: c } = le();
|
|
216
|
+
v.log.success(`Agent hooks -> ${E(H)} (${String(o.length)} scripts)`), c.length > 0 && v.log.info(`Removed stale hook script(s): ${c.join(", ")} (no longer shipped)`);
|
|
217
|
+
for (let a of C) {
|
|
218
|
+
let c = e.includes(a);
|
|
219
|
+
if (!c && !r.has(a)) continue;
|
|
220
|
+
let l = _(t, y.harnesses[a].hookSettings), u = i.get(a) ?? {}, d = r.get(a) ?? {}, f = ue(d, u, c ? o : []);
|
|
221
221
|
if (f.added === 0 && f.removed === 0) {
|
|
222
|
-
|
|
222
|
+
c && v.log.info(`Hook registrations already present in ${E(l)}`);
|
|
223
223
|
continue;
|
|
224
224
|
}
|
|
225
|
-
|
|
225
|
+
s(h(l), { recursive: !0 }), m(l, JSON.stringify(d, null, 2) + "\n"), n([l]);
|
|
226
226
|
let p = [f.added > 0 && `registered ${String(f.added)}`, f.removed > 0 && `removed ${String(f.removed)} stale`].filter(Boolean);
|
|
227
|
-
|
|
227
|
+
v.log.success(`${p.join(", ")} hook registration(s) in ${E(l)}`);
|
|
228
228
|
}
|
|
229
229
|
}
|
|
230
230
|
//#endregion
|
|
231
231
|
//#region src/cli/index.ts
|
|
232
|
-
function
|
|
233
|
-
return new
|
|
232
|
+
function Z() {
|
|
233
|
+
return new te("--harness <harness>", "claude, codex, or all").choices(w);
|
|
234
234
|
}
|
|
235
|
-
async function
|
|
236
|
-
if (t) return
|
|
235
|
+
async function fe(e, t, n) {
|
|
236
|
+
if (t) return v.log.info(`Harness from --harness flag: ${t.join(", ")}`), t;
|
|
237
237
|
let r = L(e);
|
|
238
|
-
if (r && !n) return
|
|
238
|
+
if (r && !n) return v.log.info(`Refreshing the existing install: ${r.join(", ")} — pass --reconfigure to choose differently.`), r;
|
|
239
239
|
if (!process.stdin.isTTY) return console.error("Pass --harness=claude|codex|all — no terminal to prompt in."), process.exitCode = 1, null;
|
|
240
|
-
let i = await
|
|
240
|
+
let i = await v.multiselect({
|
|
241
241
|
message: "Install into which harness (or harnesses)?",
|
|
242
|
-
options:
|
|
242
|
+
options: C.map((e) => ({
|
|
243
243
|
value: e,
|
|
244
|
-
label:
|
|
244
|
+
label: y.harnesses[e].label
|
|
245
245
|
})),
|
|
246
246
|
required: !0
|
|
247
247
|
});
|
|
248
|
-
return
|
|
248
|
+
return v.isCancel(i) ? (v.cancel("Cancelled — nothing installed."), null) : i;
|
|
249
249
|
}
|
|
250
|
-
async function
|
|
250
|
+
async function pe(e) {
|
|
251
251
|
let t = e.harness ? T(e.harness) : null, n = I();
|
|
252
|
-
if (
|
|
253
|
-
|
|
252
|
+
if (v.intro(`@imfusion/web-ui install skills — ${String(n.length)} skills`), n.length === 0) {
|
|
253
|
+
v.log.error("No skills found. Reinstall @imfusion/web-ui and try again."), v.outro("Nothing installed."), process.exitCode = 1;
|
|
254
254
|
return;
|
|
255
255
|
}
|
|
256
|
-
let r = await
|
|
256
|
+
let r = await fe(n, t, e.reconfigure === !0);
|
|
257
257
|
if (!r) return;
|
|
258
|
-
|
|
258
|
+
v.log.message(`Skills in this bundle:\n${n.map((e) => ` - ${e}`).join("\n")}`);
|
|
259
259
|
try {
|
|
260
|
-
|
|
260
|
+
se(n, r);
|
|
261
261
|
} catch (e) {
|
|
262
262
|
if (e instanceof M) {
|
|
263
|
-
|
|
263
|
+
v.log.error(e.message), v.outro("Install failed."), process.exitCode = 1;
|
|
264
264
|
return;
|
|
265
265
|
}
|
|
266
266
|
throw e;
|
|
267
267
|
}
|
|
268
|
-
let i =
|
|
269
|
-
(i === "updated" || i === "added") &&
|
|
268
|
+
let i = ie();
|
|
269
|
+
(i === "updated" || i === "added") && v.log.success(`Refreshed the ${y.namespace} block in ./AGENTS.md`), v.outro(`Done — ${String(n.length)} skills installed.`);
|
|
270
270
|
}
|
|
271
|
-
function
|
|
271
|
+
function me(e) {
|
|
272
272
|
let t = e.harness ? T(e.harness) : null, n = L(I());
|
|
273
273
|
if (!t && !n) {
|
|
274
274
|
console.error("No harness recorded. Pass --harness=claude|codex|all."), process.exitCode = 1;
|
|
@@ -278,56 +278,24 @@ function ve(e) {
|
|
|
278
278
|
if (i.length > 0) {
|
|
279
279
|
for (let e of i) console.error(`No skills installed for ${e}. Run \`npx web-ui install skills --harness=${e}\` first.`);
|
|
280
280
|
process.exitCode = 1;
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
281
|
+
} else {
|
|
282
|
+
v.intro("@imfusion/web-ui install hooks");
|
|
283
|
+
try {
|
|
284
|
+
de(r);
|
|
285
|
+
} catch (e) {
|
|
286
|
+
if (e instanceof U) {
|
|
287
|
+
console.error(e.message), process.exitCode = 1;
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
throw e;
|
|
290
291
|
}
|
|
291
|
-
|
|
292
|
-
}
|
|
293
|
-
y.outro("Done — agent hooks installed.");
|
|
294
|
-
}
|
|
295
|
-
function ye(r) {
|
|
296
|
-
let i = r ?? process.env.WEB_UI_CHECKOUT;
|
|
297
|
-
if (!i) {
|
|
298
|
-
console.error("Pass the checkout path, or set WEB_UI_CHECKOUT."), process.exitCode = 1;
|
|
299
|
-
return;
|
|
300
|
-
}
|
|
301
|
-
let o = v(i);
|
|
302
|
-
try {
|
|
303
|
-
let t = e(a, o);
|
|
304
|
-
y.log.success(`Linked ${o} into ${E(t)}`);
|
|
305
|
-
} catch (e) {
|
|
306
|
-
if (e instanceof n) {
|
|
307
|
-
console.error(e.message), process.exitCode = 1;
|
|
308
|
-
return;
|
|
309
|
-
}
|
|
310
|
-
throw e;
|
|
311
|
-
}
|
|
312
|
-
y.log.info("Syncing on every rebuild of dist/. Ctrl+C stops syncing; the app keeps the last synced build."), t(a, o, (e) => {
|
|
313
|
-
y.log.info(e);
|
|
314
|
-
});
|
|
315
|
-
}
|
|
316
|
-
function be() {
|
|
317
|
-
try {
|
|
318
|
-
for (let e of i(a)) y.log.message(e);
|
|
319
|
-
} catch (e) {
|
|
320
|
-
if (e instanceof n) {
|
|
321
|
-
console.error(e.message), process.exitCode = 1;
|
|
322
|
-
return;
|
|
323
|
-
}
|
|
324
|
-
throw e;
|
|
292
|
+
v.outro("Done — agent hooks installed.");
|
|
325
293
|
}
|
|
326
294
|
}
|
|
327
|
-
var Q = new
|
|
295
|
+
var Q = new ee();
|
|
328
296
|
Q.name("web-ui").description("Command-line tools for @imfusion/web-ui").version(P);
|
|
329
297
|
var $ = Q.command("install").description("Install @imfusion/web-ui agent skills or hooks into a project");
|
|
330
|
-
$.command("skills").description("Install skills for the chosen harness").addOption(
|
|
298
|
+
$.command("skills").description("Install skills for the chosen harness").addOption(Z()).option("--reconfigure", "Re-open the harness selection prompt on an existing install").action(pe), $.command("hooks").description("Install agent lifecycle hooks (requires skills already installed for the harness)").addOption(Z()).action(me), $.action(() => {
|
|
331
299
|
$.help();
|
|
332
300
|
}), Q.action(() => {
|
|
333
301
|
Q.help();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@imfusion/web-ui",
|
|
3
|
-
"version": "0.10.1-dev.
|
|
3
|
+
"version": "0.10.1-dev.45.ga6a3c86a",
|
|
4
4
|
"description": "The official Web UI component library for ImFusion web apps",
|
|
5
5
|
"author": "ImFusion GmbH",
|
|
6
6
|
"homepage": "https://imfusion.com",
|
|
@@ -138,7 +138,7 @@
|
|
|
138
138
|
"@types/react": "19.2.14",
|
|
139
139
|
"@types/react-dom": "19.2.3",
|
|
140
140
|
"@vitejs/plugin-react": "6.0.1",
|
|
141
|
-
"@vitest/browser-playwright": "5.0.
|
|
141
|
+
"@vitest/browser-playwright": "5.0.4",
|
|
142
142
|
"concurrently": "9.2.1",
|
|
143
143
|
"culori": "4.0.2",
|
|
144
144
|
"fast-xml-parser": "5.11.2",
|
|
@@ -148,19 +148,21 @@
|
|
|
148
148
|
"mermaid": "12.0.0",
|
|
149
149
|
"playwright": "1.60.0",
|
|
150
150
|
"prettier": "3.8.3",
|
|
151
|
+
"react": "19.2.5",
|
|
151
152
|
"react-docgen-typescript": "2.4.0",
|
|
153
|
+
"react-dom": "19.2.5",
|
|
152
154
|
"remark-gfm": "4.0.1",
|
|
153
155
|
"storybook": "10.6.2",
|
|
154
156
|
"tsx": "4.21.0",
|
|
155
157
|
"typescript": "6.0.3",
|
|
156
|
-
"vite": "npm:@voidzero-dev/vite-plus-core@1.
|
|
158
|
+
"vite": "npm:@voidzero-dev/vite-plus-core@1.2.0",
|
|
157
159
|
"vite-plugin-dts": "5.0.0",
|
|
158
|
-
"vite-plus": "1.
|
|
159
|
-
"vitest": "5.0.
|
|
160
|
+
"vite-plus": "1.2.0",
|
|
161
|
+
"vitest": "5.0.4"
|
|
160
162
|
},
|
|
161
163
|
"overrides": {
|
|
162
|
-
"vite": "npm:@voidzero-dev/vite-plus-core@1.
|
|
163
|
-
"vitest": "5.0.
|
|
164
|
+
"vite": "npm:@voidzero-dev/vite-plus-core@1.2.0",
|
|
165
|
+
"vitest": "5.0.4",
|
|
164
166
|
"storybook": {
|
|
165
167
|
".": "$storybook",
|
|
166
168
|
"vite-plus": "$vite-plus"
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
# and warns on drift. Always exits 0 — staleness never blocks a commit.
|
|
5
5
|
PKG=node_modules/@imfusion/web-ui/package.json
|
|
6
6
|
[ -f "$PKG" ] || exit 0
|
|
7
|
+
# A symlinked checkout reports its own dev version.
|
|
8
|
+
[ -L node_modules/@imfusion/web-ui ] && exit 0
|
|
7
9
|
CURRENT=$(node -p "require('./$PKG').version" 2>/dev/null) || exit 0
|
|
8
10
|
|
|
9
11
|
# .claude/skills may be a symlink to .agents/skills; skip markers already read.
|
|
@@ -10,9 +10,12 @@ git rev-parse --is-inside-work-tree >/dev/null 2>&1 || exit 0
|
|
|
10
10
|
[ -n "$(git status --porcelain -- '*.ts' '*.tsx' '*.js' '*.jsx' '*.css' 2>/dev/null)" ] || exit 0
|
|
11
11
|
# Gate only turns that actually edited files — a tree left dirty by an earlier
|
|
12
12
|
# session must not block a question-answering turn. Edit evidence: Write/Edit
|
|
13
|
-
# tool calls (Claude transcript) or apply_patch calls (Codex rollout)
|
|
13
|
+
# tool calls (Claude transcript) or apply_patch calls (Codex rollout), searched
|
|
14
|
+
# only after the turn's opening entry: the last real user prompt (not a tool
|
|
15
|
+
# result or injected meta message) or the last Codex task_started event.
|
|
14
16
|
TRANSCRIPT=$(printf '%s' "$PAYLOAD" | sed -n 's/.*"transcript_path"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -n 1)
|
|
15
17
|
[ -f "$TRANSCRIPT" ] || exit 0
|
|
16
|
-
grep -
|
|
18
|
+
TURN_START=$(grep -En '"type":"user"|"type":"task_started"' "$TRANSCRIPT" | grep -Ev '"type":"tool_result"|"isMeta":true' | tail -n 1 | cut -d: -f1)
|
|
19
|
+
tail -n +$(( ${TURN_START:-0} + 1 )) "$TRANSCRIPT" | grep -Eq '"name":"Write"|"name":"Edit"|"name":"MultiEdit"|"name":"NotebookEdit"|"name":"apply_patch"' || exit 0
|
|
17
20
|
printf '{"decision":"block","reason":"web-ui stop gate: this turn changed source files. Run the project verification (verify:typecheck, verify:lint, and verify:format at minimum), fix what it reports, then finish. If it already ran after the last change, say so and finish."}\n'
|
|
18
21
|
exit 0
|
|
@@ -3,8 +3,7 @@ name: imf-web-ui
|
|
|
3
3
|
description:
|
|
4
4
|
"Route UI work and library questions in a project that uses @imfusion/web-ui. Use this skill whenever a user adds, edits,
|
|
5
5
|
styles, or reviews UI, or asks about library setup, brand assets, favicons, theming, or usage in a consumer project, even
|
|
6
|
-
if they do not mention the library.
|
|
7
|
-
matching packaged guide or companion skill."
|
|
6
|
+
if they do not mention the library. Open only the matching packaged guide or companion skill."
|
|
8
7
|
---
|
|
9
8
|
|
|
10
9
|
# Route Web UI work
|
|
@@ -24,19 +23,18 @@ may not already have. Open a companion by invoking its skill; reading one of its
|
|
|
24
23
|
|
|
25
24
|
## 2. Route the task
|
|
26
25
|
|
|
27
|
-
| Task | Open
|
|
28
|
-
| -------------------------------------------------------------------- |
|
|
29
|
-
| Understand library setup, brand assets, theming, or usage | Packaged user guides below
|
|
30
|
-
| Look up a component, part, prop, default, or icon | `imf-web-ui-components`
|
|
31
|
-
| Choose components or shape a screen, form, or flow | `imf-web-ui-ux`
|
|
32
|
-
| Write or update documentation | `imf-web-ui-conventions`
|
|
33
|
-
| Write a wrapper, custom UI, CSS, data layer, validation, or tests | `imf-web-ui-conventions`
|
|
34
|
-
| Choose a routing, data, form, or validation library for the project | `imf-web-ui-conventions`
|
|
35
|
-
| Install the library or bootstrap project tooling | `imf-web-ui-setup`
|
|
36
|
-
| Diagnose a broken install: unstyled output, missing tokens, no theme | `imf-web-ui-setup`
|
|
37
|
-
| Inspect an existing project without changing it | `imf-web-ui-audit`
|
|
38
|
-
| Update the package, skills, or hooks | `imf-web-ui-update`
|
|
39
|
-
| Link, unlink, or use a live local Web UI checkout | `imf-web-ui-conventions` `tooling` topic |
|
|
26
|
+
| Task | Open |
|
|
27
|
+
| -------------------------------------------------------------------- | -------------------------- |
|
|
28
|
+
| Understand library setup, brand assets, theming, or usage | Packaged user guides below |
|
|
29
|
+
| Look up a component, part, prop, default, or icon | `imf-web-ui-components` |
|
|
30
|
+
| Choose components or shape a screen, form, or flow | `imf-web-ui-ux` |
|
|
31
|
+
| Write or update documentation | `imf-web-ui-conventions` |
|
|
32
|
+
| Write a wrapper, custom UI, CSS, data layer, validation, or tests | `imf-web-ui-conventions` |
|
|
33
|
+
| Choose a routing, data, form, or validation library for the project | `imf-web-ui-conventions` |
|
|
34
|
+
| Install the library or bootstrap project tooling | `imf-web-ui-setup` |
|
|
35
|
+
| Diagnose a broken install: unstyled output, missing tokens, no theme | `imf-web-ui-setup` |
|
|
36
|
+
| Inspect an existing project without changing it | `imf-web-ui-audit` |
|
|
37
|
+
| Update the package, skills, or hooks | `imf-web-ui-update` |
|
|
40
38
|
|
|
41
39
|
A new form opens `imf-web-ui-ux`, even when its fields and action are already specified. A screen often needs both
|
|
42
40
|
`imf-web-ui-ux` and `imf-web-ui-components`, in that order. Setup and audit are for project-wide questions, not every
|
|
@@ -61,7 +61,10 @@ Classify every result as one of these:
|
|
|
61
61
|
Use the report contract's severity, `path:line` evidence, concrete impact, and smallest next action. Unverified entries use
|
|
62
62
|
that same structure: unavailable runtime evidence, the impact of the unknown, and the check that resolves it. Do not promote
|
|
63
63
|
an optional tool or a working alternative to a missing finding. A `vite.config.ts` without `localWebUILink()` registered from
|
|
64
|
-
`@imfusion/web-ui/vite` is Missing.
|
|
64
|
+
`@imfusion/web-ui/vite` is Missing. A `tsconfig.json` without the `paths` block from the `tooling` topic is Missing too. Each
|
|
65
|
+
next action is the add from that topic. A major or minor mismatch between the project and Web UI on a package listed under
|
|
66
|
+
Aligned runtime packages in the `tooling` topic is a Deviation. Report both versions, with
|
|
67
|
+
`npm install <package>@<Web UI's version>` as the fix.
|
|
65
68
|
|
|
66
69
|
## Topics
|
|
67
70
|
|