@fenglimg/fabric-server 1.0.0 → 1.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/dist/chunk-U3IQH5H6.js +851 -0
- package/dist/{http-3BNWQWPP.js → http-FL3MB4L2.js} +45 -422
- package/dist/index.d.ts +61 -1
- package/dist/index.js +154 -38
- package/dist/static/assets/index-BiK8yn_c.js +5 -0
- package/dist/static/index.html +1 -1
- package/package.json +3 -3
- package/dist/chunk-KZO24GUQ.js +0 -199
- package/dist/static/assets/index-D_EcxWYV.js +0 -5
package/dist/chunk-KZO24GUQ.js
DELETED
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
// src/meta-reader.ts
|
|
2
|
-
import { readFileSync } from "fs";
|
|
3
|
-
import { join } from "path";
|
|
4
|
-
import { agentsMetaSchema } from "@fenglimg/fabric-shared";
|
|
5
|
-
import { agentsMetaNodeSchema, agentsMetaSchema as agentsMetaSchema2 } from "@fenglimg/fabric-shared";
|
|
6
|
-
var AgentsMetaFileMissingError = class extends Error {
|
|
7
|
-
constructor(metaPath) {
|
|
8
|
-
super(`Fabric agents metadata file is missing: ${metaPath}`);
|
|
9
|
-
this.metaPath = metaPath;
|
|
10
|
-
this.name = "AgentsMetaFileMissingError";
|
|
11
|
-
}
|
|
12
|
-
metaPath;
|
|
13
|
-
code = "FABRIC_META_MISSING";
|
|
14
|
-
};
|
|
15
|
-
var AgentsMetaInvalidError = class extends Error {
|
|
16
|
-
constructor(metaPath, cause) {
|
|
17
|
-
const detail = cause instanceof Error ? cause.message : String(cause);
|
|
18
|
-
super(`Fabric agents metadata file is invalid: ${metaPath}. ${detail}`);
|
|
19
|
-
this.metaPath = metaPath;
|
|
20
|
-
this.name = "AgentsMetaInvalidError";
|
|
21
|
-
}
|
|
22
|
-
metaPath;
|
|
23
|
-
code = "FABRIC_META_INVALID";
|
|
24
|
-
};
|
|
25
|
-
function getAgentsMetaPath(projectRoot) {
|
|
26
|
-
return join(projectRoot, ".fabric", "agents.meta.json");
|
|
27
|
-
}
|
|
28
|
-
function resolveProjectRoot() {
|
|
29
|
-
return process.env.FABRIC_PROJECT_ROOT ?? process.cwd();
|
|
30
|
-
}
|
|
31
|
-
function readAgentsMeta(projectRoot) {
|
|
32
|
-
const metaPath = getAgentsMetaPath(projectRoot);
|
|
33
|
-
let raw;
|
|
34
|
-
try {
|
|
35
|
-
raw = readFileSync(metaPath, "utf8");
|
|
36
|
-
} catch (error) {
|
|
37
|
-
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
|
|
38
|
-
throw new AgentsMetaFileMissingError(metaPath);
|
|
39
|
-
}
|
|
40
|
-
throw error;
|
|
41
|
-
}
|
|
42
|
-
try {
|
|
43
|
-
return agentsMetaSchema.parse(JSON.parse(raw));
|
|
44
|
-
} catch (error) {
|
|
45
|
-
throw new AgentsMetaInvalidError(metaPath, error);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// src/services/read-ledger.ts
|
|
50
|
-
import { randomUUID } from "crypto";
|
|
51
|
-
import { appendFile, readFile } from "fs/promises";
|
|
52
|
-
import { join as join2 } from "path";
|
|
53
|
-
import { ledgerEntrySchema } from "@fenglimg/fabric-shared";
|
|
54
|
-
|
|
55
|
-
// src/services/_shared.ts
|
|
56
|
-
import { resolve, sep } from "path";
|
|
57
|
-
import { createHash } from "crypto";
|
|
58
|
-
import { rename, writeFile } from "fs/promises";
|
|
59
|
-
var FABRIC_DIR = ".fabric";
|
|
60
|
-
var HUMAN_LOCK_FILE = "human-lock.json";
|
|
61
|
-
var LEDGER_FILE = ".intent-ledger.jsonl";
|
|
62
|
-
async function atomicWriteText(path, content) {
|
|
63
|
-
const tempPath = `${path}.${process.pid}.${Date.now()}.tmp`;
|
|
64
|
-
await writeFile(tempPath, content, "utf8");
|
|
65
|
-
await rename(tempPath, path);
|
|
66
|
-
}
|
|
67
|
-
function sha256(content) {
|
|
68
|
-
return `sha256:${createHash("sha256").update(content).digest("hex")}`;
|
|
69
|
-
}
|
|
70
|
-
function isNodeError(error) {
|
|
71
|
-
return error instanceof Error;
|
|
72
|
-
}
|
|
73
|
-
function assertPathWithinProjectRoot(projectRoot, file) {
|
|
74
|
-
const normalizedProjectRoot = resolve(projectRoot);
|
|
75
|
-
const absolutePath = resolve(normalizedProjectRoot, file);
|
|
76
|
-
const rootPrefix = normalizedProjectRoot.endsWith(sep) ? normalizedProjectRoot : `${normalizedProjectRoot}${sep}`;
|
|
77
|
-
if (!absolutePath.startsWith(rootPrefix)) {
|
|
78
|
-
throw new Error(`Path escapes project root: ${file}`);
|
|
79
|
-
}
|
|
80
|
-
return absolutePath;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// src/services/read-ledger.ts
|
|
84
|
-
async function readLedger(projectRoot, options = {}) {
|
|
85
|
-
const ledgerPath = join2(projectRoot, LEDGER_FILE);
|
|
86
|
-
let raw;
|
|
87
|
-
try {
|
|
88
|
-
raw = await readFile(ledgerPath, "utf8");
|
|
89
|
-
} catch (error) {
|
|
90
|
-
if (isNodeError(error) && error.code === "ENOENT") {
|
|
91
|
-
return [];
|
|
92
|
-
}
|
|
93
|
-
throw error;
|
|
94
|
-
}
|
|
95
|
-
return raw.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0).map((line, index) => parseLedgerLine(line, index)).filter((entry) => entry !== null).filter((entry) => options.source === void 0 || entry.source === options.source).filter((entry) => options.since === void 0 || entry.ts >= options.since);
|
|
96
|
-
}
|
|
97
|
-
async function appendLedgerEntry(projectRoot, entry) {
|
|
98
|
-
const ledgerPath = join2(projectRoot, LEDGER_FILE);
|
|
99
|
-
const nextEntry = ledgerEntrySchema.parse({
|
|
100
|
-
...entry,
|
|
101
|
-
id: entry.id ?? `ledger:${randomUUID()}`
|
|
102
|
-
});
|
|
103
|
-
await appendFile(ledgerPath, `${JSON.stringify(nextEntry)}
|
|
104
|
-
`, "utf8");
|
|
105
|
-
return nextEntry;
|
|
106
|
-
}
|
|
107
|
-
function parseLedgerLine(line, index) {
|
|
108
|
-
try {
|
|
109
|
-
const parsed = JSON.parse(line);
|
|
110
|
-
if (parsed.kind === "mcp-event") {
|
|
111
|
-
return null;
|
|
112
|
-
}
|
|
113
|
-
const result = ledgerEntrySchema.safeParse(parsed);
|
|
114
|
-
if (!result.success) {
|
|
115
|
-
return null;
|
|
116
|
-
}
|
|
117
|
-
return {
|
|
118
|
-
...result.data,
|
|
119
|
-
id: result.data.id ?? createDerivedId(index, line)
|
|
120
|
-
};
|
|
121
|
-
} catch {
|
|
122
|
-
return null;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
function createDerivedId(index, line) {
|
|
126
|
-
return `ledger:${index + 1}:${sha256(line).slice("sha256:".length)}`;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// src/services/read-human-lock.ts
|
|
130
|
-
import { readFile as readFile2 } from "fs/promises";
|
|
131
|
-
import { join as join3 } from "path";
|
|
132
|
-
import { humanLockEntrySchema } from "@fenglimg/fabric-shared";
|
|
133
|
-
async function readHumanLock(projectRoot) {
|
|
134
|
-
const document = await readHumanLockDocument(projectRoot);
|
|
135
|
-
return await Promise.all(
|
|
136
|
-
document.locked.map(async (entry) => {
|
|
137
|
-
const currentHash = await hashHumanLockedContent(projectRoot, entry);
|
|
138
|
-
return {
|
|
139
|
-
...entry,
|
|
140
|
-
drift: currentHash !== entry.hash,
|
|
141
|
-
current_hash: currentHash
|
|
142
|
-
};
|
|
143
|
-
})
|
|
144
|
-
);
|
|
145
|
-
}
|
|
146
|
-
async function readHumanLockEntry(projectRoot, file) {
|
|
147
|
-
const entries = await readHumanLock(projectRoot);
|
|
148
|
-
return entries.find((entry) => entry.file === file) ?? null;
|
|
149
|
-
}
|
|
150
|
-
async function readHumanLockDocument(projectRoot) {
|
|
151
|
-
const humanLockPath = join3(projectRoot, FABRIC_DIR, HUMAN_LOCK_FILE);
|
|
152
|
-
const raw = await readFile2(humanLockPath, "utf8");
|
|
153
|
-
const parsed = JSON.parse(raw);
|
|
154
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
155
|
-
throw new Error(`Fabric human lock file is invalid: ${humanLockPath}`);
|
|
156
|
-
}
|
|
157
|
-
const rawObject = parsed;
|
|
158
|
-
const lockedResult = humanLockEntrySchema.array().safeParse(rawObject.locked ?? []);
|
|
159
|
-
if (!lockedResult.success) {
|
|
160
|
-
throw new Error(`Fabric human lock file is invalid: ${humanLockPath}`);
|
|
161
|
-
}
|
|
162
|
-
return {
|
|
163
|
-
path: humanLockPath,
|
|
164
|
-
rawObject,
|
|
165
|
-
locked: lockedResult.data
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
async function hashHumanLockedContent(projectRoot, entry) {
|
|
169
|
-
const targetPath = assertPathWithinProjectRoot(projectRoot, entry.file);
|
|
170
|
-
let content;
|
|
171
|
-
try {
|
|
172
|
-
content = await readFile2(targetPath, "utf8");
|
|
173
|
-
} catch (error) {
|
|
174
|
-
if (isNodeError(error) && error.code === "ENOENT") {
|
|
175
|
-
return "missing";
|
|
176
|
-
}
|
|
177
|
-
throw error;
|
|
178
|
-
}
|
|
179
|
-
const lines = content.split(/\r?\n/);
|
|
180
|
-
const slice = lines.slice(Math.max(entry.start_line - 1, 0), Math.max(entry.end_line, 0)).join("\n");
|
|
181
|
-
return sha256(slice);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
export {
|
|
185
|
-
AgentsMetaFileMissingError,
|
|
186
|
-
AgentsMetaInvalidError,
|
|
187
|
-
resolveProjectRoot,
|
|
188
|
-
readAgentsMeta,
|
|
189
|
-
FABRIC_DIR,
|
|
190
|
-
atomicWriteText,
|
|
191
|
-
sha256,
|
|
192
|
-
assertPathWithinProjectRoot,
|
|
193
|
-
readLedger,
|
|
194
|
-
appendLedgerEntry,
|
|
195
|
-
readHumanLock,
|
|
196
|
-
readHumanLockEntry,
|
|
197
|
-
readHumanLockDocument,
|
|
198
|
-
hashHumanLockedContent
|
|
199
|
-
};
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
(function(){const e=document.createElement("link").relList;if(e&&e.supports&&e.supports("modulepreload"))return;for(const n of document.querySelectorAll('link[rel="modulepreload"]'))i(n);new MutationObserver(n=>{for(const o of n)if(o.type==="childList")for(const s of o.addedNodes)s.tagName==="LINK"&&s.rel==="modulepreload"&&i(s)}).observe(document,{childList:!0,subtree:!0});function a(n){const o={};return n.integrity&&(o.integrity=n.integrity),n.referrerPolicy&&(o.referrerPolicy=n.referrerPolicy),n.crossOrigin==="use-credentials"?o.credentials="include":n.crossOrigin==="anonymous"?o.credentials="omit":o.credentials="same-origin",o}function i(n){if(n.ep)return;n.ep=!0;const o=a(n);fetch(n.href,o)}})();var ne,k,Ve,F,Re,Ze,Qe,he,V,G,Ye,Ee,ye,ge,et,ee={},te=[],$t=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i,se=Array.isArray;function A(t,e){for(var a in e)t[a]=e[a];return t}function $e(t){t&&t.parentNode&&t.parentNode.removeChild(t)}function Ct(t,e,a){var i,n,o,s={};for(o in e)o=="key"?i=e[o]:o=="ref"?n=e[o]:s[o]=e[o];if(arguments.length>2&&(s.children=arguments.length>3?ne.call(arguments,2):a),typeof t=="function"&&t.defaultProps!=null)for(o in t.defaultProps)s[o]===void 0&&(s[o]=t.defaultProps[o]);return Z(t,s,i,n,null)}function Z(t,e,a,i,n){var o={type:t,props:e,key:a,ref:i,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:n??++Ve,__i:-1,__u:0};return n==null&&k.vnode!=null&&k.vnode(o),o}function le(t){return t.children}function Q(t,e){this.props=t,this.context=e}function D(t,e){if(e==null)return t.__?D(t.__,t.__i+1):null;for(var a;e<t.__k.length;e++)if((a=t.__k[e])!=null&&a.__e!=null)return a.__e;return typeof t.type=="function"?D(t):null}function xt(t){if(t.__P&&t.__d){var e=t.__v,a=e.__e,i=[],n=[],o=A({},e);o.__v=e.__v+1,k.vnode&&k.vnode(o),Ce(t.__P,o,e,t.__n,t.__P.namespaceURI,32&e.__u?[a]:null,i,a??D(e),!!(32&e.__u),n),o.__v=e.__v,o.__.__k[o.__i]=o,it(i,o,n),e.__e=e.__=null,o.__e!=a&&tt(o)}}function tt(t){if((t=t.__)!=null&&t.__c!=null)return t.__e=t.__c.base=null,t.__k.some(function(e){if(e!=null&&e.__e!=null)return t.__e=t.__c.base=e.__e}),tt(t)}function ke(t){(!t.__d&&(t.__d=!0)&&F.push(t)&&!ae.__r++||Re!=k.debounceRendering)&&((Re=k.debounceRendering)||Ze)(ae)}function ae(){try{for(var t,e=1;F.length;)F.length>e&&F.sort(Qe),t=F.shift(),e=F.length,xt(t)}finally{F.length=ae.__r=0}}function at(t,e,a,i,n,o,s,d,u,c,p){var l,f,h,m,y,v,_,b=i&&i.__k||te,w=e.length;for(u=It(a,e,b,u,w),l=0;l<w;l++)(h=a.__k[l])!=null&&(f=h.__i!=-1&&b[h.__i]||ee,h.__i=l,v=Ce(t,h,f,n,o,s,d,u,c,p),m=h.__e,h.ref&&f.ref!=h.ref&&(f.ref&&xe(f.ref,null,h),p.push(h.ref,h.__c||m,h)),y==null&&m!=null&&(y=m),(_=!!(4&h.__u))||f.__k===h.__k?(u=rt(h,u,t,_),_&&f.__e&&(f.__e=null)):typeof h.type=="function"&&v!==void 0?u=v:m&&(u=m.nextSibling),h.__u&=-7);return a.__e=y,u}function It(t,e,a,i,n){var o,s,d,u,c,p=a.length,l=p,f=0;for(t.__k=new Array(n),o=0;o<n;o++)(s=e[o])!=null&&typeof s!="boolean"&&typeof s!="function"?(typeof s=="string"||typeof s=="number"||typeof s=="bigint"||s.constructor==String?s=t.__k[o]=Z(null,s,null,null,null):se(s)?s=t.__k[o]=Z(le,{children:s},null,null,null):s.constructor===void 0&&s.__b>0?s=t.__k[o]=Z(s.type,s.props,s.key,s.ref?s.ref:null,s.__v):t.__k[o]=s,u=o+f,s.__=t,s.__b=t.__b+1,d=null,(c=s.__i=At(s,a,u,l))!=-1&&(l--,(d=a[c])&&(d.__u|=2)),d==null||d.__v==null?(c==-1&&(n>p?f--:n<p&&f++),typeof s.type!="function"&&(s.__u|=4)):c!=u&&(c==u-1?f--:c==u+1?f++:(c>u?f--:f++,s.__u|=4))):t.__k[o]=null;if(l)for(o=0;o<p;o++)(d=a[o])!=null&&(2&d.__u)==0&&(d.__e==i&&(i=D(d)),nt(d,d));return i}function rt(t,e,a,i){var n,o;if(typeof t.type=="function"){for(n=t.__k,o=0;n&&o<n.length;o++)n[o]&&(n[o].__=t,e=rt(n[o],e,a,i));return e}t.__e!=e&&(i&&(e&&t.type&&!e.parentNode&&(e=D(t)),a.insertBefore(t.__e,e||null)),e=t.__e);do e=e&&e.nextSibling;while(e!=null&&e.nodeType==8);return e}function At(t,e,a,i){var n,o,s,d=t.key,u=t.type,c=e[a],p=c!=null&&(2&c.__u)==0;if(c===null&&d==null||p&&d==c.key&&u==c.type)return a;if(i>(p?1:0)){for(n=a-1,o=a+1;n>=0||o<e.length;)if((c=e[s=n>=0?n--:o++])!=null&&(2&c.__u)==0&&d==c.key&&u==c.type)return s}return-1}function He(t,e,a){e[0]=="-"?t.setProperty(e,a??""):t[e]=a==null?"":typeof a!="number"||$t.test(e)?a:a+"px"}function K(t,e,a,i,n){var o,s;e:if(e=="style")if(typeof a=="string")t.style.cssText=a;else{if(typeof i=="string"&&(t.style.cssText=i=""),i)for(e in i)a&&e in a||He(t.style,e,"");if(a)for(e in a)i&&a[e]==i[e]||He(t.style,e,a[e])}else if(e[0]=="o"&&e[1]=="n")o=e!=(e=e.replace(Ye,"$1")),s=e.toLowerCase(),e=s in t||e=="onFocusOut"||e=="onFocusIn"?s.slice(2):e.slice(2),t.l||(t.l={}),t.l[e+o]=a,a?i?a[G]=i[G]:(a[G]=Ee,t.addEventListener(e,o?ge:ye,o)):t.removeEventListener(e,o?ge:ye,o);else{if(n=="http://www.w3.org/2000/svg")e=e.replace(/xlink(H|:h)/,"h").replace(/sName$/,"s");else if(e!="width"&&e!="height"&&e!="href"&&e!="list"&&e!="form"&&e!="tabIndex"&&e!="download"&&e!="rowSpan"&&e!="colSpan"&&e!="role"&&e!="popover"&&e in t)try{t[e]=a??"";break e}catch{}typeof a=="function"||(a==null||a===!1&&e[4]!="-"?t.removeAttribute(e):t.setAttribute(e,e=="popover"&&a==1?"":a))}}function je(t){return function(e){if(this.l){var a=this.l[e.type+t];if(e[V]==null)e[V]=Ee++;else if(e[V]<a[G])return;return a(k.event?k.event(e):e)}}}function Ce(t,e,a,i,n,o,s,d,u,c){var p,l,f,h,m,y,v,_,b,w,$,B,Pe,X,ce,I=e.type;if(e.constructor!==void 0)return null;128&a.__u&&(u=!!(32&a.__u),o=[d=e.__e=a.__e]),(p=k.__b)&&p(e);e:if(typeof I=="function")try{if(_=e.props,b=I.prototype&&I.prototype.render,w=(p=I.contextType)&&i[p.__c],$=p?w?w.props.value:p.__:i,a.__c?v=(l=e.__c=a.__c).__=l.__E:(b?e.__c=l=new I(_,$):(e.__c=l=new Q(_,$),l.constructor=I,l.render=Lt),w&&w.sub(l),l.state||(l.state={}),l.__n=i,f=l.__d=!0,l.__h=[],l._sb=[]),b&&l.__s==null&&(l.__s=l.state),b&&I.getDerivedStateFromProps!=null&&(l.__s==l.state&&(l.__s=A({},l.__s)),A(l.__s,I.getDerivedStateFromProps(_,l.__s))),h=l.props,m=l.state,l.__v=e,f)b&&I.getDerivedStateFromProps==null&&l.componentWillMount!=null&&l.componentWillMount(),b&&l.componentDidMount!=null&&l.__h.push(l.componentDidMount);else{if(b&&I.getDerivedStateFromProps==null&&_!==h&&l.componentWillReceiveProps!=null&&l.componentWillReceiveProps(_,$),e.__v==a.__v||!l.__e&&l.shouldComponentUpdate!=null&&l.shouldComponentUpdate(_,l.__s,$)===!1){e.__v!=a.__v&&(l.props=_,l.state=l.__s,l.__d=!1),e.__e=a.__e,e.__k=a.__k,e.__k.some(function(j){j&&(j.__=e)}),te.push.apply(l.__h,l._sb),l._sb=[],l.__h.length&&s.push(l);break e}l.componentWillUpdate!=null&&l.componentWillUpdate(_,l.__s,$),b&&l.componentDidUpdate!=null&&l.__h.push(function(){l.componentDidUpdate(h,m,y)})}if(l.context=$,l.props=_,l.__P=t,l.__e=!1,B=k.__r,Pe=0,b)l.state=l.__s,l.__d=!1,B&&B(e),p=l.render(l.props,l.state,l.context),te.push.apply(l.__h,l._sb),l._sb=[];else do l.__d=!1,B&&B(e),p=l.render(l.props,l.state,l.context),l.state=l.__s;while(l.__d&&++Pe<25);l.state=l.__s,l.getChildContext!=null&&(i=A(A({},i),l.getChildContext())),b&&!f&&l.getSnapshotBeforeUpdate!=null&&(y=l.getSnapshotBeforeUpdate(h,m)),X=p!=null&&p.type===le&&p.key==null?ot(p.props.children):p,d=at(t,se(X)?X:[X],e,a,i,n,o,s,d,u,c),l.base=e.__e,e.__u&=-161,l.__h.length&&s.push(l),v&&(l.__E=l.__=null)}catch(j){if(e.__v=null,u||o!=null)if(j.then){for(e.__u|=u?160:128;d&&d.nodeType==8&&d.nextSibling;)d=d.nextSibling;o[o.indexOf(d)]=null,e.__e=d}else{for(ce=o.length;ce--;)$e(o[ce]);we(e)}else e.__e=a.__e,e.__k=a.__k,j.then||we(e);k.__e(j,e,a)}else o==null&&e.__v==a.__v?(e.__k=a.__k,e.__e=a.__e):d=e.__e=Ft(a.__e,e,a,i,n,o,s,u,c);return(p=k.diffed)&&p(e),128&e.__u?void 0:d}function we(t){t&&(t.__c&&(t.__c.__e=!0),t.__k&&t.__k.some(we))}function it(t,e,a){for(var i=0;i<a.length;i++)xe(a[i],a[++i],a[++i]);k.__c&&k.__c(e,t),t.some(function(n){try{t=n.__h,n.__h=[],t.some(function(o){o.call(n)})}catch(o){k.__e(o,n.__v)}})}function ot(t){return typeof t!="object"||t==null||t.__b>0?t:se(t)?t.map(ot):A({},t)}function Ft(t,e,a,i,n,o,s,d,u){var c,p,l,f,h,m,y,v=a.props||ee,_=e.props,b=e.type;if(b=="svg"?n="http://www.w3.org/2000/svg":b=="math"?n="http://www.w3.org/1998/Math/MathML":n||(n="http://www.w3.org/1999/xhtml"),o!=null){for(c=0;c<o.length;c++)if((h=o[c])&&"setAttribute"in h==!!b&&(b?h.localName==b:h.nodeType==3)){t=h,o[c]=null;break}}if(t==null){if(b==null)return document.createTextNode(_);t=document.createElementNS(n,b,_.is&&_),d&&(k.__m&&k.__m(e,o),d=!1),o=null}if(b==null)v===_||d&&t.data==_||(t.data=_);else{if(o=o&&ne.call(t.childNodes),!d&&o!=null)for(v={},c=0;c<t.attributes.length;c++)v[(h=t.attributes[c]).name]=h.value;for(c in v)h=v[c],c=="dangerouslySetInnerHTML"?l=h:c=="children"||c in _||c=="value"&&"defaultValue"in _||c=="checked"&&"defaultChecked"in _||K(t,c,null,h,n);for(c in _)h=_[c],c=="children"?f=h:c=="dangerouslySetInnerHTML"?p=h:c=="value"?m=h:c=="checked"?y=h:d&&typeof h!="function"||v[c]===h||K(t,c,h,v[c],n);if(p)d||l&&(p.__html==l.__html||p.__html==t.innerHTML)||(t.innerHTML=p.__html),e.__k=[];else if(l&&(t.innerHTML=""),at(e.type=="template"?t.content:t,se(f)?f:[f],e,a,i,b=="foreignObject"?"http://www.w3.org/1999/xhtml":n,o,s,o?o[0]:a.__k&&D(a,0),d,u),o!=null)for(c=o.length;c--;)$e(o[c]);d||(c="value",b=="progress"&&m==null?t.removeAttribute("value"):m!=null&&(m!==t[c]||b=="progress"&&!m||b=="option"&&m!=v[c])&&K(t,c,m,v[c],n),c="checked",y!=null&&y!=t[c]&&K(t,c,y,v[c],n))}return t}function xe(t,e,a){try{if(typeof t=="function"){var i=typeof t.__u=="function";i&&t.__u(),i&&e==null||(t.__u=t(e))}else t.current=e}catch(n){k.__e(n,a)}}function nt(t,e,a){var i,n;if(k.unmount&&k.unmount(t),(i=t.ref)&&(i.current&&i.current!=t.__e||xe(i,null,e)),(i=t.__c)!=null){if(i.componentWillUnmount)try{i.componentWillUnmount()}catch(o){k.__e(o,e)}i.base=i.__P=null}if(i=t.__k)for(n=0;n<i.length;n++)i[n]&&nt(i[n],e,a||typeof t.type!="function");a||$e(t.__e),t.__c=t.__=t.__e=void 0}function Lt(t,e,a){return this.constructor(t,a)}function Pt(t,e,a){var i,n,o,s;e==document&&(e=document.documentElement),k.__&&k.__(t,e),n=(i=!1)?null:e.__k,o=[],s=[],Ce(e,t=e.__k=Ct(le,null,[t]),n||ee,ee,e.namespaceURI,n?null:e.firstChild?ne.call(e.childNodes):null,o,n?n.__e:e.firstChild,i,s),it(o,t,s)}function Rt(t){function e(a){var i,n;return this.getChildContext||(i=new Set,(n={})[e.__c]=this,this.getChildContext=function(){return n},this.componentWillUnmount=function(){i=null},this.shouldComponentUpdate=function(o){this.props.value!=o.value&&i.forEach(function(s){s.__e=!0,ke(s)})},this.sub=function(o){i.add(o);var s=o.componentWillUnmount;o.componentWillUnmount=function(){i&&i.delete(o),s&&s.call(o)}}),a.children}return e.__c="__cC"+et++,e.__=t,e.Provider=e.__l=(e.Consumer=function(a,i){return a.children(i)}).contextType=e,e}ne=te.slice,k={__e:function(t,e,a,i){for(var n,o,s;e=e.__;)if((n=e.__c)&&!n.__)try{if((o=n.constructor)&&o.getDerivedStateFromError!=null&&(n.setState(o.getDerivedStateFromError(t)),s=n.__d),n.componentDidCatch!=null&&(n.componentDidCatch(t,i||{}),s=n.__d),s)return n.__E=n}catch(d){t=d}throw t}},Ve=0,Q.prototype.setState=function(t,e){var a;a=this.__s!=null&&this.__s!=this.state?this.__s:this.__s=A({},this.state),typeof t=="function"&&(t=t(A({},a),this.props)),t&&A(a,t),t!=null&&this.__v&&(e&&this._sb.push(e),ke(this))},Q.prototype.forceUpdate=function(t){this.__v&&(this.__e=!0,t&&this.__h.push(t),ke(this))},Q.prototype.render=le,F=[],Ze=typeof Promise=="function"?Promise.prototype.then.bind(Promise.resolve()):setTimeout,Qe=function(t,e){return t.__v.__b-e.__v.__b},ae.__r=0,he=Math.random().toString(8),V="__d"+he,G="__a"+he,Ye=/(PointerCapture)$|Capture$/i,Ee=0,ye=je(!1),ge=je(!0),et=0;var Ht=0;function r(t,e,a,i,n,o){e||(e={});var s,d,u=e;if("ref"in u)for(d in u={},e)d=="ref"?s=e[d]:u[d]=e[d];var c={type:t,props:u,key:a,ref:s,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:--Ht,__i:-1,__u:0,__source:n,__self:o};if(typeof t=="function"&&(s=t.defaultProps))for(d in s)u[d]===void 0&&(u[d]=s[d]);return k.vnode&&k.vnode(c),c}var O,S,ue,De,Ne=0,st=[],T=k,Oe=T.__b,Ue=T.__r,Me=T.diffed,Be=T.__c,Ge=T.unmount,qe=T.__;function de(t,e){T.__h&&T.__h(S,t,Ne||e),Ne=0;var a=S.__H||(S.__H={__:[],__h:[]});return t>=a.__.length&&a.__.push({}),a.__[t]}function N(t){return Ne=1,jt(dt,t)}function jt(t,e,a){var i=de(O++,2);if(i.t=t,!i.__c&&(i.__=[dt(void 0,e),function(d){var u=i.__N?i.__N[0]:i.__[0],c=i.t(u,d);u!==c&&(i.__N=[c,i.__[1]],i.__c.setState({}))}],i.__c=S,!S.__f)){var n=function(d,u,c){if(!i.__c.__H)return!0;var p=i.__c.__H.__.filter(function(f){return f.__c});if(p.every(function(f){return!f.__N}))return!o||o.call(this,d,u,c);var l=i.__c.props!==d;return p.some(function(f){if(f.__N){var h=f.__[0];f.__=f.__N,f.__N=void 0,h!==f.__[0]&&(l=!0)}}),o&&o.call(this,d,u,c)||l};S.__f=!0;var o=S.shouldComponentUpdate,s=S.componentWillUpdate;S.componentWillUpdate=function(d,u,c){if(this.__e){var p=o;o=void 0,n(d,u,c),o=p}s&&s.call(this,d,u,c)},S.shouldComponentUpdate=n}return i.__N||i.__}function C(t,e){var a=de(O++,3);!T.__s&<(a.__H,e)&&(a.__=t,a.u=e,S.__H.__h.push(a))}function L(t,e){var a=de(O++,7);return lt(a.__H,e)&&(a.__=t(),a.__H=e,a.__h=t),a.__}function Dt(t){var e=S.context[t.__c],a=de(O++,9);return a.c=t,e?(a.__==null&&(a.__=!0,e.sub(S)),e.props.value):t.__}function Ot(){for(var t;t=st.shift();){var e=t.__H;if(t.__P&&e)try{e.__h.some(Y),e.__h.some(Se),e.__h=[]}catch(a){e.__h=[],T.__e(a,t.__v)}}}T.__b=function(t){S=null,Oe&&Oe(t)},T.__=function(t,e){t&&e.__k&&e.__k.__m&&(t.__m=e.__k.__m),qe&&qe(t,e)},T.__r=function(t){Ue&&Ue(t),O=0;var e=(S=t.__c).__H;e&&(ue===S?(e.__h=[],S.__h=[],e.__.some(function(a){a.__N&&(a.__=a.__N),a.u=a.__N=void 0})):(e.__h.some(Y),e.__h.some(Se),e.__h=[],O=0)),ue=S},T.diffed=function(t){Me&&Me(t);var e=t.__c;e&&e.__H&&(e.__H.__h.length&&(st.push(e)!==1&&De===T.requestAnimationFrame||((De=T.requestAnimationFrame)||Ut)(Ot)),e.__H.__.some(function(a){a.u&&(a.__H=a.u),a.u=void 0})),ue=S=null},T.__c=function(t,e){e.some(function(a){try{a.__h.some(Y),a.__h=a.__h.filter(function(i){return!i.__||Se(i)})}catch(i){e.some(function(n){n.__h&&(n.__h=[])}),e=[],T.__e(i,a.__v)}}),Be&&Be(t,e)},T.unmount=function(t){Ge&&Ge(t);var e,a=t.__c;a&&a.__H&&(a.__H.__.some(function(i){try{Y(i)}catch(n){e=n}}),a.__H=void 0,e&&T.__e(e,a.__v))};var Je=typeof requestAnimationFrame=="function";function Ut(t){var e,a=function(){clearTimeout(i),Je&&cancelAnimationFrame(e),setTimeout(t)},i=setTimeout(a,35);Je&&(e=requestAnimationFrame(a))}function Y(t){var e=S,a=t.__c;typeof a=="function"&&(t.__c=void 0,a()),S=e}function Se(t){var e=S;t.__c=t.__(),S=e}function lt(t,e){return!t||t.length!==e.length||e.some(function(a,i){return a!==t[i]})}function dt(t,e){return typeof e=="function"?e(t):e}var Mt=Symbol.for("preact-signals");function Ie(){if(H>1)H--;else{var t,e=!1;for((function(){var n=ie;for(ie=void 0;n!==void 0;)n.S.v===n.v&&(n.S.i=n.i),n=n.o})();q!==void 0;){var a=q;for(q=void 0,re++;a!==void 0;){var i=a.u;if(a.u=void 0,a.f&=-3,!(8&a.f)&&ut(a))try{a.c()}catch(n){e||(t=n,e=!0)}a=i}}if(re=0,H--,e)throw t}}var g=void 0;function ct(t){var e=g;g=void 0;try{return t()}finally{g=e}}var q=void 0,H=0,re=0,We=0,ie=void 0,oe=0;function ht(t){if(g!==void 0){var e=t.n;if(e===void 0||e.t!==g)return e={i:0,S:t,p:g.s,n:void 0,t:g,e:void 0,x:void 0,r:e},g.s!==void 0&&(g.s.n=e),g.s=e,t.n=e,32&g.f&&t.S(e),e;if(e.i===-1)return e.i=0,e.n!==void 0&&(e.n.p=e.p,e.p!==void 0&&(e.p.n=e.n),e.p=g.s,e.n=void 0,g.s.n=e,g.s=e),e}}function E(t,e){this.v=t,this.i=0,this.n=void 0,this.t=void 0,this.l=0,this.W=e?.watched,this.Z=e?.unwatched,this.name=e?.name}E.prototype.brand=Mt;E.prototype.h=function(){return!0};E.prototype.S=function(t){var e=this,a=this.t;a!==t&&t.e===void 0&&(t.x=a,this.t=t,a!==void 0?a.e=t:ct(function(){var i;(i=e.W)==null||i.call(e)}))};E.prototype.U=function(t){var e=this;if(this.t!==void 0){var a=t.e,i=t.x;a!==void 0&&(a.x=i,t.e=void 0),i!==void 0&&(i.e=a,t.x=void 0),t===this.t&&(this.t=i,i===void 0&&ct(function(){var n;(n=e.Z)==null||n.call(e)}))}};E.prototype.subscribe=function(t){var e=this;return Gt(function(){var a=e.value,i=g;g=void 0;try{t(a)}finally{g=i}},{name:"sub"})};E.prototype.valueOf=function(){return this.value};E.prototype.toString=function(){return this.value+""};E.prototype.toJSON=function(){return this.value};E.prototype.peek=function(){var t=g;g=void 0;try{return this.value}finally{g=t}};Object.defineProperty(E.prototype,"value",{get:function(){var t=ht(this);return t!==void 0&&(t.i=this.i),this.v},set:function(t){if(t!==this.v){if(re>100)throw new Error("Cycle detected");(function(a){H!==0&&re===0&&a.l!==We&&(a.l=We,ie={S:a,v:a.v,i:a.i,o:ie})})(this),this.v=t,this.i++,oe++,H++;try{for(var e=this.t;e!==void 0;e=e.x)e.t.N()}finally{Ie()}}}});function Ae(t,e){return new E(t,e)}function ut(t){for(var e=t.s;e!==void 0;e=e.n)if(e.S.i!==e.i||!e.S.h()||e.S.i!==e.i)return!0;return!1}function pt(t){for(var e=t.s;e!==void 0;e=e.n){var a=e.S.n;if(a!==void 0&&(e.r=a),e.S.n=e,e.i=-1,e.n===void 0){t.s=e;break}}}function mt(t){for(var e=t.s,a=void 0;e!==void 0;){var i=e.p;e.i===-1?(e.S.U(e),i!==void 0&&(i.n=e.n),e.n!==void 0&&(e.n.p=i)):a=e,e.S.n=e.r,e.r!==void 0&&(e.r=void 0),e=i}t.s=a}function U(t,e){E.call(this,void 0),this.x=t,this.s=void 0,this.g=oe-1,this.f=4,this.W=e?.watched,this.Z=e?.unwatched,this.name=e?.name}U.prototype=new E;U.prototype.h=function(){if(this.f&=-3,1&this.f)return!1;if((36&this.f)==32||(this.f&=-5,this.g===oe))return!0;if(this.g=oe,this.f|=1,this.i>0&&!ut(this))return this.f&=-2,!0;var t=g;try{pt(this),g=this;var e=this.x();(16&this.f||this.v!==e||this.i===0)&&(this.v=e,this.f&=-17,this.i++)}catch(a){this.v=a,this.f|=16,this.i++}return g=t,mt(this),this.f&=-2,!0};U.prototype.S=function(t){if(this.t===void 0){this.f|=36;for(var e=this.s;e!==void 0;e=e.n)e.S.S(e)}E.prototype.S.call(this,t)};U.prototype.U=function(t){if(this.t!==void 0&&(E.prototype.U.call(this,t),this.t===void 0)){this.f&=-33;for(var e=this.s;e!==void 0;e=e.n)e.S.U(e)}};U.prototype.N=function(){if(!(2&this.f)){this.f|=6;for(var t=this.t;t!==void 0;t=t.x)t.t.N()}};Object.defineProperty(U.prototype,"value",{get:function(){if(1&this.f)throw new Error("Cycle detected");var t=ht(this);if(this.h(),t!==void 0&&(t.i=this.i),16&this.f)throw this.v;return this.v}});function bt(t){var e=t.m;if(t.m=void 0,typeof e=="function"){H++;var a=g;g=void 0;try{e()}catch(i){throw t.f&=-2,t.f|=8,Fe(t),i}finally{g=a,Ie()}}}function Fe(t){for(var e=t.s;e!==void 0;e=e.n)e.S.U(e);t.x=void 0,t.s=void 0,bt(t)}function Bt(t){if(g!==this)throw new Error("Out-of-order effect");mt(this),g=t,this.f&=-2,8&this.f&&Fe(this),Ie()}function M(t,e){this.x=t,this.m=void 0,this.s=void 0,this.u=void 0,this.f=32,this.name=e?.name}M.prototype.c=function(){var t=this.S();try{if(8&this.f||this.x===void 0)return;var e=this.x();typeof e=="function"&&(this.m=e)}finally{t()}};M.prototype.S=function(){if(1&this.f)throw new Error("Cycle detected");this.f|=1,this.f&=-9,bt(this),pt(this),H++;var t=g;return g=this,Bt.bind(this,t)};M.prototype.N=function(){2&this.f||(this.f|=2,this.u=q,q=this)};M.prototype.d=function(){this.f|=8,1&this.f||Fe(this)};M.prototype.dispose=function(){this.d()};function Gt(t,e){var a=new M(t,e);try{a.c()}catch(n){throw a.d(),n}var i=a.d.bind(a);return i[Symbol.dispose]=i,i}async function qt(){return await J("/api/rules")}async function ft(t={}){const e=new URLSearchParams;return t.source!==void 0&&e.set("source",t.source),t.since!==void 0&&e.set("since",String(t.since)),await J(gt("/api/ledger",e))}async function Jt(){return await J("/api/doctor")}async function _t(){return await J("/api/human-lock")}async function Wt(t){return await vt("/api/human-lock/approve",t)}async function Xt(t){return await vt("/api/intent/annotate",t)}async function Kt(t){const e=new URLSearchParams;return t.ledgerId!==void 0&&e.set("ledger_id",t.ledgerId),t.ts!==void 0&&e.set("ts",String(t.ts)),await J(gt("/api/history/state",e))}function zt(){return new EventSource("/events")}function Vt(t){try{const e=JSON.parse(t);return typeof e.type=="string"&&"payload"in e?e:null}catch{return null}}async function J(t){const e=await fetch(t,{headers:{Accept:"application/json"}});return await yt(e)}async function vt(t,e){const a=await fetch(t,{method:"POST",headers:{Accept:"application/json","Content-Type":"application/json"},body:JSON.stringify(e)});return await yt(a)}async function yt(t){const e=await t.text(),a=e.length>0?JSON.parse(e):void 0;if(!t.ok)throw new Error(Zt(a,t.status));return a}function Zt(t,e){return t&&typeof t=="object"&&"error"in t&&typeof t.error?.message=="string"?t.error.message:`Fabric API request failed with HTTP ${e}.`}function gt(t,e){const a=e.toString();return a.length>0?`${t}?${a}`:t}const Xe=["meta:updated","lock:drift","lock:approved","ledger:appended","drift:detected"],pe=Ae([]),me=Ae(!1),be=Ae(0);function Qt(){const[t,e]=N({connected:me.value,lastEvent:pe.value[0]??null,version:be.value});return C(()=>{const a=zt(),i=o=>{me.value=o,e(s=>({...s,connected:o}))},n=o=>{const s=Vt(o.data);s!==null&&(pe.value=[s,...pe.value].slice(0,50),be.value+=1,e({connected:me.value,lastEvent:s,version:be.value}))};a.onopen=()=>i(!0),a.onerror=()=>i(!1);for(const o of Xe)a.addEventListener(o,n);return()=>{for(const o of Xe)a.removeEventListener(o,n);a.close(),i(!1)}},[]),t}var Yt={"cli.main.description":"Fabric CLI - AI agent collaboration framework","cli.shared.created":"Created","cli.shared.skipped":"Skipped","cli.shared.next":"Next","cli.shared.reason":"Reason","cli.shared.updated":"Updated","cli.shared.missing":"missing","cli.shared.present":"present","cli.shared.absent":"missing","cli.shared.yes":"yes","cli.shared.no":"no","cli.shared.none":"none","cli.shared.loading":"loading","cli.shared.refresh":"Refresh","cli.shared.target-invalid":"Target must be an existing directory: {target}","cli.shared.template-not-found":"Template not found: {path}","cli.shared.invalid-host-empty":"Invalid host: <empty>","cli.shared.invalid-port":"Invalid port: {value}","cli.bootstrap.description":"Install Fabric bootstrap prompts for supported AI clients.","cli.bootstrap.install.description":"Copy Fabric bootstrap templates into native client locations.","cli.bootstrap.install.args.clients.description":"Optional comma-separated client filter, for example claude,cursor,codex.","cli.bootstrap.install.no-targets":"No bootstrap targets detected. Pass --clients claude,cursor,windsurf,roo,gemini,codex to install explicitly.","cli.bootstrap.install.installed":"Installed {path}","cli.bootstrap.install.skipped-header":"Skipped {path}: Fabric Bootstrap header already present.","cli.bootstrap.install.prepended":"Prepended {path}","cli.bootstrap.errors.unknown-client":'Unknown client "{client}". Use a comma-separated list such as claude,cursor,codex.',"cli.config.description":"Manage Fabric MCP client configuration.","cli.config.install.description":"Install Fabric MCP server entries into detected client configs.","cli.config.install.args.clients.description":"Optional comma-separated client filter, for example cursor,codex,gemini.","cli.config.install.args.dry-run.description":"Preview detected write operations without modifying files.","cli.config.errors.unknown-client":'Unknown client "{client}". Use a comma-separated list such as cursor,codex,gemini.',"cli.config.errors.expected-object":"Expected object in {path}","cli.config.install.no-configs":"No Fabric MCP client config detected. Create the client directory or set clientPaths in fabric.config.json.","cli.config.install.no-config-path":"Skipping {client}: no config path detected.","cli.config.install.dry-run":"[dry-run] {client}: would write {path}","cli.config.install.wrote":"{client}: wrote {path}","cli.hooks.description":"Manage Fabric Git hook templates.","cli.hooks.install.description":"Install the Fabric Husky pre-commit hook template.","cli.hooks.install.args.target.description":"Target project path, default is the current working directory.","cli.hooks.errors.package-json-required":"package.json is required to install hooks: {path}","cli.hooks.install.hook-skipped":"Fabric hook already present in {path}, skipped.","cli.hooks.install.hook-appended":"Appended Fabric hook to existing {path}","cli.hooks.install.hook-created":"Created {path}","cli.hooks.install.prepare-left":"Left existing prepare script unchanged in {path}","cli.hooks.install.prepare-added":"Added prepare script to {path}","cli.human-lint.description":"Validate locked human-edit regions.","cli.human-lint.args.target.description":"Target project path, default is the current working directory.","cli.human-lint.drift-detected":"Human-locked content drift detected. Revert the edit or update approved hashes before committing.","cli.human-lint.table.location":"Location","cli.human-lint.table.expected":"Expected","cli.human-lint.table.got":"Got","cli.init.description":"Initialize Fabric in the target project.","cli.init.args.target.description":"Target project path. Defaults to CLI arg, EXTERNAL_FIXTURE_PATH, fabric.config.json, then cwd.","cli.init.args.debug.description":"Print target resolution details to stderr.","cli.init.created-path":"{label} {path}","cli.init.skipped-existing-path":"{label} {path}: already exists.","cli.init.next-step":"{label} {message}","cli.init.reason-message":"{label} {message}","cli.init.next-step.message":"run fab hooks install to add the Day 4 pre-commit pipeline.","cli.init.reason-message.body":".fabric/forensic.json is ready; use the agents-md-init skill to finish AGENTS.md initialization.","cli.init.claude-settings.created":"{label} {path} with Claude Stop hook.","cli.init.claude-settings.updated":"{label} {path} with Claude Stop hook.","cli.init.claude-settings.skipped":"{label} {path}: Claude Stop hook already present.","cli.init.claude-settings.skipped-invalid":"{label} {path}: unable to merge Claude Stop hook.","cli.init.claude-settings.invalid-object":"{label} {path}: expected a JSON object.","cli.init.claude-settings.invalid-json":"{label} {path}: invalid JSON ({reason}).","cli.init.claude-settings.invalid-hooks":'{label} {path}: "hooks" must be a JSON object.',"cli.init.claude-settings.invalid-stop-array":'{label} {path}: "hooks.Stop" must be an array.',"cli.init.errors.abort-existing":"ABORT: {path} already exists. fab init is non-destructive.","cli.ledger-append.description":"Append an entry to the Fabric intent ledger.","cli.ledger-append.args.target.description":"Target project path, default is the current working directory.","cli.ledger-append.args.staged.description":"Derive the entry from staged changes (used during pre-commit).","cli.ledger-append.requires-staged":"requires --staged in pre-commit context","cli.ledger-append.intent.auto":"auto: {head}{suffix}","cli.ledger-append.intent.auto-more":" +{count} more","cli.pre-commit.description":"Composite pre-commit hook: runs sync-meta --check-only, human-lint, and ledger-append --staged in one Node process.","cli.pre-commit.args.target.description":"Project root directory, defaults to cwd or EXTERNAL_FIXTURE_PATH.","cli.pre-commit.run-failed":"fabric pre-commit: {name} failed - {message}","cli.scan.description":"Scan the project to detect Fabric bootstrap candidates.","cli.scan.args.target.description":"Target absolute path. Defaults to CLI arg, EXTERNAL_FIXTURE_PATH, fabric.config.json, then cwd.","cli.scan.args.debug.description":"Print detection evidence in formatted output.","cli.scan.args.json.description":"Print the diagnostic report as JSON.","cli.scan.report.title":"Fabric scan report","cli.scan.report.target":"Target","cli.scan.report.framework":"Framework","cli.scan.report.evidence":"Evidence","cli.scan.report.readme-quality":"README quality","cli.scan.report.contributing":"CONTRIBUTING.md","cli.scan.report.files-counted":"Files counted","cli.scan.report.ignored-entries":"Ignored entries","cli.scan.report.existing-fabric":"Existing Fabric files","cli.scan.report.recommendations":"Recommendations:","cli.scan.readme-quality.ok":"ok","cli.scan.readme-quality.stub":"stub","cli.scan.recommendation.init":"L0: Run fab init to scaffold AGENTS.md with TODO markers.","cli.scan.recommendation.readme":"L0: Expand README.md before promoting project facts into AGENTS.md references.","cli.scan.recommendation.contributing":"L0: Add CONTRIBUTING.md or leave an AGENTS.md TODO reference for contribution flow.","cli.scan.recommendation.unknown-framework":"L1: Add tech-stack TODOs manually because no framework marker was detected.","cli.scan.recommendation.framework-dirs":"L1: Review {framework} directories for future scoped AGENTS.md files.","cli.serve.description":"Start the local Fabric MCP HTTP service. Set FABRIC_AUTH_TOKEN to enable Bearer auth for non-localhost binding.","cli.serve.args.port.description":"Listen port, default 7373.","cli.serve.args.host.description":"Listen host, default 127.0.0.1. Set FABRIC_AUTH_TOKEN to enable Bearer auth for non-localhost binding.","cli.serve.args.target.description":"Target project path. Defaults to CLI arg, EXTERNAL_FIXTURE_PATH, fabric.config.json, then cwd.","cli.serve.args.debug.description":"Print target resolution details to stderr.","cli.serve.ready.title":"Fabric Dashboard","cli.serve.warning.host-fallback":"--host {host} requires FABRIC_AUTH_TOKEN; falling back to 127.0.0.1 for safety","cli.serve.error.port-in-use":"Port {port} in use - try --port {nextPort}","cli.sync-meta.description":"Sync Fabric metadata from AGENTS.md files.","cli.sync-meta.args.target.description":"Target project path, default is the current working directory.","cli.sync-meta.args.check-only.description":"Exit with code 1 when .fabric/agents.meta.json is out of date.","cli.sync-meta.drift-detected":"Fabric metadata drift detected. Run fab sync-meta to update.","cli.sync-meta.updated":"{label} {path}","dashboard.app.nav.aria-label":"Dashboard views","dashboard.app.nav.rules.label":"Rules Tree","dashboard.app.nav.rules.label-bilingual":"规则树 Rules Tree","dashboard.app.nav.rules.subtitle":"meta graph","dashboard.app.nav.locks.label":"Human Lock","dashboard.app.nav.locks.label-bilingual":"人工锁 Human Lock","dashboard.app.nav.locks.subtitle":"protected regions","dashboard.app.nav.timeline.label":"Intent Timeline","dashboard.app.nav.timeline.label-bilingual":"意图时间线 Intent Timeline","dashboard.app.nav.timeline.subtitle":"ledger stream","dashboard.app.nav.history.label":"History Replay","dashboard.app.nav.history.label-bilingual":"历史回放 History Replay","dashboard.app.nav.history.subtitle":"time travel","dashboard.app.nav.doctor.label":"Doctor","dashboard.app.nav.doctor.label-bilingual":"诊断台 Doctor","dashboard.app.nav.doctor.subtitle":"fab diagnostics","dashboard.app.nav.section.diagnostics":"Diagnostics","dashboard.app.nav.drift-check":"Drift Check","dashboard.app.header.connected":"CONNECTED","dashboard.app.header.connecting":"CONNECTING","dashboard.app.live-region.received":"Received {type}","dashboard.app.breadcrumb.rules":"rules-tree","dashboard.app.breadcrumb.locks":"human-lock","dashboard.app.breadcrumb.timeline":"intent-timeline","dashboard.app.breadcrumb.history":"history-replay","dashboard.app.breadcrumb.doctor":"doctor","dashboard.rules-tree.title":"Rules Tree Browser","dashboard.rules-tree.subtitle":".fabric/agents.meta.json · L0/L1/L2 hierarchy · hash drift aware","dashboard.rules-tree.filter.placeholder":"Filter by file, glob, priority, hash...","dashboard.rules-tree.filter.aria-label":"Filter rules tree","dashboard.rules-tree.status.loading":"loading rules","dashboard.rules-tree.status.nodes":"{count} nodes · rev {revision}","dashboard.rules-tree.status.locks":"{count} human locks","dashboard.rules-tree.empty":"No matching rules found.","dashboard.rules-tree.tree.aria-label":"Fabric rules tree","dashboard.rules-tree.detail.title":"Node Detail","dashboard.rules-tree.detail.empty":"Select a rule node to inspect scope, dependencies, priority and hash.","dashboard.rules-tree.detail.file":"file","dashboard.rules-tree.detail.scope":"scope","dashboard.rules-tree.detail.priority":"priority","dashboard.rules-tree.detail.hash":"hash","dashboard.rules-tree.detail.no-deps":"no deps","dashboard.human-lock.title":"Human Lock Vault","dashboard.human-lock.subtitle":"Protected regions awaiting approval · ritual writes only","dashboard.human-lock.filters.aria-label":"Human lock filters","dashboard.human-lock.filters.all":"all","dashboard.human-lock.filters.drift":"drift","dashboard.human-lock.filters.approved":"approved","dashboard.human-lock.summary":"{drift} drift · {approved} confirmed","dashboard.human-lock.empty":"No human lock entries for this filter.","dashboard.intent-timeline.title":"Intent Timeline","dashboard.intent-timeline.subtitle":".intent-ledger.jsonl · dual-column AI | Human · sorted by timestamp desc","dashboard.intent-timeline.filter.label":"Source","dashboard.intent-timeline.filter.all":"All","dashboard.intent-timeline.summary":"AI {aiCount} · Human {humanCount}","dashboard.intent-timeline.columns.ai.title":"AI","dashboard.intent-timeline.columns.ai.entries":"{count} entries","dashboard.intent-timeline.columns.human.title":"Human","dashboard.intent-timeline.columns.human.entries":"{count} entries","dashboard.intent-timeline.empty":"No ledger entries found.","dashboard.intent-timeline.annotate.missing-id":"Cannot annotate a ledger entry without an id.","dashboard.history-replay.title":"History Replay","dashboard.history-replay.subtitle":"Time-travel through ledger commits and rehydrate the rules tree at any recorded point","dashboard.history-replay.toolbar.scrub":"Scrub","dashboard.history-replay.toolbar.latest":"Latest","dashboard.history-replay.selected.none":"No historical entry selected","dashboard.history-replay.status.replay-points":"{count} replay points","dashboard.history-replay.status.entries-applied":"{count} entries applied","dashboard.history-replay.empty.entries":"No ledger entries found for replay.","dashboard.history-replay.state.title":"Viewing state as of {label}","dashboard.history-replay.state.meta":"ledger {ledgerId} · commit {commit} · {mode}","dashboard.history-replay.status.loading":"loading snapshot","dashboard.history-replay.status.nodes":"{count} nodes","dashboard.history-replay.status.unknown-revision":"unknown revision","dashboard.history-replay.tree.aria-label":"Historical Fabric rules tree","dashboard.history-replay.empty.loading":"Loading historical snapshot...","dashboard.history-replay.empty.select":"Select a timeline entry to replay its state.","dashboard.history-replay.meta.not-available":"unavailable","dashboard.history-replay.meta.pending":"pending","dashboard.history-replay.meta.na":"n/a","dashboard.doctor.title":"Doctor Console","dashboard.doctor.subtitle":"fab doctor surface · framework, entry points, revision drift, protected paths","dashboard.doctor.toolbar.overall":"Overall","dashboard.doctor.toolbar.no-summary":"No summary yet","dashboard.doctor.toolbar.entry-points-summary":"{framework} · {count} entry points","dashboard.doctor.toolbar.entry-point-summary":"{framework} · {count} entry point","dashboard.doctor.empty.loading":"Loading doctor report...","dashboard.doctor.summary.framework":"Framework","dashboard.doctor.summary.protected-paths":"Protected paths","dashboard.doctor.summary.intent-ledger":"Intent ledger","dashboard.doctor.summary.no-meta-revision":"No meta revision yet","dashboard.doctor.summary.tracked-paths.none":"No tracked paths","dashboard.doctor.summary.tracked-paths.some":"{count} tracked","dashboard.doctor.summary.hashes-intact":"All approved hashes intact","dashboard.doctor.summary.drifted":"{count} drifted","dashboard.doctor.summary.no-ledger-entries":"No ledger entries yet","dashboard.doctor.card.entry-points":"Entry points","dashboard.doctor.card.checks":"Checks","dashboard.doctor.empty.entry-points":"No current entry points detected.","dashboard.doctor.framework.unknown":"unknown","dashboard.doctor.age.none":"No entries","dashboard.doctor.age.seconds":"{count}s ago","dashboard.doctor.age.minutes":"{count}m ago","dashboard.doctor.age.hours":"{count}h ago","dashboard.doctor.age.days":"{count}d ago","dashboard.doctor.age.weeks":"{count}w ago","dashboard.shared.refresh":"Refresh","dashboard.shared.loading":"loading","dashboard.shared.status.ok":"ok","dashboard.shared.status.warn":"warn","dashboard.shared.status.error":"error","dashboard.shared.status.confirmed":"confirmed","dashboard.shared.status.hash-drift":"hash drift","dashboard.shared.status.stale":"stale","dashboard.shared.status.orphan":"orphan","dashboard.shared.status.attention":"attention","dashboard.source.ai":"AI","dashboard.source.human":"Human","dashboard.timeline-entry.aria-label":"{source} intent {intent}","dashboard.timeline-entry.working-tree":"working tree","dashboard.timeline-entry.parent":"parent {parent}","dashboard.timeline-entry.paths":"paths","dashboard.timeline-entry.annotate":"Annotate","dashboard.timeline-entry.annotation-label":"Human annotation","dashboard.timeline-entry.annotation-placeholder":"Explain review outcome or approval context...","dashboard.timeline-entry.annotation-save":"Save annotation","dashboard.tree-node.locked":"locked","dashboard.tree-node.stale.hash-mismatch":"hash mismatch","dashboard.tree-node.stale.orphan":"orphan","dashboard.lock-card.aria-label":"{file} {lineRange} {status}","dashboard.lock-card.status.drift":"hash drift","dashboard.lock-card.status.confirmed":"confirmed","dashboard.lock-card.hash.locked":"locked hash","dashboard.lock-card.hash.current":"current hash","dashboard.lock-card.hash.diff":"diff","dashboard.lock-card.preview.drift":"DRIFT","dashboard.lock-card.preview.sync":"SYNC","dashboard.lock-card.preview.drift-detail":"Hash differs from protected region.","dashboard.lock-card.preview.sync-detail":"Protected region is in sync.","dashboard.lock-card.footer.region":"protected region · {count} lines","dashboard.lock-card.button.approve":"Approve new hash","dashboard.lock-card.button.confirmed":"Confirmed","dashboard.lock-card.diff.hash-mismatch":"hash mismatch","dashboard.lock-card.diff.no-changes":"no changes","dashboard.lock-card.diff.with-bytes":"+{added} / -{removed} · {bytes} bytes","dashboard.lock-card.diff.without-bytes":"+{added} / -{removed}","dashboard.approve-button.retry":"Retry"},ea={"cli.main.description":"Fabric CLI - AI 智能体协作框架","cli.shared.created":"已创建","cli.shared.skipped":"已跳过","cli.shared.next":"下一步","cli.shared.reason":"原因","cli.shared.updated":"已更新","cli.shared.missing":"缺失","cli.shared.present":"存在","cli.shared.absent":"缺失","cli.shared.yes":"是","cli.shared.no":"否","cli.shared.none":"无","cli.shared.loading":"加载中","cli.shared.refresh":"刷新","cli.shared.target-invalid":"目标必须是已存在的目录:{target}","cli.shared.template-not-found":"未找到模板:{path}","cli.shared.invalid-host-empty":"无效 host:<empty>","cli.shared.invalid-port":"无效端口:{value}","cli.bootstrap.description":"为支持的 AI 客户端安装 Fabric 引导提示模板。","cli.bootstrap.install.description":"将 Fabric 引导模板复制到各客户端的原生位置。","cli.bootstrap.install.args.clients.description":"可选的逗号分隔客户端过滤器,例如 claude,cursor,codex。","cli.bootstrap.install.no-targets":"未检测到可安装的 bootstrap 目标。可显式传入 --clients claude,cursor,windsurf,roo,gemini,codex。","cli.bootstrap.install.installed":"已安装 {path}","cli.bootstrap.install.skipped-header":"已跳过 {path}:Fabric Bootstrap 头部已存在。","cli.bootstrap.install.prepended":"已前置写入 {path}","cli.bootstrap.errors.unknown-client":"未知客户端“{client}”。请使用逗号分隔列表,例如 claude,cursor,codex。","cli.config.description":"管理 Fabric MCP 客户端配置。","cli.config.install.description":"将 Fabric MCP 服务端条目安装到检测到的客户端配置中。","cli.config.install.args.clients.description":"可选的逗号分隔客户端过滤器,例如 cursor,codex,gemini。","cli.config.install.args.dry-run.description":"仅预览将要发生的写入操作,不修改文件。","cli.config.errors.unknown-client":"未知客户端“{client}”。请使用逗号分隔列表,例如 cursor,codex,gemini。","cli.config.errors.expected-object":"{path} 中应为对象。","cli.config.install.no-configs":"未检测到 Fabric MCP 客户端配置。请创建客户端目录,或在 fabric.config.json 中设置 clientPaths。","cli.config.install.no-config-path":"跳过 {client}:未检测到配置路径。","cli.config.install.dry-run":"[dry-run] {client}:将写入 {path}","cli.config.install.wrote":"{client}:已写入 {path}","cli.hooks.description":"管理 Fabric Git 钩子模板。","cli.hooks.install.description":"安装 Fabric Husky pre-commit 钩子模板。","cli.hooks.install.args.target.description":"目标项目路径,默认为当前工作目录。","cli.hooks.errors.package-json-required":"安装 hooks 需要 package.json:{path}","cli.hooks.install.hook-skipped":"{path} 中已存在 Fabric hook,已跳过。","cli.hooks.install.hook-appended":"已向现有 {path} 追加 Fabric hook","cli.hooks.install.hook-created":"已创建 {path}","cli.hooks.install.prepare-left":"保留 {path} 中原有的 prepare 脚本不变","cli.hooks.install.prepare-added":"已向 {path} 添加 prepare 脚本","cli.human-lint.description":"验证锁定的人工编辑区块。","cli.human-lint.args.target.description":"目标项目路径,默认为当前工作目录。","cli.human-lint.drift-detected":"检测到 human-lock 内容漂移。请回退编辑,或在提交前更新已批准的哈希。","cli.human-lint.table.location":"位置","cli.human-lint.table.expected":"预期","cli.human-lint.table.got":"实际","cli.init.description":"在目标项目中初始化 Fabric。","cli.init.args.target.description":"目标项目路径。默认依次使用 CLI 参数、EXTERNAL_FIXTURE_PATH、fabric.config.json、当前目录。","cli.init.args.debug.description":"将目标解析细节输出到 stderr。","cli.init.created-path":"{label} {path}","cli.init.skipped-existing-path":"{label} {path}:已存在。","cli.init.next-step":"{label} {message}","cli.init.reason-message":"{label} {message}","cli.init.next-step.message":"运行 fab hooks install 以添加第 4 天的 pre-commit 流水线。","cli.init.reason-message.body":".fabric/forensic.json 已就绪;请使用 agents-md-init skill 完成 AGENTS.md 初始化。","cli.init.claude-settings.created":"{label} {path},并写入 Claude Stop hook。","cli.init.claude-settings.updated":"{label} {path},并写入 Claude Stop hook。","cli.init.claude-settings.skipped":"{label} {path}:Claude Stop hook 已存在。","cli.init.claude-settings.skipped-invalid":"{label} {path}:无法合并 Claude Stop hook。","cli.init.claude-settings.invalid-object":"{label} {path}:预期为 JSON 对象。","cli.init.claude-settings.invalid-json":"{label} {path}:JSON 无效({reason})。","cli.init.claude-settings.invalid-hooks":'{label} {path}:"hooks" 必须是 JSON 对象。',"cli.init.claude-settings.invalid-stop-array":'{label} {path}:"hooks.Stop" 必须是数组。',"cli.init.errors.abort-existing":"中止:{path} 已存在。fab init 是非破坏性的。","cli.ledger-append.description":"向 Fabric 意图日志追加一条记录。","cli.ledger-append.args.target.description":"目标项目路径,默认为当前工作目录。","cli.ledger-append.args.staged.description":"从暂存变更推导记录(用于 pre-commit 阶段)。","cli.ledger-append.requires-staged":"pre-commit 场景下必须传入 --staged","cli.ledger-append.intent.auto":"自动:{head}{suffix}","cli.ledger-append.intent.auto-more":" 等 {count} 项","cli.pre-commit.description":"复合 pre-commit 钩子:在单个 Node 进程中依次执行 sync-meta --check-only、human-lint、ledger-append --staged。","cli.pre-commit.args.target.description":"项目根目录,默认取当前目录或 EXTERNAL_FIXTURE_PATH。","cli.pre-commit.run-failed":"fabric pre-commit:{name} 失败 - {message}","cli.scan.description":"扫描项目以检测 Fabric 引导候选模块。","cli.scan.args.target.description":"目标绝对路径。默认依次使用 CLI 参数、EXTERNAL_FIXTURE_PATH、fabric.config.json、当前目录。","cli.scan.args.debug.description":"以格式化输出打印检测证据。","cli.scan.args.json.description":"以 JSON 格式输出诊断报告。","cli.scan.report.title":"Fabric 扫描报告","cli.scan.report.target":"目标","cli.scan.report.framework":"框架","cli.scan.report.evidence":"证据","cli.scan.report.readme-quality":"README 质量","cli.scan.report.contributing":"CONTRIBUTING.md","cli.scan.report.files-counted":"文件数","cli.scan.report.ignored-entries":"忽略项","cli.scan.report.existing-fabric":"现有 Fabric 文件","cli.scan.report.recommendations":"建议:","cli.scan.readme-quality.ok":"良好","cli.scan.readme-quality.stub":"草稿","cli.scan.recommendation.init":"L0:运行 fab init,为 AGENTS.md 生成带 TODO 标记的初始骨架。","cli.scan.recommendation.readme":"L0:先补充 README.md,再把项目事实沉淀到 AGENTS.md 引用中。","cli.scan.recommendation.contributing":"L0:添加 CONTRIBUTING.md,或在 AGENTS.md 中留下贡献流程的 TODO 引用。","cli.scan.recommendation.unknown-framework":"L1:当前未检测到框架标记,需要手动补充技术栈 TODO。","cli.scan.recommendation.framework-dirs":"L1:检查 {framework} 目录,后续为其补充作用域化 AGENTS.md 文件。","cli.serve.description":"启动本地 Fabric MCP HTTP 服务。若需绑定到非 localhost,请设置 FABRIC_AUTH_TOKEN 以启用 Bearer 鉴权。","cli.serve.args.port.description":"监听端口,默认 7373。","cli.serve.args.host.description":"监听主机,默认 127.0.0.1。若需绑定到非 localhost,请设置 FABRIC_AUTH_TOKEN 以启用 Bearer 鉴权。","cli.serve.args.target.description":"目标项目路径。默认依次使用 CLI 参数、EXTERNAL_FIXTURE_PATH、fabric.config.json、当前目录。","cli.serve.args.debug.description":"将目标解析细节输出到 stderr。","cli.serve.ready.title":"Fabric 仪表盘","cli.serve.warning.host-fallback":"--host {host} 需要 FABRIC_AUTH_TOKEN;为安全起见已回退到 127.0.0.1","cli.serve.error.port-in-use":"端口 {port} 已被占用,可尝试 --port {nextPort}","cli.sync-meta.description":"从 AGENTS.md 文件同步 Fabric 元数据。","cli.sync-meta.args.target.description":"目标项目路径,默认为当前工作目录。","cli.sync-meta.args.check-only.description":"如果 .fabric/agents.meta.json 已过期,则以代码 1 退出。","cli.sync-meta.drift-detected":"检测到 Fabric 元数据漂移。请运行 fab sync-meta 进行更新。","cli.sync-meta.updated":"{label} {path}","dashboard.app.nav.aria-label":"仪表盘视图导航","dashboard.app.nav.rules.label":"规则树","dashboard.app.nav.rules.label-bilingual":"规则树 Rules Tree","dashboard.app.nav.rules.subtitle":"元图","dashboard.app.nav.locks.label":"人工锁","dashboard.app.nav.locks.label-bilingual":"人工锁 Human Lock","dashboard.app.nav.locks.subtitle":"受保护区域","dashboard.app.nav.timeline.label":"意图时间线","dashboard.app.nav.timeline.label-bilingual":"意图时间线 Intent Timeline","dashboard.app.nav.timeline.subtitle":"日志流","dashboard.app.nav.history.label":"历史回放","dashboard.app.nav.history.label-bilingual":"历史回放 History Replay","dashboard.app.nav.history.subtitle":"时间回溯","dashboard.app.nav.doctor.label":"诊断台","dashboard.app.nav.doctor.label-bilingual":"诊断台 Doctor","dashboard.app.nav.doctor.subtitle":"fab 诊断","dashboard.app.nav.section.diagnostics":"诊断","dashboard.app.nav.drift-check":"漂移检查","dashboard.app.header.connected":"已连接","dashboard.app.header.connecting":"连接中","dashboard.app.live-region.received":"已收到 {type}","dashboard.app.breadcrumb.rules":"rules-tree","dashboard.app.breadcrumb.locks":"human-lock","dashboard.app.breadcrumb.timeline":"intent-timeline","dashboard.app.breadcrumb.history":"history-replay","dashboard.app.breadcrumb.doctor":"doctor","dashboard.rules-tree.title":"规则树浏览器","dashboard.rules-tree.subtitle":".fabric/agents.meta.json · L0/L1/L2 层级 · 感知哈希漂移","dashboard.rules-tree.filter.placeholder":"按文件、glob、优先级、哈希过滤...","dashboard.rules-tree.filter.aria-label":"过滤规则树","dashboard.rules-tree.status.loading":"规则加载中","dashboard.rules-tree.status.nodes":"{count} 个节点 · rev {revision}","dashboard.rules-tree.status.locks":"{count} 个人工锁","dashboard.rules-tree.empty":"没有匹配的规则。","dashboard.rules-tree.tree.aria-label":"Fabric 规则树","dashboard.rules-tree.detail.title":"节点详情","dashboard.rules-tree.detail.empty":"选择一个规则节点以查看作用域、依赖、优先级和哈希。","dashboard.rules-tree.detail.file":"文件","dashboard.rules-tree.detail.scope":"作用域","dashboard.rules-tree.detail.priority":"优先级","dashboard.rules-tree.detail.hash":"哈希","dashboard.rules-tree.detail.no-deps":"无依赖","dashboard.human-lock.title":"人工锁仓库","dashboard.human-lock.subtitle":"等待批准的受保护区域 · 仅允许仪式化写入","dashboard.human-lock.filters.aria-label":"人工锁过滤器","dashboard.human-lock.filters.all":"全部","dashboard.human-lock.filters.drift":"漂移","dashboard.human-lock.filters.approved":"已批准","dashboard.human-lock.summary":"{drift} 处漂移 · {approved} 项已确认","dashboard.human-lock.empty":"当前过滤条件下没有人工锁记录。","dashboard.intent-timeline.title":"意图时间线","dashboard.intent-timeline.subtitle":".intent-ledger.jsonl · AI | Human 双列 · 按时间倒序","dashboard.intent-timeline.filter.label":"来源","dashboard.intent-timeline.filter.all":"全部","dashboard.intent-timeline.summary":"AI {aiCount} · Human {humanCount}","dashboard.intent-timeline.columns.ai.title":"AI","dashboard.intent-timeline.columns.ai.entries":"{count} 条记录","dashboard.intent-timeline.columns.human.title":"人工","dashboard.intent-timeline.columns.human.entries":"{count} 条记录","dashboard.intent-timeline.empty":"没有找到日志记录。","dashboard.intent-timeline.annotate.missing-id":"缺少 id,无法为这条日志添加注释。","dashboard.history-replay.title":"历史回放","dashboard.history-replay.subtitle":"穿越日志提交,在任意记录点重新还原规则树状态","dashboard.history-replay.toolbar.scrub":"拖动","dashboard.history-replay.toolbar.latest":"最新","dashboard.history-replay.selected.none":"尚未选择历史记录","dashboard.history-replay.status.replay-points":"{count} 个回放点","dashboard.history-replay.status.entries-applied":"已应用 {count} 条记录","dashboard.history-replay.empty.entries":"没有可用于回放的日志记录。","dashboard.history-replay.state.title":"查看 {label} 时刻的状态","dashboard.history-replay.state.meta":"ledger {ledgerId} · commit {commit} · {mode}","dashboard.history-replay.status.loading":"快照加载中","dashboard.history-replay.status.nodes":"{count} 个节点","dashboard.history-replay.status.unknown-revision":"未知 revision","dashboard.history-replay.tree.aria-label":"历史 Fabric 规则树","dashboard.history-replay.empty.loading":"正在加载历史快照...","dashboard.history-replay.empty.select":"请选择一条时间线记录以回放其状态。","dashboard.history-replay.meta.not-available":"不可用","dashboard.history-replay.meta.pending":"等待中","dashboard.history-replay.meta.na":"无","dashboard.doctor.title":"诊断控制台","dashboard.doctor.subtitle":"fab doctor 面板 · 框架、入口点、revision 漂移、受保护路径","dashboard.doctor.toolbar.overall":"整体状态","dashboard.doctor.toolbar.no-summary":"暂无摘要","dashboard.doctor.toolbar.entry-points-summary":"{framework} · {count} 个入口点","dashboard.doctor.toolbar.entry-point-summary":"{framework} · {count} 个入口点","dashboard.doctor.empty.loading":"正在加载 doctor 报告...","dashboard.doctor.summary.framework":"框架","dashboard.doctor.summary.protected-paths":"受保护路径","dashboard.doctor.summary.intent-ledger":"意图日志","dashboard.doctor.summary.no-meta-revision":"暂无 meta revision","dashboard.doctor.summary.tracked-paths.none":"没有跟踪路径","dashboard.doctor.summary.tracked-paths.some":"已跟踪 {count} 项","dashboard.doctor.summary.hashes-intact":"所有已批准哈希均完好","dashboard.doctor.summary.drifted":"{count} 项发生漂移","dashboard.doctor.summary.no-ledger-entries":"暂无日志记录","dashboard.doctor.card.entry-points":"入口点","dashboard.doctor.card.checks":"检查项","dashboard.doctor.empty.entry-points":"当前未检测到入口点。","dashboard.doctor.framework.unknown":"未知","dashboard.doctor.age.none":"暂无记录","dashboard.doctor.age.seconds":"{count} 秒前","dashboard.doctor.age.minutes":"{count} 分钟前","dashboard.doctor.age.hours":"{count} 小时前","dashboard.doctor.age.days":"{count} 天前","dashboard.doctor.age.weeks":"{count} 周前","dashboard.shared.refresh":"刷新","dashboard.shared.loading":"加载中","dashboard.shared.status.ok":"正常","dashboard.shared.status.warn":"警告","dashboard.shared.status.error":"错误","dashboard.shared.status.confirmed":"已确认","dashboard.shared.status.hash-drift":"哈希漂移","dashboard.shared.status.stale":"过期","dashboard.shared.status.orphan":"孤立","dashboard.shared.status.attention":"注意","dashboard.source.ai":"AI","dashboard.source.human":"人工","dashboard.timeline-entry.aria-label":"{source} 意图 {intent}","dashboard.timeline-entry.working-tree":"工作区","dashboard.timeline-entry.parent":"父提交 {parent}","dashboard.timeline-entry.paths":"路径","dashboard.timeline-entry.annotate":"添加注释","dashboard.timeline-entry.annotation-label":"人工注释","dashboard.timeline-entry.annotation-placeholder":"说明审核结论或批准背景...","dashboard.timeline-entry.annotation-save":"保存注释","dashboard.tree-node.locked":"已锁定","dashboard.tree-node.stale.hash-mismatch":"哈希不匹配","dashboard.tree-node.stale.orphan":"孤立","dashboard.lock-card.aria-label":"{file} {lineRange} {status}","dashboard.lock-card.status.drift":"哈希漂移","dashboard.lock-card.status.confirmed":"已确认","dashboard.lock-card.hash.locked":"锁定哈希","dashboard.lock-card.hash.current":"当前哈希","dashboard.lock-card.hash.diff":"差异","dashboard.lock-card.preview.drift":"漂移","dashboard.lock-card.preview.sync":"同步","dashboard.lock-card.preview.drift-detail":"哈希与受保护区域不一致。","dashboard.lock-card.preview.sync-detail":"受保护区域当前保持同步。","dashboard.lock-card.footer.region":"受保护区域 · {count} 行","dashboard.lock-card.button.approve":"批准新哈希","dashboard.lock-card.button.confirmed":"已确认","dashboard.lock-card.diff.hash-mismatch":"哈希不一致","dashboard.lock-card.diff.no-changes":"无变更","dashboard.lock-card.diff.with-bytes":"+{added} / -{removed} · {bytes} 字节","dashboard.lock-card.diff.without-bytes":"+{added} / -{removed}","dashboard.approve-button.retry":"重试"},ta={en:Yt,"zh-CN":ea};function aa(t,e=ta){const a=e[t]??e.en,i=e.en;return(n,o)=>{const s=a[n]??i[n]??n;return o===void 0?s:Object.entries(o).reduce((d,[u,c])=>d.replaceAll(`{${u}}`,c),s)}}function ra(t){if(typeof t!="string")return"en";const e=t.trim().toLowerCase().replace(/\..*$/,"").replace(/_/g,"-");return e.length===0?"en":e==="zh"||e.startsWith("zh-")?"zh-CN":"en"}function ia(){return typeof navigator<"u"&&typeof navigator.language=="string"?ra(navigator.language):"en"}function oa(t=ia()){return{locale:t,t:aa(t)}}const kt=Rt(null);function na({children:t}){const e=L(()=>oa(),[]);return r(kt.Provider,{value:e,children:t})}function x(){const t=Dt(kt);if(t===null)throw new Error("useI18n must be used within an I18nProvider.");return t}function wt({variant:t,state:e="idle",size:a="md",onClick:i,children:n,ariaLabel:o}){const{t:s}=x(),[d,u]=N(e),c=e==="idle"?d:e,p=c==="busy",l=async()=>{if(!p){u("busy");try{await i(),u("success"),window.setTimeout(()=>u("idle"),900)}catch{u("error"),window.setTimeout(()=>u("idle"),1400)}}};return r("button",{type:"button",className:`action-button action-${t} action-${a} action-${c}`,"aria-label":o,"aria-busy":p,"aria-disabled":p,onClick:l,children:[p?r("span",{className:"spinner","aria-hidden":"true"}):null,c==="success"?r("span",{"aria-hidden":"true",children:"✓"}):null,c==="error"?s("dashboard.approve-button.retry"):n]})}const sa={ok:"dashboard.shared.status.confirmed",drift:"dashboard.shared.status.hash-drift",stale:"dashboard.shared.status.stale",orphan:"dashboard.shared.status.orphan",locked:"dashboard.shared.status.attention"};function P({kind:t,severity:e,message:a,diffStats:i}){const{t:n}=x();if(e==="ok"&&t==="dot")return null;const o=a??n(sa[e]),s=i===void 0?"":` +${i.added} / -${i.removed}`,d=`drift-indicator drift-${t} drift-${e}`;return t==="dot"?r("span",{className:d,"aria-label":o}):t==="banner"?r("div",{className:d,role:"status",children:[r("span",{"aria-hidden":"true",children:"!"}),r("span",{children:[o,s]})]}):r("span",{className:d,children:[r("span",{"aria-hidden":"true",children:e==="ok"?"✓":"!"}),r("span",{children:[o,s]})]})}function la({entry:t,currentHash:e,diffStats:a,diffPreview:i=[],onApprove:n,busy:o=!1}){const{t:s}=x(),d=e!==void 0&&e!==t.hash,u=d?"drift":"ok",c=s(d?"dashboard.lock-card.status.drift":"dashboard.lock-card.status.confirmed"),p=`L${t.start_line}-L${t.end_line}`;return r("article",{className:`lock-card lock-${u} ${o?"is-busy":""}`,"aria-label":s("dashboard.lock-card.aria-label",{file:t.file,lineRange:p,status:c}),children:[r("header",{className:"lock-head",children:[r("div",{className:"lock-icon","aria-hidden":"true",children:d?"!":"✓"}),r("div",{className:"lock-title",children:[r("strong",{children:t.file}),r("span",{children:p})]}),r(P,{kind:"pill",severity:d?"drift":"ok",message:c})]}),r("div",{className:"lock-body",children:[r("div",{className:"hash-block",children:[r(fe,{label:s("dashboard.lock-card.hash.locked"),value:t.hash,stale:d}),r(fe,{label:s("dashboard.lock-card.hash.current"),value:e??s("dashboard.history-replay.meta.not-available")}),r(fe,{label:s("dashboard.lock-card.hash.diff"),value:da(a,d,s),accent:d})]}),r("div",{className:"preview",children:[r("div",{className:"preview-head",children:[r("span",{children:[t.file," · ",p]}),r("span",{children:s(d?"dashboard.lock-card.preview.drift":"dashboard.lock-card.preview.sync")})]}),r("pre",{className:"preview-body",children:i.length>0?i.map(l=>r("span",{className:`line-${l.kind}`,children:[r("span",{className:"line-num",children:l.line}),l.text,`
|
|
2
|
-
`]},`${l.kind}:${l.line}:${l.text}`)):`${t.file}
|
|
3
|
-
${p}
|
|
4
|
-
${s(d?"dashboard.lock-card.preview.drift-detail":"dashboard.lock-card.preview.sync-detail")}`})]})]}),r("footer",{className:"lock-foot",children:[r("span",{className:"meta-line",children:s("dashboard.lock-card.footer.region",{count:String(t.end_line-t.start_line+1)})}),d&&e!==void 0&&n!==void 0?r(wt,{variant:"approve",state:o?"busy":"idle",ariaLabel:s("dashboard.lock-card.button.approve"),onClick:()=>n(t),children:s("dashboard.lock-card.button.approve")}):r("button",{className:"action-button action-approve action-success",type:"button","aria-disabled":"true",children:["✓ ",s("dashboard.lock-card.button.confirmed")]})]})]})}function fe({label:t,value:e,stale:a=!1,accent:i=!1}){return r("div",{className:"hash-row",children:[r("span",{className:"hash-key",children:t}),r("span",{className:`hash-value ${a?"is-stale":""} ${i?"is-accent":""}`,children:e})]})}function da(t,e,a){return t===void 0?a(e?"dashboard.lock-card.diff.hash-mismatch":"dashboard.lock-card.diff.no-changes"):t.bytes!==void 0?a("dashboard.lock-card.diff.with-bytes",{added:String(t.added),removed:String(t.removed),bytes:String(t.bytes)}):a("dashboard.lock-card.diff.without-bytes",{added:String(t.added),removed:String(t.removed)})}function Te({source:t,size:e="sm",variant:a="filled",interactive:i=!1,selected:n=!1,onClick:o}){const{t:s}=x(),d=["source-badge",`source-badge-${t}`,`source-badge-${e}`,`source-badge-${a}`,n?"is-selected":""].filter(Boolean).join(" "),u=s(`dashboard.source.${t}`);return i?r("button",{className:d,type:"button","aria-pressed":n,onClick:o,children:[r("span",{className:"source-badge-dot","aria-hidden":"true"}),u]}):r("span",{className:d,children:[r("span",{className:"source-badge-dot","aria-hidden":"true"}),u]})}function Nt({entry:t,onAnnotate:e,expanded:a=!1,readOnly:i=!1}){const{locale:n,t:o}=x(),[s,d]=N(a),[u,c]=N(""),p=t.source==="ai",l=!i&&p&&e!==void 0&&t.id!==void 0,f=async()=>{const h=u.trim();!p||e===void 0||h.length===0||(await e(t,h),c(""),d(!1))};return r("article",{className:`timeline-entry timeline-${t.source}`,"aria-label":o("dashboard.timeline-entry.aria-label",{source:o(`dashboard.source.${t.source}`),intent:t.intent}),children:[r("div",{className:`dot-axis ${t.source}`,"aria-hidden":"true"}),r("div",{className:"timeline-head",children:[r(Te,{source:t.source}),p?r("span",{className:"commit-hash",children:t.commit_sha??o("dashboard.timeline-entry.working-tree")}):null,p?null:r("span",{className:"commit-hash",children:o("dashboard.timeline-entry.parent",{parent:t.parent_sha})}),p?null:r("span",{className:"diff-badge",children:t.diff_stat}),r("time",{className:"entry-time",dateTime:new Date(t.ts).toISOString(),children:ca(t.ts,n)})]}),r("h3",{className:"entry-title",children:t.intent}),r("div",{className:"entry-meta",children:[r("span",{children:[r("span",{className:"meta-key",children:o("dashboard.timeline-entry.paths")})," ",t.affected_paths.length]}),t.affected_paths.slice(0,3).map(h=>r("span",{children:h},h))]}),!p&&t.annotation!==void 0?r("div",{className:"entry-body",children:t.annotation}):null,p&&l?r("div",{className:"entry-foot",children:r("button",{className:"ghost-button",type:"button",onClick:()=>d(h=>!h),children:o("dashboard.timeline-entry.annotate")})}):null,s&&p?r("form",{className:"annotate-form",onSubmit:h=>{h.preventDefault(),f()},children:[r("label",{htmlFor:`annotate-${t.id??t.ts}`,children:o("dashboard.timeline-entry.annotation-label")}),r("input",{id:`annotate-${t.id??t.ts}`,className:"annotate-input",value:u,onInput:h=>c(h.currentTarget.value),placeholder:o("dashboard.timeline-entry.annotation-placeholder")}),r(wt,{variant:"annotate",size:"sm",onClick:f,children:o("dashboard.timeline-entry.annotation-save")})]}):null]})}function ca(t,e){return new Intl.DateTimeFormat(e,{hour:"2-digit",minute:"2-digit",second:"2-digit"}).format(new Date(t))}function Le({node:t,level:e,selected:a=!1,onSelect:i,humanLockedNearby:n=!1,staleReason:o=null,defaultExpanded:s=!1,readOnly:d=!1,children:u=[]}){const{t:c}=x(),[p,l]=N(s),f=u.length>0,h=t.file,m=o===null?"ok":o==="orphan"?"orphan":"stale",y=()=>{d||(f&&l(_=>!_),i?.(h))},v=_=>{d||((_.key==="Enter"||_.key===" ")&&(_.preventDefault(),y()),_.key==="ArrowRight"&&f&&l(!0),_.key==="ArrowLeft"&&f&&l(!1))};return r("div",{className:`tree-node-group tree-level-${e}`,children:[r("div",{className:["tree-node",a?"is-selected":"",p?"is-expanded":"",n?"is-locked":"",o!==null?"is-stale":"",d?"is-readonly":""].filter(Boolean).join(" "),role:"treeitem","aria-expanded":f?p:void 0,"aria-level":e+1,"aria-readonly":d||void 0,tabIndex:d?-1:0,onClick:d?void 0:y,onKeyDown:d?void 0:v,children:[r("span",{className:"tree-caret","aria-hidden":"true",children:f?"›":"·"}),r("span",{className:"tree-icon","aria-hidden":"true",children:e===0?"F":e===1?"D":"R"}),r("span",{className:"tree-label",children:h}),n?r("span",{className:"badge badge-locked",children:c("dashboard.tree-node.locked")}):null,o!==null?r(P,{kind:"pill",severity:m,message:c(`dashboard.tree-node.stale.${o}`)}):null,r("span",{className:"tree-meta",children:[r("span",{className:"badge badge-level",children:["L",e]}),r("span",{className:"tree-hash",children:ha(t.hash)})]})]}),f&&p?r("div",{className:"tree-children",role:"group",children:u.map(_=>r(Le,{..._,onSelect:i,readOnly:d},`${_.node.file}:${_.level}`))}):null]})}function ha(t){return t.length>18?`${t.slice(0,12)}…`:t}function ua({lastEvent:t}){const{t:e}=x(),[a,i]=N(null),[n,o]=N([]),[s,d]=N(null),[u,c]=N(""),[p,l]=N(null),f=async()=>{try{const[v,_]=await Promise.all([qt(),_t().catch(()=>[])]);i(v),o(_),l(null)}catch(v){l(v instanceof Error?v.message:String(v))}};C(()=>{f()},[]),C(()=>{(t?.type==="meta:updated"||t?.type==="drift:detected"||t?.type==="lock:drift")&&f()},[t]);const h=L(()=>new Set(n.map(v=>v.file)),[n]),m=L(()=>a===null?[]:St(a,h,u),[a,h,u]),y=s===null?null:a?.nodes[s]??null;return r("section",{className:"view",children:[r(W,{title:e("dashboard.rules-tree.title"),subtitle:e("dashboard.rules-tree.subtitle")}),p!==null?r(P,{kind:"banner",severity:"stale",message:p}):null,r("div",{className:"view-split",children:[r("div",{className:"tree-panel",children:[r("div",{className:"tree-filter",children:[r("input",{value:u,onInput:v=>c(v.currentTarget.value),placeholder:e("dashboard.rules-tree.filter.placeholder"),"aria-label":e("dashboard.rules-tree.filter.aria-label")}),r("button",{className:"ghost-button",type:"button",onClick:()=>{f()},children:e("dashboard.shared.refresh")})]}),r("div",{className:"status-line",children:[r("span",{children:a===null?e("dashboard.rules-tree.status.loading"):e("dashboard.rules-tree.status.nodes",{count:String(Object.keys(a.nodes).length),revision:a.revision})}),r("span",{children:e("dashboard.rules-tree.status.locks",{count:String(n.length)})})]}),r("div",{className:"tree",role:"tree","aria-label":e("dashboard.rules-tree.tree.aria-label"),children:m.length>0?m.map(v=>r(Le,{...v,selected:v.node.file===s,onSelect:d},v.node.file)):r("div",{className:"empty-card",children:e("dashboard.rules-tree.empty")})})]}),r("aside",{className:"detail-panel",children:[r("h3",{children:e("dashboard.rules-tree.detail.title")}),y===null?r("p",{className:"muted",children:e("dashboard.rules-tree.detail.empty")}):r("div",{className:"kv",children:[r(z,{label:e("dashboard.rules-tree.detail.file"),value:y.file}),r(z,{label:e("dashboard.rules-tree.detail.scope"),value:y.scope_glob}),r(z,{label:e("dashboard.rules-tree.detail.priority"),value:y.priority}),r(z,{label:e("dashboard.rules-tree.detail.hash"),value:y.hash}),r("pre",{className:"code",children:y.deps.length>0?y.deps.join(`
|
|
5
|
-
`):e("dashboard.rules-tree.detail.no-deps")})]})]})]})]})}function W({title:t,subtitle:e}){return r("div",{className:"view-header",children:r("div",{children:[r("h1",{className:"view-title",children:t}),r("p",{className:"view-subtitle",children:e})]})})}function z({label:t,value:e}){return r("div",{className:"kv-row",children:[r("span",{className:"kv-key",children:t}),r("span",{className:"kv-value",children:e})]})}function St(t,e,a){const i=a.trim().toLowerCase(),n=Object.values(t.nodes).filter(d=>i.length===0||JSON.stringify(d).toLowerCase().includes(i)).sort((d,u)=>d.file.localeCompare(u.file)),o=new Map;for(const d of n){const u=d.file.split("/")[0]??"root";o.set(u,[...o.get(u)??[],d])}return[{node:{file:`revision:${t.revision}`,scope_glob:"**/*",deps:[],priority:"high",hash:t.revision},level:0,defaultExpanded:!0,children:Array.from(o.entries()).map(([d,u])=>({node:{file:d,scope_glob:`${d}/**/*`,deps:[],priority:"medium",hash:`${u.length} nodes`},level:1,defaultExpanded:!0,children:u.map(c=>({node:c,level:2,humanLockedNearby:e.has(c.file),staleReason:c.hash.length===0?"hash-mismatch":null}))}))}]}function pa({lastEvent:t}){const{locale:e,t:a}=x(),[i,n]=N(null),[o,s]=N(!0),[d,u]=N(null),c=async()=>{s(!0);try{n(await Jt()),u(null)}catch(p){u(p instanceof Error?p.message:String(p))}finally{s(!1)}};return C(()=>{c()},[]),C(()=>{(t?.type==="meta:updated"||t?.type==="lock:approved"||t?.type==="lock:drift"||t?.type==="ledger:appended"||t?.type==="drift:detected")&&c()},[t]),r("section",{className:"view",children:[r(W,{title:a("dashboard.doctor.title"),subtitle:a("dashboard.doctor.subtitle")}),d!==null?r(P,{kind:"banner",severity:"stale",message:d}):null,r("div",{className:"filter-bar doctor-toolbar",children:[r("span",{className:"filter-label",children:a("dashboard.doctor.toolbar.overall")}),r(P,{kind:"pill",severity:Tt(i?.status??"warn"),message:a(i===null?"dashboard.shared.loading":`dashboard.shared.status.${i.status}`)}),r("span",{className:"filter-date",children:i===null?a("dashboard.doctor.toolbar.no-summary"):i.summary.entryPoints.length===1?a("dashboard.doctor.toolbar.entry-point-summary",{framework:ve(i.summary.framework,a),count:"1"}):a("dashboard.doctor.toolbar.entry-points-summary",{framework:ve(i.summary.framework,a),count:String(i.summary.entryPoints.length)})}),r("button",{className:"ghost-button",type:"button",onClick:()=>{c()},children:a("dashboard.shared.refresh")})]}),o&&i===null?r("div",{className:"empty-card",children:a("dashboard.doctor.empty.loading")}):null,i!==null?r("div",{className:"doctor-layout",children:[r("div",{className:"doctor-summary-grid",children:[r(_e,{label:a("dashboard.doctor.summary.framework"),value:ve(i.summary.framework,a),detail:i.summary.metaRevision===null?a("dashboard.doctor.summary.no-meta-revision"):`rev ${i.summary.metaRevision}`}),r(_e,{label:a("dashboard.doctor.summary.protected-paths"),value:i.summary.protectedPathCount===0?a("dashboard.doctor.summary.tracked-paths.none"):a("dashboard.doctor.summary.tracked-paths.some",{count:String(i.summary.protectedPathCount)}),detail:i.summary.protectedPathsIntact?a("dashboard.doctor.summary.hashes-intact"):a("dashboard.doctor.summary.drifted",{count:String(i.summary.driftCount)})}),r(_e,{label:a("dashboard.doctor.summary.intent-ledger"),value:ba(i.summary.lastLedgerEntryAgeMs,a),detail:i.summary.lastLedgerEntryTs===null?a("dashboard.doctor.summary.no-ledger-entries"):new Date(i.summary.lastLedgerEntryTs).toLocaleString(e)})]}),r("div",{className:"doctor-panels",children:[r("article",{className:"doctor-card",children:[r("div",{className:"doctor-card-head",children:[r("h3",{children:a("dashboard.doctor.card.entry-points")}),r("span",{children:i.summary.entryPoints.length})]}),i.summary.entryPoints.length>0?r("div",{className:"doctor-entry-list",children:i.summary.entryPoints.map(p=>r("div",{className:"doctor-entry",children:[r("strong",{children:p.path}),r("span",{children:p.reason})]},`${p.path}:${p.reason}`))}):r("div",{className:"empty-card doctor-empty",children:a("dashboard.doctor.empty.entry-points")})]}),r("article",{className:"doctor-card",children:[r("div",{className:"doctor-card-head",children:[r("h3",{children:a("dashboard.doctor.card.checks")}),r("span",{children:i.checks.length})]}),r("div",{className:"doctor-check-list",children:i.checks.map(p=>r(ma,{check:p},p.name))})]})]})]}):null]})}function _e({label:t,value:e,detail:a}){return r("article",{className:"doctor-summary-card",children:[r("span",{className:"doctor-summary-label",children:t}),r("strong",{className:"doctor-summary-value",children:e}),r("span",{className:"doctor-summary-detail",children:a})]})}function ma({check:t}){const{t:e}=x();return r("div",{className:`doctor-check doctor-check-${t.status}`,children:[r("div",{className:"doctor-check-head",children:[r("strong",{children:t.name}),r(P,{kind:"pill",severity:Tt(t.status),message:e(`dashboard.shared.status.${t.status}`)})]}),r("p",{children:t.message})]})}function Tt(t){switch(t){case"ok":return"ok";case"warn":return"locked";case"error":return"stale"}}function ve(t,e){const a=[t.kind,t.version,t.subkind].filter(i=>i!=="unknown");return a.length>0?a.join(" · "):e("dashboard.doctor.framework.unknown")}function ba(t,e){if(t===null)return e("dashboard.doctor.age.none");const a=Math.floor(t/1e3);if(a<60)return e("dashboard.doctor.age.seconds",{count:String(a)});const i=Math.floor(a/60);if(i<60)return e("dashboard.doctor.age.minutes",{count:String(i)});const n=Math.floor(i/60);if(n<48)return e("dashboard.doctor.age.hours",{count:String(n)});const o=Math.floor(n/24);return o<14?e("dashboard.doctor.age.days",{count:String(o)}):e("dashboard.doctor.age.weeks",{count:String(Math.floor(o/7))})}function fa({lastEvent:t}){const{locale:e,t:a}=x(),[i,n]=N([]),[o,s]=N(null),[d,u]=N(null),[c,p]=N(!1),[l,f]=N(null),h=async()=>{try{const b=(await ft()).sort((w,$)=>w.ts-$.ts);n(b),s(w=>b.length===0?null:w!==null&&b.some($=>$.id===w)?w:b.at(-1)?.id??null),f(null)}catch(b){f(b instanceof Error?b.message:String(b))}};C(()=>{h()},[]),C(()=>{t?.type==="ledger:appended"&&h()},[t]),C(()=>{if(o===null){u(null);return}let b=!1;return p(!0),Kt({ledgerId:o}).then(w=>{b||(u(w),f(null))}).catch(w=>{b||(u(null),f(w instanceof Error?w.message:String(w)))}).finally(()=>{b||p(!1)}),()=>{b=!0}},[o]);const m=L(()=>i.findIndex(b=>b.id===o),[i,o]),y=m>=0?i[m]??null:null,v=y===null?a("dashboard.history-replay.selected.none"):new Date(y.ts).toLocaleString(e),_=L(()=>d===null?[]:St(d.meta,new Set,""),[d]);return r("section",{className:"view",children:[r(W,{title:a("dashboard.history-replay.title"),subtitle:a("dashboard.history-replay.subtitle")}),l!==null?r(P,{kind:"banner",severity:"stale",message:l}):null,r("div",{className:"filter-bar history-toolbar",children:[r("span",{className:"filter-label",children:a("dashboard.history-replay.toolbar.scrub")}),r("input",{className:"history-slider",type:"range",min:"0",max:Math.max(i.length-1,0),value:m>=0?m:0,disabled:i.length===0,onInput:b=>{const w=Number.parseInt(b.currentTarget.value,10),$=i[w];$?.id!==void 0&&s($.id)}}),r("span",{className:"filter-date",children:v}),r("button",{className:"ghost-button",type:"button",disabled:i.length===0,onClick:()=>s(i.at(-1)?.id??null),children:a("dashboard.history-replay.toolbar.latest")})]}),r("div",{className:"view-split history-layout",children:[r("div",{className:"tree-panel history-timeline-panel",children:[r("div",{className:"status-line",children:[r("span",{children:a("dashboard.history-replay.status.replay-points",{count:String(i.length)})}),r("span",{children:a("dashboard.history-replay.status.entries-applied",{count:String(d?.metadata.replayed_count??0)})})]}),r("div",{className:"history-timeline-list",children:i.length>0?[...i].reverse().map(b=>r("div",{className:`history-timeline-item ${b.id===o?"selected":""}`,role:"button",tabIndex:0,onClick:()=>s(b.id??null),onKeyDown:w=>{(w.key==="Enter"||w.key===" ")&&(w.preventDefault(),s(b.id??null))},children:r(Nt,{entry:b,readOnly:!0})},b.id??`${b.source}:${b.ts}:${b.intent}`)):r("div",{className:"empty-card",children:a("dashboard.history-replay.empty.entries")})})]}),r("div",{className:"tree-panel",children:[r("div",{className:"tree-filter history-state-head",children:r("div",{children:[r("div",{className:"history-state-title",children:a("dashboard.history-replay.state.title",{label:v})}),r("div",{className:"meta-line",children:a("dashboard.history-replay.state.meta",{ledgerId:d?.metadata.at_ledger_id??a("dashboard.history-replay.meta.na"),commit:d?.metadata.at_commit??a("dashboard.history-replay.meta.not-available"),mode:d?.metadata.mode??a("dashboard.history-replay.meta.pending")})})]})}),r("div",{className:"status-line",children:[r("span",{children:d===null?a("dashboard.history-replay.status.loading"):a("dashboard.history-replay.status.nodes",{count:String(Object.keys(d.meta.nodes).length)})}),r("span",{children:d?.meta.revision??a("dashboard.history-replay.status.unknown-revision")})]}),r("div",{className:"tree",role:"tree","aria-label":a("dashboard.history-replay.tree.aria-label"),children:[c?r("div",{className:"empty-card",children:a("dashboard.history-replay.empty.loading")}):null,!c&&_.length>0?_.map(b=>r(Le,{...b,readOnly:!0},b.node.file)):null,!c&&_.length===0?r("div",{className:"empty-card",children:a("dashboard.history-replay.empty.select")}):null]})]})]})]})}function _a({lastEvent:t}){const{t:e}=x(),[a,i]=N([]),[n,o]=N("all"),[s,d]=N(null),[u,c]=N(null),p=async()=>{try{i(await _t()),c(null)}catch(m){c(m instanceof Error?m.message:String(m))}};C(()=>{p()},[]),C(()=>{(t?.type==="lock:drift"||t?.type==="lock:approved")&&p()},[t]);const l=L(()=>({all:a.length,drift:a.filter(m=>m.drift).length,approved:a.filter(m=>!m.drift).length}),[a]),f=a.filter(m=>n==="all"||(n==="drift"?m.drift:!m.drift)),h=async m=>{const y=a.find(v=>R(v)===R(m));if(y!==void 0){d(R(m));try{const v=await Wt({file:y.file,start_line:y.start_line,end_line:y.end_line,new_hash:y.current_hash});i(_=>_.map(b=>R(b)===R(m)?v.entry:b)),c(null)}catch(v){throw c(v instanceof Error?v.message:String(v)),v}finally{d(null)}}};return r("section",{className:"view",children:[r(W,{title:e("dashboard.human-lock.title"),subtitle:e("dashboard.human-lock.subtitle")}),u!==null?r(P,{kind:"banner",severity:"drift",message:u}):null,r("div",{className:"filter-bar",role:"tablist","aria-label":e("dashboard.human-lock.filters.aria-label"),children:[["all","drift","approved"].map(m=>r("button",{className:`filter-chip ${n===m?"active":""} ${m}`,type:"button",role:"tab","aria-selected":n===m,onClick:()=>o(m),children:[e(`dashboard.human-lock.filters.${m}`),r("span",{className:"count",children:l[m]})]},m)),r("span",{className:"filter-date",children:e("dashboard.human-lock.summary",{drift:String(l.drift),approved:String(l.approved)})})]}),r("div",{className:"lock-grid",children:f.length>0?f.map(m=>r(la,{entry:m,currentHash:m.current_hash,onApprove:h,busy:s===R(m)},R(m))):r("div",{className:"empty-card",children:e("dashboard.human-lock.empty")})})]})}function R(t){return`${t.file}:${t.start_line}:${t.end_line}`}function va({lastEvent:t}){const{t:e}=x(),[a,i]=N([]),[n,o]=N("all"),[s,d]=N(null),u=async()=>{try{i((await ft()).sort((h,m)=>m.ts-h.ts)),d(null)}catch(h){d(h instanceof Error?h.message:String(h))}};C(()=>{u()},[]),C(()=>{t?.type==="ledger:appended"&&i(h=>[t.payload,...h].sort((m,y)=>y.ts-m.ts))},[t]);const c=L(()=>a.filter(h=>n==="all"||h.source===n),[a,n]),p=a.filter(h=>h.source==="ai").length,l=a.length-p,f=async(h,m)=>{if(h.id===void 0)throw new Error(e("dashboard.intent-timeline.annotate.missing-id"));const y=await Xt({ledger_entry_id:h.id,annotation:m});y.created&&i(v=>[y.entry,...v].sort((_,b)=>b.ts-_.ts))};return r("section",{className:"view",children:[r(W,{title:e("dashboard.intent-timeline.title"),subtitle:e("dashboard.intent-timeline.subtitle")}),s!==null?r("div",{className:"empty-card",children:s}):null,r("div",{className:"filter-bar",children:[r("span",{className:"filter-label",children:e("dashboard.intent-timeline.filter.label")}),r("button",{className:`filter-chip ${n==="all"?"active":""}`,type:"button",onClick:()=>o("all"),children:[e("dashboard.intent-timeline.filter.all")," ",a.length]}),r(Te,{source:"ai",interactive:!0,selected:n==="ai",onClick:()=>o("ai")}),r(Te,{source:"human",interactive:!0,selected:n==="human",onClick:()=>o("human")}),r("span",{className:"filter-date",children:e("dashboard.intent-timeline.summary",{aiCount:String(p),humanCount:String(l)})})]}),r("div",{className:"col-headers",children:[r("div",{className:"col-head ai",children:[r("strong",{children:e("dashboard.intent-timeline.columns.ai.title")}),r("span",{children:e("dashboard.intent-timeline.columns.ai.entries",{count:String(p)})})]}),r("div",{className:"col-head human",children:[r("strong",{children:e("dashboard.intent-timeline.columns.human.title")}),r("span",{children:e("dashboard.intent-timeline.columns.human.entries",{count:String(l)})})]})]}),r("div",{className:"timeline-grid",children:[r("div",{className:"axis",children:r("div",{className:"axis-line"})}),c.length>0?c.map(h=>r(Nt,{entry:h,onAnnotate:f},h.id??`${h.source}:${h.ts}:${h.intent}`)):r("div",{className:"empty-card timeline-empty",children:e("dashboard.intent-timeline.empty")})]})]})}function ya(){return r(na,{children:r(ga,{})})}function ga(){const{t}=x(),[e,a]=N(Ke()),i=Qt(),n=[{id:"rules",hash:"#/rules",label:t("dashboard.app.nav.rules.label-bilingual"),subtitle:t("dashboard.app.nav.rules.subtitle"),breadcrumb:t("dashboard.app.breadcrumb.rules")},{id:"locks",hash:"#/locks",label:t("dashboard.app.nav.locks.label-bilingual"),subtitle:t("dashboard.app.nav.locks.subtitle"),breadcrumb:t("dashboard.app.breadcrumb.locks")},{id:"timeline",hash:"#/timeline",label:t("dashboard.app.nav.timeline.label-bilingual"),subtitle:t("dashboard.app.nav.timeline.subtitle"),breadcrumb:t("dashboard.app.breadcrumb.timeline")},{id:"history",hash:"#/history",label:t("dashboard.app.nav.history.label-bilingual"),subtitle:t("dashboard.app.nav.history.subtitle"),breadcrumb:t("dashboard.app.breadcrumb.history")},{id:"doctor",hash:"#/doctor",label:t("dashboard.app.nav.doctor.label-bilingual"),subtitle:t("dashboard.app.nav.doctor.subtitle"),breadcrumb:t("dashboard.app.breadcrumb.doctor")}];C(()=>{const s=()=>a(Ke());return window.addEventListener("hashchange",s),window.location.hash===""&&(window.location.hash="#/rules"),()=>window.removeEventListener("hashchange",s)},[]);const o=L(()=>n.find(s=>s.id===e)??n[0],[e]);return r(ka,{connected:i.connected,port:ze(),activeRoute:o.id,children:[r("aside",{className:"sidebar",children:[r("div",{className:"brand",children:[r("span",{className:"brand-logo",children:"F"}),r("span",{children:"fabric"}),r("span",{className:"brand-version",children:"v1.0.0"})]}),r("nav",{"aria-label":t("dashboard.app.nav.aria-label"),children:n.map(s=>r("a",{className:`nav-item ${s.id===e?"active":""}`,href:s.hash,"aria-current":s.id===e?"page":void 0,children:[r("span",{className:"dot","aria-hidden":"true"}),r("span",{children:s.label}),r("small",{children:s.subtitle})]},s.id))}),r("div",{className:"nav-section",children:t("dashboard.app.nav.section.diagnostics")}),r("span",{className:"nav-item muted-nav",children:[r("span",{className:"dot"}),t("dashboard.app.nav.drift-check")]})]}),r("main",{className:"main",children:[r("header",{className:"header",children:[r("div",{className:"breadcrumb",children:[r("span",{children:window.location.pathname==="/"?"~":window.location.pathname}),r("span",{className:"sep",children:"/"}),r("strong",{children:o.breadcrumb})]}),r("div",{className:"header-actions",children:[r("span",{className:`badge-live ${i.connected?"connected":"disconnected"}`,children:[r("span",{className:"pulse","aria-hidden":"true"}),i.connected?t("dashboard.app.header.connected"):t("dashboard.app.header.connecting")]}),r("span",{className:"port-label",children:[":",ze()," /events"]})]})]}),e==="rules"?r(ua,{lastEvent:i.lastEvent}):null,e==="locks"?r(_a,{lastEvent:i.lastEvent}):null,e==="timeline"?r(va,{lastEvent:i.lastEvent}):null,e==="history"?r(fa,{lastEvent:i.lastEvent}):null,e==="doctor"?r(pa,{lastEvent:i.lastEvent}):null]}),r("div",{className:"live-region","aria-live":"polite","aria-atomic":"true",children:i.lastEvent===null?"":t("dashboard.app.live-region.received",{type:i.lastEvent.type})})]})}function ka({connected:t,port:e,activeRoute:a,children:i}){return r("div",{className:`app-shell ${t?"is-connected":"is-disconnected"}`,"data-port":e,"data-route":a,children:i})}function Ke(){switch(window.location.hash){case"#/locks":return"locks";case"#/timeline":return"timeline";case"#/history":return"history";case"#/doctor":return"doctor";default:return"rules"}}function ze(){const t=Number.parseInt(window.location.port,10);return Number.isFinite(t)?t:7373}const Et=document.getElementById("app");if(Et===null)throw new Error("Fabric Dashboard root element #app was not found.");Pt(r(ya,{}),Et);
|