@wairon/cli 5.0.2-dev.15 → 5.0.2-dev.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +93 -24
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +14 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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.0.2-dev.
|
|
68
|
+
WAIRON_VERSION = "5.0.2-dev.16";
|
|
69
69
|
GITHUB_REPO = "SYW-Apps/Waffle-AIron";
|
|
70
70
|
ARCHITECT_AGENT_ID = "agent-architect";
|
|
71
71
|
ARCHITECT_TEMPLATE_ID = "architect";
|
|
@@ -8012,11 +8012,15 @@ function projectSubsystemSurface(subsystemId) {
|
|
|
8012
8012
|
const interfaces = loadInterfaceSpecs();
|
|
8013
8013
|
const types = loadTypeSpecs();
|
|
8014
8014
|
const entries = [];
|
|
8015
|
+
const unprojectable = [];
|
|
8015
8016
|
for (const pub of target.publicInterfaces ?? []) {
|
|
8016
8017
|
if (!pub.component) continue;
|
|
8017
8018
|
const comp = components.find((c) => c.id === pub.component || c.id === `${subsystemId}::${pub.component}`);
|
|
8018
8019
|
if (!comp) continue;
|
|
8019
|
-
if (comp.componentType
|
|
8020
|
+
if (!CROSS_BOUNDARY_TARGETS.has(comp.componentType)) {
|
|
8021
|
+
unprojectable.push({ component: pub.component, componentType: comp.componentType });
|
|
8022
|
+
continue;
|
|
8023
|
+
}
|
|
8020
8024
|
const compInterfaces = interfaces.filter((i) => i.component === comp.id && (!pub.interface || i.id === pub.interface || i.id === `${subsystemId}::${pub.interface}`));
|
|
8021
8025
|
const methods = compInterfaces.flatMap((i) => i.methods);
|
|
8022
8026
|
entries.push({
|
|
@@ -8030,13 +8034,18 @@ function projectSubsystemSurface(subsystemId) {
|
|
|
8030
8034
|
component: localName(comp.id),
|
|
8031
8035
|
methods,
|
|
8032
8036
|
...comp.dispatch && comp.dispatch.length ? { dispatch: comp.dispatch } : {},
|
|
8033
|
-
// Project the backing
|
|
8037
|
+
// Project the backing component's auth + basePath so the codec can emit
|
|
8034
8038
|
// OpenAPI security + per-portal servers self-contained from the snapshot.
|
|
8035
8039
|
...comp.auth && comp.auth.scheme !== "none" ? { auth: comp.auth } : {},
|
|
8036
8040
|
...comp.basePath ? { basePath: comp.basePath } : {},
|
|
8037
8041
|
details: pub.details ?? ""
|
|
8038
8042
|
});
|
|
8039
8043
|
}
|
|
8044
|
+
for (const skipped of unprojectable) {
|
|
8045
|
+
console.error(
|
|
8046
|
+
`[surfaces] skipped "${subsystemId}::${skipped.component}": a published ${skipped.componentType} can never serve a cross-boundary caller, so it stays out of every chained child's sibling surface \u2014 publish this surface through a Portal, a Gateway, or an Observer (for events).`
|
|
8047
|
+
);
|
|
8048
|
+
}
|
|
8040
8049
|
return SurfaceSnapshotSchema.parse({
|
|
8041
8050
|
projectName: `${system.name}::${subsystemId}`,
|
|
8042
8051
|
origin: "generated",
|
|
@@ -8215,7 +8224,7 @@ function checkChildSurfaceFreshness(rootDir = getProjectRoot()) {
|
|
|
8215
8224
|
}
|
|
8216
8225
|
return issues;
|
|
8217
8226
|
}
|
|
8218
|
-
var fs9, path10, SURFACES_DIRNAME;
|
|
8227
|
+
var fs9, path10, SURFACES_DIRNAME, CROSS_BOUNDARY_TARGETS;
|
|
8219
8228
|
var init_surfaces = __esm({
|
|
8220
8229
|
"src/core/surfaces.ts"() {
|
|
8221
8230
|
"use strict";
|
|
@@ -8230,6 +8239,7 @@ var init_surfaces = __esm({
|
|
|
8230
8239
|
init_type_analysis();
|
|
8231
8240
|
init_openapi();
|
|
8232
8241
|
SURFACES_DIRNAME = "surfaces";
|
|
8242
|
+
CROSS_BOUNDARY_TARGETS = /* @__PURE__ */ new Set(["Portal", "Gateway", "Observer"]);
|
|
8233
8243
|
}
|
|
8234
8244
|
});
|
|
8235
8245
|
|
|
@@ -27490,9 +27500,14 @@ function lockProject(cfg, credential, project2) {
|
|
|
27490
27500
|
}
|
|
27491
27501
|
return executeApprovedLock(cfg, project2);
|
|
27492
27502
|
}
|
|
27493
|
-
function
|
|
27503
|
+
function boundLifecycleRoot(cfg, projectId, subproject) {
|
|
27494
27504
|
const root = existingProjectRoot(cfg.dataDir, projectId);
|
|
27495
27505
|
if (!root) throw new Error(`Unknown project "${projectId}".`);
|
|
27506
|
+
if (!subproject) return root;
|
|
27507
|
+
return resolveSubprojectMounts(projectId, root, subproject.split(SUBPROJECT_SEPARATOR));
|
|
27508
|
+
}
|
|
27509
|
+
function executeApprovedLock(cfg, projectId, subproject) {
|
|
27510
|
+
const root = boundLifecycleRoot(cfg, projectId, subproject);
|
|
27496
27511
|
return runWithProjectRoot(root, () => {
|
|
27497
27512
|
hostGit.sync();
|
|
27498
27513
|
const result = validateProjectAsComplete();
|
|
@@ -27664,9 +27679,8 @@ function promoteProject(cfg, credential, project2) {
|
|
|
27664
27679
|
}
|
|
27665
27680
|
return executeApprovedPromote(cfg, project2);
|
|
27666
27681
|
}
|
|
27667
|
-
function executeApprovedPromote(cfg, projectId) {
|
|
27668
|
-
const root =
|
|
27669
|
-
if (!root) throw new Error(`Unknown project "${projectId}".`);
|
|
27682
|
+
function executeApprovedPromote(cfg, projectId, subproject) {
|
|
27683
|
+
const root = boundLifecycleRoot(cfg, projectId, subproject);
|
|
27670
27684
|
return runWithProjectRoot(root, () => {
|
|
27671
27685
|
const lock = hostCore.readLockRecord();
|
|
27672
27686
|
if (!lock) {
|
|
@@ -31551,38 +31565,58 @@ function initializeProject(cfg, credential, request) {
|
|
|
31551
31565
|
}
|
|
31552
31566
|
}
|
|
31553
31567
|
}
|
|
31554
|
-
function lockProject2(cfg, credential, projectId) {
|
|
31568
|
+
function lockProject2(cfg, credential, projectId, subproject) {
|
|
31555
31569
|
return lifecycleAction(cfg, credential, projectId, {
|
|
31556
31570
|
action: "project:lock",
|
|
31557
31571
|
verb: "Lock",
|
|
31558
31572
|
noun: "lock",
|
|
31573
|
+
subproject,
|
|
31559
31574
|
execute: () => {
|
|
31560
|
-
const lock = executeApprovedLock(cfg, projectId);
|
|
31575
|
+
const lock = executeApprovedLock(cfg, projectId, subproject);
|
|
31561
31576
|
return {
|
|
31562
31577
|
status: "completed",
|
|
31563
31578
|
action: "project:lock",
|
|
31564
|
-
summary: `Locked project "${projectId}" (status: ${lock.status}).`,
|
|
31579
|
+
summary: `Locked project "${projectId}"${subprojectSuffix(subproject)} (status: ${lock.status}).`,
|
|
31565
31580
|
lock
|
|
31566
31581
|
};
|
|
31567
31582
|
}
|
|
31568
31583
|
});
|
|
31569
31584
|
}
|
|
31570
|
-
function promoteProject2(cfg, credential, projectId) {
|
|
31585
|
+
function promoteProject2(cfg, credential, projectId, subproject) {
|
|
31571
31586
|
return lifecycleAction(cfg, credential, projectId, {
|
|
31572
31587
|
action: "project:promote",
|
|
31573
31588
|
verb: "Promote",
|
|
31574
31589
|
noun: "promotion",
|
|
31590
|
+
subproject,
|
|
31575
31591
|
execute: () => {
|
|
31576
|
-
const promo = executeApprovedPromote(cfg, projectId);
|
|
31592
|
+
const promo = executeApprovedPromote(cfg, projectId, subproject);
|
|
31577
31593
|
return {
|
|
31578
31594
|
status: "completed",
|
|
31579
31595
|
action: "project:promote",
|
|
31580
|
-
summary: `Promotion of project "${projectId}": ${promo.status} \u2014 ${promo.message}`,
|
|
31596
|
+
summary: `Promotion of project "${projectId}"${subprojectSuffix(subproject)}: ${promo.status} \u2014 ${promo.message}`,
|
|
31581
31597
|
promote: promo
|
|
31582
31598
|
};
|
|
31583
31599
|
}
|
|
31584
31600
|
});
|
|
31585
31601
|
}
|
|
31602
|
+
function subprojectSuffix(subproject) {
|
|
31603
|
+
return subproject ? ` subproject "${subproject}"` : "";
|
|
31604
|
+
}
|
|
31605
|
+
var SUBPROJECT_SCOPE_PAYLOAD = "SubprojectScope";
|
|
31606
|
+
function subprojectScopePayload(subproject) {
|
|
31607
|
+
if (!subproject) return {};
|
|
31608
|
+
return { payloadType: SUBPROJECT_SCOPE_PAYLOAD, payload: JSON.stringify({ subproject }) };
|
|
31609
|
+
}
|
|
31610
|
+
function readSubprojectScope(req) {
|
|
31611
|
+
if (req.payloadType !== SUBPROJECT_SCOPE_PAYLOAD || !req.payload) return void 0;
|
|
31612
|
+
const parsed = JSON.parse(req.payload);
|
|
31613
|
+
if (typeof parsed.subproject !== "string" || !parsed.subproject) {
|
|
31614
|
+
throw new Error(
|
|
31615
|
+
`Approved ${req.kind} request "${req.id}" carries a ${SUBPROJECT_SCOPE_PAYLOAD} payload with no usable subproject qualifier \u2014 refusing to execute, because falling back to the whole project would widen the scope the requester was confined to.`
|
|
31616
|
+
);
|
|
31617
|
+
}
|
|
31618
|
+
return parsed.subproject;
|
|
31619
|
+
}
|
|
31586
31620
|
function lifecycleAction(cfg, credential, projectId, opts) {
|
|
31587
31621
|
const principal = requirePrincipal7(cfg, credential);
|
|
31588
31622
|
const effective = authorize(cfg.dataDir, principal, PROJECT_WRITE_CAPABILITY4, "project", projectId);
|
|
@@ -31608,8 +31642,9 @@ function lifecycleAction(cfg, credential, projectId, opts) {
|
|
|
31608
31642
|
const pending = buildPendingRequest(
|
|
31609
31643
|
principal,
|
|
31610
31644
|
opts.action,
|
|
31611
|
-
`${opts.verb} project ${projectId}`,
|
|
31612
|
-
projectId
|
|
31645
|
+
`${opts.verb} project ${projectId}${subprojectSuffix(opts.subproject)}`,
|
|
31646
|
+
projectId,
|
|
31647
|
+
subprojectScopePayload(opts.subproject)
|
|
31613
31648
|
);
|
|
31614
31649
|
return createPendingOutcome(cfg, principal, pending, opts.action);
|
|
31615
31650
|
}
|
|
@@ -31683,12 +31718,14 @@ function executeApproved(cfg, req) {
|
|
|
31683
31718
|
return `Initialized project "${rec.id}" under the active pack policy.`;
|
|
31684
31719
|
}
|
|
31685
31720
|
case "project:lock": {
|
|
31686
|
-
const
|
|
31687
|
-
|
|
31721
|
+
const scope = readSubprojectScope(req);
|
|
31722
|
+
const lock = executeApprovedLock(cfg, req.projectId ?? "", scope);
|
|
31723
|
+
return `Locked project "${req.projectId}"${subprojectSuffix(scope)} (status: ${lock.status}).`;
|
|
31688
31724
|
}
|
|
31689
31725
|
case "project:promote": {
|
|
31690
|
-
const
|
|
31691
|
-
|
|
31726
|
+
const scope = readSubprojectScope(req);
|
|
31727
|
+
const promo = executeApprovedPromote(cfg, req.projectId ?? "", scope);
|
|
31728
|
+
return `Promotion of project "${req.projectId}"${subprojectSuffix(scope)}: ${promo.status} \u2014 ${promo.message}`;
|
|
31692
31729
|
}
|
|
31693
31730
|
default:
|
|
31694
31731
|
throw new Error(`Unsupported approval kind "${req.kind}".`);
|
|
@@ -36421,6 +36458,12 @@ var PROJECT_OPS_TOOLS = /* @__PURE__ */ new Set([
|
|
|
36421
36458
|
"sdd_host_produce",
|
|
36422
36459
|
"sdd_host_commit_project"
|
|
36423
36460
|
]);
|
|
36461
|
+
var PROJECT_RECORD_TOOLS = /* @__PURE__ */ new Set([
|
|
36462
|
+
"sdd_host_initialize_project",
|
|
36463
|
+
"sdd_host_get_approval_status",
|
|
36464
|
+
"sdd_host_await_approval",
|
|
36465
|
+
...PROJECT_OPS_TOOLS
|
|
36466
|
+
]);
|
|
36424
36467
|
function jsonRpcRequests(body) {
|
|
36425
36468
|
const arr = Array.isArray(body) ? body : [body];
|
|
36426
36469
|
return arr.filter((m) => !!m && typeof m === "object" && "method" in m);
|
|
@@ -36486,7 +36529,27 @@ function dataPlanePermissionError(cfg, principal, projectId, body) {
|
|
|
36486
36529
|
}
|
|
36487
36530
|
};
|
|
36488
36531
|
}
|
|
36489
|
-
|
|
36532
|
+
function subprojectConfinementError(projectId, subproject, body) {
|
|
36533
|
+
if (!subproject) return void 0;
|
|
36534
|
+
const msg = jsonRpcRequest(body);
|
|
36535
|
+
if (!msg || msg.method !== "tools/call") return void 0;
|
|
36536
|
+
const name = msg.params?.name;
|
|
36537
|
+
if (typeof name !== "string" || !PROJECT_RECORD_TOOLS.has(name)) return void 0;
|
|
36538
|
+
return {
|
|
36539
|
+
jsonrpc: "2.0",
|
|
36540
|
+
id: msg.id ?? null,
|
|
36541
|
+
result: {
|
|
36542
|
+
content: [
|
|
36543
|
+
{
|
|
36544
|
+
type: "text",
|
|
36545
|
+
text: `Refused \u2014 ${name} acts on the whole project "${projectId}", but this credential is bound to subproject "${projectId}${SUBPROJECT_SEPARATOR}${subproject}". An unqualified credential for "${projectId}" is required to call ${name}.`
|
|
36546
|
+
}
|
|
36547
|
+
],
|
|
36548
|
+
isError: true
|
|
36549
|
+
}
|
|
36550
|
+
};
|
|
36551
|
+
}
|
|
36552
|
+
async function dispatchProjectLifecycleTool(cfg, credential, projectId, body, subproject) {
|
|
36490
36553
|
const msg = jsonRpcRequest(body);
|
|
36491
36554
|
if (!msg || msg.method !== "tools/call") return void 0;
|
|
36492
36555
|
const name = msg.params?.name;
|
|
@@ -36503,10 +36566,10 @@ async function dispatchProjectLifecycleTool(cfg, credential, projectId, body) {
|
|
|
36503
36566
|
value = initializeProject(cfg, credential, args);
|
|
36504
36567
|
break;
|
|
36505
36568
|
case "sdd_host_lock_project":
|
|
36506
|
-
value = lockProject2(cfg, credential, projectId);
|
|
36569
|
+
value = lockProject2(cfg, credential, projectId, subproject);
|
|
36507
36570
|
break;
|
|
36508
36571
|
case "sdd_host_promote_project":
|
|
36509
|
-
value = promoteProject2(cfg, credential, projectId);
|
|
36572
|
+
value = promoteProject2(cfg, credential, projectId, subproject);
|
|
36510
36573
|
break;
|
|
36511
36574
|
case "sdd_host_await_approval":
|
|
36512
36575
|
value = await awaitApproval(
|
|
@@ -36613,7 +36676,13 @@ async function handleMcpRequest(cfg, req, res, body, credential) {
|
|
|
36613
36676
|
await runWithProjectRoot(binding.rootPath, async () => {
|
|
36614
36677
|
const projectId = binding.projectId;
|
|
36615
36678
|
const subproject = binding.subproject;
|
|
36616
|
-
const
|
|
36679
|
+
const confinementError = subprojectConfinementError(projectId, subproject, body);
|
|
36680
|
+
if (confinementError !== void 0) {
|
|
36681
|
+
sendJson(res, 200, confinementError);
|
|
36682
|
+
auditToolCall(cfg.dataDir, principal, projectId, body, deriveMcpOutcome(confinementError), subproject);
|
|
36683
|
+
return;
|
|
36684
|
+
}
|
|
36685
|
+
const dispatchedResponse = await dispatchProjectLifecycleTool(cfg, cred, projectId, body, subproject);
|
|
36617
36686
|
if (dispatchedResponse !== void 0) {
|
|
36618
36687
|
sendJson(res, 200, dispatchedResponse);
|
|
36619
36688
|
auditToolCall(cfg.dataDir, principal, projectId, body, deriveMcpOutcome(dispatchedResponse), subproject);
|