@nac3/forge-cli 1.19.1 → 1.19.3

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.
Files changed (64) hide show
  1. package/dist/bin/yf.d.ts.map +1 -1
  2. package/dist/bin/yf.js +2 -0
  3. package/dist/bin/yf.js.map +1 -1
  4. package/dist/chat/panel.d.ts.map +1 -1
  5. package/dist/chat/panel.js +198 -2
  6. package/dist/chat/panel.js.map +1 -1
  7. package/dist/chat/server.d.ts.map +1 -1
  8. package/dist/chat/server.js +136 -2
  9. package/dist/chat/server.js.map +1 -1
  10. package/dist/chat/tools/session_verbs.d.ts +10 -0
  11. package/dist/chat/tools/session_verbs.d.ts.map +1 -1
  12. package/dist/chat/tools/session_verbs.js +22 -12
  13. package/dist/chat/tools/session_verbs.js.map +1 -1
  14. package/dist/chat/tools/urazuke.d.ts +4 -0
  15. package/dist/chat/tools/urazuke.d.ts.map +1 -1
  16. package/dist/chat/tools/urazuke.js +21 -0
  17. package/dist/chat/tools/urazuke.js.map +1 -1
  18. package/dist/chat/tools.d.ts.map +1 -1
  19. package/dist/chat/tools.js +22 -0
  20. package/dist/chat/tools.js.map +1 -1
  21. package/dist/chat/urazuke_section.d.ts +1 -0
  22. package/dist/chat/urazuke_section.d.ts.map +1 -1
  23. package/dist/chat/urazuke_section.js +1 -0
  24. package/dist/chat/urazuke_section.js.map +1 -1
  25. package/dist/commands/task.d.ts +18 -0
  26. package/dist/commands/task.d.ts.map +1 -0
  27. package/dist/commands/task.js +126 -0
  28. package/dist/commands/task.js.map +1 -0
  29. package/dist/commands/urazuke.d.ts.map +1 -1
  30. package/dist/commands/urazuke.js +29 -0
  31. package/dist/commands/urazuke.js.map +1 -1
  32. package/dist/mcp/bridge_registry.d.ts +1 -1
  33. package/dist/nac3/dispatch_log.d.ts.map +1 -1
  34. package/dist/nac3/dispatch_log.js +16 -11
  35. package/dist/nac3/dispatch_log.js.map +1 -1
  36. package/dist/nac3/internal_manifest.d.ts.map +1 -1
  37. package/dist/nac3/internal_manifest.js +43 -0
  38. package/dist/nac3/internal_manifest.js.map +1 -1
  39. package/dist/tasks/alive.d.ts +38 -0
  40. package/dist/tasks/alive.d.ts.map +1 -0
  41. package/dist/tasks/alive.js +66 -0
  42. package/dist/tasks/alive.js.map +1 -0
  43. package/dist/urazuke/announce.d.ts +21 -0
  44. package/dist/urazuke/announce.d.ts.map +1 -0
  45. package/dist/urazuke/announce.js +40 -0
  46. package/dist/urazuke/announce.js.map +1 -0
  47. package/dist/urazuke/current.d.ts +25 -1
  48. package/dist/urazuke/current.d.ts.map +1 -1
  49. package/dist/urazuke/current.js +38 -3
  50. package/dist/urazuke/current.js.map +1 -1
  51. package/dist/urazuke/gate.d.ts +5 -0
  52. package/dist/urazuke/gate.d.ts.map +1 -1
  53. package/dist/urazuke/gate.js +7 -5
  54. package/dist/urazuke/gate.js.map +1 -1
  55. package/dist/urazuke/section.d.ts.map +1 -1
  56. package/dist/urazuke/section.js +1 -0
  57. package/dist/urazuke/section.js.map +1 -1
  58. package/dist/urazuke/start.d.ts +64 -0
  59. package/dist/urazuke/start.d.ts.map +1 -0
  60. package/dist/urazuke/start.js +91 -0
  61. package/dist/urazuke/start.js.map +1 -0
  62. package/dist/version.d.ts +1 -1
  63. package/dist/version.js +1 -1
  64. package/package.json +1 -1
@@ -1777,6 +1777,89 @@ async function route(req, res, ctx) {
1777
1777
  }
1778
1778
  return;
1779
1779
  }
1780
+ /* One project document, for the links of the Urazuke card modal. Gated to
1781
+ * the project root: a path that escapes it is refused. */
1782
+ if (req.method === 'GET' && url.pathname === '/api/forge/project-doc') {
1783
+ const rel = (url.searchParams.get('path') || '').trim();
1784
+ if (!rel) {
1785
+ sendJson(res, 400, { ok: false, error: 'path required' });
1786
+ return;
1787
+ }
1788
+ try {
1789
+ const nodePath = await import('node:path');
1790
+ const fsp = await import('node:fs/promises');
1791
+ const abs = nodePath.resolve(ctx.projectRoot, rel);
1792
+ const inside = abs === ctx.projectRoot || abs.startsWith(ctx.projectRoot + nodePath.sep);
1793
+ if (!inside) {
1794
+ sendJson(res, 403, { ok: false, error: 'path outside the project' });
1795
+ return;
1796
+ }
1797
+ const st = await fsp.stat(abs);
1798
+ if (!st.isFile()) {
1799
+ sendJson(res, 404, { ok: false, error: 'not a file' });
1800
+ return;
1801
+ }
1802
+ if (st.size > 2 * 1024 * 1024) {
1803
+ sendJson(res, 413, { ok: false, error: 'file too big for the panel (2 MB)' });
1804
+ return;
1805
+ }
1806
+ const content = await fsp.readFile(abs, 'utf8');
1807
+ const ext = nodePath.extname(abs).replace('.', '').toLowerCase();
1808
+ sendJson(res, 200, { ok: true, path: nodePath.relative(ctx.projectRoot, abs).split(nodePath.sep).join('/'), content, language: ext || null });
1809
+ }
1810
+ catch (e) {
1811
+ sendJson(res, 404, { ok: false, error: e instanceof Error ? e.message : String(e) });
1812
+ }
1813
+ return;
1814
+ }
1815
+ /* One pending item in full, for the click on a Workflow task. */
1816
+ if (req.method === 'GET' && url.pathname === '/api/forge/pending-item') {
1817
+ const id = (url.searchParams.get('id') || '').trim();
1818
+ if (!id) {
1819
+ sendJson(res, 400, { ok: false, error: 'id required' });
1820
+ return;
1821
+ }
1822
+ try {
1823
+ const { findPending } = await import('../pending/store.js');
1824
+ const item = await findPending(ctx.projectSlug || '', id);
1825
+ if (!item) {
1826
+ sendJson(res, 404, { ok: false, error: 'pending ' + id + ' not found' });
1827
+ return;
1828
+ }
1829
+ sendJson(res, 200, { ok: true, item });
1830
+ }
1831
+ catch (e) {
1832
+ sendJson(res, 500, { ok: false, error: e instanceof Error ? e.message : String(e) });
1833
+ }
1834
+ return;
1835
+ }
1836
+ /* URAZUKE start (2026-10-19): the panel button. */
1837
+ if (req.method === 'POST' && url.pathname === '/api/forge/urazuke-start') {
1838
+ let body = {};
1839
+ try {
1840
+ body = JSON.parse(await readBody(req) || '{}');
1841
+ }
1842
+ catch {
1843
+ body = {};
1844
+ }
1845
+ try {
1846
+ const { startUrazuke } = await import('../urazuke/start.js');
1847
+ const r = await startUrazuke(ctx.projectSlug || '', ctx.projectRoot, { force: body.force === true });
1848
+ if (r.ok) {
1849
+ try {
1850
+ const { urazukeCurrent } = await import('../urazuke/current.js');
1851
+ const { announceStepIfChanged } = await import('../urazuke/announce.js');
1852
+ await announceStepIfChanged(ctx.projectSlug || '', await urazukeCurrent(ctx.projectSlug || '', ctx.projectRoot));
1853
+ }
1854
+ catch { /* best effort */ }
1855
+ }
1856
+ sendJson(res, r.ok ? 200 : 409, { ...r });
1857
+ }
1858
+ catch (e) {
1859
+ sendJson(res, 500, { ok: false, error: e instanceof Error ? e.message : String(e) });
1860
+ }
1861
+ return;
1862
+ }
1780
1863
  if (req.method === 'POST' && url.pathname === '/api/forge/urazuke-prompts') {
1781
1864
  let body;
1782
1865
  try {
@@ -4594,6 +4677,8 @@ async function handleMobilePair(_req, res) {
4594
4677
  * Devuelve {enabled, tabs:[{key,title,kind,content}]}. El panel
4595
4678
  * las materializa al abrir (salvo las que el usuario cerro) y
4596
4679
  * hace polling para auto-refrescarlas. */
4680
+ /* One leftover-tasks notice per panel process (2026-10-20). */
4681
+ let leftoverTasksAnnounced = false;
4597
4682
  async function handleStartupTabs(_req, res, ctx, url) {
4598
4683
  const slug = ctx.projectSlug || '';
4599
4684
  let enabled = true;
@@ -4702,7 +4787,17 @@ async function handleStartupTabs(_req, res, ctx, url) {
4702
4787
  catch {
4703
4788
  ladderActive = false;
4704
4789
  }
4705
- hidden.push(ladderActive ? 'startup_workflow' : 'startup_urazuke');
4790
+ let urazukeOn = false;
4791
+ try {
4792
+ urazukeOn = await (await import('../urazuke/enabled.js')).urazukeEnabled();
4793
+ }
4794
+ catch {
4795
+ urazukeOn = false;
4796
+ }
4797
+ if (ladderActive)
4798
+ hidden.push('startup_workflow');
4799
+ else if (!urazukeOn)
4800
+ hidden.push('startup_urazuke');
4706
4801
  /* 4: workflow como GRAFO de nodos (las 6 fases del flujo yujin
4707
4802
  * con sus pasos), coloreadas por estado (done/pendiente) cuando
4708
4803
  * hay workflow state. Cumple el pedido de "workflow como grafo
@@ -4749,6 +4844,12 @@ async function handleStartupTabs(_req, res, ctx, url) {
4749
4844
  } : null;
4750
4845
  tabs.push({ key: 'startup_urazuke', title: t('startup.tab.urazuke'), kind: 'urazuke', content: JSON.stringify({ ladder, current }) });
4751
4846
  }
4847
+ else if (slugU && urazukeOn) {
4848
+ /* No ladder yet: the tab offers the door in (yujin.urazuke.start). */
4849
+ const { urazukeStartHint } = await import('../urazuke/start.js');
4850
+ const start = await urazukeStartHint(slugU, ctx.projectRoot);
4851
+ tabs.push({ key: 'startup_urazuke', title: t('startup.tab.urazuke'), kind: 'urazuke', content: JSON.stringify({ ladder: null, current: null, start }) });
4852
+ }
4752
4853
  }
4753
4854
  catch { /* sin escalera: la pestana no aparece */ }
4754
4855
  /* 5: PND-007 -- Tareas de fondo (se llena en vivo client-side). */
@@ -6206,12 +6307,37 @@ async function handleChat(req, res, ctx) {
6206
6307
  * the mechanical state of its checks, injected every turn. This is the
6207
6308
  * mechanism that replaces the advisory 18-step flow: the brain gets the
6208
6309
  * method's exact instruction, and the close gate refuses a red step. */
6310
+ /* Live background tasks (2026-10-20): the brain sees what is still up so
6311
+ * it does not relaunch it, and the owner gets one notice when the panel
6312
+ * opens with servers left over from another session. */
6313
+ let liveTasksSection = '';
6314
+ try {
6315
+ const { liveTasks, renderLiveTasksSection, renderLeftoverNotice } = await import('../tasks/alive.js');
6316
+ const live = await liveTasks(ctx.projectSlug || '');
6317
+ liveTasksSection = renderLiveTasksSection(live);
6318
+ if (!leftoverTasksAnnounced) {
6319
+ leftoverTasksAnnounced = true;
6320
+ const notice = renderLeftoverNotice(live);
6321
+ if (notice) {
6322
+ const { enqueuePanelDispatch } = await import('./panel_queue.js');
6323
+ enqueuePanelDispatch('system.chat-log', { text: notice }, new Date().toISOString());
6324
+ }
6325
+ }
6326
+ }
6327
+ catch (_) { /* swallow */ }
6209
6328
  let urazukeSection = '';
6210
6329
  try {
6211
6330
  const { buildUrazukeSection } = await import('./urazuke_section.js');
6212
6331
  const r = await buildUrazukeSection({ project_slug: ctx.projectSlug || '', project_root: ctx.projectRoot, char_budget: 6000 });
6213
6332
  if (r.rendered_text)
6214
6333
  urazukeSection = r.rendered_text;
6334
+ /* The owner sees in the chat which step runs and what is expected of
6335
+ * them (never the prompt): one system line per step change. */
6336
+ try {
6337
+ const { announceStepIfChanged } = await import('../urazuke/announce.js');
6338
+ await announceStepIfChanged(ctx.projectSlug || '', r.current);
6339
+ }
6340
+ catch { /* best effort */ }
6215
6341
  }
6216
6342
  catch (_) { /* swallow */ }
6217
6343
  /* alpha.59z.15 HITO 6.3 -- prefetch global learnings from
@@ -6245,6 +6371,14 @@ async function handleChat(req, res, ctx) {
6245
6371
  try {
6246
6372
  const { readLimitsConfig } = await import('../core/limits_config.js');
6247
6373
  multiagentEnabled = (await readLimitsConfig()).multiagent.enabled === true;
6374
+ /* 2026-10-19: on the Claude Plan without another provider's key the
6375
+ * children cannot run; hide the verbs instead of letting the brain
6376
+ * discover it by four dead sub-sessions. */
6377
+ if (multiagentEnabled) {
6378
+ const { hasUsableChildBrain } = await import('./tools/session_verbs.js');
6379
+ if (!(await hasUsableChildBrain()))
6380
+ multiagentEnabled = false;
6381
+ }
6248
6382
  }
6249
6383
  catch (_) { /* config failure -> stay OFF (safe default) */ }
6250
6384
  /* alpha.59z.37 NAC-3 v3.x backend tools -- prefetch the
@@ -6413,7 +6547,7 @@ async function handleChat(req, res, ctx) {
6413
6547
  * stable-first suffix lets a prefix cache extend through the unchanged
6414
6548
  * dynamic lines instead of missing on the first per-turn byte. ~84% of
6415
6549
  * this block was byte-identical turn-to-turn yet re-sent uncached. */
6416
- systemDynamic: projectContextSection + sizingSection + urazukeSection + wiringSection + toolingSection + recentSessionsRecap + graphSection + snapshotSection + workflowSection + approvalPostureSection + toolStatusSection(),
6550
+ systemDynamic: projectContextSection + sizingSection + liveTasksSection + urazukeSection + wiringSection + toolingSection + recentSessionsRecap + graphSection + snapshotSection + workflowSection + approvalPostureSection + toolStatusSection(),
6417
6551
  maxTokens: _maxTokensPerTurn,
6418
6552
  /* Tope del turno en Plan, POR TURNO (Pablo 2026-10-04). Se leia solo al
6419
6553
  * construir el cliente, asi que subir claude_cli_timeout_ms en el panel