@wairon/cli 5.0.2-dev.4 → 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 +216 -11
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +152 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2650,8 +2650,17 @@ var MODEL = __MODEL_JSON__;
|
|
|
2650
2650
|
var configuredLineStyle = ['bezier', 'straight', 'taxi'].indexOf(diagramConfig.lineStyle) >= 0 ? diagramConfig.lineStyle : 'bezier';
|
|
2651
2651
|
var defaultViewKind = diagramConfig.defaultView === 'types' ? 'types' : (diagramConfig.defaultView === 'databases' && showDatabaseTab ? 'databases' : 'system');
|
|
2652
2652
|
|
|
2653
|
+
// Stage J: a deep link (opts.initialRoute) seeds the initial view directly so a
|
|
2654
|
+
// refresh / shared URL renders the right scope with NO root-first flash. Parsed
|
|
2655
|
+
// by the same resolver as openRoute (hoisted below). No onViewChange fires for
|
|
2656
|
+
// this initial seed.
|
|
2657
|
+
var initialView = { kind: defaultViewKind, id: null };
|
|
2658
|
+
if (typeof opts !== 'undefined' && opts && typeof opts.initialRoute === 'string' && opts.initialRoute.length) {
|
|
2659
|
+
initialView = resolveRoute(opts.initialRoute);
|
|
2660
|
+
}
|
|
2661
|
+
|
|
2653
2662
|
var state = {
|
|
2654
|
-
view:
|
|
2663
|
+
view: initialView,
|
|
2655
2664
|
internals: typeof saved.internals === 'boolean' ? saved.internals : false,
|
|
2656
2665
|
externals: typeof saved.externals === 'boolean' ? saved.externals : true,
|
|
2657
2666
|
dataCoupling: typeof saved.dataCoupling === 'boolean' ? saved.dataCoupling : false,
|
|
@@ -2670,6 +2679,9 @@ var MODEL = __MODEL_JSON__;
|
|
|
2670
2679
|
// Set by buildTypeElements when the ERD is degraded for performance (huge
|
|
2671
2680
|
// scopes); consumed by renderTypesNotice to explain the level-of-detail.
|
|
2672
2681
|
var typesNotice = '';
|
|
2682
|
+
// Stage J: true while openRoute is applying a URL-driven view change, so the
|
|
2683
|
+
// onViewChange callback is suppressed and we do not loop URL -> engine -> URL.
|
|
2684
|
+
var applyingRoute = false;
|
|
2673
2685
|
|
|
2674
2686
|
function viewKey() {
|
|
2675
2687
|
// 'types2' + detail level: table sizes differ per detail, and the prefix
|
|
@@ -4099,6 +4111,78 @@ var MODEL = __MODEL_JSON__;
|
|
|
4099
4111
|
state.typesRenderAll = false; // a fresh scope re-evaluates the LOD budget
|
|
4100
4112
|
rebuild(true);
|
|
4101
4113
|
renderPanel();
|
|
4114
|
+
notifyViewChange();
|
|
4115
|
+
}
|
|
4116
|
+
|
|
4117
|
+
// ---- Stage J: URL <-> view routing ----------------------------------------
|
|
4118
|
+
// The canvas navigation lives in the URL path (refresh-safe + shareable). A
|
|
4119
|
+
// route is the string AFTER /canvas/<project>: '' = system root; a '/'-joined
|
|
4120
|
+
// NAMESPACE (e.g. 'a/b') that resolves against the model to a subsystem or a
|
|
4121
|
+
// component; or the 'types'/'databases' view modes with an optional scope.
|
|
4122
|
+
// A segment is the '::' namespace with '/' as separator, each part encoded.
|
|
4123
|
+
function encSeg(s) { return encodeURIComponent(String(s)); }
|
|
4124
|
+
function routeOf(view) {
|
|
4125
|
+
if (!view) return '';
|
|
4126
|
+
var k = view.kind;
|
|
4127
|
+
if (k === 'system') return '';
|
|
4128
|
+
if (k === 'types' || k === 'databases') {
|
|
4129
|
+
return view.id ? k + '/' + view.id.split('::').map(encSeg).join('/') : k;
|
|
4130
|
+
}
|
|
4131
|
+
if (k === 'subsystem') {
|
|
4132
|
+
return view.id ? view.id.split('::').map(encSeg).join('/') : '';
|
|
4133
|
+
}
|
|
4134
|
+
if (k === 'component') {
|
|
4135
|
+
// A component's full namespace path IS its id: a chained subproject carries
|
|
4136
|
+
// the subsystem prefix in the id (a::b::comp), a flat project uses the bare
|
|
4137
|
+
// id (comp). Serializing comp.id split on '::' round-trips exactly via the
|
|
4138
|
+
// compById lookup in resolveRoute. Owner-pattern nesting is deliberately NOT
|
|
4139
|
+
// encoded (ownership is a separate axis; comp.id does not embed the owner).
|
|
4140
|
+
var c = compById[view.id];
|
|
4141
|
+
var full = c ? c.id : view.id;
|
|
4142
|
+
return full.split('::').map(encSeg).join('/');
|
|
4143
|
+
}
|
|
4144
|
+
return '';
|
|
4145
|
+
}
|
|
4146
|
+
function resolveRoute(routeStr) {
|
|
4147
|
+
var parts = String(routeStr || '').split('/').filter(function (s) { return s.length > 0; }).map(decodeURIComponent);
|
|
4148
|
+
if (!parts.length) return { kind: 'system', id: null };
|
|
4149
|
+
// NOTE: a subsystem literally named 'types'/'databases' is SHADOWED by these
|
|
4150
|
+
// view-mode routes (acceptable \u2014 the modes own those first segments).
|
|
4151
|
+
if (parts[0] === 'types') {
|
|
4152
|
+
return { kind: 'types', id: parts.length > 1 ? parts.slice(1).join('::') : null };
|
|
4153
|
+
}
|
|
4154
|
+
if (parts[0] === 'databases') {
|
|
4155
|
+
if (!showDatabaseTab) return { kind: 'system', id: null };
|
|
4156
|
+
return { kind: 'databases', id: parts.length > 1 ? parts.slice(1).join('::') : null };
|
|
4157
|
+
}
|
|
4158
|
+
var joined = parts.join('::');
|
|
4159
|
+
if (subById[joined]) return { kind: 'subsystem', id: joined };
|
|
4160
|
+
if (compById[joined]) return { kind: 'component', id: joined };
|
|
4161
|
+
return { kind: 'system', id: null }; // unknown id -> fall back to the root
|
|
4162
|
+
}
|
|
4163
|
+
// Apply a route (URL -> engine) WITHOUT echoing back through onViewChange.
|
|
4164
|
+
function openRoute(routeStr) {
|
|
4165
|
+
var v = resolveRoute(routeStr);
|
|
4166
|
+
if (state.view.kind === v.kind && state.view.id === v.id) return;
|
|
4167
|
+
applyingRoute = true;
|
|
4168
|
+
try {
|
|
4169
|
+
state.view = { kind: v.kind, id: v.id };
|
|
4170
|
+
state.selected = null;
|
|
4171
|
+
state.selectedKind = null;
|
|
4172
|
+
state.typesRenderAll = false;
|
|
4173
|
+
rebuild(true);
|
|
4174
|
+
renderPanel();
|
|
4175
|
+
} finally {
|
|
4176
|
+
applyingRoute = false;
|
|
4177
|
+
}
|
|
4178
|
+
}
|
|
4179
|
+
// Notify the embedder (engine -> URL) of the current view; suppressed while a
|
|
4180
|
+
// route is being applied so the URL is not driven in a loop.
|
|
4181
|
+
function notifyViewChange() {
|
|
4182
|
+
if (applyingRoute) return;
|
|
4183
|
+
if (typeof opts !== 'undefined' && opts && typeof opts.onViewChange === 'function') {
|
|
4184
|
+
try { opts.onViewChange(routeOf(state.view)); } catch (e) { /* ignore */ }
|
|
4185
|
+
}
|
|
4102
4186
|
}
|
|
4103
4187
|
// Explain (and offer to override) a performance-degraded ERD.
|
|
4104
4188
|
function renderTypesNotice() {
|
|
@@ -4249,6 +4333,7 @@ var MODEL = __MODEL_JSON__;
|
|
|
4249
4333
|
if (t.ghost) {
|
|
4250
4334
|
state.view = parentViewOf(t.kind, t.id);
|
|
4251
4335
|
rebuild(true);
|
|
4336
|
+
notifyViewChange();
|
|
4252
4337
|
select(t.kind, t.id, true);
|
|
4253
4338
|
return;
|
|
4254
4339
|
}
|
|
@@ -5269,10 +5354,12 @@ var MODEL = __MODEL_JSON__;
|
|
|
5269
5354
|
if (kind === 'type' && state.view.kind !== 'types' && state.view.kind !== 'databases') {
|
|
5270
5355
|
state.view = { kind: 'types', id: typesScopeFromView() };
|
|
5271
5356
|
rebuild(true);
|
|
5357
|
+
notifyViewChange();
|
|
5272
5358
|
} else if (kind === 'component' && (state.view.kind === 'types' || state.view.kind === 'databases')) {
|
|
5273
5359
|
var c = compById[id];
|
|
5274
5360
|
state.view = { kind: 'subsystem', id: c ? c.subsystem : null };
|
|
5275
5361
|
rebuild(true);
|
|
5362
|
+
notifyViewChange();
|
|
5276
5363
|
}
|
|
5277
5364
|
state.selectedKind = kind;
|
|
5278
5365
|
state.selected = id;
|
|
@@ -5331,6 +5418,14 @@ var MODEL = __MODEL_JSON__;
|
|
|
5331
5418
|
if (!exposes || !openApiAllowed()) return '';
|
|
5332
5419
|
return '<div class="openbtn"><button class="tbtn" data-openapi-tag="' + esc(tag || '') + '">\\u25A4 View OpenAPI \\u2197</button></div>';
|
|
5333
5420
|
}
|
|
5421
|
+
// "Open in Specs" \u2014 deep-links the focused spec into the hosted Specs value
|
|
5422
|
+
// editor via a host hook (opts.onOpenSpec). Hidden when no host provides it
|
|
5423
|
+
// (standalone file, shared page): those have no editor to open. kind is the
|
|
5424
|
+
// spec layer, id its qualified spec id.
|
|
5425
|
+
function openSpecButton(kind, id) {
|
|
5426
|
+
if (typeof opts === 'undefined' || !opts || typeof opts.onOpenSpec !== 'function') return '';
|
|
5427
|
+
return '<div class="openbtn"><button class="tbtn" data-openspec-kind="' + kind + '" data-openspec-id="' + esc(id) + '">\\u270E Open in Specs \\u2197</button></div>';
|
|
5428
|
+
}
|
|
5334
5429
|
|
|
5335
5430
|
function renderPanel() {
|
|
5336
5431
|
var head = '', body = '';
|
|
@@ -5353,7 +5448,8 @@ var MODEL = __MODEL_JSON__;
|
|
|
5353
5448
|
+ (scopeFocus ? staticChip('current view') : '')
|
|
5354
5449
|
+ chip(c.subsystem, 'subsystem', c.subsystem)
|
|
5355
5450
|
+ (scopeFocus ? '' : openViewButton('component', c.id, c.owns.length > 0))
|
|
5356
|
-
+ openApiButton(componentExposesApi(c), c.apiTag)
|
|
5451
|
+
+ openApiButton(componentExposesApi(c), c.apiTag)
|
|
5452
|
+
+ openSpecButton('component', c.id);
|
|
5357
5453
|
|
|
5358
5454
|
var linkedTypes = MODEL.types.filter(function (t) { return t.componentClass === c.id; });
|
|
5359
5455
|
if (linkedTypes.length) {
|
|
@@ -5437,7 +5533,8 @@ var MODEL = __MODEL_JSON__;
|
|
|
5437
5533
|
MODEL.types.forEach(function (t2) { if (t2.id === focusId) ty = t2; });
|
|
5438
5534
|
if (ty) {
|
|
5439
5535
|
head = '<h2>' + esc(ty.name) + '</h2>' + staticChip('\\u00AB' + ty.kind + '\\u00BB')
|
|
5440
|
-
+ (ty.subsystem ? chip(ty.subsystem, 'subsystem', ty.subsystem) : staticChip('system-level shared'))
|
|
5536
|
+
+ (ty.subsystem ? chip(ty.subsystem, 'subsystem', ty.subsystem) : staticChip('system-level shared'))
|
|
5537
|
+
+ openSpecButton('type', ty.id);
|
|
5441
5538
|
|
|
5442
5539
|
if (ty.componentClass) {
|
|
5443
5540
|
head += '<div style="margin-top:6px"><b style="font-size:11px">Class Component:</b> ' + chip(ty.componentClass, 'component', ty.componentClass) + '</div>';
|
|
@@ -5513,7 +5610,8 @@ var MODEL = __MODEL_JSON__;
|
|
|
5513
5610
|
+ (s.status ? staticChip(s.status) : '')
|
|
5514
5611
|
+ (scopeFocus ? staticChip('current view') : '')
|
|
5515
5612
|
+ (scopeFocus ? '' : openViewButton('subsystem', s.id, subKids > 0))
|
|
5516
|
-
+ openApiButton(subsystemExposesApi(s.id), '')
|
|
5613
|
+
+ openApiButton(subsystemExposesApi(s.id), '')
|
|
5614
|
+
+ openSpecButton('subsystem', s.id);
|
|
5517
5615
|
body += '<p class="desc">' + esc(s.description) + '</p>';
|
|
5518
5616
|
if (s.trustedLinks.length) {
|
|
5519
5617
|
body += section('Trusted links (fast lanes)', s.trustedLinks.length, s.trustedLinks.map(function (t2) {
|
|
@@ -5571,6 +5669,16 @@ var MODEL = __MODEL_JSON__;
|
|
|
5571
5669
|
});
|
|
5572
5670
|
})(oapis[oi]);
|
|
5573
5671
|
}
|
|
5672
|
+
var ospecs = panel.querySelectorAll('[data-openspec-kind]');
|
|
5673
|
+
for (var si = 0; si < ospecs.length; si++) {
|
|
5674
|
+
(function (b) {
|
|
5675
|
+
b.addEventListener('click', function () {
|
|
5676
|
+
if (typeof opts !== 'undefined' && opts && typeof opts.onOpenSpec === 'function') {
|
|
5677
|
+
opts.onOpenSpec(b.getAttribute('data-openspec-kind'), b.getAttribute('data-openspec-id') || '');
|
|
5678
|
+
}
|
|
5679
|
+
});
|
|
5680
|
+
})(ospecs[si]);
|
|
5681
|
+
}
|
|
5574
5682
|
var flows = panel.querySelectorAll('[data-flow-comp]');
|
|
5575
5683
|
for (var j = 0; j < flows.length; j++) {
|
|
5576
5684
|
(function (b) {
|
|
@@ -5583,6 +5691,23 @@ var MODEL = __MODEL_JSON__;
|
|
|
5583
5691
|
}
|
|
5584
5692
|
|
|
5585
5693
|
renderPanel();
|
|
5694
|
+
// Stage G: a deep link may focus a component and/or open a method's narrative
|
|
5695
|
+
// modal once the seeded view + DOM + cy graph exist. The host parses the URL hash
|
|
5696
|
+
// into opts.initialSelect / opts.initialFlow \u2014 both carry the component id, so this
|
|
5697
|
+
// works whether the seeded view is the component itself or its parent subsystem
|
|
5698
|
+
// (a leaf component has no meaningful "inside", so Specs deep-links open the parent
|
|
5699
|
+
// and focus the component here).
|
|
5700
|
+
(function () {
|
|
5701
|
+
if (typeof opts === 'undefined' || !opts) return;
|
|
5702
|
+
var f = opts.initialFlow, s = opts.initialSelect;
|
|
5703
|
+
var focusComp = (f && f.comp) || (s && s.comp);
|
|
5704
|
+
if (focusComp && compById[focusComp]) {
|
|
5705
|
+
try { select('component', focusComp, true); } catch (e) { /* ignore */ }
|
|
5706
|
+
}
|
|
5707
|
+
if (f && f.comp && f.method && compById[f.comp]) {
|
|
5708
|
+
try { openFlow(f.comp, f.method, f.mode === 'steps' ? 'steps' : 'flow'); } catch (e) { /* ignore */ }
|
|
5709
|
+
}
|
|
5710
|
+
})();
|
|
5586
5711
|
})();
|
|
5587
5712
|
</script>
|
|
5588
5713
|
</body>
|
|
@@ -12030,6 +12155,28 @@ function buildGraphModel(level) {
|
|
|
12030
12155
|
...t.subsystem ? { parentId: t.subsystem } : {}
|
|
12031
12156
|
});
|
|
12032
12157
|
}
|
|
12158
|
+
const componentByInterface = /* @__PURE__ */ new Map();
|
|
12159
|
+
for (const c of model.components) {
|
|
12160
|
+
for (const intf of c.interfaces) componentByInterface.set(intf.id, c.id);
|
|
12161
|
+
}
|
|
12162
|
+
for (const impl of loadImplementationSpecs()) {
|
|
12163
|
+
const componentId = componentByInterface.get(impl.contract);
|
|
12164
|
+
if (!componentId) continue;
|
|
12165
|
+
nodes.push({
|
|
12166
|
+
id: impl.id,
|
|
12167
|
+
label: impl.name,
|
|
12168
|
+
kind: "implementation",
|
|
12169
|
+
level: 4,
|
|
12170
|
+
parentId: componentId,
|
|
12171
|
+
...impl.status ? { status: impl.status } : {}
|
|
12172
|
+
});
|
|
12173
|
+
candidates.push({ from: componentId, to: impl.id, edgeKind: "owns" });
|
|
12174
|
+
}
|
|
12175
|
+
for (const c of model.components) {
|
|
12176
|
+
for (const memberId of c.owns) {
|
|
12177
|
+
candidates.push({ from: c.id, to: memberId, edgeKind: "owns" });
|
|
12178
|
+
}
|
|
12179
|
+
}
|
|
12033
12180
|
for (const e of model.edges) {
|
|
12034
12181
|
candidates.push({ from: e.from, to: e.to, edgeKind: "depends_on" });
|
|
12035
12182
|
}
|
|
@@ -15240,7 +15387,7 @@ function defaultTargetConfig(type) {
|
|
|
15240
15387
|
enabled: true
|
|
15241
15388
|
};
|
|
15242
15389
|
}
|
|
15243
|
-
var WAIRON_VERSION = "5.0.2-dev.
|
|
15390
|
+
var WAIRON_VERSION = "5.0.2-dev.6";
|
|
15244
15391
|
var GITHUB_REPO = "SYW-Apps/Waffle-AIron";
|
|
15245
15392
|
var ARCHITECT_AGENT_ID = "agent-architect";
|
|
15246
15393
|
var ARCHITECT_TEMPLATE_ID = "architect";
|