@wairon/cli 5.0.2-dev.5 → 5.0.2-dev.6

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 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.5";
68
+ WAIRON_VERSION = "5.0.2-dev.6";
69
69
  GITHUB_REPO = "SYW-Apps/Waffle-AIron";
70
70
  ARCHITECT_AGENT_ID = "agent-architect";
71
71
  ARCHITECT_TEMPLATE_ID = "architect";
@@ -6072,6 +6072,14 @@ var MODEL = __MODEL_JSON__;
6072
6072
  if (!exposes || !openApiAllowed()) return '';
6073
6073
  return '<div class="openbtn"><button class="tbtn" data-openapi-tag="' + esc(tag || '') + '">\\u25A4 View OpenAPI \\u2197</button></div>';
6074
6074
  }
6075
+ // "Open in Specs" \u2014 deep-links the focused spec into the hosted Specs value
6076
+ // editor via a host hook (opts.onOpenSpec). Hidden when no host provides it
6077
+ // (standalone file, shared page): those have no editor to open. kind is the
6078
+ // spec layer, id its qualified spec id.
6079
+ function openSpecButton(kind, id) {
6080
+ if (typeof opts === 'undefined' || !opts || typeof opts.onOpenSpec !== 'function') return '';
6081
+ return '<div class="openbtn"><button class="tbtn" data-openspec-kind="' + kind + '" data-openspec-id="' + esc(id) + '">\\u270E Open in Specs \\u2197</button></div>';
6082
+ }
6075
6083
 
6076
6084
  function renderPanel() {
6077
6085
  var head = '', body = '';
@@ -6094,7 +6102,8 @@ var MODEL = __MODEL_JSON__;
6094
6102
  + (scopeFocus ? staticChip('current view') : '')
6095
6103
  + chip(c.subsystem, 'subsystem', c.subsystem)
6096
6104
  + (scopeFocus ? '' : openViewButton('component', c.id, c.owns.length > 0))
6097
- + openApiButton(componentExposesApi(c), c.apiTag);
6105
+ + openApiButton(componentExposesApi(c), c.apiTag)
6106
+ + openSpecButton('component', c.id);
6098
6107
 
6099
6108
  var linkedTypes = MODEL.types.filter(function (t) { return t.componentClass === c.id; });
6100
6109
  if (linkedTypes.length) {
@@ -6178,7 +6187,8 @@ var MODEL = __MODEL_JSON__;
6178
6187
  MODEL.types.forEach(function (t2) { if (t2.id === focusId) ty = t2; });
6179
6188
  if (ty) {
6180
6189
  head = '<h2>' + esc(ty.name) + '</h2>' + staticChip('\\u00AB' + ty.kind + '\\u00BB')
6181
- + (ty.subsystem ? chip(ty.subsystem, 'subsystem', ty.subsystem) : staticChip('system-level shared'));
6190
+ + (ty.subsystem ? chip(ty.subsystem, 'subsystem', ty.subsystem) : staticChip('system-level shared'))
6191
+ + openSpecButton('type', ty.id);
6182
6192
 
6183
6193
  if (ty.componentClass) {
6184
6194
  head += '<div style="margin-top:6px"><b style="font-size:11px">Class Component:</b> ' + chip(ty.componentClass, 'component', ty.componentClass) + '</div>';
@@ -6254,7 +6264,8 @@ var MODEL = __MODEL_JSON__;
6254
6264
  + (s.status ? staticChip(s.status) : '')
6255
6265
  + (scopeFocus ? staticChip('current view') : '')
6256
6266
  + (scopeFocus ? '' : openViewButton('subsystem', s.id, subKids > 0))
6257
- + openApiButton(subsystemExposesApi(s.id), '');
6267
+ + openApiButton(subsystemExposesApi(s.id), '')
6268
+ + openSpecButton('subsystem', s.id);
6258
6269
  body += '<p class="desc">' + esc(s.description) + '</p>';
6259
6270
  if (s.trustedLinks.length) {
6260
6271
  body += section('Trusted links (fast lanes)', s.trustedLinks.length, s.trustedLinks.map(function (t2) {
@@ -6312,6 +6323,16 @@ var MODEL = __MODEL_JSON__;
6312
6323
  });
6313
6324
  })(oapis[oi]);
6314
6325
  }
6326
+ var ospecs = panel.querySelectorAll('[data-openspec-kind]');
6327
+ for (var si = 0; si < ospecs.length; si++) {
6328
+ (function (b) {
6329
+ b.addEventListener('click', function () {
6330
+ if (typeof opts !== 'undefined' && opts && typeof opts.onOpenSpec === 'function') {
6331
+ opts.onOpenSpec(b.getAttribute('data-openspec-kind'), b.getAttribute('data-openspec-id') || '');
6332
+ }
6333
+ });
6334
+ })(ospecs[si]);
6335
+ }
6315
6336
  var flows = panel.querySelectorAll('[data-flow-comp]');
6316
6337
  for (var j = 0; j < flows.length; j++) {
6317
6338
  (function (b) {
@@ -6324,6 +6345,23 @@ var MODEL = __MODEL_JSON__;
6324
6345
  }
6325
6346
 
6326
6347
  renderPanel();
6348
+ // Stage G: a deep link may focus a component and/or open a method's narrative
6349
+ // modal once the seeded view + DOM + cy graph exist. The host parses the URL hash
6350
+ // into opts.initialSelect / opts.initialFlow \u2014 both carry the component id, so this
6351
+ // works whether the seeded view is the component itself or its parent subsystem
6352
+ // (a leaf component has no meaningful "inside", so Specs deep-links open the parent
6353
+ // and focus the component here).
6354
+ (function () {
6355
+ if (typeof opts === 'undefined' || !opts) return;
6356
+ var f = opts.initialFlow, s = opts.initialSelect;
6357
+ var focusComp = (f && f.comp) || (s && s.comp);
6358
+ if (focusComp && compById[focusComp]) {
6359
+ try { select('component', focusComp, true); } catch (e) { /* ignore */ }
6360
+ }
6361
+ if (f && f.comp && f.method && compById[f.comp]) {
6362
+ try { openFlow(f.comp, f.method, f.mode === 'steps' ? 'steps' : 'flow'); } catch (e) { /* ignore */ }
6363
+ }
6364
+ })();
6327
6365
  })();
6328
6366
  </script>
6329
6367
  </body>
@@ -12705,6 +12743,28 @@ function buildGraphModel(level) {
12705
12743
  ...t.subsystem ? { parentId: t.subsystem } : {}
12706
12744
  });
12707
12745
  }
12746
+ const componentByInterface = /* @__PURE__ */ new Map();
12747
+ for (const c of model.components) {
12748
+ for (const intf of c.interfaces) componentByInterface.set(intf.id, c.id);
12749
+ }
12750
+ for (const impl of loadImplementationSpecs()) {
12751
+ const componentId = componentByInterface.get(impl.contract);
12752
+ if (!componentId) continue;
12753
+ nodes.push({
12754
+ id: impl.id,
12755
+ label: impl.name,
12756
+ kind: "implementation",
12757
+ level: 4,
12758
+ parentId: componentId,
12759
+ ...impl.status ? { status: impl.status } : {}
12760
+ });
12761
+ candidates.push({ from: componentId, to: impl.id, edgeKind: "owns" });
12762
+ }
12763
+ for (const c of model.components) {
12764
+ for (const memberId of c.owns) {
12765
+ candidates.push({ from: c.id, to: memberId, edgeKind: "owns" });
12766
+ }
12767
+ }
12708
12768
  for (const e of model.edges) {
12709
12769
  candidates.push({ from: e.from, to: e.to, edgeKind: "depends_on" });
12710
12770
  }
@@ -27670,6 +27730,7 @@ function removeIdentityProviderRecord(dataDir, id) {
27670
27730
  }
27671
27731
  var PROJECT_CREATE_CAPABILITY = "project:create";
27672
27732
  var PROJECT_WRITE_CAPABILITY = "project:write";
27733
+ var PROJECT_READ_CAPABILITY = "project:read";
27673
27734
  var POLICY_MANAGE_CAPABILITY = "project:admin";
27674
27735
  function carriesInstancePermission(cfg, principal, capability) {
27675
27736
  return authorize(cfg.dataDir, principal, capability, "instance", "").value === "yes";
@@ -27734,6 +27795,19 @@ function recordProjectProfileSelection(root, selection) {
27734
27795
  writeYamlFile(AI_PATHS.projectConfig(), raw);
27735
27796
  });
27736
27797
  }
27798
+ function readProjectType(root) {
27799
+ return runWithProjectRoot(root, () => {
27800
+ const raw = readYamlFile(AI_PATHS.projectConfig());
27801
+ return raw?.projectType ?? "backend";
27802
+ });
27803
+ }
27804
+ function writeProjectType(root, projectType) {
27805
+ runWithProjectRoot(root, () => {
27806
+ const raw = readYamlFile(AI_PATHS.projectConfig()) ?? {};
27807
+ raw["projectType"] = projectType;
27808
+ writeYamlFile(AI_PATHS.projectConfig(), raw);
27809
+ });
27810
+ }
27737
27811
  function requestPackNames(request) {
27738
27812
  const sel = request.profileSelection;
27739
27813
  if (!sel) return [];
@@ -27928,6 +28002,32 @@ function reconcileProjectPolicy(cfg, credential, projectId) {
27928
28002
  );
27929
28003
  return result;
27930
28004
  }
28005
+ function getProjectConfig(cfg, credential, projectId) {
28006
+ const principal = requirePrincipal4(cfg, credential);
28007
+ if (authorize(cfg.dataDir, principal, PROJECT_READ_CAPABILITY, "project", projectId).value !== "yes") {
28008
+ throw new ForbiddenError(
28009
+ "reading a project's configuration requires project:read over the project"
28010
+ );
28011
+ }
28012
+ const root = resolveProjectRoot(cfg.dataDir, principal, projectId);
28013
+ if (!root) throw new Error(`Unknown project "${projectId}".`);
28014
+ const projectType = readProjectType(root);
28015
+ const locked = runWithProjectRoot(root, () => hostCore.readLockRecord() !== null);
28016
+ return { projectType, locked };
28017
+ }
28018
+ function setProjectType(cfg, credential, projectId, projectType) {
28019
+ const principal = requirePrincipal4(cfg, credential);
28020
+ if (authorize(cfg.dataDir, principal, PROJECT_WRITE_CAPABILITY, "project", projectId).value !== "yes") {
28021
+ throw new ForbiddenError(
28022
+ "changing a project's configuration requires project:write over the project"
28023
+ );
28024
+ }
28025
+ const root = resolveProjectRoot(cfg.dataDir, principal, projectId);
28026
+ if (!root) throw new Error(`Unknown project "${projectId}".`);
28027
+ writeProjectType(root, projectType);
28028
+ const locked = runWithProjectRoot(root, () => hostCore.readLockRecord() !== null);
28029
+ return { projectType, locked };
28030
+ }
27931
28031
  function getPackPolicy(cfg, credential) {
27932
28032
  requirePrincipal4(cfg, credential);
27933
28033
  return getPackPolicyRecord(cfg.dataDir) ?? PERMISSIVE_DEFAULT_POLICY;
@@ -27991,7 +28091,7 @@ function handlePolicyRequest(cfg, credential, req, res, body, url) {
27991
28091
 
27992
28092
  // src/server/identity.ts
27993
28093
  var PROJECT_ADMIN_CAPABILITY2 = "project:admin";
27994
- var PROJECT_READ_CAPABILITY = "project:read";
28094
+ var PROJECT_READ_CAPABILITY2 = "project:read";
27995
28095
  var PROJECT_WRITE_CAPABILITY2 = "project:write";
27996
28096
  function requireInstanceProjectAdmin(cfg, principal, what) {
27997
28097
  if (authorize(cfg.dataDir, principal, PROJECT_ADMIN_CAPABILITY2, "instance", "").value !== "yes") {
@@ -28137,7 +28237,7 @@ function revokeToken(cfg, credential, tokenId) {
28137
28237
  }
28138
28238
  function mintSelfToken(cfg, credential, projectId, write) {
28139
28239
  const principal = requirePrincipal5(cfg, credential);
28140
- if (authorize(cfg.dataDir, principal, PROJECT_READ_CAPABILITY, "project", projectId).value !== "yes") {
28240
+ if (authorize(cfg.dataDir, principal, PROJECT_READ_CAPABILITY2, "project", projectId).value !== "yes") {
28141
28241
  throw new ForbiddenError("caller lacks project:read on the requested project");
28142
28242
  }
28143
28243
  if (write && authorize(cfg.dataDir, principal, PROJECT_WRITE_CAPABILITY2, "project", projectId).value !== "yes") {
@@ -28783,7 +28883,7 @@ function audienceDistance(resolution, targetProjectId) {
28783
28883
  // src/server/landscape.ts
28784
28884
  var yamlLib = __toESM(require("js-yaml"));
28785
28885
  var PROJECT_ADMIN_CAPABILITY3 = "project:admin";
28786
- var PROJECT_READ_CAPABILITY2 = "project:read";
28886
+ var PROJECT_READ_CAPABILITY3 = "project:read";
28787
28887
  var PROJECT_WRITE_CAPABILITY3 = "project:write";
28788
28888
  function requirePrincipal6(cfg, credential) {
28789
28889
  const principal = authenticateCredential(cfg.dataDir, credential);
@@ -28797,7 +28897,7 @@ function readView(cfg, principal) {
28797
28897
  if (isInstanceAdmin(principal)) {
28798
28898
  return { all: true, projectIds: /* @__PURE__ */ new Set(), unitIds: /* @__PURE__ */ new Set(), contextUnitIds: /* @__PURE__ */ new Set() };
28799
28899
  }
28800
- const read = visibleScopes(cfg.dataDir, principal, PROJECT_READ_CAPABILITY2);
28900
+ const read = visibleScopes(cfg.dataDir, principal, PROJECT_READ_CAPABILITY3);
28801
28901
  const admin = visibleScopes(cfg.dataDir, principal, PROJECT_ADMIN_CAPABILITY3);
28802
28902
  const unitIds = /* @__PURE__ */ new Set([...actionableUnitIds(read), ...actionableUnitIds(admin)]);
28803
28903
  const contextUnitIds = new Set(
@@ -28812,13 +28912,13 @@ function readView(cfg, principal) {
28812
28912
  }
28813
28913
  function requireLandscapeReach(cfg, principal, view, what) {
28814
28914
  if (view.all || view.projectIds.size > 0 || view.unitIds.size > 0) return;
28815
- if (permitsCap(cfg, principal, PROJECT_READ_CAPABILITY2, "instance", "") || permitsCap(cfg, principal, PROJECT_ADMIN_CAPABILITY3, "instance", "")) {
28915
+ if (permitsCap(cfg, principal, PROJECT_READ_CAPABILITY3, "instance", "") || permitsCap(cfg, principal, PROJECT_ADMIN_CAPABILITY3, "instance", "")) {
28816
28916
  return;
28817
28917
  }
28818
28918
  throw new ForbiddenError(`${what} requires project:read reach`);
28819
28919
  }
28820
28920
  function requireObserverScope(cfg, principal, observerProjectId) {
28821
- const covered = permitsCap(cfg, principal, PROJECT_READ_CAPABILITY2, "project", observerProjectId) || permitsCap(cfg, principal, PROJECT_WRITE_CAPABILITY3, "project", observerProjectId);
28921
+ const covered = permitsCap(cfg, principal, PROJECT_READ_CAPABILITY3, "project", observerProjectId) || permitsCap(cfg, principal, PROJECT_WRITE_CAPABILITY3, "project", observerProjectId);
28822
28922
  if (!covered) {
28823
28923
  throw new ForbiddenError("caller lacks scope over the current project");
28824
28924
  }
@@ -30876,6 +30976,12 @@ function evaluateProjectPolicy2(cfg, credential, projectId) {
30876
30976
  function reconcileProjectPolicy2(cfg, credential, projectId) {
30877
30977
  return reconcileProjectPolicy(cfg, credential, projectId);
30878
30978
  }
30979
+ function getProjectConfig2(cfg, credential, projectId) {
30980
+ return getProjectConfig(cfg, credential, projectId);
30981
+ }
30982
+ function setProjectType2(cfg, credential, projectId, projectType) {
30983
+ return setProjectType(cfg, credential, projectId, projectType);
30984
+ }
30879
30985
  function listProducers2(cfg, credential, project2) {
30880
30986
  return listProducers(cfg, credential, project2);
30881
30987
  }
@@ -34178,6 +34284,12 @@ function opsPolicyEvaluate(cfg, sessionId, url, res) {
34178
34284
  function opsPolicyReconcile(cfg, sessionId, body, res) {
34179
34285
  sendJson(res, 200, reconcileProjectPolicy2(cfg, sessionId, String(body?.projectId ?? "")));
34180
34286
  }
34287
+ function opsGetProjectConfig(cfg, sessionId, url, res) {
34288
+ sendJson(res, 200, getProjectConfig2(cfg, sessionId, q(url, "projectId") ?? ""));
34289
+ }
34290
+ function opsSetProjectConfig(cfg, sessionId, body, res) {
34291
+ sendJson(res, 200, setProjectType2(cfg, sessionId, String(body?.projectId ?? ""), String(body?.projectType ?? "")));
34292
+ }
34181
34293
  function opsListProducers(cfg, sessionId, url, res) {
34182
34294
  sendJson(res, 200, { producers: listProducers2(cfg, sessionId, q(url, "projectId") ?? "") });
34183
34295
  }
@@ -34410,6 +34522,12 @@ async function handleWebRequest(cfg, req, res, body, url, ctx) {
34410
34522
  if (req.method === "POST" && parts.length === 4 && parts[2] === "packs" && parts[3] === "adopt") {
34411
34523
  return opsAdoptProjectPack(cfg, sessionId, body, res);
34412
34524
  }
34525
+ if (req.method === "GET" && parts.length === 3 && parts[2] === "config") {
34526
+ return opsGetProjectConfig(cfg, sessionId, url, res);
34527
+ }
34528
+ if (req.method === "POST" && parts.length === 3 && parts[2] === "config") {
34529
+ return opsSetProjectConfig(cfg, sessionId, body, res);
34530
+ }
34413
34531
  if (req.method === "GET" && parts.length === 3 && parts[2] === "policy") {
34414
34532
  return opsPolicyEvaluate(cfg, sessionId, url, res);
34415
34533
  }