@nac3/forge-cli 1.0.57 → 1.0.59

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.
@@ -3625,19 +3625,25 @@ async function handlePanelInvoke(req, res, ctx) {
3625
3625
  const payload = (result.server_payload && typeof result.server_payload === 'object')
3626
3626
  ? result.server_payload : null;
3627
3627
  const shortVerb = String(verb.id || '').replace(/^yujin\./, '');
3628
- /* Enforce KIND SELECTION server-side: a create-tab `graph` whose title
3629
- * reads like a flow/proceso is promoted to a real BPMN diagram before it
3630
- * is enqueued or persisted (some brains ignore the always-on doctrine). */
3628
+ /* Enforce KIND SELECTION server-side for a create-tab `graph` that is
3629
+ * really a flow/proceso. First time -> reject with a nudge so the brain
3630
+ * redoes it as native BPMN (B); on reincidence -> convert deterministically
3631
+ * (A). Done BEFORE enqueue + board_artifacts persistence, so the panel and
3632
+ * the disk never see the graph-drawn flow. */
3631
3633
  if (shortVerb === 'pizarron.create-tab') {
3632
- const { maybePromoteFlow } = await import('./flow_bpmn.js');
3633
- const promoted = maybePromoteFlow({
3634
+ const { decideFlowTab } = await import('./flow_bpmn.js');
3635
+ const decision = decideFlowTab({
3634
3636
  kind: String(dispatchArgs.kind || ''),
3635
3637
  content: String(dispatchArgs.content || ''),
3636
3638
  title: String(dispatchArgs.title || ''),
3637
3639
  });
3638
- if (promoted.promoted) {
3639
- dispatchArgs.kind = promoted.kind;
3640
- dispatchArgs.content = promoted.content;
3640
+ if (decision.action === 'reject') {
3641
+ sendJson(res, 200, { ok: false, text: decision.message });
3642
+ return;
3643
+ }
3644
+ if (decision.action === 'convert') {
3645
+ dispatchArgs.kind = decision.kind;
3646
+ dispatchArgs.content = decision.content;
3641
3647
  }
3642
3648
  }
3643
3649
  const { enqueuePanelDispatch } = await import('./panel_queue.js');
@@ -3803,7 +3809,15 @@ async function handleStartupTabs(_req, res, ctx, url) {
3803
3809
  const allEdges = slug ? await listAllEdges(slug) : [];
3804
3810
  const nodeIdSet = new Set(nodes.map((n) => n.id));
3805
3811
  const edges = allEdges.filter((e) => nodeIdSet.has(e.from_id) && nodeIdSet.has(e.to_id));
3806
- const gNodes = nodes.map((n) => ({ id: n.id, label: n.name || n.id, weight: n.weight, kind: n.kind, confidence: n.confidence, detail: n.purpose || '' }));
3812
+ /* Galaxy graph: attach each node's LAST CHANGE (unix ts) so the panel can
3813
+ * colour newest -> blue, oldest -> red. One git-log pass + mtime fallback. */
3814
+ const { fileLastChangeMap, nodeLastChange, pathFromPurpose } = await import('../semantic_graph/last_change.js');
3815
+ const _lcMap = await fileLastChangeMap(ctx.projectRoot).catch(() => new Map());
3816
+ const gNodes = await Promise.all(nodes.map(async (n) => ({
3817
+ id: n.id, label: n.name || n.id, weight: n.weight, kind: n.kind,
3818
+ confidence: n.confidence, detail: n.purpose || '',
3819
+ lastChange: await nodeLastChange(ctx.projectRoot, pathFromPurpose(n.purpose || ''), _lcMap),
3820
+ })));
3807
3821
  const gEdges = edges.map((e) => ({ from: e.from_id, to: e.to_id, kind: e.kind }));
3808
3822
  tabs.push({ key: 'startup_graph', title: t('startup.tab.graph'), kind: 'graph', content: JSON.stringify({ nodes: gNodes, edges: gEdges }) });
3809
3823
  /* Grafo semantico = misma data en markdown (tabla de nodos por