@wairon/cli 5.1.1-dev.40 → 5.1.1-dev.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/cli/index.js +58 -8
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +16 -8
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -175,6 +175,7 @@ See [docs/cli.md](docs/cli.md). Summary:
|
|
|
175
175
|
| `wairon domains list \| scan \| add \| remove` | Domains (subsystem-derived + free-standing) |
|
|
176
176
|
| `wairon skills list \| install` | Manage the SDD skills installed into your tools |
|
|
177
177
|
| `wairon lock [-y]` | Validate the tree as-complete and freeze it (generates the implementer agents) |
|
|
178
|
+
| `wairon lock-check [--strict]` | Merge gate: is the design in this tree the design that was approved? Importable as a [reusable workflow](.github/workflows/lock-check.yml) |
|
|
178
179
|
| `wairon mcp serve \| install \| status` | The wairon MCP server (`sdd_*` tools) |
|
|
179
180
|
| `wairon serve [--port] [--data-dir] [--no-auth]` | Self-host: HTTP MCP for many isolated projects + admin plane |
|
|
180
181
|
| `wairon host project \| key \| lock \| promote` | Administer the hosting server (projects, keys, state-scoped lock/promote) |
|
package/dist/cli/index.js
CHANGED
|
@@ -65,7 +65,7 @@ var init_defaults = __esm({
|
|
|
65
65
|
copilot: ".github/prompts",
|
|
66
66
|
codex: ".codex/agents"
|
|
67
67
|
};
|
|
68
|
-
WAIRON_VERSION = "5.1.1-dev.
|
|
68
|
+
WAIRON_VERSION = "5.1.1-dev.41";
|
|
69
69
|
GITHUB_REPO = "SYW-Apps/Waffle-AIron";
|
|
70
70
|
SUPPORTED_ALIASES = ["wai"];
|
|
71
71
|
SCAN_EXCLUDE_DIRS = /* @__PURE__ */ new Set([
|
|
@@ -3136,6 +3136,10 @@ var init_budget_policy = __esm({
|
|
|
3136
3136
|
function canonicalize(value) {
|
|
3137
3137
|
return JSON.stringify(sortKeys(value));
|
|
3138
3138
|
}
|
|
3139
|
+
function compareOrdinal(a, b) {
|
|
3140
|
+
if (a < b) return -1;
|
|
3141
|
+
return a > b ? 1 : 0;
|
|
3142
|
+
}
|
|
3139
3143
|
function sortKeys(v) {
|
|
3140
3144
|
if (Array.isArray(v)) return v.map(sortKeys);
|
|
3141
3145
|
if (v && typeof v === "object") {
|
|
@@ -3156,14 +3160,17 @@ var init_canonical_json = __esm({
|
|
|
3156
3160
|
});
|
|
3157
3161
|
|
|
3158
3162
|
// src/core/statehash.ts
|
|
3163
|
+
function inIdentityOrder(specs) {
|
|
3164
|
+
return specs.map((spec) => ({ spec, content: canonicalize(spec) })).sort((a, b) => compareOrdinal(a.spec.id, b.spec.id) || compareOrdinal(a.content, b.content)).map((entry) => entry.spec);
|
|
3165
|
+
}
|
|
3159
3166
|
function computeStateId() {
|
|
3160
3167
|
const tree = {
|
|
3161
3168
|
system: loadSystemSpec(),
|
|
3162
|
-
subsystems: loadSubsystemSpecs(),
|
|
3163
|
-
components: loadComponentSpecs(),
|
|
3164
|
-
interfaces: loadInterfaceSpecs(),
|
|
3165
|
-
implementations: loadImplementationSpecs(),
|
|
3166
|
-
types: loadTypeSpecs()
|
|
3169
|
+
subsystems: inIdentityOrder(loadSubsystemSpecs()),
|
|
3170
|
+
components: inIdentityOrder(loadComponentSpecs()),
|
|
3171
|
+
interfaces: inIdentityOrder(loadInterfaceSpecs()),
|
|
3172
|
+
implementations: inIdentityOrder(loadImplementationSpecs()),
|
|
3173
|
+
types: inIdentityOrder(loadTypeSpecs())
|
|
3167
3174
|
};
|
|
3168
3175
|
const digest2 = crypto.createHash("sha256").update(canonicalize(tree)).digest("hex");
|
|
3169
3176
|
return { algorithm: CONTENT_ALGORITHM, digest: digest2 };
|
|
@@ -8426,7 +8433,7 @@ function discoverPacks(dir) {
|
|
|
8426
8433
|
return [];
|
|
8427
8434
|
}
|
|
8428
8435
|
const refs = [];
|
|
8429
|
-
for (const e of entries.sort((a, b) => a.name
|
|
8436
|
+
for (const e of entries.sort((a, b) => compareOrdinal(a.name, b.name))) {
|
|
8430
8437
|
const full = path12.join(dir, e.name);
|
|
8431
8438
|
if (e.isDirectory()) {
|
|
8432
8439
|
if (packDirEntry(full)) refs.push(full);
|
|
@@ -8716,6 +8723,7 @@ var init_extensions = __esm({
|
|
|
8716
8723
|
init_fs();
|
|
8717
8724
|
init_project_config();
|
|
8718
8725
|
init_version();
|
|
8726
|
+
init_canonical_json();
|
|
8719
8727
|
init_project();
|
|
8720
8728
|
init_packstore();
|
|
8721
8729
|
ProfileDefSchema = import_zod9.z.object({
|
|
@@ -22436,7 +22444,7 @@ var init_core = __esm({
|
|
|
22436
22444
|
|
|
22437
22445
|
// src/core/rules/gate-identity.ts
|
|
22438
22446
|
function doctrineIdentity(doctrine, builtinRules, gate) {
|
|
22439
|
-
const byKey = (items, key) => [...items].sort((a, b) => key(a)
|
|
22447
|
+
const byKey = (items, key) => [...items].sort((a, b) => compareOrdinal(key(a), key(b)));
|
|
22440
22448
|
return {
|
|
22441
22449
|
/**
|
|
22442
22450
|
* The BUILTIN rule set, by identity rather than by wairon version.
|
|
@@ -30445,6 +30453,37 @@ var path35 = __toESM(require("path"));
|
|
|
30445
30453
|
init_core();
|
|
30446
30454
|
init_fs();
|
|
30447
30455
|
init_validation();
|
|
30456
|
+
function checkApproval(strict) {
|
|
30457
|
+
if (!loadSystemSpec()) {
|
|
30458
|
+
return {
|
|
30459
|
+
state: "no-tree",
|
|
30460
|
+
approved: !strict,
|
|
30461
|
+
message: strict ? "No SDD spec tree here (.wai/specs) \u2014 and --strict asks for an approved design, so this is a failure. Run `wairon init` to start one, or drop --strict." : "No SDD spec tree here (.wai/specs) \u2014 there is no design to approve, so nothing is gated."
|
|
30462
|
+
};
|
|
30463
|
+
}
|
|
30464
|
+
const lock = readLockState(computeGateStateId());
|
|
30465
|
+
const record2 = lock.record;
|
|
30466
|
+
switch (lock.state) {
|
|
30467
|
+
case "locked":
|
|
30468
|
+
return {
|
|
30469
|
+
state: "locked",
|
|
30470
|
+
approved: true,
|
|
30471
|
+
message: `The design in this tree is the approved design \u2014 approved ${record2.lockedAt} by ${describeApprover(record2.lockedBy)}.`
|
|
30472
|
+
};
|
|
30473
|
+
case "stale":
|
|
30474
|
+
return {
|
|
30475
|
+
state: "stale",
|
|
30476
|
+
approved: false,
|
|
30477
|
+
message: `The design changed after it was approved (the approval on record is ${record2.lockedAt} by ${describeApprover(record2.lockedBy)}). Nothing says a human has seen what is about to merge. Fix: run \`wairon lock\` on this branch and commit the updated .wai/lock.json.`
|
|
30478
|
+
};
|
|
30479
|
+
default:
|
|
30480
|
+
return {
|
|
30481
|
+
state: "unlocked",
|
|
30482
|
+
approved: !strict,
|
|
30483
|
+
message: strict ? "No approval on record (.wai/lock.json is absent), and --strict asks for one. Run `wairon lock` and commit the record." : "No approval on record (.wai/lock.json is absent) \u2014 this project has not opted into the approval gate, so nothing is gated. Run `wairon lock` and commit the record to turn it on, or pass --strict to fail here instead."
|
|
30484
|
+
};
|
|
30485
|
+
}
|
|
30486
|
+
}
|
|
30448
30487
|
async function runLock(options = {}, gate) {
|
|
30449
30488
|
const diff = diffAgainstApproval();
|
|
30450
30489
|
if (!diff) {
|
|
@@ -47147,6 +47186,17 @@ async function statusCommand(opts) {
|
|
|
47147
47186
|
}
|
|
47148
47187
|
await runStatus({ subsystem: opts.subsystem, recursive: opts.recursive });
|
|
47149
47188
|
}
|
|
47189
|
+
async function lockCheckCommand(opts) {
|
|
47190
|
+
const verdict = checkApproval(opts.strict === true);
|
|
47191
|
+
if (!verdict.approved) logger.error(verdict.message);
|
|
47192
|
+
else if (verdict.state === "locked") logger.success(verdict.message);
|
|
47193
|
+
else logger.info(verdict.message);
|
|
47194
|
+
if (verdict.approved) return;
|
|
47195
|
+
process.exit(1);
|
|
47196
|
+
}
|
|
47197
|
+
program.command("lock-check").description("Merge gate: is the design in this working tree the design that was approved? Compares the tree's gate identity against the committed .wai/lock.json. Exits 1 when the design moved past its approval; passes with a notice when the project never locked, unless --strict.").option("--strict", "also fail when nothing was ever approved, or when there is no spec tree at all").action(async (opts) => {
|
|
47198
|
+
await lockCheckCommand(opts);
|
|
47199
|
+
});
|
|
47150
47200
|
program.command("lock").description("Final check before implementation: validate the spec tree as complete, freeze all specs to complete, and (re)generate the agent topology \u2014 only if it validates. In an attached checkout, locks the hosted project instead.").option("-y, --yes", "skip the confirmation prompt (for scripts / CI)").option("--subsystem <id>", "only lock specs in the specified subsystem").option("--no-recursive", "do not recursively validate subprojects").action(async (opts) => {
|
|
47151
47201
|
await lockCommand(opts);
|
|
47152
47202
|
});
|