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

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.4";
68
+ WAIRON_VERSION = "5.0.2-dev.5";
69
69
  GITHUB_REPO = "SYW-Apps/Waffle-AIron";
70
70
  ARCHITECT_AGENT_ID = "agent-architect";
71
71
  ARCHITECT_TEMPLATE_ID = "architect";
@@ -3304,8 +3304,17 @@ var MODEL = __MODEL_JSON__;
3304
3304
  var configuredLineStyle = ['bezier', 'straight', 'taxi'].indexOf(diagramConfig.lineStyle) >= 0 ? diagramConfig.lineStyle : 'bezier';
3305
3305
  var defaultViewKind = diagramConfig.defaultView === 'types' ? 'types' : (diagramConfig.defaultView === 'databases' && showDatabaseTab ? 'databases' : 'system');
3306
3306
 
3307
+ // Stage J: a deep link (opts.initialRoute) seeds the initial view directly so a
3308
+ // refresh / shared URL renders the right scope with NO root-first flash. Parsed
3309
+ // by the same resolver as openRoute (hoisted below). No onViewChange fires for
3310
+ // this initial seed.
3311
+ var initialView = { kind: defaultViewKind, id: null };
3312
+ if (typeof opts !== 'undefined' && opts && typeof opts.initialRoute === 'string' && opts.initialRoute.length) {
3313
+ initialView = resolveRoute(opts.initialRoute);
3314
+ }
3315
+
3307
3316
  var state = {
3308
- view: { kind: defaultViewKind, id: null },
3317
+ view: initialView,
3309
3318
  internals: typeof saved.internals === 'boolean' ? saved.internals : false,
3310
3319
  externals: typeof saved.externals === 'boolean' ? saved.externals : true,
3311
3320
  dataCoupling: typeof saved.dataCoupling === 'boolean' ? saved.dataCoupling : false,
@@ -3324,6 +3333,9 @@ var MODEL = __MODEL_JSON__;
3324
3333
  // Set by buildTypeElements when the ERD is degraded for performance (huge
3325
3334
  // scopes); consumed by renderTypesNotice to explain the level-of-detail.
3326
3335
  var typesNotice = '';
3336
+ // Stage J: true while openRoute is applying a URL-driven view change, so the
3337
+ // onViewChange callback is suppressed and we do not loop URL -> engine -> URL.
3338
+ var applyingRoute = false;
3327
3339
 
3328
3340
  function viewKey() {
3329
3341
  // 'types2' + detail level: table sizes differ per detail, and the prefix
@@ -4753,6 +4765,78 @@ var MODEL = __MODEL_JSON__;
4753
4765
  state.typesRenderAll = false; // a fresh scope re-evaluates the LOD budget
4754
4766
  rebuild(true);
4755
4767
  renderPanel();
4768
+ notifyViewChange();
4769
+ }
4770
+
4771
+ // ---- Stage J: URL <-> view routing ----------------------------------------
4772
+ // The canvas navigation lives in the URL path (refresh-safe + shareable). A
4773
+ // route is the string AFTER /canvas/<project>: '' = system root; a '/'-joined
4774
+ // NAMESPACE (e.g. 'a/b') that resolves against the model to a subsystem or a
4775
+ // component; or the 'types'/'databases' view modes with an optional scope.
4776
+ // A segment is the '::' namespace with '/' as separator, each part encoded.
4777
+ function encSeg(s) { return encodeURIComponent(String(s)); }
4778
+ function routeOf(view) {
4779
+ if (!view) return '';
4780
+ var k = view.kind;
4781
+ if (k === 'system') return '';
4782
+ if (k === 'types' || k === 'databases') {
4783
+ return view.id ? k + '/' + view.id.split('::').map(encSeg).join('/') : k;
4784
+ }
4785
+ if (k === 'subsystem') {
4786
+ return view.id ? view.id.split('::').map(encSeg).join('/') : '';
4787
+ }
4788
+ if (k === 'component') {
4789
+ // A component's full namespace path IS its id: a chained subproject carries
4790
+ // the subsystem prefix in the id (a::b::comp), a flat project uses the bare
4791
+ // id (comp). Serializing comp.id split on '::' round-trips exactly via the
4792
+ // compById lookup in resolveRoute. Owner-pattern nesting is deliberately NOT
4793
+ // encoded (ownership is a separate axis; comp.id does not embed the owner).
4794
+ var c = compById[view.id];
4795
+ var full = c ? c.id : view.id;
4796
+ return full.split('::').map(encSeg).join('/');
4797
+ }
4798
+ return '';
4799
+ }
4800
+ function resolveRoute(routeStr) {
4801
+ var parts = String(routeStr || '').split('/').filter(function (s) { return s.length > 0; }).map(decodeURIComponent);
4802
+ if (!parts.length) return { kind: 'system', id: null };
4803
+ // NOTE: a subsystem literally named 'types'/'databases' is SHADOWED by these
4804
+ // view-mode routes (acceptable \u2014 the modes own those first segments).
4805
+ if (parts[0] === 'types') {
4806
+ return { kind: 'types', id: parts.length > 1 ? parts.slice(1).join('::') : null };
4807
+ }
4808
+ if (parts[0] === 'databases') {
4809
+ if (!showDatabaseTab) return { kind: 'system', id: null };
4810
+ return { kind: 'databases', id: parts.length > 1 ? parts.slice(1).join('::') : null };
4811
+ }
4812
+ var joined = parts.join('::');
4813
+ if (subById[joined]) return { kind: 'subsystem', id: joined };
4814
+ if (compById[joined]) return { kind: 'component', id: joined };
4815
+ return { kind: 'system', id: null }; // unknown id -> fall back to the root
4816
+ }
4817
+ // Apply a route (URL -> engine) WITHOUT echoing back through onViewChange.
4818
+ function openRoute(routeStr) {
4819
+ var v = resolveRoute(routeStr);
4820
+ if (state.view.kind === v.kind && state.view.id === v.id) return;
4821
+ applyingRoute = true;
4822
+ try {
4823
+ state.view = { kind: v.kind, id: v.id };
4824
+ state.selected = null;
4825
+ state.selectedKind = null;
4826
+ state.typesRenderAll = false;
4827
+ rebuild(true);
4828
+ renderPanel();
4829
+ } finally {
4830
+ applyingRoute = false;
4831
+ }
4832
+ }
4833
+ // Notify the embedder (engine -> URL) of the current view; suppressed while a
4834
+ // route is being applied so the URL is not driven in a loop.
4835
+ function notifyViewChange() {
4836
+ if (applyingRoute) return;
4837
+ if (typeof opts !== 'undefined' && opts && typeof opts.onViewChange === 'function') {
4838
+ try { opts.onViewChange(routeOf(state.view)); } catch (e) { /* ignore */ }
4839
+ }
4756
4840
  }
4757
4841
  // Explain (and offer to override) a performance-degraded ERD.
4758
4842
  function renderTypesNotice() {
@@ -4903,6 +4987,7 @@ var MODEL = __MODEL_JSON__;
4903
4987
  if (t.ghost) {
4904
4988
  state.view = parentViewOf(t.kind, t.id);
4905
4989
  rebuild(true);
4990
+ notifyViewChange();
4906
4991
  select(t.kind, t.id, true);
4907
4992
  return;
4908
4993
  }
@@ -5923,10 +6008,12 @@ var MODEL = __MODEL_JSON__;
5923
6008
  if (kind === 'type' && state.view.kind !== 'types' && state.view.kind !== 'databases') {
5924
6009
  state.view = { kind: 'types', id: typesScopeFromView() };
5925
6010
  rebuild(true);
6011
+ notifyViewChange();
5926
6012
  } else if (kind === 'component' && (state.view.kind === 'types' || state.view.kind === 'databases')) {
5927
6013
  var c = compById[id];
5928
6014
  state.view = { kind: 'subsystem', id: c ? c.subsystem : null };
5929
6015
  rebuild(true);
6016
+ notifyViewChange();
5930
6017
  }
5931
6018
  state.selectedKind = kind;
5932
6019
  state.selected = id;