wicked-crew-api-types 0.25.0 → 0.29.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/index.d.ts +547 -4
- package/package.json +1 -1
package/index.d.ts
CHANGED
|
@@ -1156,8 +1156,15 @@ export interface ConformanceRule {
|
|
|
1156
1156
|
excludes?: string[];
|
|
1157
1157
|
/** Ordering within a severity band + gate priority. Engine default: 1.0. */
|
|
1158
1158
|
weight?: number;
|
|
1159
|
-
/**
|
|
1160
|
-
|
|
1159
|
+
/**
|
|
1160
|
+
* Enforcement half (from the retired policy model). Absent ⇒ the rule is RECALL-ONLY: it is
|
|
1161
|
+
* surfaced to workers but never enters decide()/select(), so it can neither block a gate nor
|
|
1162
|
+
* `catch` an eval sample — which is why a store of effect-less rules evals to "every bad
|
|
1163
|
+
* sample is a gap" (api-types 0.27.0, the #394/#395 companion). `deny` blocks (the only effect
|
|
1164
|
+
* the evals credit as a catch); `warn` surfaces without blocking (the operator-authorable
|
|
1165
|
+
* middle band); `allow_with_conditions` permits with obligations; `allow` permits outright.
|
|
1166
|
+
*/
|
|
1167
|
+
effect?: 'deny' | 'warn' | 'allow_with_conditions' | 'allow';
|
|
1161
1168
|
trigger?: { contains?: string };
|
|
1162
1169
|
obligations?: string[];
|
|
1163
1170
|
/** The frozen acceptance-criteria text (becomes a claim's `criteria` when the rule decides a gate). */
|
|
@@ -1319,6 +1326,380 @@ export interface SteeringLandingResult {
|
|
|
1319
1326
|
error?: string;
|
|
1320
1327
|
}
|
|
1321
1328
|
|
|
1329
|
+
// ── Skills — the daemon-owned garden plugin root, published as immutable snapshots (api-types 0.28.0) ──
|
|
1330
|
+
//
|
|
1331
|
+
// api-types 0.29.0 (design amendment v3.6, crew #490): the installer-managed copy
|
|
1332
|
+
// `<config dir>/plugins/wicked-garden` is a LAST-resort seed source — `SkillSourceKind` gains
|
|
1333
|
+
// `installer-copy`, and `DiagnosticsSkillsFinding.kind` gains the persistent `skills.source` warning
|
|
1334
|
+
// and the fail-closed `skills.manifest` error.
|
|
1335
|
+
//
|
|
1336
|
+
// Skills are files (skills keystone, design v3 + amendments v3.1/v3.2). The daemon owns ONE
|
|
1337
|
+
// effective `wicked-garden`-shaped plugin root — `<state home>/skills/effective/`, the dependency
|
|
1338
|
+
// closure of the installed plugin: `.claude-plugin/{plugin.json,archetypes.json,components.json}`,
|
|
1339
|
+
// `skills/**` (nested layout verbatim), `scripts/**` minus CI + dev tools, `schemas/`,
|
|
1340
|
+
// `docs/examples/`, `pyproject.toml`, `uv.lock` — seeded from the LIVE installed plugin into a
|
|
1341
|
+
// content-addressed `baseline/<contentHash>/`. The operator edits files in place, replaces a
|
|
1342
|
+
// skill, adds one, disables one (manifest state — the files stay), resets one (content from the
|
|
1343
|
+
// baseline; never enablement). Nothing a worker runs is read from `effective/`: PUBLISHING
|
|
1344
|
+
// validates the whole tree and writes an IMMUTABLE, read-only `snapshots/<gen>/` (enabled skills
|
|
1345
|
+
// only, closure included, `snapshot.json`, and the generated delivery views —
|
|
1346
|
+
// `views/copilot/.github/skills/<name>/` holding the enabled PORTABLE skills, part of the content
|
|
1347
|
+
// hash), then flips `current -> snapshots/<gen>`; the engine receives the resolved snapshot path
|
|
1348
|
+
// as `WICKED_SKILLS_SNAPSHOT`. The daemon NEVER writes into the user's own CLI directories
|
|
1349
|
+
// (`~/.codex`, `~/.pi`, `~/.copilot`, `~/.config/opencode`, `~/.claude`): skills reach non-Claude
|
|
1350
|
+
// workers only through per-launch, wicked-owned delivery core performs from the snapshot (v3.2) —
|
|
1351
|
+
// a CLI without a lever (codex today) runs without wicked skills, and a unit on such a seat that
|
|
1352
|
+
// requires one is REFUSED at launch (no proceed-with-disclosure setting exists).
|
|
1353
|
+
// `/skills` is a file manager whose EVERY mutation is CAS-guarded (`expectedRevision`) and
|
|
1354
|
+
// answers 2xx `{verdict, findings[], revision}` — a `blocked` verdict is a normal response,
|
|
1355
|
+
// including a publish refused because one is in flight (`publish-in-flight`) or aborted because the
|
|
1356
|
+
// root changed under it (`root-changed`), neither of which wrote anything. 409 (`{error, revision}`)
|
|
1357
|
+
// is EXCLUSIVELY a stale `expectedRevision` (a CAS conflict).
|
|
1358
|
+
|
|
1359
|
+
/** What a skill IS, from its frontmatter — fork-first: `context: fork` → fork worker (a subagent
|
|
1360
|
+
* body); else `user-invocable: true` → router (an operator-facing entry point); else module (a
|
|
1361
|
+
* nested reference skill routers/workers pull in). */
|
|
1362
|
+
export type SkillKind = 'router' | 'fork-worker' | 'module';
|
|
1363
|
+
|
|
1364
|
+
/** `shipped` = every own file byte-identical to the baseline; `override` = a shipped skill with
|
|
1365
|
+
* edited/replaced files; `user-added` = no baseline (added through the API, or upstream dropped
|
|
1366
|
+
* it while the operator's edits were kept). */
|
|
1367
|
+
export type SkillProvenance = 'shipped' | 'override' | 'user-added';
|
|
1368
|
+
|
|
1369
|
+
/** Where a baseline was captured from. `claude-plugin-cache` is the marketplace cache
|
|
1370
|
+
* (`<config dir>/plugins/cache/wicked-garden/wicked-garden/<version>` — the plugin Claude Code
|
|
1371
|
+
* runs); `installer-copy` is the installer-managed `<config dir>/plugins/wicked-garden` copy
|
|
1372
|
+
* (`npx wicked-installer install wicked-garden`), accepted only as the LAST resort when no cache
|
|
1373
|
+
* exists (design v3.6, api-types 0.29.0) and flagged by the `skills.source` diagnostics finding
|
|
1374
|
+
* while it is the current baseline; `checkout` is a git working tree; `directory` any other
|
|
1375
|
+
* explicit plugin-shaped directory. */
|
|
1376
|
+
export type SkillSourceKind = 'claude-plugin-cache' | 'installer-copy' | 'checkout' | 'directory';
|
|
1377
|
+
|
|
1378
|
+
/** The per-baseline `uv sync` state (`<baseline>/.venv`, provisioned once per content hash — the
|
|
1379
|
+
* publish that needs it AWAITS it — and shared read-only by every snapshot that links it):
|
|
1380
|
+
* `pending` until a successful publish records it, `synced` on success (the snapshot carries a
|
|
1381
|
+
* `.venv` link), `skipped` when the bundle carries no `pyproject.toml` (nothing to provision; no
|
|
1382
|
+
* link). `failed` (uv missing or a sync error) is BLOCKING for the publish (`venv-failed`) and is
|
|
1383
|
+
* therefore never the recorded state of a published baseline — the record keeps its previous
|
|
1384
|
+
* value; a later publish retries. */
|
|
1385
|
+
export type SkillVenvState = 'pending' | 'synced' | 'failed' | 'skipped';
|
|
1386
|
+
|
|
1387
|
+
/** One captured baseline — keyed in `SkillManifest.baselines` by the content hash of its bundle
|
|
1388
|
+
* (sorted relative paths + sha256 digests), never by the version string alone: two installs of
|
|
1389
|
+
* "12.32.0" with different bytes are two baselines. */
|
|
1390
|
+
export interface SkillBaselineRecord {
|
|
1391
|
+
/** `version` from the source's `.claude-plugin/plugin.json`. */
|
|
1392
|
+
plugin_version: string;
|
|
1393
|
+
source: { kind: SkillSourceKind; path: string };
|
|
1394
|
+
/** HEAD sha for a `checkout` source; `null` otherwise (or when git could not answer). */
|
|
1395
|
+
git_sha: string | null;
|
|
1396
|
+
/** ISO-8601 instant the baseline was captured. */
|
|
1397
|
+
captured_at: string;
|
|
1398
|
+
venv: SkillVenvState;
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
export interface SkillEntry {
|
|
1402
|
+
/** Plugin-relative directory, nested layout preserved (`skills/engineering/frontend`). Never
|
|
1403
|
+
* renamed — sibling `../` links depend on it. */
|
|
1404
|
+
dir: string;
|
|
1405
|
+
kind: SkillKind;
|
|
1406
|
+
/** Core-by-reference: in the registered-reference closure — a `skill_ref` of a workflow the
|
|
1407
|
+
* daemon knows (core drop-ins, crew-generated, user-registered) or a skill one of those names in
|
|
1408
|
+
* its SKILL.md (repo-learn → search, mem). Disabling or renaming it is blocking. */
|
|
1409
|
+
core: boolean;
|
|
1410
|
+
/** `false` when the skill's files resolve `${CLAUDE_PLUGIN_ROOT}`, invoke a script relative to
|
|
1411
|
+
* the cwd (`python3 -u scripts/x.py`, `./scripts/x`, …), or link `../` — Claude-only by nature:
|
|
1412
|
+
* excluded from the snapshot's `views/copilot/` and from the per-launch skill lists core builds
|
|
1413
|
+
* for the other CLIs. `portable` is the admission key for every non-Claude view (design v3.2). */
|
|
1414
|
+
portable: boolean;
|
|
1415
|
+
/** Manifest state, orthogonal to content: a disabled skill's files stay in `effective/` and are
|
|
1416
|
+
* excluded from the next published snapshot. Reset never flips it. */
|
|
1417
|
+
enabled: boolean;
|
|
1418
|
+
provenance: SkillProvenance;
|
|
1419
|
+
/** ISO-8601 instant of the last edit/replace/add through the API; `null` when untouched. */
|
|
1420
|
+
editedAt: string | null;
|
|
1421
|
+
/** A refreshed baseline changed a file this skill overrides — the new side is readable as
|
|
1422
|
+
* `?side=baseline` for diffing; the operator's content is kept. */
|
|
1423
|
+
upgradeAvailable: boolean;
|
|
1424
|
+
/** `upgradeAvailable`, or the last refresh found a name collision (upstream now ships a skill
|
|
1425
|
+
* under this user-added name at another dir). Cleared by reset / a later refresh. */
|
|
1426
|
+
conflict: boolean;
|
|
1427
|
+
/** The held-back UPSTREAM skill's directory in the current baseline when the last refresh found a
|
|
1428
|
+
* name collision (upstream ships this name at another dir than the operator's skill); `null`
|
|
1429
|
+
* otherwise. `GET /skills/:name/files/*path?side=baseline` reads THIS directory for such a skill,
|
|
1430
|
+
* so the two sides of the collision are comparable — the answer's `path` names the file actually
|
|
1431
|
+
* read (api-types 0.28.0). Re-derived by every refresh. */
|
|
1432
|
+
upstreamDir: string | null;
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
/** One managed file (plugin-relative path → hashes). `baselineHash` `null` = user-added file;
|
|
1436
|
+
* `effectiveHash` `null` = a baseline file absent from `effective/` (removed by a direct
|
|
1437
|
+
* filesystem edit — reset restores it; the skill reads `override` until then). */
|
|
1438
|
+
export interface SkillFileRecord {
|
|
1439
|
+
baselineHash: string | null;
|
|
1440
|
+
effectiveHash: string | null;
|
|
1441
|
+
/** The hash this file had in the most recent published snapshot; `null` = never published. */
|
|
1442
|
+
lastPublishedHash: string | null;
|
|
1443
|
+
/** The last refresh saw BOTH sides change (kept the effective side). */
|
|
1444
|
+
conflict: boolean;
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1447
|
+
/** The most recent publish. */
|
|
1448
|
+
export interface SkillPublishedRecord {
|
|
1449
|
+
gen: number;
|
|
1450
|
+
/** Hash over the snapshot's files (sorted relative paths + sha256 digests), `snapshot.json` excluded. */
|
|
1451
|
+
contentHash: string;
|
|
1452
|
+
/** ISO-8601 instant. */
|
|
1453
|
+
at: string;
|
|
1454
|
+
/** sha256 of the exact `snapshot.json` bytes publish wrote. `snapshot.json` is excluded from the
|
|
1455
|
+
* content hash, so the crew-owned manifest AUTHENTICATES it: `current` verifies only the
|
|
1456
|
+
* generation this record names, with metadata hashing to this value (api-types 0.28.0). */
|
|
1457
|
+
snapshotHash: string;
|
|
1458
|
+
}
|
|
1459
|
+
|
|
1460
|
+
/** `<skills root>/manifest.json` — the state of the daemon-owned root. (The v3 mirror ledger is
|
|
1461
|
+
* withdrawn with the mirror — design v3.2 §1: the daemon never writes into the user's CLI dirs.) */
|
|
1462
|
+
export interface SkillManifest {
|
|
1463
|
+
version: 2;
|
|
1464
|
+
/** Monotonic; bumped by EVERY mutation. Every mutating request carries it as `expectedRevision`. */
|
|
1465
|
+
revision: number;
|
|
1466
|
+
/** Content hash of the current baseline (`baseline/<hash>/`). */
|
|
1467
|
+
baseline: string;
|
|
1468
|
+
baselines: Record<string, SkillBaselineRecord>;
|
|
1469
|
+
/** Keyed by frontmatter `name` (`wicked-garden-<dir segments joined by '-'>`). */
|
|
1470
|
+
skills: Record<string, SkillEntry>;
|
|
1471
|
+
/** Every managed file under `effective/`, plugin-relative. */
|
|
1472
|
+
files: Record<string, SkillFileRecord>;
|
|
1473
|
+
published: SkillPublishedRecord | null;
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1476
|
+
/** `GET /skills` 200 body. 503 when the root is not seeded (no installed plugin was found) or when
|
|
1477
|
+
* `current` exists but fails verification (realpath outside `snapshots/`, malformed
|
|
1478
|
+
* `snapshot.json`, content hash mismatch) — a corrupt root is a loud error, never an empty catalog. */
|
|
1479
|
+
export interface SkillsManifestResponse {
|
|
1480
|
+
manifest: SkillManifest;
|
|
1481
|
+
revision: number;
|
|
1482
|
+
/** The resolved skills root on the daemon host (`<state home>/skills` by default). */
|
|
1483
|
+
root: string;
|
|
1484
|
+
/** The VERIFIED published snapshot `current` resolves to, or `null` before the first publish.
|
|
1485
|
+
* `path` is the absolute REAL path of `snapshots/<gen>` — byte-identical to the one input the
|
|
1486
|
+
* engine is handed (`WICKED_SKILLS_SNAPSHOT`; design v3.1 §2). */
|
|
1487
|
+
current: { gen: number; path: string } | null;
|
|
1488
|
+
}
|
|
1489
|
+
|
|
1490
|
+
export interface SkillFileEntry {
|
|
1491
|
+
/** POSIX path relative to the skill dir. */
|
|
1492
|
+
path: string;
|
|
1493
|
+
size: number;
|
|
1494
|
+
sha256: string;
|
|
1495
|
+
/** This file's manifest record (`null` for a file present on disk but not yet recorded). */
|
|
1496
|
+
record: SkillFileRecord | null;
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1499
|
+
/** `GET /skills/:name/files` 200 body — the skill's OWN files (a nested skill's files are its own). */
|
|
1500
|
+
export interface SkillFileTree {
|
|
1501
|
+
name: string;
|
|
1502
|
+
dir: string;
|
|
1503
|
+
enabled: boolean;
|
|
1504
|
+
files: SkillFileEntry[];
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
/** `GET /skills/:name/files/*path` and `GET /skills/support/*path` 200 body — a typed, capped read.
|
|
1508
|
+
* Save is disabled on `truncated` or `binary`. `?side=baseline` reads the baseline copy instead
|
|
1509
|
+
* (the "new side" of a refresh conflict). */
|
|
1510
|
+
export interface SkillReadResult {
|
|
1511
|
+
/** Plugin-relative path served. */
|
|
1512
|
+
path: string;
|
|
1513
|
+
/** UTF-8 text — the first 512 KB when `truncated`; `null` when `binary` (there is no text to show). */
|
|
1514
|
+
content: string | null;
|
|
1515
|
+
/** The file's FULL size in bytes. */
|
|
1516
|
+
size: number;
|
|
1517
|
+
truncated: boolean;
|
|
1518
|
+
binary: boolean;
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1521
|
+
export type SkillFindingKind =
|
|
1522
|
+
| 'name-invalid'
|
|
1523
|
+
| 'name-collision'
|
|
1524
|
+
| 'name-mismatch'
|
|
1525
|
+
| 'frontmatter-invalid'
|
|
1526
|
+
| 'missing-skill-md'
|
|
1527
|
+
| 'unregistered-skill'
|
|
1528
|
+
| 'nested-skill-create'
|
|
1529
|
+
| 'core-disable'
|
|
1530
|
+
| 'core-rename'
|
|
1531
|
+
| 'core-missing'
|
|
1532
|
+
| 'support-file-edit'
|
|
1533
|
+
| 'non-portable'
|
|
1534
|
+
/** A `${CLAUDE_PLUGIN_ROOT}/<p>` or `../<p>` reference in an enabled skill's files that does not
|
|
1535
|
+
* resolve inside the would-be snapshot. Severity follows the TARGET (design v3.4 §1): a reference
|
|
1536
|
+
* that ESCAPES the plugin root (`..` climbing out — it reaches whatever lies beside the snapshot on
|
|
1537
|
+
* the worker host) is `blocking`; one whose target is MISSING (it normalizes inside the root but
|
|
1538
|
+
* the snapshot does not carry it — a file the bundle omits, or a skill that is disabled) is a
|
|
1539
|
+
* `warning`: a content bug the skill's author owns, published as found — a publish with only
|
|
1540
|
+
* warnings answers `verdict: 'warnings'` with the findings AND a written snapshot (api-types
|
|
1541
|
+
* 0.28.0). */
|
|
1542
|
+
| 'unresolved-ref'
|
|
1543
|
+
/** A path the store refuses BY NAME rather than reads through: a shape that could leave its root
|
|
1544
|
+
* (`..`, an absolute piece), a component that crosses a symlink, or — under `effective/`, where
|
|
1545
|
+
* every entry is classified — a symlink or a special node (socket, fifo, device) anywhere,
|
|
1546
|
+
* the contents of a pruned directory (`.venv`, `node_modules`, `__pycache__`) INCLUDED: such a
|
|
1547
|
+
* directory is never copied or hashed, but what it holds is still judged, and a link inside one
|
|
1548
|
+
* blocks with the reason (a provisioned environment lives under `baseline/`, not the editable
|
|
1549
|
+
* root). Blocking; `file` names the entry, `skill` its owning skill when it has one. */
|
|
1550
|
+
| 'path-invalid'
|
|
1551
|
+
| 'unknown-skill'
|
|
1552
|
+
| 'no-baseline'
|
|
1553
|
+
| 'fs-drift'
|
|
1554
|
+
| 'refresh-conflict'
|
|
1555
|
+
| 'empty-snapshot'
|
|
1556
|
+
/** `.claude-plugin/plugin.json`, `archetypes.json` or `components.json` is absent from `effective/`
|
|
1557
|
+
* — the plugin manifest + the runtime catalogs are REQUIRED snapshot members (blocking at
|
|
1558
|
+
* publish; api-types 0.28.0). */
|
|
1559
|
+
| 'missing-plugin-manifest'
|
|
1560
|
+
/** The plugin manifest or a runtime catalog is present but not what its reader expects — does
|
|
1561
|
+
* not parse as JSON, is not a JSON object, or `archetypes.json` lacks its `archetypes`
|
|
1562
|
+
* collection (blocking at publish; api-types 0.28.0). A manifest without `name` is
|
|
1563
|
+
* `name-mismatch`. */
|
|
1564
|
+
| 'catalog-invalid'
|
|
1565
|
+
/** The baseline's shared read-only Python env could not be provisioned (uv missing, `uv sync`
|
|
1566
|
+
* failed, or the env could not be locked) while the bundle carries a `pyproject.toml` — the env
|
|
1567
|
+
* is REQUIRED, so the publish is blocked and nothing (the provisioning state included) is
|
|
1568
|
+
* persisted (api-types 0.28.0). */
|
|
1569
|
+
| 'venv-failed'
|
|
1570
|
+
/** A publish was refused because one is already running (one at a time) — nothing was written, so
|
|
1571
|
+
* it is a 2xx `blocked` envelope, not a 409 (409 is only a stale `expectedRevision`; api-types
|
|
1572
|
+
* 0.28.0). Re-read `GET /skills` and retry against the revision it answers. */
|
|
1573
|
+
| 'publish-in-flight'
|
|
1574
|
+
/** A publish was aborted because the skills root changed under it — nothing was written to either
|
|
1575
|
+
* root; a 2xx `blocked` envelope (api-types 0.28.0). Re-read `GET /skills` and retry. */
|
|
1576
|
+
| 'root-changed'
|
|
1577
|
+
/** A path outside the bundle closure — the ONE allowlist of what the seed copies, what the support
|
|
1578
|
+
* API may address, and what a snapshot may carry: the five runtime catalogs under `.claude-plugin`
|
|
1579
|
+
* BY NAME (`plugin.json`, `archetypes.json`, `components.json`, `specialist.json`,
|
|
1580
|
+
* `stack-registry.json` — `marketplace.json`, a publish-time listing, is outside), everything under
|
|
1581
|
+
* `skills`, `schemas` and `docs/examples`, everything under `scripts` except the `ci` and `wg`
|
|
1582
|
+
* directories and any `wg-`-prefixed dev tooling, plus `pyproject.toml` and `uv.lock`. A support
|
|
1583
|
+
* add/PUT there is a 2xx `blocked` envelope (nothing written); a file found there under
|
|
1584
|
+
* `effective/` at publish/analyze (a direct filesystem edit) is a BLOCKING finding naming the path
|
|
1585
|
+
* — a snapshot never ships it (api-types 0.28.0). */
|
|
1586
|
+
| 'outside-closure'
|
|
1587
|
+
/** A content-addressed `baseline/<hash>` whose tree does not hash to its name (a bundle file
|
|
1588
|
+
* modified, planted or removed, or a symlink inside), or a baseline file whose bytes do not match
|
|
1589
|
+
* the hash the manifest recorded for it. Baselines are re-verified before EVERY reuse: a refresh
|
|
1590
|
+
* refuses to reuse it (2xx `blocked`, nothing copied), reset refuses to restore from it (nothing
|
|
1591
|
+
* written), publish/analyze report it blocking (before AND after the env was provisioned in it).
|
|
1592
|
+
* Read-only mode bits on the baseline are a guard, never the integrity boundary — the hash is
|
|
1593
|
+
* (api-types 0.28.0). */
|
|
1594
|
+
| 'baseline-corrupt';
|
|
1595
|
+
|
|
1596
|
+
export type SkillFindingSeverity = 'warning' | 'blocking';
|
|
1597
|
+
|
|
1598
|
+
/** `blocked` = at least one blocking finding (nothing was written / published); `warnings` =
|
|
1599
|
+
* proceeded with warnings; `clear` = nothing to say. */
|
|
1600
|
+
export type SkillVerdict = 'clear' | 'warnings' | 'blocked';
|
|
1601
|
+
|
|
1602
|
+
export interface SkillConflictFinding {
|
|
1603
|
+
kind: SkillFindingKind;
|
|
1604
|
+
severity: SkillFindingSeverity;
|
|
1605
|
+
/** The skill this finding is about, or `null` for a catalog / support-file finding. */
|
|
1606
|
+
skill: string | null;
|
|
1607
|
+
/** Plugin-relative file the finding names, or `null`. */
|
|
1608
|
+
file: string | null;
|
|
1609
|
+
/** 1-based line in `file`, when the finding is anchored to one. */
|
|
1610
|
+
line: number | null;
|
|
1611
|
+
/** The OTHER catalog skill this finding is against (a collision, a core guard), or `null`. */
|
|
1612
|
+
againstSkill: string | null;
|
|
1613
|
+
againstIsCore: boolean;
|
|
1614
|
+
/** The concrete fact (names, paths, the parse error). */
|
|
1615
|
+
evidence: string;
|
|
1616
|
+
/** Why it matters. */
|
|
1617
|
+
explanation: string;
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1620
|
+
/** `POST /skills/analyze` 200 body (a PURE dry run of the publish validation: nothing persisted,
|
|
1621
|
+
* `revision` unchanged — drift it observes is reported, and recorded only by the publish that
|
|
1622
|
+
* ships it) — and the base of every mutation result. */
|
|
1623
|
+
export interface SkillAnalyzeResult {
|
|
1624
|
+
verdict: SkillVerdict;
|
|
1625
|
+
findings: SkillConflictFinding[];
|
|
1626
|
+
revision: number;
|
|
1627
|
+
}
|
|
1628
|
+
|
|
1629
|
+
/** Every `/skills` mutation's 200 body. `blocked` ⇒ nothing was written and `revision` is unchanged. */
|
|
1630
|
+
export interface SkillMutationResult extends SkillAnalyzeResult {
|
|
1631
|
+
skill?: SkillEntry & { name: string };
|
|
1632
|
+
}
|
|
1633
|
+
|
|
1634
|
+
/** `POST /skills/publish` 200 body. `snapshot` is `null` when the verdict is `blocked` — and then
|
|
1635
|
+
* `revision` is unchanged (a blocked publish persists nothing — not the drift it observed, not the
|
|
1636
|
+
* baseline's provisioning state). `path` is the absolute REAL path of the locked, read-only
|
|
1637
|
+
* generation; its `snapshot.json` carries the skill rows and the `views` block (`views.copilot`:
|
|
1638
|
+
* the `views/copilot` dir + the portable skills laid out in it). One publish runs at a time — a
|
|
1639
|
+
* concurrent one wrote nothing and answers a 2xx `blocked` `publish-in-flight` envelope
|
|
1640
|
+
* (`snapshot: null`), not a 409. */
|
|
1641
|
+
export interface SkillPublishResult extends SkillAnalyzeResult {
|
|
1642
|
+
snapshot: { gen: number; path: string; contentHash: string; skills: number } | null;
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1645
|
+
/** `POST /skills/refresh-baseline` 200 body — the three-way merge per FILE (baseline_old /
|
|
1646
|
+
* baseline_new / effective): unchanged → take new; user-modified & upstream-unchanged → keep;
|
|
1647
|
+
* both changed → keep + `conflict` (new side readable as `?side=baseline`); user-DELETED &
|
|
1648
|
+
* upstream-changed → the deletion is kept + `conflict` (a deletion is a modification; reset
|
|
1649
|
+
* restores upstream); upstream-deleted & user-unmodified → remove; upstream-deleted &
|
|
1650
|
+
* user-modified → keep as user-added; a new upstream skill whose path-derived name is a
|
|
1651
|
+
* user-added skill's → conflict. 502 when no plugin is installed. */
|
|
1652
|
+
export interface SkillRefreshResult extends SkillAnalyzeResult {
|
|
1653
|
+
previous_baseline: string;
|
|
1654
|
+
baseline: string;
|
|
1655
|
+
plugin_version: string;
|
|
1656
|
+
/** Skills whose files were replaced from the new baseline. */
|
|
1657
|
+
taken: string[];
|
|
1658
|
+
/** Skills that kept operator content (upstream unchanged, or a flagged conflict). */
|
|
1659
|
+
kept: string[];
|
|
1660
|
+
added: string[];
|
|
1661
|
+
removed: string[];
|
|
1662
|
+
/** Skills flagged `conflict` by this refresh. */
|
|
1663
|
+
conflicts: string[];
|
|
1664
|
+
}
|
|
1665
|
+
|
|
1666
|
+
/** The 409 body of a `/skills` mutation whose `expectedRevision` is stale — a CAS conflict, the
|
|
1667
|
+
* ONLY thing that answers 409. A publish refused because another is in flight, or aborted because
|
|
1668
|
+
* the skills root changed under it, wrote nothing and instead answers a 2xx `blocked` findings
|
|
1669
|
+
* envelope (`publish-in-flight` / `root-changed`; api-types 0.28.0), never a 409. */
|
|
1670
|
+
export interface SkillRevisionConflict {
|
|
1671
|
+
error: string;
|
|
1672
|
+
/** The current revision — re-read `GET /skills` (or use this) and retry. */
|
|
1673
|
+
revision: number;
|
|
1674
|
+
}
|
|
1675
|
+
|
|
1676
|
+
/** The body of `POST /skills/:name/{enable,disable,reset}`, `POST /skills/publish` and
|
|
1677
|
+
* `POST /skills/refresh-baseline`. */
|
|
1678
|
+
export interface SkillRevisionBody {
|
|
1679
|
+
expectedRevision: number;
|
|
1680
|
+
}
|
|
1681
|
+
|
|
1682
|
+
/** `PUT /skills/:name/files/*path` and `PUT /skills/support/*path` body. `content` is UTF-8 text,
|
|
1683
|
+
* at most 512 KB. */
|
|
1684
|
+
export interface PutSkillFileBody {
|
|
1685
|
+
content: string;
|
|
1686
|
+
expectedRevision: number;
|
|
1687
|
+
}
|
|
1688
|
+
|
|
1689
|
+
/** `POST /skills` body — add a user skill. `files` maps skill-relative POSIX paths to UTF-8 text
|
|
1690
|
+
* and must include `SKILL.md`; the skill lands at `skills/<name minus "wicked-garden-">`. */
|
|
1691
|
+
export interface AddSkillBody {
|
|
1692
|
+
name: string;
|
|
1693
|
+
files: Record<string, string>;
|
|
1694
|
+
expectedRevision: number;
|
|
1695
|
+
}
|
|
1696
|
+
|
|
1697
|
+
/** `POST /skills/:name/replace` body — replace the skill's OWN files wholesale (nested skills untouched). */
|
|
1698
|
+
export interface ReplaceSkillBody {
|
|
1699
|
+
files: Record<string, string>;
|
|
1700
|
+
expectedRevision: number;
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1322
1703
|
// ── Governance wiki management (scoreboard + meta) ─────────────────────────────
|
|
1323
1704
|
|
|
1324
1705
|
/**
|
|
@@ -1465,7 +1846,17 @@ export interface GovernanceEvalNearestRule {
|
|
|
1465
1846
|
* remediation pointer for "which rule needs sharpening".
|
|
1466
1847
|
*/
|
|
1467
1848
|
export interface GovernanceEvalResult {
|
|
1468
|
-
sample: Pick<GovernanceEvalSample, 'id' | 'description' | 'kind' | 'steering_type'
|
|
1849
|
+
sample: Pick<GovernanceEvalSample, 'id' | 'description' | 'kind' | 'steering_type'> & {
|
|
1850
|
+
/**
|
|
1851
|
+
* The sample's PAYLOAD identity — `sha256:` over the canonical JSON of its full payload (id,
|
|
1852
|
+
* description, kind, steering_type, signals). The engine echoes only the four fields above
|
|
1853
|
+
* (input `signals` never ride a result row), so this is stamped by a PRODUCER that held the
|
|
1854
|
+
* samples it staged (the internal-corpus `run`); a row without it cannot be proven to be the
|
|
1855
|
+
* same action as a row with the same id in another run, and the offline comparison reports
|
|
1856
|
+
* such a pair as unverified rather than comparable.
|
|
1857
|
+
*/
|
|
1858
|
+
payload_hash?: string;
|
|
1859
|
+
};
|
|
1469
1860
|
expected: 'deny' | 'allow';
|
|
1470
1861
|
fired: string[];
|
|
1471
1862
|
verdict: 'caught' | 'gap' | 'false_positive';
|
|
@@ -1480,15 +1871,73 @@ export interface GovernanceEvalSummary {
|
|
|
1480
1871
|
false_positives: number;
|
|
1481
1872
|
}
|
|
1482
1873
|
|
|
1874
|
+
/**
|
|
1875
|
+
* One steering rule in the judged store that NO sample of the run exercised — the inverse blind
|
|
1876
|
+
* spot of `summary.gaps` (core #394): a gap is a sample nothing caught, but a rule with zero
|
|
1877
|
+
* exercising samples produces no result row at all and so is invisible to the summary. Each
|
|
1878
|
+
* entry names the rule and the Steering sub-page it belongs to, so the corpus can grow a sample
|
|
1879
|
+
* for it (or the rule can be retired as untestable).
|
|
1880
|
+
*/
|
|
1881
|
+
export interface GovernanceEvalUnexercisedRule {
|
|
1882
|
+
rule_id: string;
|
|
1883
|
+
steering_type: SteeringType;
|
|
1884
|
+
}
|
|
1885
|
+
|
|
1886
|
+
/**
|
|
1887
|
+
* One steering type's row of {@link GovernanceEvalRuleCoverage.per_type} (evals.rs `TypeCoverage`):
|
|
1888
|
+
* how many of the run's eligible decide-lane rules OF THAT TYPE fired for at least one sample, and
|
|
1889
|
+
* how many fired for none. `unexercised` here is a COUNT — the ids are the parent's `unexercised`
|
|
1890
|
+
* list, whose rows each carry their `steering_type`, so the two reconcile per type.
|
|
1891
|
+
*/
|
|
1892
|
+
export interface GovernanceEvalTypeCoverage {
|
|
1893
|
+
exercised: number;
|
|
1894
|
+
unexercised: number;
|
|
1895
|
+
}
|
|
1896
|
+
|
|
1897
|
+
/**
|
|
1898
|
+
* Rule-side coverage of an eval run (core #394/#395 — evals.rs `RuleCoverage`): the decide-lane
|
|
1899
|
+
* rules ELIGIBLE for the run (every active effect-bearing rule, narrowed to the run's `--type`
|
|
1900
|
+
* slice when one was given) partitioned into `exercised` (fired — blocking or not — for at least
|
|
1901
|
+
* one sample; a COUNT) and `unexercised` (fired for none; the ids, each with its steering type).
|
|
1902
|
+
* Together with `summary` it separates "the corpus lacks a behavior" from "the store lacks a rule"
|
|
1903
|
+
* — the two readings a bare gap count conflates. `recall_only` counts the active rules in the slice
|
|
1904
|
+
* carrying NO effect — outside the partition because the gate never fires them (core #395).
|
|
1905
|
+
* `per_type` is the same partition per steering type — all seven keys, zeros included (the engine
|
|
1906
|
+
* pins the shape).
|
|
1907
|
+
*
|
|
1908
|
+
* Every engine that emits `rule_coverage` at all (core #394 onward) serializes all four fields on
|
|
1909
|
+
* every report (serde, no skip). `recall_only` and `per_type` are declared optional on the CONTRACT
|
|
1910
|
+
* only because the daemon persists a run's coverage VERBATIM and validates none of its fields, so a
|
|
1911
|
+
* stored record is exactly as complete as its producer made it and the contract never promises what
|
|
1912
|
+
* was never checked: a consumer reads an absent `per_type` as "the engine reports no per-type
|
|
1913
|
+
* coverage" (the offline comparison says exactly that), never as zeros. `exercised` and
|
|
1914
|
+
* `unexercised` are required — no engine ever emitted one without the other.
|
|
1915
|
+
*
|
|
1916
|
+
* A run's `results[].fired` is NOT this partition's evidence: `fired` is the BLOCKING subset of the
|
|
1917
|
+
* firings, and under a type filter it may name rules of OTHER types — the filter slices the samples
|
|
1918
|
+
* and this denominator, never the gate (evals.rs `run_evals` / `evaluate_sample`).
|
|
1919
|
+
*/
|
|
1920
|
+
export interface GovernanceEvalRuleCoverage {
|
|
1921
|
+
exercised: number;
|
|
1922
|
+
unexercised: GovernanceEvalUnexercisedRule[];
|
|
1923
|
+
recall_only?: number;
|
|
1924
|
+
per_type?: Record<SteeringType, GovernanceEvalTypeCoverage>;
|
|
1925
|
+
}
|
|
1926
|
+
|
|
1483
1927
|
/**
|
|
1484
1928
|
* The `POST /testing/evals/run` 200 body — the engine's serde report passed through VERBATIM
|
|
1485
1929
|
* (snake_case field names, `degraded` spelled `null` when the run was full-fidelity;
|
|
1486
|
-
* `'facet-only'` when the
|
|
1930
|
+
* `'facet-only'` when the gap-hint embedder was unavailable and hints fell back to lexical
|
|
1931
|
+
* matching — the verdicts are the same either way, only `nearest_rules` degrades).
|
|
1932
|
+
*
|
|
1933
|
+
* `rule_coverage` is OPTIONAL on purpose: an engine that predates core #394 emits a report
|
|
1934
|
+
* without it, and that report still validates — the daemon never fabricates the field.
|
|
1487
1935
|
*/
|
|
1488
1936
|
export interface GovernanceEvalReport {
|
|
1489
1937
|
results: GovernanceEvalResult[];
|
|
1490
1938
|
summary: GovernanceEvalSummary;
|
|
1491
1939
|
degraded: 'facet-only' | null;
|
|
1940
|
+
rule_coverage?: GovernanceEvalRuleCoverage;
|
|
1492
1941
|
}
|
|
1493
1942
|
|
|
1494
1943
|
/** The `POST /testing/corpora/import` request body — a named eval corpus for later runs. */
|
|
@@ -1553,6 +2002,12 @@ export interface EvalRunSummary {
|
|
|
1553
2002
|
per_type: Partial<Record<SteeringType, EvalRunPerTypeCount>>;
|
|
1554
2003
|
/** `'facet-only'` when the run degraded to facet matching; null when it ran full-fidelity. */
|
|
1555
2004
|
degraded: 'facet-only' | null;
|
|
2005
|
+
/**
|
|
2006
|
+
* The report's {@link GovernanceEvalReport.rule_coverage}, persisted VERBATIM (like `degraded`,
|
|
2007
|
+
* never recomputed daemon-side). ABSENT — not null — when the engine that ran the eval predates
|
|
2008
|
+
* core #394 and emitted no coverage, so a history row honestly shows which runs measured it.
|
|
2009
|
+
*/
|
|
2010
|
+
rule_coverage?: GovernanceEvalRuleCoverage;
|
|
1556
2011
|
}
|
|
1557
2012
|
|
|
1558
2013
|
/**
|
|
@@ -1963,6 +2418,15 @@ export interface SystemSettings {
|
|
|
1963
2418
|
* the engine default `~/.wicked-worker`.
|
|
1964
2419
|
*/
|
|
1965
2420
|
worker_config_root?: string;
|
|
2421
|
+
/*
|
|
2422
|
+
* There is NO skills setting (skills keystone, api-types 0.28.0). The daemon-owned skills root is
|
|
2423
|
+
* `<state home>/skills` — the directory holding `manifest.json`, `baseline/<hash>/`, `effective/`,
|
|
2424
|
+
* `snapshots/<gen>/` and the `current` symlink — full stop: not configurable (a `skills_root` a
|
|
2425
|
+
* client sends is dropped and named in the audit entry's `ignored`; design v3.1 §1 one storage
|
|
2426
|
+
* root, v3.2 §1 never a user CLI directory), and there is no mirror knob either (the daemon never
|
|
2427
|
+
* writes into the user's own CLI directories). `GET /skills` → `root` and `GET /diagnostics` →
|
|
2428
|
+
* `skills.root` report where it is.
|
|
2429
|
+
*/
|
|
1966
2430
|
/**
|
|
1967
2431
|
* The repo-scoped launch delivery DEFAULT (crew#393; api-types 0.18.0, additive). What a
|
|
1968
2432
|
* `POST /runs` with `repoRef` + a CODE-WORK `workflow` (a def with at least one
|
|
@@ -2246,6 +2710,32 @@ export interface InteractiveDocDeleteResponse {
|
|
|
2246
2710
|
ledger: InteractiveDocDeleteLedgerReport;
|
|
2247
2711
|
}
|
|
2248
2712
|
|
|
2713
|
+
/**
|
|
2714
|
+
* One row of `GET /projects/:projectId/interactive/api/docs` (crew#472) — the bridge's own
|
|
2715
|
+
* `GET /api/docs` row (interactive's `listDocs` shape, relayed field-for-field) stamped with the
|
|
2716
|
+
* project whose mount it was listed under. Docs roots are partitioned per project (the `default`
|
|
2717
|
+
* project keeps the legacy shared root), so `projectId` is the attribution a client rendering
|
|
2718
|
+
* docs from several projects at once cannot otherwise recover.
|
|
2719
|
+
*/
|
|
2720
|
+
export interface InteractiveDocSummary {
|
|
2721
|
+
/** The doc name (slug). */
|
|
2722
|
+
name: string;
|
|
2723
|
+
/** Manifest `kind`; a manifest without one lists as `doc`. */
|
|
2724
|
+
kind: 'doc' | 'html' | 'source' | 'demo';
|
|
2725
|
+
/** Head version. */
|
|
2726
|
+
head: number;
|
|
2727
|
+
/** Lineage size. */
|
|
2728
|
+
versions: number;
|
|
2729
|
+
/** ISO-8601 timestamp of the head version, or null when the lineage is empty. */
|
|
2730
|
+
updated_at: string | null;
|
|
2731
|
+
/** Present only on a retired (tombstoned) row, which lists only with `?includeRetired=1`. */
|
|
2732
|
+
retired?: true;
|
|
2733
|
+
/** ISO-8601 retirement timestamp; present with `retired`. */
|
|
2734
|
+
retired_at?: string;
|
|
2735
|
+
/** The crew project this row was listed under — the mount's `:projectId`. */
|
|
2736
|
+
projectId: string;
|
|
2737
|
+
}
|
|
2738
|
+
|
|
2249
2739
|
/**
|
|
2250
2740
|
* One normalized entry of the merged project activity feed
|
|
2251
2741
|
* (`GET /projects/:id/activity`, ADR §5.2): core events of member runs/chats
|
|
@@ -2881,6 +3371,59 @@ export interface DiagnosticsResponse {
|
|
|
2881
3371
|
/** Bounded tail of the daemon's own error-level log lines, newest first. */
|
|
2882
3372
|
recentErrors: DiagnosticsRecentError[];
|
|
2883
3373
|
acp: AcpDiagnostics;
|
|
3374
|
+
/** The skills seam's last outcome (api-types 0.28.0) — see `DiagnosticsSkills`. */
|
|
3375
|
+
skills: DiagnosticsSkills;
|
|
3376
|
+
}
|
|
3377
|
+
|
|
3378
|
+
/** The skills seam's state as `GET /diagnostics` reports it (skills keystone, api-types 0.28.0). */
|
|
3379
|
+
export type DiagnosticsSkillsState = 'published' | 'fallback' | 'blocked' | 'config-error' | 'disabled';
|
|
3380
|
+
|
|
3381
|
+
/** One finding the skills degradation ladder produced (design v3 §3). */
|
|
3382
|
+
export interface DiagnosticsSkillsFinding {
|
|
3383
|
+
/** `skills.fallback` = no wicked-garden installed (engine input left unset / restored to the boot
|
|
3384
|
+
* value — the engine resolves the live cache itself); `skills.blocked` = the first publish is
|
|
3385
|
+
* blocked (engine input points at a non-existent refusal path — launches fail loudly until the
|
|
3386
|
+
* catalog is fixed); `skills.config` = the configured root is corrupt/unusable (same refusal;
|
|
3387
|
+
* `error`), or — as a `warning` on the `published` state — the root lies OUTSIDE the daemon
|
|
3388
|
+
* state home, so core's fence cross-check (`WICKED_CREW_STATE_HOME`) refuses every launch;
|
|
3389
|
+
* `skills.source` (`warning`, api-types 0.29.0, design v3.6) = the CURRENT baseline was seeded
|
|
3390
|
+
* from the installer-managed copy (`SkillSourceKind` `installer-copy`) — the daemon works, but
|
|
3391
|
+
* that copy receives no marketplace updates until the plugin is registered with Claude Code; it
|
|
3392
|
+
* persists (alongside the ladder's own finding, if any) until a refresh from the marketplace
|
|
3393
|
+
* cache re-records the baseline's provenance (byte-identical or not); `skills.manifest`
|
|
3394
|
+
* (`error`, api-types 0.29.0) = `manifest.json` could not be read when diagnostics were taken
|
|
3395
|
+
* (corrupt, unreadable, or the root no longer the one the store bound) — reported as
|
|
3396
|
+
* `config-error` with the cause instead of the stale boot outcome; the exported engine input is
|
|
3397
|
+
* unchanged until the daemon restarts. */
|
|
3398
|
+
kind: 'skills.fallback' | 'skills.blocked' | 'skills.config' | 'skills.source' | 'skills.manifest';
|
|
3399
|
+
severity: 'warning' | 'error';
|
|
3400
|
+
message: string;
|
|
3401
|
+
}
|
|
3402
|
+
|
|
3403
|
+
/**
|
|
3404
|
+
* `GET /diagnostics` → `skills`: whether the engine is being handed a verified snapshot, and if not,
|
|
3405
|
+
* why — the one read-only answer to "why do launches refuse the skills snapshot". `disabled` is a
|
|
3406
|
+
* daemon booted without the seam (the manifest collector, some tests).
|
|
3407
|
+
*/
|
|
3408
|
+
export interface DiagnosticsSkills {
|
|
3409
|
+
state: DiagnosticsSkillsState;
|
|
3410
|
+
/** The resolved skills root on the daemon host; `null` when `disabled`. */
|
|
3411
|
+
root: string | null;
|
|
3412
|
+
/** The VERIFIED published snapshot (`current` realpath-contained, `snapshot.json` + content hash
|
|
3413
|
+
* checked), or `null`. `path` is the absolute REAL path of `snapshots/<gen>`. */
|
|
3414
|
+
current: { gen: number; path: string } | null;
|
|
3415
|
+
/** What `WICKED_SKILLS_SNAPSHOT` — the engine's ONE skills input (v3.1 §2, v3.4 §2;
|
|
3416
|
+
* `WICKED_SKILLS_CURRENT` is never set, `WICKED_CREW_STATE_HOME` is not exported) — is exported as
|
|
3417
|
+
* right now: the real snapshot path, a `<root>/refused/…` refusal path, `""` when the process
|
|
3418
|
+
* booted with an explicitly EMPTY value (preserved — a configuration error core refuses, state
|
|
3419
|
+
* `config-error`; design v3.5 §4), or `null` = unset. */
|
|
3420
|
+
engineInput: string | null;
|
|
3421
|
+
/** DIAGNOSTICS-ONLY: the canonical realpath of the daemon state home, reported for humans. It is
|
|
3422
|
+
* NOT an engine input — `WICKED_CREW_STATE_HOME` is retired (v3.4 §2): core reads only
|
|
3423
|
+
* `WICKED_SKILLS_SNAPSHOT` and derives the state home from its `<state home>/skills/snapshots/<gen>`
|
|
3424
|
+
* layout. `null` only when `disabled`. */
|
|
3425
|
+
stateHome: string | null;
|
|
3426
|
+
findings: DiagnosticsSkillsFinding[];
|
|
2884
3427
|
}
|
|
2885
3428
|
|
|
2886
3429
|
// ── Memory proposal queue (DES-MEM-FACETED-001 §5.0, api-types 0.21.0) ─────────
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wicked-crew-api-types",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.29.0",
|
|
4
4
|
"description": "The wire contract of the wicked-crew daemon's /api/v1 REST surface and /ws CoreEvent frames \u2014 types only, zero runtime",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "./index.d.ts",
|