@lmzhen/dsh-evolution-core 0.26.15 → 0.26.26
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/lib/index.js +759 -38
- package/lib/types/curator.d.ts +2 -0
- package/lib/types/index.d.ts +6 -0
- package/lib/types/package-identity.d.ts +14 -0
- package/lib/types/preset-composition.d.ts +1 -1
- package/lib/types/probe.d.ts +9 -3
- package/lib/types/reachability.d.ts +46 -0
- package/lib/types/skill-store.d.ts +34 -3
- package/lib/types/store-ledger.d.ts +44 -0
- package/lib/types/tree-write.d.ts +53 -0
- package/lib/types/write-authority.d.ts +87 -0
- package/lib/types/write-gates.d.ts +111 -0
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { parse } from "yaml";
|
|
2
|
-
import { basename, dirname, join, resolve } from "node:path";
|
|
3
1
|
import { copyFileSync, existsSync, readFileSync, readdirSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { parse } from "yaml";
|
|
4
5
|
import { cp, lstat, mkdir, open, readFile, readdir, rename, rm, stat } from "node:fs/promises";
|
|
5
6
|
import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
6
7
|
import { homedir } from "node:os";
|
|
7
|
-
import { fileURLToPath } from "node:url";
|
|
8
8
|
import { scopeOf } from "@deepseek-ai/dsh-scope";
|
|
9
9
|
import { z } from "zod";
|
|
10
10
|
//#region lib/types/citations.js
|
|
@@ -204,6 +204,357 @@ function scanBodyHooks(content) {
|
|
|
204
204
|
};
|
|
205
205
|
}
|
|
206
206
|
//#endregion
|
|
207
|
+
//#region lib/types/tree-write.js
|
|
208
|
+
/**
|
|
209
|
+
* G1/1.5 (S7-09): the TYPED critical section around a tree write.
|
|
210
|
+
*
|
|
211
|
+
* The control-plane lock used to wrap a whole pass, LLM call and all: an operator undo/restore waited up to
|
|
212
|
+
* one `curatorReviewTimeoutMs` (~120s) for a review that was merely thinking. The fix is to give the critical
|
|
213
|
+
* section a shape that a review cannot be squeezed into.
|
|
214
|
+
*
|
|
215
|
+
* WHAT THIS TYPE CAN AND CANNOT DO (the plan wording says "cannot be put inside the lock by TYPE" - that is
|
|
216
|
+
* only half true and the half that is false is the half people rely on): a callback is a CLOSURE, so even
|
|
217
|
+
* with `view` as its only parameter it can still reach `this.io` / `this.ctx` / `this.llm` from the enclosing
|
|
218
|
+
* scope. TypeScript cannot stop that, and a criterion claiming it would never go red.
|
|
219
|
+
*
|
|
220
|
+
* What the type DOES give: new code has no other entry - the callback is handed a `SnapshotView` and nothing
|
|
221
|
+
* else, so a phase that needs `io` or `llm` has to stay OUTSIDE and be passed its result in. What the type
|
|
222
|
+
* CANNOT give is covered by the companion source guard (see the family gates): an `io` / `llm` / `this.`
|
|
223
|
+
* / `ctx.` reference inside a `withTreeWrite` callback is a violation, and that guard is the executable form
|
|
224
|
+
* of "cannot be put inside the lock".
|
|
225
|
+
*
|
|
226
|
+
* @module @lmzhen/dsh-evolution-core/tree-write
|
|
227
|
+
*/
|
|
228
|
+
/**
|
|
229
|
+
* Run one tree-writing section under a caller-owned serial queue, exposing ONLY a {@link SnapshotView}.
|
|
230
|
+
*
|
|
231
|
+
* The queue is passed in rather than owned here: the lock belongs to whoever serializes the control plane
|
|
232
|
+
* (the curator), and a second lock would be a second answer to one question.
|
|
233
|
+
* @param acquire - the caller serial queue (e.g. the curator mutex), returning its release.
|
|
234
|
+
* @param view - what this section sees while it holds the lock.
|
|
235
|
+
* @param fn - the section. It may only use the view.
|
|
236
|
+
* @returns whatever the section returns.
|
|
237
|
+
*/
|
|
238
|
+
async function withTreeWrite(acquire, view, fn) {
|
|
239
|
+
const release = await acquire();
|
|
240
|
+
try {
|
|
241
|
+
return await fn(view);
|
|
242
|
+
} finally {
|
|
243
|
+
release();
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
//#endregion
|
|
247
|
+
//#region lib/types/package-identity.js
|
|
248
|
+
/**
|
|
249
|
+
* G1/1.8 (G-04): the SCOPE this build was published under, DERIVED from a manifest instead of written as a
|
|
250
|
+
* literal in running code.
|
|
251
|
+
*
|
|
252
|
+
* The family used to hard-code `@deepseek-ai/dsh-...` names and let `prepare-release.mjs --scope @lmzhen`
|
|
253
|
+
* patch the text afterwards. A published install therefore depended on a release-time string rewrite
|
|
254
|
+
* reaching every copy, and the copies had already drifted (doctor.ts, index.ts, preset-composition.ts and
|
|
255
|
+
* its .mjs mirror each spelled the identity). The scope is knowable at runtime: it is the scope segment of
|
|
256
|
+
* the nearest `package.json` above the calling module. Nothing to rewrite, one owner of the answer.
|
|
257
|
+
*
|
|
258
|
+
* @module @lmzhen/dsh-evolution-core/package-identity
|
|
259
|
+
*/
|
|
260
|
+
/**
|
|
261
|
+
* The scope segment of the nearest `package.json` at or above `from`.
|
|
262
|
+
* @param from - the calling module URL (its own manifest is the answer).
|
|
263
|
+
* @returns the scope, e.g. `@deepseek-ai` or `@lmzhen`; an unscoped manifest yields an empty string.
|
|
264
|
+
*/
|
|
265
|
+
function scopeOfNearestManifest(from) {
|
|
266
|
+
let dir = dirname(from instanceof URL ? fileURLToPath(from) : fileURLToPath(new URL(from)));
|
|
267
|
+
for (let hops = 0; hops < 32; hops += 1) {
|
|
268
|
+
const manifest = join(dir, "package.json");
|
|
269
|
+
if (existsSync(manifest)) {
|
|
270
|
+
const parsed = JSON.parse(readFileSync(manifest, "utf8"));
|
|
271
|
+
const name = typeof parsed.name === "string" ? parsed.name : "";
|
|
272
|
+
return name.startsWith("@") ? name.split("/")[0] ?? "" : "";
|
|
273
|
+
}
|
|
274
|
+
const parent = dirname(dir);
|
|
275
|
+
if (parent === dir) break;
|
|
276
|
+
dir = parent;
|
|
277
|
+
}
|
|
278
|
+
return "";
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* One family/platform package name under the RUNNING scope.
|
|
282
|
+
* @param bareName - the name without any scope, e.g. `dsh-agent-preset`.
|
|
283
|
+
* @param from - the calling module URL.
|
|
284
|
+
* @returns `scope/bareName`, or `bareName` when the manifest carries no scope.
|
|
285
|
+
*/
|
|
286
|
+
function scopedPackageName(bareName, from) {
|
|
287
|
+
const scope = scopeOfNearestManifest(from);
|
|
288
|
+
return scope === "" ? bareName : scope + "/" + bareName;
|
|
289
|
+
}
|
|
290
|
+
//#endregion
|
|
291
|
+
//#region lib/types/write-authority.js
|
|
292
|
+
/** The mode a deployment that configures nothing gets. */
|
|
293
|
+
const DEFAULT_WRITE_CONFIRM_MODE = "auto";
|
|
294
|
+
/** Seconds a timeout-mode prompt waits before the write is cancelled. */
|
|
295
|
+
const DEFAULT_WRITE_CONFIRM_TIMEOUT_SECONDS = 120;
|
|
296
|
+
/**
|
|
297
|
+
* The batch-one migration aid: every call site becomes ONE of these instead of hand-building the
|
|
298
|
+
* object - so the shape cannot drift between callers, and each site still has to say its own
|
|
299
|
+
* origin out loud (origin is required here on purpose: the whole point is that no caller inherits
|
|
300
|
+
* a default identity).
|
|
301
|
+
*/
|
|
302
|
+
function authorityFrom(input) {
|
|
303
|
+
return {
|
|
304
|
+
origin: input.origin,
|
|
305
|
+
threatExemptLabels: input.threatExemptLabels ?? [],
|
|
306
|
+
protectedNames: input.protectedNames,
|
|
307
|
+
readNames: input.readNames,
|
|
308
|
+
...input.confirm === void 0 ? {} : { confirm: input.confirm },
|
|
309
|
+
...input.confirmMode === void 0 ? {} : { confirmMode: input.confirmMode },
|
|
310
|
+
...input.confirmTimeoutSeconds === void 0 ? {} : { confirmTimeoutSeconds: input.confirmTimeoutSeconds },
|
|
311
|
+
warn: input.warn ?? (() => {})
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
//#endregion
|
|
315
|
+
//#region lib/types/write-gates.js
|
|
316
|
+
/**
|
|
317
|
+
* The write-admission sequence: ONE ordered table of the reasons a skill write is refused.
|
|
318
|
+
*
|
|
319
|
+
* Two points read this table (design `dsh-evolution-write-gate-design.md` §3). The ADMISSION
|
|
320
|
+
* point (`execute`, BEFORE the approval seam) runs every gate that applies to `'admission'`, so a
|
|
321
|
+
* write that is refused is never staged and never spends the operator's attention twice. The
|
|
322
|
+
* EXECUTION point (the `executeCore` funnel, reached by the direct path and by the approval
|
|
323
|
+
* replay) runs the gates that apply to `'execution'`: the stored plan of a replayed write passed
|
|
324
|
+
* no schema, and the protected list can change while a record sits pending, so those verdicts are
|
|
325
|
+
* re-decided at the bytes.
|
|
326
|
+
*
|
|
327
|
+
* Order is part of the contract: a gate that can only refuse comes before one that needs a round
|
|
328
|
+
* trip with the operator, so a write that is refused anyway never asks anything.
|
|
329
|
+
*
|
|
330
|
+
* A gate decides whether a write may be ATTEMPTED. The library decides whether it can be
|
|
331
|
+
* PERFORMED — its own structured refusals (a restructure element that is not an object, a patch
|
|
332
|
+
* anchor that no longer matches, an `absorbed_into` that does not exist) stay where the bytes are
|
|
333
|
+
* read.
|
|
334
|
+
*
|
|
335
|
+
* Rule bodies live in `evolution-core` (the read-before-write rule in `skill-reads`, the
|
|
336
|
+
* required-argument table in `SKILL_ACTION_REQUIRED_FIELDS`); this module owns the ORDER and the
|
|
337
|
+
* applicability of each gate, which is an execution-point fact of this tool.
|
|
338
|
+
* @module @lmzhen/dsh-evolution-core/write-gates
|
|
339
|
+
*/
|
|
340
|
+
/** The confirm question's stable id — one question per write, so an answer to an earlier prompt
|
|
341
|
+
* can never be read as the answer to a later one. */
|
|
342
|
+
const CONFIRM_QUESTION_ID = "evolution-skill-write";
|
|
343
|
+
/** The cancel label every confirm question offers. */
|
|
344
|
+
const CANCEL_LABEL = "取消";
|
|
345
|
+
/** What a `timeout`-mode deadline settles with: comparable by identity against the seam's
|
|
346
|
+
* boolean, so the two outcomes stay distinguishable without a mutable flag (which a linter
|
|
347
|
+
* cannot follow through a timer callback, and a reader cannot either). */
|
|
348
|
+
const CONFIRM_TIMED_OUT = "confirm-timed-out";
|
|
349
|
+
/**
|
|
350
|
+
* How the ONE confirmation behaves (registry `skillWriteConfirm`).
|
|
351
|
+
*
|
|
352
|
+
* `auto` writes without asking — the default, because an unattended run (a background pass, a
|
|
353
|
+
* scheduled review, a headless session) must not park a tool call on a question nobody will answer.
|
|
354
|
+
* `ask` waits for as long as it takes, which is the deployment that wants the gate in the loop.
|
|
355
|
+
* `timeout` asks and cancels the write on its own deadline.
|
|
356
|
+
*/
|
|
357
|
+
/** A usable deadline: the configured value when it is a positive finite number, else the default. */
|
|
358
|
+
function timeoutSecondsOf(configured) {
|
|
359
|
+
return configured !== void 0 && Number.isFinite(configured) && configured >= 1 ? Math.floor(configured) : 120;
|
|
360
|
+
}
|
|
361
|
+
/** The scalar fields the tool schema types as strings; the replay channel has no schema.
|
|
362
|
+
* `action` is one of them: a non-string action used to fall through to the library as "Unknown
|
|
363
|
+
* action" while the read gate re-defaulted it to `patch` and refused with E-318 (review
|
|
364
|
+
* 2026-09-26, P2), so the shape gate refuses it by name instead. */
|
|
365
|
+
const SCALAR_ARG_FIELDS = [
|
|
366
|
+
"action",
|
|
367
|
+
"name",
|
|
368
|
+
"content",
|
|
369
|
+
"old_string",
|
|
370
|
+
"new_string",
|
|
371
|
+
"file_path",
|
|
372
|
+
"file_content",
|
|
373
|
+
"absorbed_into"
|
|
374
|
+
];
|
|
375
|
+
/** The scalar fields the tool schema types as BOOLEANS; the replay channel has no schema either.
|
|
376
|
+
* T2-V3/A28: `args.replace_all === true` answered "false" for anything else, so a staged
|
|
377
|
+
* `replace_all: 'yes'` silently patched only the FIRST occurrence — a wrong count with no signal.
|
|
378
|
+
* The plan channel already refuses a non-boolean `replace_all` by name (S1-C1); this is the same
|
|
379
|
+
* rule on the replay channel, so the two channels cannot disagree about one flag. */
|
|
380
|
+
const FLAG_ARG_FIELDS = ["replace_all"];
|
|
381
|
+
/**
|
|
382
|
+
* Assemble a gate context from a caller's services. The protected list is read HERE, so no caller can
|
|
383
|
+
* forget it or read it from a second place.
|
|
384
|
+
* @param services - the four required services plus the optional registry knobs.
|
|
385
|
+
* @param request - the point asking, the arguments under test, and the write origin.
|
|
386
|
+
* @returns a context the shared sequence accepts.
|
|
387
|
+
*/
|
|
388
|
+
function skillWriteGateContext(services, request) {
|
|
389
|
+
return {
|
|
390
|
+
point: request.point,
|
|
391
|
+
args: request.args,
|
|
392
|
+
origin: request.origin,
|
|
393
|
+
protectedNames: protectedSkillNamesOf(services.policy),
|
|
394
|
+
readNames: services.readNames,
|
|
395
|
+
confirm: services.confirm,
|
|
396
|
+
...services.confirmMode === void 0 ? {} : { confirmMode: services.confirmMode },
|
|
397
|
+
...services.confirmTimeoutSeconds === void 0 ? {} : { confirmTimeoutSeconds: services.confirmTimeoutSeconds },
|
|
398
|
+
...services.describeTarget === void 0 ? {} : { describeTarget: services.describeTarget },
|
|
399
|
+
warn: services.warn
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
function protectedSkillNamesOf(policy) {
|
|
403
|
+
return (policy?.get?.())?.protectedSkillNames;
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Narrow the arguments once for every gate.
|
|
407
|
+
*
|
|
408
|
+
* The admission point reaches the gates AFTER the schema, the replay channel BEFORE any
|
|
409
|
+
* validation, so a gate reads only what it can prove: anything else counts as absent, exactly as
|
|
410
|
+
* the missing-argument check already treated a non-string action.
|
|
411
|
+
* @param args - the arguments as the caller sent them.
|
|
412
|
+
* @returns the narrowed view.
|
|
413
|
+
*/
|
|
414
|
+
function gateArgsOf(args) {
|
|
415
|
+
const scalars = typeof args === "object" && args !== null ? args : {};
|
|
416
|
+
const action = scalars.action;
|
|
417
|
+
const name = scalars.name;
|
|
418
|
+
const absorbedInto = scalars.absorbed_into;
|
|
419
|
+
return {
|
|
420
|
+
action: typeof action === "string" ? action : void 0,
|
|
421
|
+
name: typeof name === "string" ? name : "",
|
|
422
|
+
absorbedInto: typeof absorbedInto === "string" && absorbedInto.trim() !== "" ? absorbedInto : void 0,
|
|
423
|
+
scalars
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
/** The sequence, in order. A gate whose `appliesTo` omits the asking point is skipped. */
|
|
427
|
+
const GATES = [
|
|
428
|
+
{
|
|
429
|
+
id: "argument-shape",
|
|
430
|
+
appliesTo: ["admission", "execution"],
|
|
431
|
+
run: ({ view }) => {
|
|
432
|
+
for (const field of SCALAR_ARG_FIELDS) {
|
|
433
|
+
const value = view.scalars[field];
|
|
434
|
+
if (value === void 0 || value === null || typeof value === "string") continue;
|
|
435
|
+
return `skill_manage: "${field}" must be a string (got ${typeof value}); refusing the write.`;
|
|
436
|
+
}
|
|
437
|
+
for (const field of FLAG_ARG_FIELDS) {
|
|
438
|
+
const value = view.scalars[field];
|
|
439
|
+
if (value === void 0 || value === null || typeof value === "boolean") continue;
|
|
440
|
+
return `skill_manage: "${field}" must be a boolean (got ${typeof value}); refusing the write.`;
|
|
441
|
+
}
|
|
442
|
+
return null;
|
|
443
|
+
}
|
|
444
|
+
},
|
|
445
|
+
{
|
|
446
|
+
id: "missing-args",
|
|
447
|
+
appliesTo: ["admission", "execution"],
|
|
448
|
+
run: ({ view }) => {
|
|
449
|
+
const action = view.action;
|
|
450
|
+
const missing = (action === void 0 || !Object.hasOwn(SKILL_ACTION_REQUIRED_FIELDS, action) ? [] : SKILL_ACTION_REQUIRED_FIELDS[action] ?? []).filter((field) => view.scalars[field] === void 0 || view.scalars[field] === null);
|
|
451
|
+
if (missing.length === 0) return null;
|
|
452
|
+
return `skill_manage ${action} requires ${missing.join(", ")}; the tool description lists the arguments per action.`;
|
|
453
|
+
}
|
|
454
|
+
},
|
|
455
|
+
{
|
|
456
|
+
id: "policy-protection",
|
|
457
|
+
appliesTo: ["admission", "execution"],
|
|
458
|
+
run: ({ view, origin, protectedNames }) => {
|
|
459
|
+
if (origin === "foreground") return null;
|
|
460
|
+
if (view.name === "" || !protectedNames?.includes(view.name)) return null;
|
|
461
|
+
return `skill_manage: "${view.name}" is protected by the current policy (protectedSkillNames); replayed/autonomous writes are refused.`;
|
|
462
|
+
}
|
|
463
|
+
},
|
|
464
|
+
{
|
|
465
|
+
id: "read-before-write",
|
|
466
|
+
appliesTo: ["admission"],
|
|
467
|
+
run: ({ view, origin, readNames, warn }) => {
|
|
468
|
+
if (origin === "foreground") return null;
|
|
469
|
+
if (readNames === void 0) {
|
|
470
|
+
warn("skill_manage: the read-before-write check could not run for this call — the session log is not readable here, so the write is allowed.");
|
|
471
|
+
return null;
|
|
472
|
+
}
|
|
473
|
+
if (view.action === void 0) return null;
|
|
474
|
+
if (!isUnreadWrite({
|
|
475
|
+
action: view.action,
|
|
476
|
+
name: view.name
|
|
477
|
+
}, readNames)) return null;
|
|
478
|
+
return errorText("e-318-skill-write-without-a-read", { a1: view.name });
|
|
479
|
+
}
|
|
480
|
+
},
|
|
481
|
+
{
|
|
482
|
+
id: "human-confirm",
|
|
483
|
+
appliesTo: ["admission"],
|
|
484
|
+
run: async ({ view, origin, confirm, warn, confirmMode, confirmTimeoutSeconds, describeTarget }) => {
|
|
485
|
+
const action = view.action;
|
|
486
|
+
if (action === void 0 || origin !== "foreground" || view.name === "") return null;
|
|
487
|
+
if (!(action === "create" || action === "delete" && view.absorbedInto === void 0)) return null;
|
|
488
|
+
const mode = confirmMode ?? "auto";
|
|
489
|
+
if (mode === "auto") return null;
|
|
490
|
+
if (confirm === void 0) {
|
|
491
|
+
warn("skill_manage: no confirmation channel is mounted, so the write proceeds unconfirmed.");
|
|
492
|
+
return null;
|
|
493
|
+
}
|
|
494
|
+
const confirmLabel = action === "create" ? "创建" : "删除";
|
|
495
|
+
const seconds = timeoutSecondsOf(confirmTimeoutSeconds);
|
|
496
|
+
const cancel = new AbortController();
|
|
497
|
+
let timer;
|
|
498
|
+
const deadline = mode === "timeout" ? new Promise((resolve) => {
|
|
499
|
+
timer = setTimeout(() => {
|
|
500
|
+
cancel.abort();
|
|
501
|
+
resolve(CONFIRM_TIMED_OUT);
|
|
502
|
+
}, seconds * 1e3);
|
|
503
|
+
timer.unref();
|
|
504
|
+
}) : void 0;
|
|
505
|
+
const context = await describeTarget?.();
|
|
506
|
+
const details = [context?.description === void 0 || context.description === "" ? null : "功能:" + context.description, context?.versions === void 0 ? null : "已记录的内容版本数:" + String(context.versions)].filter((line) => line !== null);
|
|
507
|
+
const consequence = action === "create" ? `创建技能 "${view.name}"?会在家族目录树里新建一个技能目录。` : `删除技能 "${view.name}"?它会被归档到 .archive 并离开目录。`;
|
|
508
|
+
const asked = confirm({
|
|
509
|
+
action,
|
|
510
|
+
name: view.name,
|
|
511
|
+
confirmLabel,
|
|
512
|
+
question: {
|
|
513
|
+
id: CONFIRM_QUESTION_ID,
|
|
514
|
+
header: "确认",
|
|
515
|
+
question: details.length === 0 ? consequence : consequence + " " + details.join(" · "),
|
|
516
|
+
options: [{ label: confirmLabel }, { label: CANCEL_LABEL }]
|
|
517
|
+
},
|
|
518
|
+
...mode === "timeout" ? { signal: cancel.signal } : {}
|
|
519
|
+
});
|
|
520
|
+
let outcome;
|
|
521
|
+
try {
|
|
522
|
+
outcome = deadline === void 0 ? await asked : await Promise.race([asked, deadline]);
|
|
523
|
+
} finally {
|
|
524
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
525
|
+
}
|
|
526
|
+
if (outcome === true) return null;
|
|
527
|
+
if (outcome === CONFIRM_TIMED_OUT || cancel.signal.aborted) return errorText("e-319-skill-write-confirm-timed-out", {
|
|
528
|
+
a1: view.name,
|
|
529
|
+
a2: action === "create" ? "创建" : "删除",
|
|
530
|
+
a3: String(seconds)
|
|
531
|
+
});
|
|
532
|
+
return errorText("e-317-skill-write-not-confirmed", {
|
|
533
|
+
a1: view.name,
|
|
534
|
+
a2: action === "create" ? "创建" : "删除"
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
];
|
|
539
|
+
/**
|
|
540
|
+
* Run the sequence for one write attempt.
|
|
541
|
+
* @param context - the asking point, the write, and the seams the human-facing gate needs.
|
|
542
|
+
* @returns the FIRST refusal, or null when every applicable gate passed. Both points return the
|
|
543
|
+
* message as the tool result unchanged, so the two entries refuse with identical wording.
|
|
544
|
+
*/
|
|
545
|
+
async function runWriteGates(context) {
|
|
546
|
+
const input = {
|
|
547
|
+
...context,
|
|
548
|
+
view: gateArgsOf(context.args)
|
|
549
|
+
};
|
|
550
|
+
for (const gate of GATES) {
|
|
551
|
+
if (!gate.appliesTo.includes(context.point)) continue;
|
|
552
|
+
const refusal = await gate.run(input);
|
|
553
|
+
if (refusal !== null) return refusal;
|
|
554
|
+
}
|
|
555
|
+
return null;
|
|
556
|
+
}
|
|
557
|
+
//#endregion
|
|
207
558
|
//#region lib/types/reference-rewrite.js
|
|
208
559
|
/**
|
|
209
560
|
* Reference re-homing plans (0.5.0 V1, design §16.7).
|
|
@@ -2481,6 +2832,7 @@ function buildCuratorRunReport(input) {
|
|
|
2481
2832
|
...input.snapshotPath === void 0 ? {} : { snapshotPath: input.snapshotPath },
|
|
2482
2833
|
...input.llmReviewEnabled === void 0 ? {} : { llmReviewEnabled: input.llmReviewEnabled },
|
|
2483
2834
|
...input.nominationsWarnings === void 0 ? {} : { nominationsWarnings: [...input.nominationsWarnings] },
|
|
2835
|
+
...input.scanWarnings === void 0 ? {} : { scanWarnings: [...input.scanWarnings] },
|
|
2484
2836
|
...input.wouldPrune === void 0 ? {} : { wouldPrune: input.wouldPrune === null ? null : [...input.wouldPrune] }
|
|
2485
2837
|
};
|
|
2486
2838
|
}
|
|
@@ -2505,7 +2857,8 @@ function renderCuratorReportMarkdown(report) {
|
|
|
2505
2857
|
...report.routeStubs === void 0 ? [] : [`- **Stale route stubs**: ${report.routeStubs.stubs}`],
|
|
2506
2858
|
...report.llmReviewEnabled === void 0 ? [] : [`- **llmReview**: ${report.llmReviewEnabled}`],
|
|
2507
2859
|
...report.wouldPrune === void 0 ? [] : [report.wouldPrune === null ? "- **Would prune (archiveRetention=report)**: unknown (archive listing unreadable)" : `- **Would prune (archiveRetention=report)**: ${report.wouldPrune.length}`],
|
|
2508
|
-
...report.nominationsWarnings === void 0 || report.nominationsWarnings.length === 0 ? [] : [`- **Nomination warnings**: ${report.nominationsWarnings.join("; ")}`]
|
|
2860
|
+
...report.nominationsWarnings === void 0 || report.nominationsWarnings.length === 0 ? [] : [`- **Nomination warnings**: ${report.nominationsWarnings.join("; ")}`],
|
|
2861
|
+
...report.scanWarnings === void 0 || report.scanWarnings.length === 0 ? [] : report.scanWarnings.map((warning) => "- **Dedup scan**: " + warning)
|
|
2509
2862
|
];
|
|
2510
2863
|
const section = (title, items) => items.length === 0 ? [] : [
|
|
2511
2864
|
"",
|
|
@@ -4750,7 +5103,7 @@ function compositionRowIds(composition) {
|
|
|
4750
5103
|
return ids;
|
|
4751
5104
|
}
|
|
4752
5105
|
/** The platform package a DECLARATIVE preset row names (0.2.x replaced preset directories with it). */
|
|
4753
|
-
const AGENT_PRESET_PACKAGE = "
|
|
5106
|
+
const AGENT_PRESET_PACKAGE = scopedPackageName("dsh-agent-preset", import.meta.url);
|
|
4754
5107
|
/**
|
|
4755
5108
|
* Compose the DECLARATIVE preset row from the platform base composition and the family delta.
|
|
4756
5109
|
*
|
|
@@ -4795,7 +5148,7 @@ function composePresetRow(baseComposition, deltaComposition, identity) {
|
|
|
4795
5148
|
const plugins = denseBlockSequence(composePresetComposition(baseComposition, deltaComposition)).split("\n").map((line) => line === "" ? "" : " " + line).join("\n");
|
|
4796
5149
|
return [
|
|
4797
5150
|
"- id: " + identity.rowId,
|
|
4798
|
-
" name: '
|
|
5151
|
+
" name: '" + AGENT_PRESET_PACKAGE + "'",
|
|
4799
5152
|
" config:",
|
|
4800
5153
|
" id: " + identity.id,
|
|
4801
5154
|
" name: " + JSON.stringify(identity.name),
|
|
@@ -6529,11 +6882,6 @@ const PLATFORM_SERVICE_PROBES = Object.freeze([
|
|
|
6529
6882
|
feature: "every durable read and write (the IO seam)",
|
|
6530
6883
|
side: "host"
|
|
6531
6884
|
},
|
|
6532
|
-
{
|
|
6533
|
-
service: "fs",
|
|
6534
|
-
feature: "the platform filesystem the evolution-io-fs backend maps the seam onto (locks + writeText(expected) version CAS)",
|
|
6535
|
-
side: "host"
|
|
6536
|
-
},
|
|
6537
6885
|
{
|
|
6538
6886
|
service: "hmr",
|
|
6539
6887
|
feature: "the preset install read-merge-write commit (the platform HMR lock serializes it)",
|
|
@@ -9352,6 +9700,16 @@ function staleRouteStubs(indexes) {
|
|
|
9352
9700
|
* re-probes after its copies so a mid-copy writer demotes to `skipped`
|
|
9353
9701
|
* (OPT-07); the movers' probe→rename window is owned by the io.ts protocol.
|
|
9354
9702
|
*/
|
|
9703
|
+
/**
|
|
9704
|
+
* The CLASS boundary default authority (G1/1.1, Stage 2).
|
|
9705
|
+
*
|
|
9706
|
+
* The FACTORY (newSkillLibrary) requires an explicit authority and the v35 A6 register pins every
|
|
9707
|
+
* production construction, so a production caller cannot omit one. The class is the INTERNAL
|
|
9708
|
+
* boundary: arch rule N7 forbids constructing it directly in production, while ~200 test fixtures do
|
|
9709
|
+
* exactly that and ARE the operator, so an omitted authority reads as foreground here - named and
|
|
9710
|
+
* stated instead of silent.
|
|
9711
|
+
*/
|
|
9712
|
+
const CLASS_DEFAULT_AUTHORITY = authorityFrom({ origin: "foreground" });
|
|
9355
9713
|
/** 0.3.16 (S1.13, T-6): the pointer-line prefix written into a body when a
|
|
9356
9714
|
* section is moved to references/ — single literal, both restructure and
|
|
9357
9715
|
* append-mode consolidation emit the same discoverability line. */
|
|
@@ -9721,6 +10079,28 @@ function planRestructureSections(body, moves) {
|
|
|
9721
10079
|
}))
|
|
9722
10080
|
};
|
|
9723
10081
|
}
|
|
10082
|
+
/**
|
|
10083
|
+
* WHY MODULE SCOPE (S4.4): the serial queue must be shared ACROSS SkillLibrary instances. Six services
|
|
10084
|
+
* each build their own store over the SAME skill root (tool face / curator face / review face), and a
|
|
10085
|
+
* per-instance queue - which is what `this.serial = makeSerialQueue()` was - let two of them run
|
|
10086
|
+
* read->plan->commit against one tree at the same time. The mutex cannot live on an instance because
|
|
10087
|
+
* instances share nothing (S2-02, G1/1.4); it cannot be a file lock either, because the point is to
|
|
10088
|
+
* order IN-PROCESS phases before the io transact layer sees them. Keyed by root: two roots are
|
|
10089
|
+
* independent trees and must not wait on each other.
|
|
10090
|
+
*/
|
|
10091
|
+
const ROOT_SERIAL = /* @__PURE__ */ new Map();
|
|
10092
|
+
/** The ONE queue for a skill root, created on first use (module scope, see above).
|
|
10093
|
+
* @param root - the resolved skill root; the key, so two spellings of one directory share a queue.
|
|
10094
|
+
* @returns the queue every instance over this root serializes through.
|
|
10095
|
+
*/
|
|
10096
|
+
function serialForRoot(root) {
|
|
10097
|
+
const key = resolve(root);
|
|
10098
|
+
const existing = ROOT_SERIAL.get(key);
|
|
10099
|
+
if (existing !== void 0) return existing;
|
|
10100
|
+
const created = makeSerialQueue();
|
|
10101
|
+
ROOT_SERIAL.set(key, created);
|
|
10102
|
+
return created;
|
|
10103
|
+
}
|
|
9724
10104
|
var SkillLibrary = class {
|
|
9725
10105
|
root;
|
|
9726
10106
|
limits;
|
|
@@ -9739,20 +10119,24 @@ var SkillLibrary = class {
|
|
|
9739
10119
|
/** V10-03 (P2-18): see the constructor's threatExemptLabels. Empty by
|
|
9740
10120
|
* default — the strict ANY-hit-blocks policy is unchanged. */
|
|
9741
10121
|
threatExemptLabels;
|
|
10122
|
+
/** G1/1.1: default authority; a call may override (origin is per-invocation). */
|
|
10123
|
+
/** G1/1.1/Stage 2: the ONE default every mutator reads. Per-call overrides still win. */
|
|
10124
|
+
authority;
|
|
9742
10125
|
/** skill-history.ts: the content history is best-effort, so a failure must not be SILENT —
|
|
9743
10126
|
* but it is a deployment condition, not a per-write event, so it warns once per instance. */
|
|
9744
10127
|
historyWarned = false;
|
|
9745
|
-
constructor(root = skillsRoot(), io = nodeEvolutionIo(), limits = DEFAULT_SKILL_LIMITS, onMutation, transact, threatExemptLabels) {
|
|
10128
|
+
constructor(root = skillsRoot(), io = nodeEvolutionIo(), limits = DEFAULT_SKILL_LIMITS, onMutation, transact, threatExemptLabels, authority = CLASS_DEFAULT_AUTHORITY) {
|
|
9746
10129
|
this.root = root;
|
|
9747
10130
|
this.io = io;
|
|
9748
10131
|
this.limits = limits;
|
|
9749
10132
|
this.onMutation = onMutation;
|
|
9750
10133
|
this.threatExemptLabels = threatExemptLabels ?? [];
|
|
10134
|
+
this.authority = authority;
|
|
9751
10135
|
this.transact = transact ?? (io.transact ? (ioLike, path, task) => {
|
|
9752
10136
|
const t = ioLike.transact;
|
|
9753
10137
|
return t ? t(path, task) : transactIo(ioLike, path, task);
|
|
9754
10138
|
} : void 0);
|
|
9755
|
-
this.serial =
|
|
10139
|
+
this.serial = serialForRoot(this.root);
|
|
9756
10140
|
}
|
|
9757
10141
|
/**
|
|
9758
10142
|
* Run one single-file read-modify-write for a mutator. When `transact` was
|
|
@@ -9867,6 +10251,32 @@ var SkillLibrary = class {
|
|
|
9867
10251
|
* a swallowed error would silently downgrade the anchor to
|
|
9868
10252
|
* last-writer-wins.
|
|
9869
10253
|
*/
|
|
10254
|
+
/**
|
|
10255
|
+
* S4-01 (G0/0.7): the ONE three-state read the staging/replay anchors use.
|
|
10256
|
+
*
|
|
10257
|
+
* The two absorbing reads below absorb ENOENT/EISDIR and rethrow everything else, and the callers then
|
|
10258
|
+
* each wrote their own try/catch to turn a rethrow into a decision - three near-copies of one posture,
|
|
10259
|
+
* and the newest of them silently dropped the anchor instead of refusing. A read failure is its own
|
|
10260
|
+
* state, so it gets its own name here: `unknown` with the reason, next to `present` and `absent`.
|
|
10261
|
+
* Failing closed is then the CALLER decision (they refuse on unknown), not something each call site has
|
|
10262
|
+
* to re-derive from a thrown error.
|
|
10263
|
+
*/
|
|
10264
|
+
async readSkillProbe(rawName) {
|
|
10265
|
+
return await this.probeOf(() => this.read(rawName));
|
|
10266
|
+
}
|
|
10267
|
+
/** The support-file face of {@link readSkillProbe}. */
|
|
10268
|
+
async readSupportFileProbe(rawName, filePath) {
|
|
10269
|
+
return await this.probeOf(() => this.readSupportFile(rawName, filePath));
|
|
10270
|
+
}
|
|
10271
|
+
/** One place that turns the absorbing reads into three states. `null` is absent; a throw is unknown. */
|
|
10272
|
+
async probeOf(read) {
|
|
10273
|
+
try {
|
|
10274
|
+
const value = await read();
|
|
10275
|
+
return value === null ? probeAbsent() : probePresent(value);
|
|
10276
|
+
} catch (error) {
|
|
10277
|
+
return probeUnknown(probeReason(error));
|
|
10278
|
+
}
|
|
10279
|
+
}
|
|
9870
10280
|
async readSupportFile(name, filePath) {
|
|
9871
10281
|
const bad = this.badName(name, { allowReserved: true });
|
|
9872
10282
|
if (bad) throw new Error(bad);
|
|
@@ -9899,7 +10309,9 @@ var SkillLibrary = class {
|
|
|
9899
10309
|
}
|
|
9900
10310
|
async list(options = {}) {
|
|
9901
10311
|
const summaries = [];
|
|
9902
|
-
for (const
|
|
10312
|
+
for (const entry of await this.io.list(this.root)) {
|
|
10313
|
+
if (entry.startsWith(".")) continue;
|
|
10314
|
+
const name = entry;
|
|
9903
10315
|
const dir = this.dirOf(name);
|
|
9904
10316
|
let md;
|
|
9905
10317
|
try {
|
|
@@ -9996,7 +10408,7 @@ var SkillLibrary = class {
|
|
|
9996
10408
|
* (P1-1/v14 — the name guard lives HERE as well as at every entry point, so
|
|
9997
10409
|
* no caller can build a path from an unvalidated name).
|
|
9998
10410
|
*/
|
|
9999
|
-
async writeProtection(rawName, origin =
|
|
10411
|
+
async writeProtection(rawName, origin = this.authority.origin) {
|
|
10000
10412
|
const name = rawName.trim();
|
|
10001
10413
|
const badName = this.badName(name);
|
|
10002
10414
|
if (badName) return badName;
|
|
@@ -10274,7 +10686,7 @@ var SkillLibrary = class {
|
|
|
10274
10686
|
* protective mutation, so the autonomous pipeline may never call it. The
|
|
10275
10687
|
* marker write is the only state change; content is untouched.
|
|
10276
10688
|
*/
|
|
10277
|
-
async setPinned(name, pinned, origin =
|
|
10689
|
+
async setPinned(name, pinned, origin = this.authority.origin) {
|
|
10278
10690
|
return await this.serial(() => this.setPinnedCore(name, pinned, origin));
|
|
10279
10691
|
}
|
|
10280
10692
|
async setPinnedCore(name, pinned, origin) {
|
|
@@ -10329,7 +10741,7 @@ var SkillLibrary = class {
|
|
|
10329
10741
|
path: dir
|
|
10330
10742
|
};
|
|
10331
10743
|
}
|
|
10332
|
-
async create(name, content, origin =
|
|
10744
|
+
async create(name, content, origin = this.authority.origin) {
|
|
10333
10745
|
const normalized = name.trim();
|
|
10334
10746
|
return await this.serial(() => this.createCore(normalized, content, origin));
|
|
10335
10747
|
}
|
|
@@ -10456,7 +10868,7 @@ var SkillLibrary = class {
|
|
|
10456
10868
|
...norm.changed ? { normalizedFrontmatterFields: norm.fields } : {}
|
|
10457
10869
|
};
|
|
10458
10870
|
}
|
|
10459
|
-
async update(rawName, content, origin =
|
|
10871
|
+
async update(rawName, content, origin = this.authority.origin, anchor) {
|
|
10460
10872
|
const name = rawName.trim();
|
|
10461
10873
|
return await this.serial(() => this.updateCore(name, content, origin, anchor));
|
|
10462
10874
|
}
|
|
@@ -10545,7 +10957,7 @@ var SkillLibrary = class {
|
|
|
10545
10957
|
};
|
|
10546
10958
|
}, anchor !== void 0 ? () => anchorUnverifiable(name, null) : (error) => unreadableTarget(name, error));
|
|
10547
10959
|
}
|
|
10548
|
-
async patch(rawName, oldString, newString, filePath = "", replaceAll = false, origin =
|
|
10960
|
+
async patch(rawName, oldString, newString, filePath = "", replaceAll = false, origin = this.authority.origin) {
|
|
10549
10961
|
const name = rawName.trim();
|
|
10550
10962
|
return await this.serial(() => this.patchCore(name, oldString, newString, filePath, replaceAll, origin));
|
|
10551
10963
|
}
|
|
@@ -10767,7 +11179,7 @@ var SkillLibrary = class {
|
|
|
10767
11179
|
if (typeof name !== "string") return false;
|
|
10768
11180
|
return name !== "" && name !== "." && name !== ".." && !name.includes("/") && !name.includes("\\") && basename(name) === name;
|
|
10769
11181
|
}
|
|
10770
|
-
async archive(rawName, options = {}) {
|
|
11182
|
+
async archive(rawName, options = {}, origin = this.authority.origin) {
|
|
10771
11183
|
const name = rawName.trim();
|
|
10772
11184
|
const badName = this.badName(name, { allowReserved: true });
|
|
10773
11185
|
if (badName) return {
|
|
@@ -10834,7 +11246,7 @@ var SkillLibrary = class {
|
|
|
10834
11246
|
try {
|
|
10835
11247
|
await this.io.writeText(join(dest, ".archive-name"), `${name}\n`);
|
|
10836
11248
|
} catch {}
|
|
10837
|
-
await this.audit(name, "archive", md, null, reason);
|
|
11249
|
+
await this.audit(name, "archive", md, null, reason, void 0, void 0, void 0, origin);
|
|
10838
11250
|
this.notifyMutation({
|
|
10839
11251
|
action: "archive",
|
|
10840
11252
|
name,
|
|
@@ -10934,7 +11346,7 @@ var SkillLibrary = class {
|
|
|
10934
11346
|
* still refuses, and the refusal names it. The archived source keeps whatever
|
|
10935
11347
|
* the body did not need.
|
|
10936
11348
|
*/
|
|
10937
|
-
async consolidate(target, sources, origin =
|
|
11349
|
+
async consolidate(target, sources, origin = this.authority.origin, options = {}) {
|
|
10938
11350
|
const targetName = target.trim();
|
|
10939
11351
|
const normalizedSources = [...new Set(sources.map((name) => name.trim()))].filter((name) => name !== targetName);
|
|
10940
11352
|
const mode = options.mode ?? "append";
|
|
@@ -11128,7 +11540,7 @@ var SkillLibrary = class {
|
|
|
11128
11540
|
* support-directory links is refused (those links' files stay behind in the
|
|
11129
11541
|
* same package; the moved text belongs in references/ beside them).
|
|
11130
11542
|
*/
|
|
11131
|
-
async restructure(rawName, moves, origin =
|
|
11543
|
+
async restructure(rawName, moves, origin = this.authority.origin) {
|
|
11132
11544
|
const name = rawName.trim();
|
|
11133
11545
|
return await this.serial(() => this.restructureCore(name, moves, origin));
|
|
11134
11546
|
}
|
|
@@ -11345,7 +11757,7 @@ var SkillLibrary = class {
|
|
|
11345
11757
|
};
|
|
11346
11758
|
return {
|
|
11347
11759
|
ok: false,
|
|
11348
|
-
message: `目录树变更失败:${reason}。回滚无法恢复 ${stuck.join(", ")}
|
|
11760
|
+
message: `目录树变更失败:${reason}。回滚无法恢复 ${stuck.join(", ")}:可恢复性由当前快照决定:${await this.snapshotRecoveryAvailability()} —— 若上面不是「最新快照」,请重新应用这次变更。`
|
|
11349
11761
|
};
|
|
11350
11762
|
}
|
|
11351
11763
|
const unitId = plan.unitId ?? "u-" + Date.now().toString(36) + "-" + (nextUnitSeq += 1).toString(36);
|
|
@@ -11384,7 +11796,7 @@ var SkillLibrary = class {
|
|
|
11384
11796
|
* recoverability: archival never deletes, and this is the control-plane
|
|
11385
11797
|
* path back. The `.archive-reason` marker is dropped on restore.
|
|
11386
11798
|
*/
|
|
11387
|
-
async restoreFromArchive(rawName) {
|
|
11799
|
+
async restoreFromArchive(rawName, origin = this.authority.origin) {
|
|
11388
11800
|
const name = rawName.trim();
|
|
11389
11801
|
const bad = this.badName(name, { allowReserved: true });
|
|
11390
11802
|
if (bad) return {
|
|
@@ -11450,7 +11862,7 @@ var SkillLibrary = class {
|
|
|
11450
11862
|
};
|
|
11451
11863
|
return {
|
|
11452
11864
|
ok: false,
|
|
11453
|
-
message: `.archive 里没有「${name}」对应的 frontmatter 名,但有 ${unreadable.length} 个名字相似的归档项:${unreadable.join(", ")}。这些归档项没有可读的 SKILL.md
|
|
11865
|
+
message: `.archive 里没有「${name}」对应的 frontmatter 名,但有 ${unreadable.length} 个名字相似的归档项:${unreadable.join(", ")}。这些归档项没有可读的 SKILL.md(或名字对不上),按名字恢复无法区分它们:请把目录改成技能名后再次恢复;快照这条路的当前状态是:${await this.snapshotRecoveryAvailability()}。`
|
|
11454
11866
|
};
|
|
11455
11867
|
}
|
|
11456
11868
|
const source = join(archiveRoot, chosen);
|
|
@@ -11472,7 +11884,7 @@ var SkillLibrary = class {
|
|
|
11472
11884
|
for (const marker of [".archive-reason", ".archive-name"]) if (await this.io.exists(join(dest, marker))) await this.io.remove(join(dest, marker));
|
|
11473
11885
|
const restoredProbe = await probeText(this.io, join(dest, "SKILL.md"));
|
|
11474
11886
|
if (isUnknown(restoredProbe)) console.warn(`evolution-skill-store: the restored SKILL.md of "${name}" could not be read back (${restoredProbe.reason}); the restore is recorded without after-bytes`);
|
|
11475
|
-
await this.audit(name, "restore", null, isPresent(restoredProbe) ? restoredProbe.value : null, `restored from ${source}
|
|
11887
|
+
await this.audit(name, "restore", null, isPresent(restoredProbe) ? restoredProbe.value : null, `restored from ${source}`, void 0, void 0, void 0, origin);
|
|
11476
11888
|
this.notifyMutation({
|
|
11477
11889
|
action: "restore",
|
|
11478
11890
|
name,
|
|
@@ -11484,7 +11896,7 @@ var SkillLibrary = class {
|
|
|
11484
11896
|
path: dest
|
|
11485
11897
|
};
|
|
11486
11898
|
}
|
|
11487
|
-
async writeSupportFile(rawName, filePath, content, origin =
|
|
11899
|
+
async writeSupportFile(rawName, filePath, content, origin = this.authority.origin, anchor) {
|
|
11488
11900
|
const name = rawName.trim();
|
|
11489
11901
|
return await this.serial(() => this.writeSupportFileCore(name, filePath, content, origin, anchor));
|
|
11490
11902
|
}
|
|
@@ -11568,7 +11980,7 @@ var SkillLibrary = class {
|
|
|
11568
11980
|
};
|
|
11569
11981
|
}, anchor !== void 0 ? () => anchorUnverifiable(name, filePath) : (error) => unreadableTarget(name + "/" + filePath, error));
|
|
11570
11982
|
}
|
|
11571
|
-
async removeSupportFile(rawName, filePath, origin =
|
|
11983
|
+
async removeSupportFile(rawName, filePath, origin = this.authority.origin, anchor, unitId) {
|
|
11572
11984
|
const name = rawName.trim();
|
|
11573
11985
|
return await this.serial(() => this.removeSupportFileCore(name, filePath, origin, anchor, unitId));
|
|
11574
11986
|
}
|
|
@@ -11827,6 +12239,22 @@ var SkillLibrary = class {
|
|
|
11827
12239
|
}
|
|
11828
12240
|
}
|
|
11829
12241
|
/** Keep only the newest N snapshots (Hermes keep=5 parity); older ones are removed outright. */
|
|
12242
|
+
/**
|
|
12243
|
+
* G3/3.4: can a snapshot actually be used right now?
|
|
12244
|
+
*
|
|
12245
|
+
* The recovery messages used to promise "restore it from a snapshot" without asking whether a usable
|
|
12246
|
+
* snapshot exists (audit S1-01: the message promised recoverability from a chain that is five deep and
|
|
12247
|
+
* whose newest member held 9 of 35 skills). Three states, like every other reading here: a fragment
|
|
12248
|
+
* naming the usable snapshot, a fragment saying there is none, or a fragment saying the directory could
|
|
12249
|
+
* not be read - the caller embeds whichever it gets, so the sentence is generated by the capability.
|
|
12250
|
+
*/
|
|
12251
|
+
async snapshotRecoveryAvailability() {
|
|
12252
|
+
const listed = await this.listSnapshots();
|
|
12253
|
+
if (isUnknown(listed)) return "快照目录读不出来(" + listed.reason + ")";
|
|
12254
|
+
const latest = isPresent(listed) ? listed.value[0] : void 0;
|
|
12255
|
+
if (!latest) return "当前没有可用快照";
|
|
12256
|
+
return "最新快照 " + latest.path;
|
|
12257
|
+
}
|
|
11830
12258
|
async retainSnapshots(keep) {
|
|
11831
12259
|
const listed = await this.listSnapshots();
|
|
11832
12260
|
if (isUnknown(listed)) {
|
|
@@ -11990,12 +12418,15 @@ var SkillLibrary = class {
|
|
|
11990
12418
|
}
|
|
11991
12419
|
}
|
|
11992
12420
|
const restoresSuppressed = manifest.sidecars.includes(".curator-suppressed.json");
|
|
11993
|
-
|
|
11994
|
-
|
|
11995
|
-
if (entry === ".
|
|
11996
|
-
if (entry === ".
|
|
11997
|
-
|
|
11998
|
-
|
|
12421
|
+
const declared = new Set([...manifest.skills, ...manifest.sidecars]);
|
|
12422
|
+
const doomed = rootEntries.filter((entry) => {
|
|
12423
|
+
if (entry === ".archive" || entry === ".backups" || entry === ".mutations.json") return false;
|
|
12424
|
+
if (entry === ".history") return false;
|
|
12425
|
+
if (entry === ".curator-suppressed.json" && restoresSuppressed) return false;
|
|
12426
|
+
return !declared.has(entry);
|
|
12427
|
+
});
|
|
12428
|
+
if (doomed.length > 0) console.warn("skill-store: snapshot restore will delete " + String(doomed.length) + " live entr(y|ies) the snapshot does not declare: " + doomed.join(", "));
|
|
12429
|
+
for (const entry of doomed) await this.io.remove(join(this.root, entry));
|
|
11999
12430
|
for (const name of manifest.skills) await this.io.copy(join(snapshotPath, name), join(this.root, name));
|
|
12000
12431
|
for (const sidecar of manifest.sidecars) await this.io.copy(join(snapshotPath, sidecar), join(this.root, sidecar));
|
|
12001
12432
|
{
|
|
@@ -12009,10 +12440,300 @@ var SkillLibrary = class {
|
|
|
12009
12440
|
}
|
|
12010
12441
|
};
|
|
12011
12442
|
function newSkillLibrary(options) {
|
|
12012
|
-
const { config, io, limits, ctx, transact, threatExemptLabels } = options;
|
|
12443
|
+
const { config, io, limits, ctx, transact, threatExemptLabels, authority } = options;
|
|
12013
12444
|
return new SkillLibrary(resolveSkillsRoot(config ?? {}), io, limits, ctx ? (event) => {
|
|
12014
12445
|
ctx.emit("evolution/skill-mutated", event);
|
|
12015
|
-
} : void 0, transact, [...threatExemptLabels ?? []]);
|
|
12446
|
+
} : void 0, transact, [...threatExemptLabels ?? []], authority);
|
|
12447
|
+
}
|
|
12448
|
+
//#endregion
|
|
12449
|
+
//#region lib/types/store-ledger.js
|
|
12450
|
+
/**
|
|
12451
|
+
* G3/3.2 (audit 06-performance.md 接缝 C): ONE declaration for every bounded store.
|
|
12452
|
+
*
|
|
12453
|
+
* Before this file the family had eight retention rules scattered across four packages and no place
|
|
12454
|
+
* that could answer "how long does this record live under the current policy" (S1.md 4.3): six caps
|
|
12455
|
+
* were named constants, three lived inline (snapshots 5, reports 20/20/10, archive 365d). Each entry
|
|
12456
|
+
* below states its bound AND the code that declares it, so a gate can compare the two sets.
|
|
12457
|
+
*
|
|
12458
|
+
* `declare` is an ARRAY because one store may have several declaration sites (the report buckets are
|
|
12459
|
+
* kept by two packages). The `inline` branch matches a CODE SNIPPET rather than a line number: line
|
|
12460
|
+
* numbers rot on every edit above them, a snippet survives (and a snippet that stops matching is the
|
|
12461
|
+
* detector the gate wants). No naming convention is assumed anywhere - that is the whole point of a
|
|
12462
|
+
* ledger: the list IS the declaration.
|
|
12463
|
+
*/
|
|
12464
|
+
/** The one list. A new bounded store that is not registered here is what the G3 gate refuses. */
|
|
12465
|
+
const STORE_LEDGER = [
|
|
12466
|
+
{
|
|
12467
|
+
id: "archive-entries",
|
|
12468
|
+
owner: "evolution-core",
|
|
12469
|
+
unit: "entries",
|
|
12470
|
+
bound: "365 days, report-only by default (the removal policy is report, not delete)",
|
|
12471
|
+
cutoff: "archivedAt older than the retention window",
|
|
12472
|
+
trigger: "run-end",
|
|
12473
|
+
artifact: "count of .archive entries and their ages",
|
|
12474
|
+
declare: [{
|
|
12475
|
+
kind: "inline",
|
|
12476
|
+
file: "packages/evolution-core/src/skill-store.ts",
|
|
12477
|
+
contains: "ARCHIVE_RETENTION_DAYS = 365",
|
|
12478
|
+
value: "365 days"
|
|
12479
|
+
}, {
|
|
12480
|
+
kind: "named",
|
|
12481
|
+
module: "evolution-core/src/limits.ts",
|
|
12482
|
+
name: "DEFAULT_ARCHIVE_RETENTION_POLICY",
|
|
12483
|
+
value: "report"
|
|
12484
|
+
}]
|
|
12485
|
+
},
|
|
12486
|
+
{
|
|
12487
|
+
id: "skill-snapshots",
|
|
12488
|
+
owner: "evolution-core",
|
|
12489
|
+
unit: "entries",
|
|
12490
|
+
bound: "5 snapshots",
|
|
12491
|
+
cutoff: "oldest snapshot beyond the keep window",
|
|
12492
|
+
trigger: "run-end",
|
|
12493
|
+
artifact: "snapshot count and total bytes",
|
|
12494
|
+
declare: [{
|
|
12495
|
+
kind: "inline",
|
|
12496
|
+
file: "packages/evolution-core/src/skill-store.ts",
|
|
12497
|
+
contains: "retainSnapshots(5)",
|
|
12498
|
+
value: "5"
|
|
12499
|
+
}]
|
|
12500
|
+
},
|
|
12501
|
+
{
|
|
12502
|
+
id: "skill-versions",
|
|
12503
|
+
owner: "evolution-core",
|
|
12504
|
+
unit: "entries",
|
|
12505
|
+
bound: "20 versions per skill",
|
|
12506
|
+
cutoff: "history index entries beyond versionKeep",
|
|
12507
|
+
trigger: "write",
|
|
12508
|
+
artifact: "history index length per skill",
|
|
12509
|
+
declare: [{
|
|
12510
|
+
kind: "named",
|
|
12511
|
+
module: "evolution-core/src/constants.ts",
|
|
12512
|
+
name: "DEFAULT_SKILL_VERSION_KEEP",
|
|
12513
|
+
value: 20
|
|
12514
|
+
}]
|
|
12515
|
+
},
|
|
12516
|
+
{
|
|
12517
|
+
id: "pending-resolved",
|
|
12518
|
+
owner: "evolution-state-storage",
|
|
12519
|
+
unit: "entries",
|
|
12520
|
+
bound: "200 resolved pending records",
|
|
12521
|
+
cutoff: "resolved records beyond the cap",
|
|
12522
|
+
trigger: "write",
|
|
12523
|
+
artifact: "resolved record count",
|
|
12524
|
+
declare: [{
|
|
12525
|
+
kind: "named",
|
|
12526
|
+
module: "evolution-state-storage/src/constants.ts",
|
|
12527
|
+
name: "PENDING_RESOLVED_CAP",
|
|
12528
|
+
value: 200
|
|
12529
|
+
}]
|
|
12530
|
+
},
|
|
12531
|
+
{
|
|
12532
|
+
id: "review-session",
|
|
12533
|
+
owner: "evolution-state-storage",
|
|
12534
|
+
unit: "entries",
|
|
12535
|
+
bound: "500 review session rows",
|
|
12536
|
+
cutoff: "rows beyond the session cap",
|
|
12537
|
+
trigger: "write",
|
|
12538
|
+
artifact: "review state row count",
|
|
12539
|
+
declare: [{
|
|
12540
|
+
kind: "named",
|
|
12541
|
+
module: "evolution-state-storage/src/constants.ts",
|
|
12542
|
+
name: "REVIEW_STATE_SESSION_CAP",
|
|
12543
|
+
value: 500
|
|
12544
|
+
}]
|
|
12545
|
+
},
|
|
12546
|
+
{
|
|
12547
|
+
id: "reports",
|
|
12548
|
+
owner: "evolution-commands",
|
|
12549
|
+
unit: "files",
|
|
12550
|
+
bound: "20/20/10 files across the three report buckets",
|
|
12551
|
+
cutoff: "reports beyond each bucket keep",
|
|
12552
|
+
trigger: "run-end",
|
|
12553
|
+
artifact: "report file count per bucket",
|
|
12554
|
+
declare: [{
|
|
12555
|
+
kind: "inline",
|
|
12556
|
+
file: "packages/evolution-commands/src/index.ts",
|
|
12557
|
+
contains: "maintain-",
|
|
12558
|
+
value: "20"
|
|
12559
|
+
}, {
|
|
12560
|
+
kind: "inline",
|
|
12561
|
+
file: "packages/evolution-curator/src/index.ts",
|
|
12562
|
+
contains: "errorKeep",
|
|
12563
|
+
value: "10"
|
|
12564
|
+
}]
|
|
12565
|
+
},
|
|
12566
|
+
{
|
|
12567
|
+
id: "event-archives",
|
|
12568
|
+
owner: "evolution-core",
|
|
12569
|
+
unit: "files",
|
|
12570
|
+
bound: "10 archived event logs",
|
|
12571
|
+
cutoff: "archives beyond the retention count",
|
|
12572
|
+
trigger: "write",
|
|
12573
|
+
artifact: "event archive count",
|
|
12574
|
+
declare: [{
|
|
12575
|
+
kind: "named",
|
|
12576
|
+
module: "evolution-core/src/evolution-events.ts",
|
|
12577
|
+
name: "EVENT_LOG_RETAIN_ARCHIVES",
|
|
12578
|
+
value: 10
|
|
12579
|
+
}]
|
|
12580
|
+
},
|
|
12581
|
+
{
|
|
12582
|
+
id: "run-records",
|
|
12583
|
+
owner: "evolution-core",
|
|
12584
|
+
unit: "entries",
|
|
12585
|
+
bound: "50 run records",
|
|
12586
|
+
cutoff: "runs beyond the record cap",
|
|
12587
|
+
trigger: "write",
|
|
12588
|
+
artifact: "runs.json record count",
|
|
12589
|
+
declare: [{
|
|
12590
|
+
kind: "named",
|
|
12591
|
+
module: "evolution-core/src/run-registry.ts",
|
|
12592
|
+
name: "DEFAULT_RUN_RECORDS",
|
|
12593
|
+
value: 50
|
|
12594
|
+
}]
|
|
12595
|
+
},
|
|
12596
|
+
{
|
|
12597
|
+
id: "support-reads",
|
|
12598
|
+
owner: "evolution-core",
|
|
12599
|
+
unit: "entries",
|
|
12600
|
+
bound: "200 support_reads keys",
|
|
12601
|
+
cutoff: "keys beyond the read-path cap",
|
|
12602
|
+
trigger: "write",
|
|
12603
|
+
artifact: "usage sidecar key count",
|
|
12604
|
+
declare: [{
|
|
12605
|
+
kind: "named",
|
|
12606
|
+
module: "evolution-core/src/usage.ts",
|
|
12607
|
+
name: "MAX_SUPPORT_READ_PATHS",
|
|
12608
|
+
value: 200
|
|
12609
|
+
}]
|
|
12610
|
+
}
|
|
12611
|
+
];
|
|
12612
|
+
//#endregion
|
|
12613
|
+
//#region lib/types/reachability.js
|
|
12614
|
+
/**
|
|
12615
|
+
* G3/3.4: the READ-ONLY reachability reconciliation.
|
|
12616
|
+
*
|
|
12617
|
+
* Three resource domains have grown past their owners' view: content blobs whose index entries were
|
|
12618
|
+
* trimmed away (skill-history: "Trimming drops INDEX entries; orphan blobs stay"), report files no run
|
|
12619
|
+
* record points at, and snapshot directories whose manifest holds almost nothing. The audit measured
|
|
12620
|
+
* them once (233 blobs / 11.40 MiB / 75.4% unreachable; 52 orphan report .md; 4/5 empty snapshot trees,
|
|
12621
|
+
* the newest holding 9 of 35 skills); this module answers the same three questions, from the tree in
|
|
12622
|
+
* front of it, and NOTHING ELSE: it deletes nothing, repairs nothing, and adds no timer.
|
|
12623
|
+
*
|
|
12624
|
+
* Every path is a parameter. The reconciliation must not grow its own idea of where a domain lives -
|
|
12625
|
+
* the callers already know (historyRoot / the reports directory / the snapshot root), and a second
|
|
12626
|
+
* guess here would be a second owner of that fact.
|
|
12627
|
+
*/
|
|
12628
|
+
const HISTORY_BASELINE = "233 blobs / 11.40 MiB unreachable (75.4%)";
|
|
12629
|
+
const REPORTS_BASELINE = "52 orphan report .md";
|
|
12630
|
+
const BACKUPS_BASELINE = "4/5 empty snapshot trees; the newest held 9/35 skills";
|
|
12631
|
+
/** Every sha256 any skill index references, across the whole history root. */
|
|
12632
|
+
async function referencedBlobs(io, historyRoot) {
|
|
12633
|
+
const referenced = /* @__PURE__ */ new Set();
|
|
12634
|
+
const skillsDir = join(historyRoot, "skills");
|
|
12635
|
+
const namesProbe = await probeList(io, skillsDir);
|
|
12636
|
+
if (isUnknown(namesProbe)) return void 0;
|
|
12637
|
+
const names = isPresent(namesProbe) ? namesProbe.value : [];
|
|
12638
|
+
for (const name of names) {
|
|
12639
|
+
const probe = await probeText(io, join(skillsDir, name, "index.json"));
|
|
12640
|
+
if (isUnknown(probe)) return void 0;
|
|
12641
|
+
if (!isPresent(probe)) continue;
|
|
12642
|
+
for (const match of probe.value.matchAll(/[a-f0-9]{64}/g)) referenced.add(match[0]);
|
|
12643
|
+
}
|
|
12644
|
+
return referenced;
|
|
12645
|
+
}
|
|
12646
|
+
/**
|
|
12647
|
+
* The history domain: blobs on disk minus the blobs the indexes still reference.
|
|
12648
|
+
* @param io - the tree reader.
|
|
12649
|
+
* @param historyRoot - the history root (`.history`), passed in, never guessed.
|
|
12650
|
+
* @returns the reading, with the audit baseline quoted for comparison.
|
|
12651
|
+
*/
|
|
12652
|
+
async function historyReachability(io, historyRoot) {
|
|
12653
|
+
const blobsProbe = await probeList(io, join(historyRoot, "blobs"));
|
|
12654
|
+
const referenced = await referencedBlobs(io, historyRoot);
|
|
12655
|
+
if (isUnknown(blobsProbe) || referenced === void 0) return {
|
|
12656
|
+
domain: "history.blobs",
|
|
12657
|
+
unit: "bytes",
|
|
12658
|
+
total: 0,
|
|
12659
|
+
reachable: 0,
|
|
12660
|
+
unreachable: 0,
|
|
12661
|
+
baseline: HISTORY_BASELINE,
|
|
12662
|
+
unmeasured: "a blob listing or an index read failed; this domain was not measured"
|
|
12663
|
+
};
|
|
12664
|
+
const blobs = isPresent(blobsProbe) ? blobsProbe.value : [];
|
|
12665
|
+
const reachable = blobs.filter((blob) => referenced.has(blob)).length;
|
|
12666
|
+
return {
|
|
12667
|
+
domain: "history.blobs",
|
|
12668
|
+
unit: "bytes",
|
|
12669
|
+
total: blobs.length,
|
|
12670
|
+
reachable,
|
|
12671
|
+
unreachable: blobs.length - reachable,
|
|
12672
|
+
baseline: HISTORY_BASELINE
|
|
12673
|
+
};
|
|
12674
|
+
}
|
|
12675
|
+
/**
|
|
12676
|
+
* The reports domain: files no run record points at. A record WITHOUT a `resultRef` still owns the
|
|
12677
|
+
* conventional path (`reports/maintain-<id>.json`), so that path counts as reachable - counting only
|
|
12678
|
+
* explicit refs would report compliant files as orphans and the number could never match the baseline.
|
|
12679
|
+
* @param io - the tree reader.
|
|
12680
|
+
* @param reportsDir - the reports directory, passed in.
|
|
12681
|
+
* @param runIds - every run id the run records carry.
|
|
12682
|
+
* @param resultRefs - every explicit resultRef those records carry.
|
|
12683
|
+
*/
|
|
12684
|
+
async function reportsReachability(io, reportsDir, runIds, resultRefs) {
|
|
12685
|
+
const listed = await probeList(io, reportsDir);
|
|
12686
|
+
if (isUnknown(listed)) return {
|
|
12687
|
+
domain: "reports.files",
|
|
12688
|
+
unit: "files",
|
|
12689
|
+
total: 0,
|
|
12690
|
+
reachable: 0,
|
|
12691
|
+
unreachable: 0,
|
|
12692
|
+
baseline: REPORTS_BASELINE,
|
|
12693
|
+
unmeasured: "the reports directory could not be listed; this domain was not measured"
|
|
12694
|
+
};
|
|
12695
|
+
const files = isPresent(listed) ? listed.value : [];
|
|
12696
|
+
const reachableNames = /* @__PURE__ */ new Set();
|
|
12697
|
+
for (const ref of resultRefs) reachableNames.add(ref.slice(ref.lastIndexOf("/") + 1));
|
|
12698
|
+
for (const id of runIds) reachableNames.add("maintain-" + id + ".json");
|
|
12699
|
+
const reachable = files.filter((file) => reachableNames.has(file)).length;
|
|
12700
|
+
return {
|
|
12701
|
+
domain: "reports.files",
|
|
12702
|
+
unit: "files",
|
|
12703
|
+
total: files.length,
|
|
12704
|
+
reachable,
|
|
12705
|
+
unreachable: files.length - reachable,
|
|
12706
|
+
baseline: REPORTS_BASELINE
|
|
12707
|
+
};
|
|
12708
|
+
}
|
|
12709
|
+
/**
|
|
12710
|
+
* The backups domain: snapshot trees and how much each holds. `skillsPerSnapshot` is measured by the
|
|
12711
|
+
* caller (it already reads manifests); an empty tree is one whose manifest lists no skill.
|
|
12712
|
+
* @param io - the tree reader.
|
|
12713
|
+
* @param backupsRoot - the snapshot root, passed in.
|
|
12714
|
+
* @param skillsPerSnapshot - the caller's manifest reading, one entry per snapshot directory.
|
|
12715
|
+
*/
|
|
12716
|
+
async function backupsReachability(io, backupsRoot, skillsPerSnapshot) {
|
|
12717
|
+
const listed = await probeList(io, backupsRoot);
|
|
12718
|
+
if (isUnknown(listed)) return {
|
|
12719
|
+
domain: "backups.trees",
|
|
12720
|
+
unit: "files",
|
|
12721
|
+
total: 0,
|
|
12722
|
+
reachable: 0,
|
|
12723
|
+
unreachable: 0,
|
|
12724
|
+
baseline: BACKUPS_BASELINE,
|
|
12725
|
+
unmeasured: "the snapshot root could not be listed; this domain was not measured"
|
|
12726
|
+
};
|
|
12727
|
+
const dirs = isPresent(listed) ? listed.value : [];
|
|
12728
|
+
const empty = skillsPerSnapshot.filter((count) => count === 0).length;
|
|
12729
|
+
return {
|
|
12730
|
+
domain: "backups.trees",
|
|
12731
|
+
unit: "files",
|
|
12732
|
+
total: dirs.length,
|
|
12733
|
+
reachable: dirs.length - empty,
|
|
12734
|
+
unreachable: empty,
|
|
12735
|
+
baseline: BACKUPS_BASELINE
|
|
12736
|
+
};
|
|
12016
12737
|
}
|
|
12017
12738
|
//#endregion
|
|
12018
12739
|
//#region lib/types/params.js
|
|
@@ -13983,4 +14704,4 @@ function foldUntrustedLines(text, limit) {
|
|
|
13983
14704
|
return limit > 0 ? marked.slice(0, limit) : marked;
|
|
13984
14705
|
}
|
|
13985
14706
|
//#endregion
|
|
13986
|
-
export { AGENT_PRESET_PACKAGE, AGENT_PRESET_ROOT_HINT, AUTHORING_DESCRIPTION_BAR, AUTHORING_SPLIT_LINE_CHARS, BASELINE_ACTION, CITATION_SUPPORT_DIRS, COMBINED_REVIEW_PLAN_PROMPT, COMBINED_REVIEW_PROMPT, COMPLETION_SKILL_REVIEW_PROMPT, CONTENT_SPLIT_HINT, COST_ASCII_TOKEN_HIGH, COST_ASCII_TOKEN_LOW, COST_CJK_TOKEN_HIGH, COST_CJK_TOKEN_LOW, CURATOR_DRY_RUN_BANNER, CURATOR_PROMPT, DEDUP_MAX_PAIR_COMPARISONS, DEDUP_SIMILARITY_THRESHOLD, DEFAULT_ADMISSION, DEFAULT_ARCHIVE_AFTER_DAYS, DEFAULT_ARCHIVE_RETENTION_POLICY, DEFAULT_CITATION_POLICY, DEFAULT_CITATION_REF_BUDGET, DEFAULT_CONSOLIDATION_FAILURES, DEFAULT_CURATOR_BOOT_GRACE_SECONDS, DEFAULT_CURATOR_INTERVAL_HOURS, DEFAULT_CURATOR_MODEL, DEFAULT_CURATOR_REVIEW_MAX_TOKENS, DEFAULT_HEALTH_THRESHOLDS, DEFAULT_MAX_OPS_PER_PLAN, DEFAULT_MEMORY_CHAR_LIMIT, DEFAULT_MEMORY_REVIEW_MODEL, DEFAULT_MIN_IDLE_HOURS, DEFAULT_MUTATION_CAP, DEFAULT_PROBE_TIMEOUT_MS, DEFAULT_REFERENCE_REWRITE_POLICY, DEFAULT_REVIEW_CONTEXT_MESSAGES, DEFAULT_REVIEW_MEMORY_INTERVAL, DEFAULT_REVIEW_MESSAGE_CHARS, DEFAULT_REVIEW_SKILL_INTERVAL, DEFAULT_REVIEW_TIMEOUT_MS, DEFAULT_RUN_RECORDS, DEFAULT_SKILL_CONTENT_CHARS, DEFAULT_SKILL_LIMITS, DEFAULT_SKILL_REVIEW_COMPLETION_MIN_TOOL_CALLS, DEFAULT_SKILL_REVIEW_MODEL, DEFAULT_SKILL_REVIEW_TRIGGER, DEFAULT_SKILL_VERSION_KEEP, DEFAULT_STALE_AFTER_DAYS, DEFAULT_SUBSTANTIVE_MIN_AGENT_CHARS, DEFAULT_SUBSTANTIVE_MIN_TOOL_CALLS, DEFAULT_SUBSTANTIVE_MIN_USER_CHARS, DEFAULT_SUPPORT_FILE_CHAR_POLICY, DEFAULT_SUPPORT_READ_TOOL_NAMES, DEFAULT_THREAT_MAX_SCAN_CHARS, DEFAULT_USER_CHAR_LIMIT, DISPATCH_EVENT_TYPES, DRIFT_MAX_LINE_CHARS, DRIFT_SIGNALS_VERSION, DRIFT_SIGNAL_NOUNS, DSH_AUTHORING_STANDARDS, EMPTY_PATCH_SEED, ENTRY_DELIMITER, EVENT_ARCHIVE_PREFIX, EVENT_LOG_RETAIN_ARCHIVES, EVENT_LOG_ROTATE_AT, EVENT_LOG_VERSION, EVOLUTION_ERRORS, EVOLUTION_WRITE_TOOLS, EvolutionGateSet, FAMILY_SESSION_TOOL_NAMES, FORBIDDEN_CONTROL_KEYS, FUZZY_MAX_PATTERN_CHARS, FUZZY_MAX_WORK, HEALTH_STAMP_RE, HISTORY_DIR, HISTORY_INDEX_VERSION, HOOK_LINE_RE, INSTANCE_KEYS, KEEP_LINE_RE, LONG_RUNS, LOW_QUALITY_THRESHOLD, MAINTAIN_OUTPUT_INSTRUCTION, MAINTAIN_PROMPT, MAX_DESCRIPTION_LENGTH, MAX_REQUEST_BODY_BYTES, MAX_RESTRUCTURE_MOVES, MAX_SKILL_CONTENT_CHARS, MAX_SKILL_FILE_BYTES, MAX_SKILL_NAME_LENGTH, MAX_SUPPORT_READ_PATHS, MAX_TIMER_DELAY_MS, MEMORY_GUIDANCE_SECTION_ORDER, MEMORY_REVIEW_PROMPT, MIN_STAMP_BODY_CHARS, MUTATIONS_FILE_VERSION, MemoryStore, NAMESPACE_MIGRATIONS, NATIVE_CALL_EVENT, NATIVE_RESULT_EVENT, PARAM_ALIASES, PARAM_EXPOSURE, PARAM_GROUP_LABELS, PARAM_NAMESPACES, PATTERN_OVERLAP, PLATFORM_CATALOG_DESCRIPTION_DEFAULT, PLATFORM_ESTIMATE_CHARS_PER_TOKEN, PLATFORM_SERVICE_PROBES, POLICY_STAGE_DEFAULTS, PROMPT_BUNDLE, PROMPT_BUNDLE_ID, PROMPT_BUNDLE_VERSION, PROTECTED_BUILTIN_SKILLS, PTC_DISPATCH_EVENT, PTC_DISPATCH_START_EVENT, QUALITY_WEIGHTS, READ_REQUIRED_ACTIONS, RESTRUCTURE_TARGET_RE, RETENTION_FEEDBACK_KEEP_RATIO, RETENTION_FEEDBACK_MIN_CHARS, RULES, RUNS_SCHEMA_VERSION, SKILLS_GUIDANCE, SKILLS_GUIDANCE_SECTION_ORDER, SKILL_ACTION_REQUIRED_FIELDS, SKILL_NAME_RE, SKILL_REVIEW_PLAN_PROMPT, SKILL_REVIEW_PROMPT, SNAPSHOT_EXTRA_NAME_RE, SUMMARY_DUPLICATE_HINT_THRESHOLD, SUPPORT_DIRS, SUPPORT_SPRAWL_FILES, SUPPRESSED_FILE_VERSION, SkillLibrary, TEXT_DIFF_MAX_CHARS, TEXT_DIFF_MAX_LINES, THREAT_EXEMPTION_HINT, TOKEN_ASCII_WEIGHT, TOKEN_CJK_WEIGHT, ToolDispatchNormalizer, ToolDispatchPayloadError, UNTRUSTED_LINE_BREAK, UNTRUSTED_LINE_MARK, UPSTREAM_LIMIT_CHARS_PER_TOKEN, VERSION_SUMMARY_MAX_CHARS, absentHostServices, admissionVerdict, advanceReview, affinity, ageCopyKey, allowRowCollisions, anchorVerdict, appendEvolutionEvent, applyCuratorLifecycleFields, applyCuratorMetaFields, applyNamespaceMigration, applyReferenceRewrite, asRecord, assertDispatchPayload, assertSkillsRootAliasRetired, assessStructureHealth, atomicWriteFiles, authoringFeedback, basePresetPlugins, blobPath, bodyCost, buildCuratorRunReport, buildHealthBaseline, buildLearnPrompt, bumpPatch, bumpSupportRead, bumpUse, bumpView, callingScope, candidateSkills, canonicalWriteId, claimInstance, clampOnce, clampedNumber, classifyNamespaceMigration, clearReviewChannel, collectReadSkillNames, composePresetComposition, composePresetEntry, composePresetInsert, composePresetRow, compositionRowIds, computeDedupGroups, computeDriftSignals, computeLifecycleTransitions, computePrefixClusters, computeQualityScores, computeScopeView, contentHash, contentRetentionFeedback, countDispatches, countReferenceFiles, createGateSet, daysSinceIso, declaredReportStamp, denseBlockSequence, describeReferenceRewrite, diffFindings, dispatchKeyOf, dispatchStepOf, displayBodyOf, duplicateHeadings, elapsedSince, emptyRecord, entryTarget, errorText, evaluateThreat, eventsFile, evidenceKindIndex, evolutionActivityProjection, evolutionEventPayloadIssue, evolutionEvidenceProjection, evolutionHome, evolutionIoAdapter, evolutionReadsProjection, evolutionRoot, evolutionSignalsProjection, filterUnreadSkillOps, findDriftSignal, foldCuratorFields, foldToolDispatches, foldTurnEvent, foldTurnEvents, foldUntrustedLines, frontmatterBlock, frontmatterCatalogInvalid, fuzzyPatch, getRecord, h2Sections, historyIndexFile, historyRoot, identity, idleDays, initialTurnFold, installEvolutionProjections, instanceClaimKey, instanceClaimedWriteSites, instanceHolder, isAbsent, isBookkeepingFrame, isCommittedWarning, isDeprecatedParamId, isFileShapedPath, isLandmark, isLoopbackRequest, isMissingPath, isPresent, isProcessAlive, isProgramToolName, isRecord, isReviewChannelSession, isSkillReadToolName, isSkillToolName, isUnknown, isUnreadWrite, landmarkVerdict, latestActivityAt, latestVersionAt, lifecycleCandidate, lintBody, lintSkill, listDirectories, listEventArchives, liveBool, liveEnum, liveNumber, liveString, loadMutations, loadRowOverrides, loadSuppressedNames, loadUsage, loadVersionContent, loadVersions, makeSerialQueue, mapProbe, markAgentCreated, markReviewChannel, markerEntryName, memoryRoot, mergePresetRow, missingSupportPointers, mutateUsage, mutationsFile, narrowNameMatches, nearDuplicateSummaries, neutralizePromptVariables, newRunRegistry, newSkillLibrary, nextHistoryIndex, nodeEvolutionIo, normalizeFrontmatter, normalizeUsageRecord, normalizeVersionSummary, observeEvent, orderVersions, overlongLines, paramNamespace, paramRowId, paramSettingsId, parseCuratorNominations, parseEvolutionEvents, parseFrontmatter, parseHistoryIndex, partitionVersions, payloadText, persistedWriteSite, persistedWriteSites, pickWithPolicy, planNamespaceMigration, planReferenceRewrite, planRehoming, policyStageLimits, presetPatchText, presetRowBlock, presetRowBody, presetRowId, probeAbsent, probeDesktopScope, probeList, probeMtime, probePresent, probeReason, probeText, probeUnknown, projectionText, readDispatchSignal, readEvolutionEvents, readEvolutionTimeline, readHistoryIndex, readJsonBody, readJsonObject, readNumberParam, readParam, readingStats, recordMutation, recordVersions, redactSecrets, relatedSkillNames, releaseInstance, removePresetRow, renameWithRetry, renderCuratorReportMarkdown, renderLongRunTable, reportTime, reportsSweepLockTarget, resolveBasePresetPatch, resolveCitations, resolveExecOrigins, resolveOrigins, resolveParamId, resolveRootConfig, resolveSkillsRoot, resolveUnitMembers, resolveUnitMembersFromIndexes, restructureCandidates, retainEventArchives, retirementReport, reviewPrompt, rowBlockSpan, rowSiblingEnd, runsFile, saveSuppressedNames, saveUsage, scanBodyHooks, scanContentThreats, scanMemoryThreats, scanThreats, scopedProbeReport, sessionAudited, sessionEvidenceIndex, sessionLastEventTime, sessionReadNames, sessionReadSkillNames, sessionSeesFamilyTools, sessionTurnSignals, skillReadNameOf, skillRowCells, skillStateKey, skillsRoot, staleRouteStubs, supportFileReadOf, suppressedFile, sweepReports, sweepReviewChannelSessions, textDiffFacts, tokenLineFor, transactIo, transactTaskGuard, trimPatternBoundaries, trimTrailingBlankLines, unhookedSupportPointers, unitMembersAreComplete, unwrapLive, updateSuppressedNames, usageFile, usageObserved, userSetKeys, validateFrontmatter, validateRestructureTarget, valueOr, verifyPromptBundle, versionActionKind, versionRowCells, versionSummaryPrompt, versionTarget, vocabulary, writeDurableTmp, writeJson, writePathSymbols, yamlPlainScalarNeedsQuotes };
|
|
14707
|
+
export { AGENT_PRESET_PACKAGE, AGENT_PRESET_ROOT_HINT, AUTHORING_DESCRIPTION_BAR, AUTHORING_SPLIT_LINE_CHARS, BASELINE_ACTION, CITATION_SUPPORT_DIRS, COMBINED_REVIEW_PLAN_PROMPT, COMBINED_REVIEW_PROMPT, COMPLETION_SKILL_REVIEW_PROMPT, CONTENT_SPLIT_HINT, COST_ASCII_TOKEN_HIGH, COST_ASCII_TOKEN_LOW, COST_CJK_TOKEN_HIGH, COST_CJK_TOKEN_LOW, CURATOR_DRY_RUN_BANNER, CURATOR_PROMPT, DEDUP_MAX_PAIR_COMPARISONS, DEDUP_SIMILARITY_THRESHOLD, DEFAULT_ADMISSION, DEFAULT_ARCHIVE_AFTER_DAYS, DEFAULT_ARCHIVE_RETENTION_POLICY, DEFAULT_CITATION_POLICY, DEFAULT_CITATION_REF_BUDGET, DEFAULT_CONSOLIDATION_FAILURES, DEFAULT_CURATOR_BOOT_GRACE_SECONDS, DEFAULT_CURATOR_INTERVAL_HOURS, DEFAULT_CURATOR_MODEL, DEFAULT_CURATOR_REVIEW_MAX_TOKENS, DEFAULT_HEALTH_THRESHOLDS, DEFAULT_MAX_OPS_PER_PLAN, DEFAULT_MEMORY_CHAR_LIMIT, DEFAULT_MEMORY_REVIEW_MODEL, DEFAULT_MIN_IDLE_HOURS, DEFAULT_MUTATION_CAP, DEFAULT_PROBE_TIMEOUT_MS, DEFAULT_REFERENCE_REWRITE_POLICY, DEFAULT_REVIEW_CONTEXT_MESSAGES, DEFAULT_REVIEW_MEMORY_INTERVAL, DEFAULT_REVIEW_MESSAGE_CHARS, DEFAULT_REVIEW_SKILL_INTERVAL, DEFAULT_REVIEW_TIMEOUT_MS, DEFAULT_RUN_RECORDS, DEFAULT_SKILL_CONTENT_CHARS, DEFAULT_SKILL_LIMITS, DEFAULT_SKILL_REVIEW_COMPLETION_MIN_TOOL_CALLS, DEFAULT_SKILL_REVIEW_MODEL, DEFAULT_SKILL_REVIEW_TRIGGER, DEFAULT_SKILL_VERSION_KEEP, DEFAULT_STALE_AFTER_DAYS, DEFAULT_SUBSTANTIVE_MIN_AGENT_CHARS, DEFAULT_SUBSTANTIVE_MIN_TOOL_CALLS, DEFAULT_SUBSTANTIVE_MIN_USER_CHARS, DEFAULT_SUPPORT_FILE_CHAR_POLICY, DEFAULT_SUPPORT_READ_TOOL_NAMES, DEFAULT_THREAT_MAX_SCAN_CHARS, DEFAULT_USER_CHAR_LIMIT, DEFAULT_WRITE_CONFIRM_MODE, DEFAULT_WRITE_CONFIRM_TIMEOUT_SECONDS, DISPATCH_EVENT_TYPES, DRIFT_MAX_LINE_CHARS, DRIFT_SIGNALS_VERSION, DRIFT_SIGNAL_NOUNS, DSH_AUTHORING_STANDARDS, EMPTY_PATCH_SEED, ENTRY_DELIMITER, EVENT_ARCHIVE_PREFIX, EVENT_LOG_RETAIN_ARCHIVES, EVENT_LOG_ROTATE_AT, EVENT_LOG_VERSION, EVOLUTION_ERRORS, EVOLUTION_WRITE_TOOLS, EvolutionGateSet, FAMILY_SESSION_TOOL_NAMES, FORBIDDEN_CONTROL_KEYS, FUZZY_MAX_PATTERN_CHARS, FUZZY_MAX_WORK, HEALTH_STAMP_RE, HISTORY_DIR, HISTORY_INDEX_VERSION, HOOK_LINE_RE, INSTANCE_KEYS, KEEP_LINE_RE, LONG_RUNS, LOW_QUALITY_THRESHOLD, MAINTAIN_OUTPUT_INSTRUCTION, MAINTAIN_PROMPT, MAX_DESCRIPTION_LENGTH, MAX_REQUEST_BODY_BYTES, MAX_RESTRUCTURE_MOVES, MAX_SKILL_CONTENT_CHARS, MAX_SKILL_FILE_BYTES, MAX_SKILL_NAME_LENGTH, MAX_SUPPORT_READ_PATHS, MAX_TIMER_DELAY_MS, MEMORY_GUIDANCE_SECTION_ORDER, MEMORY_REVIEW_PROMPT, MIN_STAMP_BODY_CHARS, MUTATIONS_FILE_VERSION, MemoryStore, NAMESPACE_MIGRATIONS, NATIVE_CALL_EVENT, NATIVE_RESULT_EVENT, PARAM_ALIASES, PARAM_EXPOSURE, PARAM_GROUP_LABELS, PARAM_NAMESPACES, PATTERN_OVERLAP, PLATFORM_CATALOG_DESCRIPTION_DEFAULT, PLATFORM_ESTIMATE_CHARS_PER_TOKEN, PLATFORM_SERVICE_PROBES, POLICY_STAGE_DEFAULTS, PROMPT_BUNDLE, PROMPT_BUNDLE_ID, PROMPT_BUNDLE_VERSION, PROTECTED_BUILTIN_SKILLS, PTC_DISPATCH_EVENT, PTC_DISPATCH_START_EVENT, QUALITY_WEIGHTS, READ_REQUIRED_ACTIONS, RESTRUCTURE_TARGET_RE, RETENTION_FEEDBACK_KEEP_RATIO, RETENTION_FEEDBACK_MIN_CHARS, RULES, RUNS_SCHEMA_VERSION, SKILLS_GUIDANCE, SKILLS_GUIDANCE_SECTION_ORDER, SKILL_ACTION_REQUIRED_FIELDS, SKILL_NAME_RE, SKILL_REVIEW_PLAN_PROMPT, SKILL_REVIEW_PROMPT, SNAPSHOT_EXTRA_NAME_RE, STORE_LEDGER, SUMMARY_DUPLICATE_HINT_THRESHOLD, SUPPORT_DIRS, SUPPORT_SPRAWL_FILES, SUPPRESSED_FILE_VERSION, SkillLibrary, TEXT_DIFF_MAX_CHARS, TEXT_DIFF_MAX_LINES, THREAT_EXEMPTION_HINT, TOKEN_ASCII_WEIGHT, TOKEN_CJK_WEIGHT, ToolDispatchNormalizer, ToolDispatchPayloadError, UNTRUSTED_LINE_BREAK, UNTRUSTED_LINE_MARK, UPSTREAM_LIMIT_CHARS_PER_TOKEN, VERSION_SUMMARY_MAX_CHARS, absentHostServices, admissionVerdict, advanceReview, affinity, ageCopyKey, allowRowCollisions, anchorVerdict, appendEvolutionEvent, applyCuratorLifecycleFields, applyCuratorMetaFields, applyNamespaceMigration, applyReferenceRewrite, asRecord, assertDispatchPayload, assertSkillsRootAliasRetired, assessStructureHealth, atomicWriteFiles, authoringFeedback, authorityFrom, backupsReachability, basePresetPlugins, blobPath, bodyCost, buildCuratorRunReport, buildHealthBaseline, buildLearnPrompt, bumpPatch, bumpSupportRead, bumpUse, bumpView, callingScope, candidateSkills, canonicalWriteId, claimInstance, clampOnce, clampedNumber, classifyNamespaceMigration, clearReviewChannel, collectReadSkillNames, composePresetComposition, composePresetEntry, composePresetInsert, composePresetRow, compositionRowIds, computeDedupGroups, computeDriftSignals, computeLifecycleTransitions, computePrefixClusters, computeQualityScores, computeScopeView, contentHash, contentRetentionFeedback, countDispatches, countReferenceFiles, createGateSet, daysSinceIso, declaredReportStamp, denseBlockSequence, describeReferenceRewrite, diffFindings, dispatchKeyOf, dispatchStepOf, displayBodyOf, duplicateHeadings, elapsedSince, emptyRecord, entryTarget, errorText, evaluateThreat, eventsFile, evidenceKindIndex, evolutionActivityProjection, evolutionEventPayloadIssue, evolutionEvidenceProjection, evolutionHome, evolutionIoAdapter, evolutionReadsProjection, evolutionRoot, evolutionSignalsProjection, filterUnreadSkillOps, findDriftSignal, foldCuratorFields, foldToolDispatches, foldTurnEvent, foldTurnEvents, foldUntrustedLines, frontmatterBlock, frontmatterCatalogInvalid, fuzzyPatch, getRecord, h2Sections, historyIndexFile, historyReachability, historyRoot, identity, idleDays, initialTurnFold, installEvolutionProjections, instanceClaimKey, instanceClaimedWriteSites, instanceHolder, isAbsent, isBookkeepingFrame, isCommittedWarning, isDeprecatedParamId, isFileShapedPath, isLandmark, isLoopbackRequest, isMissingPath, isPresent, isProcessAlive, isProgramToolName, isRecord, isReviewChannelSession, isSkillReadToolName, isSkillToolName, isUnknown, isUnreadWrite, landmarkVerdict, latestActivityAt, latestVersionAt, lifecycleCandidate, lintBody, lintSkill, listDirectories, listEventArchives, liveBool, liveEnum, liveNumber, liveString, loadMutations, loadRowOverrides, loadSuppressedNames, loadUsage, loadVersionContent, loadVersions, makeSerialQueue, mapProbe, markAgentCreated, markReviewChannel, markerEntryName, memoryRoot, mergePresetRow, missingSupportPointers, mutateUsage, mutationsFile, narrowNameMatches, nearDuplicateSummaries, neutralizePromptVariables, newRunRegistry, newSkillLibrary, nextHistoryIndex, nodeEvolutionIo, normalizeFrontmatter, normalizeUsageRecord, normalizeVersionSummary, observeEvent, orderVersions, overlongLines, paramNamespace, paramRowId, paramSettingsId, parseCuratorNominations, parseEvolutionEvents, parseFrontmatter, parseHistoryIndex, partitionVersions, payloadText, persistedWriteSite, persistedWriteSites, pickWithPolicy, planNamespaceMigration, planReferenceRewrite, planRehoming, policyStageLimits, presetPatchText, presetRowBlock, presetRowBody, presetRowId, probeAbsent, probeDesktopScope, probeList, probeMtime, probePresent, probeReason, probeText, probeUnknown, projectionText, protectedSkillNamesOf, readDispatchSignal, readEvolutionEvents, readEvolutionTimeline, readHistoryIndex, readJsonBody, readJsonObject, readNumberParam, readParam, readingStats, recordMutation, recordVersions, redactSecrets, referencedBlobs, relatedSkillNames, releaseInstance, removePresetRow, renameWithRetry, renderCuratorReportMarkdown, renderLongRunTable, reportTime, reportsReachability, reportsSweepLockTarget, resolveBasePresetPatch, resolveCitations, resolveExecOrigins, resolveOrigins, resolveParamId, resolveRootConfig, resolveSkillsRoot, resolveUnitMembers, resolveUnitMembersFromIndexes, restructureCandidates, retainEventArchives, retirementReport, reviewPrompt, rowBlockSpan, rowSiblingEnd, runWriteGates, runsFile, saveSuppressedNames, saveUsage, scanBodyHooks, scanContentThreats, scanMemoryThreats, scanThreats, scopeOfNearestManifest, scopedPackageName, scopedProbeReport, sessionAudited, sessionEvidenceIndex, sessionLastEventTime, sessionReadNames, sessionReadSkillNames, sessionSeesFamilyTools, sessionTurnSignals, skillReadNameOf, skillRowCells, skillStateKey, skillWriteGateContext, skillsRoot, staleRouteStubs, supportFileReadOf, suppressedFile, sweepReports, sweepReviewChannelSessions, textDiffFacts, tokenLineFor, transactIo, transactTaskGuard, trimPatternBoundaries, trimTrailingBlankLines, unhookedSupportPointers, unitMembersAreComplete, unwrapLive, updateSuppressedNames, usageFile, usageObserved, userSetKeys, validateFrontmatter, validateRestructureTarget, valueOr, verifyPromptBundle, versionActionKind, versionRowCells, versionSummaryPrompt, versionTarget, vocabulary, withTreeWrite, writeDurableTmp, writeJson, writePathSymbols, yamlPlainScalarNeedsQuotes };
|