@zq-silk/yui 2.2.0 → 2.3.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/README.md +4 -2
- package/dist/cli/commandCatalog.js +8 -3
- package/dist/cli/interactionPolicy.js +4 -0
- package/dist/commands/taskCommands.js +5 -7
- package/dist/commands/taskIntegrationCommands.js +5 -16
- package/dist/controlPlaneCli.js +28 -21
- package/dist/controller/clientRuntime.js +3 -2
- package/dist/integration/gitIntegrationService.js +8 -67
- package/dist/job/jobCleanupInspection.js +67 -0
- package/dist/repository/gitWorkspace.js +41 -12
- package/dist/repository/taskWorkspaceCoordinator.js +72 -145
- package/dist/repository/taskWorkspacePreparer.js +39 -43
- package/dist/repository/workspaceCleanupInspection.js +88 -7
- package/dist/resources/resourceRegistrar.js +16 -10
- package/dist/runtime/integrationRuntimeIsolation.js +21 -0
- package/dist/runtime/taskRuntimeIsolation.js +91 -21
- package/dist/task/archiveDiagnostics.js +26 -8
- package/dist/task/archivePreflight.js +26 -9
- package/dist/task/leaderArchive.js +9 -15
- package/dist/web/assets/client/api.js +8 -0
- package/dist/web/assets/client/app.js +10 -6
- package/dist/web/assets/client/components.js +95 -36
- package/dist/web/assets/client/detail.js +110 -64
- package/dist/web/assets/client/dock.js +95 -11
- package/dist/web/assets/client/evidence.js +286 -94
- package/dist/web/assets/client/i18n.js +178 -62
- package/dist/web/assets/client/overview.js +9 -13
- package/dist/web/assets/client/records.js +142 -7
- package/dist/web/assets/client/sections.js +234 -198
- package/dist/web/assets/icons.js +4 -0
- package/dist/web/assets/styles/components.js +64 -17
- package/dist/web/assets/styles/responsive.js +7 -5
- package/dist/web/assets/styles/tokens.js +1 -1
- package/dist/web/assets/styles/views.js +48 -31
- package/dist/web/webServer.js +12 -1
- package/dist/web/webTaskSurface.js +8 -1
- package/docs/observability/README.md +13 -3
- package/docs/observability/README.zh-CN.md +10 -3
- package/docs/release-workflow.md +25 -0
- package/docs/release-workflow.zh-CN.md +19 -0
- package/docs/task-delivery.md +36 -8
- package/docs/task-delivery.zh-CN.md +24 -7
- package/i18n/README.zh-CN.md +3 -2
- package/package.json +1 -1
- package/skills/yui-leader/references/execution.md +2 -1
- package/skills/yui-leader/references/integration.md +20 -0
- package/skills/yui-operator/SKILL.md +4 -0
- package/skills/yui-reviewer/SKILL.md +3 -0
- package/skills/yui-runtime/SKILL.md +4 -0
- package/skills/yui-runtime/references/publication.md +20 -4
- package/skills/yui-worker/SKILL.md +3 -0
|
@@ -2,7 +2,7 @@ export const RECORDS_SCRIPT = String.raw `
|
|
|
2
2
|
// Context record access. Every business fact keeps its Context reference; an
|
|
3
3
|
// expanded value is a current read, never a mutation of the snapshot.
|
|
4
4
|
import { h, icon } from "/assets/js/dom.js";
|
|
5
|
-
import { richText, mono, button, note } from "/assets/js/components.js";
|
|
5
|
+
import { richText, mono, button, note, disclosure } from "/assets/js/components.js";
|
|
6
6
|
|
|
7
7
|
export function entriesOf(core, store) {
|
|
8
8
|
return core.records.filter(function (entry) { return entry.ref.store === store; });
|
|
@@ -12,6 +12,127 @@ export function valuesOf(core, store) {
|
|
|
12
12
|
return entriesOf(core, store).filter(function (entry) { return !entry.omitted; }).map(function (entry) { return entry.value; });
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
// The family total from the same bounded read as its samples. The current
|
|
16
|
+
// view counts current records only: open work, active runs, open questions.
|
|
17
|
+
export function totalOf(core, store) {
|
|
18
|
+
const row = (core.collections || []).find(function (item) { return item.store === store; });
|
|
19
|
+
return row ? row.total : entriesOf(core, store).length;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// List and omitted-value summaries join known fields in a fixed order
|
|
23
|
+
// ("title: …; status: …"). Split them for display only; the exact record
|
|
24
|
+
// stays one read away.
|
|
25
|
+
const SUMMARY_KEYS = ["title", "objective", "question", "summary", "body", "status", "type"];
|
|
26
|
+
export function summaryFields(summary) {
|
|
27
|
+
const fields = {};
|
|
28
|
+
if (!summary) return fields;
|
|
29
|
+
const pattern = new RegExp("(?:^|; )(" + SUMMARY_KEYS.join("|") + "): ", "g");
|
|
30
|
+
const marks = [];
|
|
31
|
+
let match;
|
|
32
|
+
while ((match = pattern.exec(summary))) {
|
|
33
|
+
const rank = SUMMARY_KEYS.indexOf(match[1]);
|
|
34
|
+
if (marks.length && rank <= marks[marks.length - 1].rank) continue;
|
|
35
|
+
marks.push({ key: match[1], rank: rank, start: match.index, from: match.index + match[0].length });
|
|
36
|
+
}
|
|
37
|
+
marks.forEach(function (mark, index) {
|
|
38
|
+
fields[mark.key] = summary.slice(mark.from, index + 1 < marks.length ? marks[index + 1].start : summary.length);
|
|
39
|
+
});
|
|
40
|
+
return fields;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// --- Exact reads -------------------------------------------------------------
|
|
44
|
+
// One inspect per reference digest, held in view state so a refresh with an
|
|
45
|
+
// unchanged reference never reads again. A changed digest is a new read.
|
|
46
|
+
export function readExact(entry, taskId, actions, cache) {
|
|
47
|
+
const key = entry.ref.store + "/" + entry.ref.refId;
|
|
48
|
+
const hit = cache[key];
|
|
49
|
+
if (hit && hit.digest === entry.ref.digest) return hit.promise;
|
|
50
|
+
const promise = actions.inspect(taskId, entry.ref);
|
|
51
|
+
const slot = { digest: entry.ref.digest, promise: promise, result: null };
|
|
52
|
+
cache[key] = slot;
|
|
53
|
+
promise.then(function (result) { slot.result = result; }, function () { if (cache[key] === slot) delete cache[key]; });
|
|
54
|
+
return promise;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// A row drawn from its exact value: synchronously when cached, otherwise the
|
|
58
|
+
// honest summary card until the read returns and replaces it in place.
|
|
59
|
+
export function exactRow(entry, taskId, t, actions, cache, render) {
|
|
60
|
+
if (!entry.omitted) return render(entry.value, null);
|
|
61
|
+
const hit = cache[entry.ref.store + "/" + entry.ref.refId];
|
|
62
|
+
if (hit && hit.digest === entry.ref.digest && hit.result) return render(hit.result.value, hit.result);
|
|
63
|
+
const placeholder = recordCard(entry, taskId, t, actions);
|
|
64
|
+
placeholder.dataset.reading = "true";
|
|
65
|
+
readExact(entry, taskId, actions, cache).then(function (result) {
|
|
66
|
+
if (placeholder.isConnected) placeholder.replaceWith(render(result.value, result));
|
|
67
|
+
}, function () { placeholder.dataset.reading = "false"; });
|
|
68
|
+
return placeholder;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// A closed row drawn from a list summary; its exact value is read on first
|
|
72
|
+
// open. Open rows are remembered in view state and reopen after a redraw.
|
|
73
|
+
export function lazyRow(item, taskId, t, actions, options) {
|
|
74
|
+
const opts = options || {};
|
|
75
|
+
const key = item.ref.store + ":" + item.ref.refId;
|
|
76
|
+
const element = h("details.lazy-row");
|
|
77
|
+
if (item.status) element.dataset.status = item.status;
|
|
78
|
+
const body = h("div.lazy-body");
|
|
79
|
+
element.append(h("summary.lazy-head", null, icon("chevron", "disclosure-chevron"), opts.head), body);
|
|
80
|
+
let state = "idle";
|
|
81
|
+
function load() {
|
|
82
|
+
if (state !== "idle") return;
|
|
83
|
+
state = "reading";
|
|
84
|
+
element.dataset.reading = "true";
|
|
85
|
+
body.replaceChildren(h("p.faint.small", null, t("record.reading")));
|
|
86
|
+
readExact({ ref: item.ref }, taskId, actions, opts.cache || {}).then(function (result) {
|
|
87
|
+
state = "done";
|
|
88
|
+
const raw = disclosure(t("record.raw"), null);
|
|
89
|
+
raw.body.append(h("pre.code-block", null, JSON.stringify(result.value, null, 2)));
|
|
90
|
+
body.replaceChildren();
|
|
91
|
+
body.append(h("div.lazy-content", null, opts.render ? opts.render(result.value, result) : null), raw);
|
|
92
|
+
}, function (error) {
|
|
93
|
+
state = "idle";
|
|
94
|
+
body.replaceChildren(note(t("record.changed") + " · " + error.message, "bad"));
|
|
95
|
+
}).then(function () { element.dataset.reading = "false"; });
|
|
96
|
+
}
|
|
97
|
+
element.addEventListener("toggle", function () {
|
|
98
|
+
if (opts.openRows) { if (element.open) opts.openRows[key] = true; else delete opts.openRows[key]; }
|
|
99
|
+
if (element.open) load();
|
|
100
|
+
});
|
|
101
|
+
if (opts.openRows && opts.openRows[key]) element.open = true;
|
|
102
|
+
return element;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// --- Paged family discovery --------------------------------------------------
|
|
106
|
+
// Pages of one Context family for the current Context cursor. A continuation
|
|
107
|
+
// never mixes versions: after the cursor changes, the first page is re-read.
|
|
108
|
+
export function familyState(view, store) {
|
|
109
|
+
view.families = view.families || {};
|
|
110
|
+
if (!view.families[store]) view.families[store] = { items: [], total: null, nextCursor: null, pages: 0, key: null, error: null, pending: null };
|
|
111
|
+
return view.families[store];
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function loadFamily(view, taskId, store, key, actions, options) {
|
|
115
|
+
const state = familyState(view, store);
|
|
116
|
+
const more = !!(options && options.more);
|
|
117
|
+
if (state.pending) return state.pending;
|
|
118
|
+
if (more ? !state.nextCursor : state.key === key && state.pages && !state.error) return Promise.resolve(state);
|
|
119
|
+
state.pending = actions.list(taskId, store, { limit: (options && options.limit) || 40, cursor: more ? state.nextCursor : null })
|
|
120
|
+
.then(function (page) {
|
|
121
|
+
if (!more) { state.items = []; state.pages = 0; }
|
|
122
|
+
state.items = state.items.concat(page.items);
|
|
123
|
+
state.total = page.total;
|
|
124
|
+
state.nextCursor = page.nextCursor;
|
|
125
|
+
state.pages += 1;
|
|
126
|
+
state.key = more ? state.key : key;
|
|
127
|
+
state.error = null;
|
|
128
|
+
state.errorKey = null;
|
|
129
|
+
return state;
|
|
130
|
+
}, function (error) { state.error = error.message; state.errorKey = more ? state.key : key; return state; })
|
|
131
|
+
.then(function (result) { state.pending = null; return result; });
|
|
132
|
+
return state.pending;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// --- Cards ---------------------------------------------------------------------
|
|
15
136
|
// A generic, honest card for any record: omitted values say so and can be
|
|
16
137
|
// read by reference; reading never acknowledges or accepts anything.
|
|
17
138
|
export function recordCard(entry, taskId, t, actions, options) {
|
|
@@ -31,7 +152,12 @@ export function recordCard(entry, taskId, t, actions, options) {
|
|
|
31
152
|
if (facts.length) element.append(h("p.faint.small", null, facts.join(" · ")));
|
|
32
153
|
if (entry.ref.store === "job") element.append(note(t("job." + value.status + ".note", t("job.terminal.note")), value.status === "unknown-needs-attention" ? "warn" : ""));
|
|
33
154
|
} else {
|
|
34
|
-
|
|
155
|
+
const fields = summaryFields(entry.summary);
|
|
156
|
+
const lead = fields.title || fields.question || fields.objective;
|
|
157
|
+
if (lead) element.append(h("p.record-lead", null, lead));
|
|
158
|
+
const text = fields.summary || fields.body || (lead === fields.objective ? null : fields.objective);
|
|
159
|
+
if (text) element.append(h("p.faint", null, text));
|
|
160
|
+
if (!lead && !text) element.append(h("p.faint", null, entry.summary || t("record.omitted")));
|
|
35
161
|
}
|
|
36
162
|
element.append(recordReader(entry, taskId, t, actions));
|
|
37
163
|
return element;
|
|
@@ -39,7 +165,9 @@ export function recordCard(entry, taskId, t, actions, options) {
|
|
|
39
165
|
|
|
40
166
|
// Shared source access for cards, history and discussion, including records
|
|
41
167
|
// whose compact value is present but does not display every durable field.
|
|
42
|
-
|
|
168
|
+
// With a renderer, the exact value is drawn richly and the raw record stays
|
|
169
|
+
// available behind a disclosure.
|
|
170
|
+
export function recordReader(entry, taskId, t, actions, render) {
|
|
43
171
|
const element = h("div.stack");
|
|
44
172
|
const expand = button(t("record.read"), { icon: "eye", variant: "link" });
|
|
45
173
|
expand.addEventListener("click", async function () {
|
|
@@ -47,10 +175,17 @@ export function recordReader(entry, taskId, t, actions) {
|
|
|
47
175
|
element.dataset.reading = "true";
|
|
48
176
|
try {
|
|
49
177
|
const result = await actions.inspect(taskId, entry.ref);
|
|
50
|
-
|
|
51
|
-
if (
|
|
52
|
-
|
|
53
|
-
|
|
178
|
+
const rich = render ? render(result.value, result) : null;
|
|
179
|
+
if (rich) {
|
|
180
|
+
const raw = disclosure(t("record.raw"), null);
|
|
181
|
+
raw.body.append(h("pre.code-block", null, JSON.stringify(result.value, null, 2)));
|
|
182
|
+
element.append(rich, raw);
|
|
183
|
+
} else {
|
|
184
|
+
if (result.result && result.result.output) element.append(richText(t("record.output"), result.result.output, t));
|
|
185
|
+
if (result.result && result.result.diagnostic) element.append(richText(t("record.diagnostic"), result.result.diagnostic, t));
|
|
186
|
+
element.append(h("pre.code-block", null, JSON.stringify(result.value, null, 2)));
|
|
187
|
+
if (result.execution) element.append(h("pre.code-block", null, JSON.stringify(result.execution, null, 2)));
|
|
188
|
+
}
|
|
54
189
|
expand.remove();
|
|
55
190
|
} catch {
|
|
56
191
|
expand.disabled = false;
|