@illuminis/comprism 0.1.5 → 0.1.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.
Files changed (100) hide show
  1. package/out/agent/command.js +4 -4
  2. package/out/agent/session.d.ts +6 -1
  3. package/out/agent/session.js +17 -8
  4. package/out/commands/agents.js +3 -3
  5. package/out/commands/ask.js +8 -8
  6. package/out/commands/codemap.d.ts +1 -1
  7. package/out/commands/codemap.js +3 -3
  8. package/out/commands/commands-thin.js +4 -4
  9. package/out/commands/config.js +1 -1
  10. package/out/commands/cost.js +4 -4
  11. package/out/commands/hooks.js +1 -1
  12. package/out/commands/install.d.ts +1 -1
  13. package/out/commands/install.js +3 -2
  14. package/out/commands/instructions.js +1 -1
  15. package/out/commands/integrations.js +4 -4
  16. package/out/commands/keys.js +6 -6
  17. package/out/commands/login.js +37 -21
  18. package/out/commands/permissions.js +2 -2
  19. package/out/commands/plugins.js +3 -3
  20. package/out/commands/privacy.js +2 -2
  21. package/out/commands/repl.js +107 -83
  22. package/out/commands/review.js +6 -6
  23. package/out/commands/settings.js +30 -123
  24. package/out/commands/skills.js +2 -2
  25. package/out/commands/unattended.js +6 -6
  26. package/out/commands/update.js +1 -1
  27. package/out/commands/welcome.js +20 -29
  28. package/out/commands/worktrees.d.ts +1 -1
  29. package/out/graph/sync.d.ts +1 -1
  30. package/out/graph/sync.js +6 -6
  31. package/out/lib/attach.js +4 -3
  32. package/out/lib/commandlist.d.ts +1 -1
  33. package/out/lib/commandlist.js +2 -2
  34. package/out/lib/config.d.ts +3 -2
  35. package/out/lib/config.js +7 -8
  36. package/out/lib/connection.js +1 -1
  37. package/out/lib/gateway.d.ts +5 -5
  38. package/out/lib/machine.js +1 -1
  39. package/out/lib/project-ops.d.ts +1 -1
  40. package/out/lib/project-ops.js +4 -4
  41. package/out/lib/queue.js +1 -1
  42. package/out/lib/readiness.d.ts +3 -30
  43. package/out/lib/readiness.js +13 -82
  44. package/out/lib/servicecommand.d.ts +14 -0
  45. package/out/lib/servicecommand.js +74 -0
  46. package/out/lib/sessions.js +3 -3
  47. package/out/lib/ui.d.ts +9 -6
  48. package/out/lib/ui.js +20 -26
  49. package/out/lib/voice.js +1 -1
  50. package/out/lib/words.d.ts +20 -0
  51. package/out/lib/words.js +27 -0
  52. package/out/machine/codemap/build.d.ts +45 -0
  53. package/out/machine/codemap/build.js +91 -0
  54. package/out/machine/codemap/facts.d.ts +47 -0
  55. package/out/machine/codemap/facts.js +12 -0
  56. package/out/machine/codemap/files.d.ts +45 -0
  57. package/out/machine/codemap/files.js +207 -0
  58. package/out/machine/codemap/read-locales.d.ts +29 -0
  59. package/out/machine/codemap/read-locales.js +246 -0
  60. package/out/machine/codemap/read-python.d.ts +11 -0
  61. package/out/machine/codemap/read-python.js +116 -0
  62. package/out/machine/codemap/read-typescript.d.ts +16 -0
  63. package/out/machine/codemap/read-typescript.js +292 -0
  64. package/out/machine/executor/browser.d.ts +14 -0
  65. package/out/machine/executor/browser.js +270 -0
  66. package/out/machine/executor/diagnostics.d.ts +2 -0
  67. package/out/machine/executor/diagnostics.js +181 -0
  68. package/out/machine/executor/documents.d.ts +40 -0
  69. package/out/machine/executor/documents.js +170 -0
  70. package/out/machine/executor/files.d.ts +2 -0
  71. package/out/machine/executor/files.js +590 -0
  72. package/out/machine/executor/git.d.ts +48 -0
  73. package/out/machine/executor/git.js +145 -0
  74. package/out/machine/executor/hooks.d.ts +51 -0
  75. package/out/machine/executor/hooks.js +154 -0
  76. package/out/machine/executor/index.d.ts +45 -0
  77. package/out/machine/executor/index.js +367 -0
  78. package/out/machine/executor/notebook.d.ts +2 -0
  79. package/out/machine/executor/notebook.js +147 -0
  80. package/out/machine/executor/paths.d.ts +20 -0
  81. package/out/machine/executor/paths.js +154 -0
  82. package/out/machine/executor/sandbox.d.ts +40 -0
  83. package/out/machine/executor/sandbox.js +299 -0
  84. package/out/machine/executor/shell.d.ts +86 -0
  85. package/out/machine/executor/shell.js +582 -0
  86. package/out/machine/executor/toolservers.d.ts +20 -0
  87. package/out/machine/executor/toolservers.js +189 -0
  88. package/out/machine/executor/worktree.d.ts +9 -0
  89. package/out/machine/executor/worktree.js +119 -0
  90. package/out/machine/folder/project.d.ts +28 -0
  91. package/out/machine/folder/project.js +114 -0
  92. package/out/machine/runtime/home.d.ts +2 -0
  93. package/out/machine/runtime/home.js +48 -0
  94. package/out/machine/runtime/needs.d.ts +30 -0
  95. package/out/machine/runtime/needs.js +89 -0
  96. package/out/machine/runtime/self.d.ts +23 -0
  97. package/out/machine/runtime/self.js +124 -0
  98. package/out/providers/index.js +2 -1
  99. package/out/thin.js +11 -10
  100. package/package.json +4 -4
@@ -45,8 +45,8 @@ async function cmdPrivacy() {
45
45
  const reply = await (0, gateway_1.ask)({ intent: "privacy", prompt: "" });
46
46
  if (!reply.ok || reply.served === false) {
47
47
  out(ui.fail(reply.served === false
48
- ? "Your workspace is running an older build that does not answer this yet."
49
- : `Your workspace could not be reached: ${reply.message || "no answer"}`));
48
+ ? "Your organization is running an older build that does not answer this yet."
49
+ : `Your organization could not be reached: ${reply.message || "no answer"}`));
50
50
  return 1;
51
51
  }
52
52
  out();
@@ -80,7 +80,7 @@ const keyboard_1 = require("../lib/keyboard");
80
80
  const machine_1 = require("../lib/machine");
81
81
  const ui = __importStar(require("../lib/ui"));
82
82
  const render_1 = require("../agent/render");
83
- const shell_1 = require("../executor/shell");
83
+ const shell_1 = require("../machine/executor/shell");
84
84
  const voice = __importStar(require("../lib/voice"));
85
85
  const out = (s = '') => process.stdout.write(s + '\n');
86
86
  /**
@@ -285,7 +285,7 @@ function sessionWords() {
285
285
  return [...COMMANDS, 'project', 'folders', 'instructions', 'remember', 'detach', 'output', 'processes', 'stop', 'agents'];
286
286
  }
287
287
  async function refreshList() {
288
- const { resolveProject } = await Promise.resolve().then(() => __importStar(require('../lib/project')));
288
+ const { resolveProject } = await Promise.resolve().then(() => __importStar(require('../machine/folder/project')));
289
289
  const root = resolveProject(await sessionFolder(), place.added).root;
290
290
  const got = await (0, commandlist_1.fetchCommandList)(root, sessionWords());
291
291
  // A failed refresh keeps the list already held rather than emptying it.
@@ -356,11 +356,12 @@ async function showHelpers() {
356
356
  out();
357
357
  }
358
358
  /** The permission modes, in the order Shift+Tab moves through them (4.5). */
359
+ /** The modes Shift+Tab steps through, as the service last listed them. */
359
360
  const MODES = ['read_only', 'approve_writes', 'auto_edit', 'full_auto'];
360
361
  /** How the next job in this session runs: its mode and whether it plans first
361
362
  * (manual 4.1, 4.5). Changed by `mode`, Shift+Tab, `plan` and `plan off`, and
362
363
  * applied from the next job; the service still decides what each mode allows. */
363
- const steering_ = { mode: 'approve_writes', plan: false, pin: '', effort: '' };
364
+ const steering_ = { mode: 'approve_writes', plan: false, pin: '', effort: '', modes: MODES };
364
365
  /**
365
366
  * The line as a command, with a leading slash taken off.
366
367
  *
@@ -623,7 +624,7 @@ function printHelp() {
623
624
  out();
624
625
  drawList(listedItems());
625
626
  if (!listed?.ok) {
626
- out(ui.c.amber(' Your workspace could not be asked for its skills, so only this tool\'s own words are shown.'));
627
+ out(ui.c.amber(' Your organization could not be asked for its skills, so only this tool\'s own words are shown.'));
627
628
  out();
628
629
  }
629
630
  else if (listed.needsUpdate.length > 0) {
@@ -645,9 +646,42 @@ function printHelp() {
645
646
  /**
646
647
  * The folders this session works in (manual 2.1 and 2.3). `project <path>`
647
648
  * changes the folder for the rest of the session; `folders add <path>` allows
648
- * another. Neither changes the saved default, which is `comprism project`.
649
+ * another. Neither changes the saved default, which is `comprism workspace`.
649
650
  */
650
- const place = { folder: null, added: [] };
651
+ const place = { folder: null, added: [], workspace: '' };
652
+ /**
653
+ * One command the service runs itself (web manual 13.2, 13.3). The service says
654
+ * what it means and writes every line; this answers whether a folder exists on
655
+ * this computer when asked, prints the lines, and carries out the one action it
656
+ * names. True when the session's workspace or folders changed; the request to
657
+ * run when a next step was chosen.
658
+ */
659
+ async function serviceCommand(words) {
660
+ const { runServiceCommand } = await Promise.resolve().then(() => __importStar(require('../lib/servicecommand')));
661
+ const said = await runServiceCommand(words, { cwd: await sessionFolder(), current: place.workspace });
662
+ if (!said.reached) {
663
+ out(ui.fail(said.message || 'Your organization could not answer that.'));
664
+ return false;
665
+ }
666
+ for (const line of said.lines)
667
+ out(line);
668
+ const a = said.action;
669
+ if (!a)
670
+ return false;
671
+ if (a.run)
672
+ return a.run;
673
+ if (a.open_workspace)
674
+ place.workspace = a.open_workspace;
675
+ if (a.use_folder) {
676
+ place.folder = a.use_folder;
677
+ (await Promise.resolve().then(() => __importStar(require('../lib/project-ops')))).useSessionFolder(a.use_folder);
678
+ }
679
+ if (a.add_folder && !place.added.includes(a.add_folder))
680
+ place.added.push(a.add_folder);
681
+ if (a.remove_folder)
682
+ place.added = place.added.filter((f) => f !== a.remove_folder);
683
+ return true;
684
+ }
651
685
  async function sessionFolder() {
652
686
  if (place.folder)
653
687
  return place.folder;
@@ -656,7 +690,7 @@ async function sessionFolder() {
656
690
  }
657
691
  /** The line this session begins with, as the service wrote it (manual 2.2). */
658
692
  async function projectLine() {
659
- const { resolveProject, asWire } = await Promise.resolve().then(() => __importStar(require('../lib/project')));
693
+ const { resolveProject, asWire } = await Promise.resolve().then(() => __importStar(require('../machine/folder/project')));
660
694
  const { ask } = await Promise.resolve().then(() => __importStar(require('../lib/gateway')));
661
695
  const facts = resolveProject(await sessionFolder(), place.added);
662
696
  const reply = await ask({ intent: 'project', prompt: '', project: asWire(facts, 'approve_writes') });
@@ -685,7 +719,7 @@ async function contextOf(intent, jobId, keep = '', sessionKey) {
685
719
  intent, prompt: keep, ...(jobId ? { jobId } : {}), ...(sessionKey ? { spendSession: sessionKey } : {}),
686
720
  });
687
721
  if (!reply.ok || !reply.context) {
688
- out(ui.fail(reply.message || 'Your workspace could not answer that.'));
722
+ out(ui.fail(reply.message || 'Your organization could not answer that.'));
689
723
  }
690
724
  else {
691
725
  for (const line of reply.context.lines)
@@ -704,7 +738,7 @@ async function showTranscript(jobId) {
704
738
  const { ask } = await Promise.resolve().then(() => __importStar(require('../lib/gateway')));
705
739
  const reply = await ask({ intent: 'transcript', prompt: '', jobId });
706
740
  if (!reply.ok || !reply.transcript) {
707
- out(ui.fail(reply.message || 'The transcript could not be read from your workspace.'));
741
+ out(ui.fail(reply.message || 'The transcript could not be read from your organization.'));
708
742
  }
709
743
  else {
710
744
  for (const line of reply.transcript.lines)
@@ -1022,7 +1056,7 @@ async function runRepl(how = {}) {
1022
1056
  });
1023
1057
  }
1024
1058
  if (!state.reached) {
1025
- out(ui.fail(`Your workspace could not be reached, so ${ui.c.bold('nothing is known')} about your keys.`));
1059
+ out(ui.fail(`Your organization could not be reached, so ${ui.c.bold('nothing is known')} about your keys.`));
1026
1060
  out(` ${ui.c.dim(state.why)}`);
1027
1061
  out(` ${ui.c.dim('check the address with')} ${ui.c.bold('comprism status')}${ui.c.dim(', or sign in again with')} ${ui.c.bold('comprism login')}`);
1028
1062
  out();
@@ -1059,6 +1093,14 @@ async function runRepl(how = {}) {
1059
1093
  }
1060
1094
  steering_.pin = said.pin ?? '';
1061
1095
  steering_.effort = said.effort === 'normal' ? '' : said.effort;
1096
+ // Mode and plan are the service's too (CLI manual 4.1, 4.5); kept here only
1097
+ // to send with the next job and to draw the prompt.
1098
+ if (said.mode)
1099
+ steering_.mode = said.mode;
1100
+ if (typeof said.plan === 'boolean')
1101
+ steering_.plan = said.plan;
1102
+ if (said.modes?.length)
1103
+ steering_.modes = said.modes;
1062
1104
  return said;
1063
1105
  };
1064
1106
  if (how.latest || how.resume || how.pick) {
@@ -1346,7 +1388,7 @@ async function runRepl(how = {}) {
1346
1388
  * a drag and drop, and the files wait for the question that follows.
1347
1389
  */
1348
1390
  const gather = async (typed) => {
1349
- const { resolveProject } = await Promise.resolve().then(() => __importStar(require('../lib/project')));
1391
+ const { resolveProject } = await Promise.resolve().then(() => __importStar(require('../machine/folder/project')));
1350
1392
  const here = await sessionFolder();
1351
1393
  const root = resolveProject(here, place.added).root;
1352
1394
  completion.root = root;
@@ -1639,11 +1681,15 @@ async function runRepl(how = {}) {
1639
1681
  keys().on('keypress', (_s, key) => {
1640
1682
  if (!key || key.name !== 'tab' || !key.shift || working || answering || leaving)
1641
1683
  return;
1642
- const next = MODES[(MODES.indexOf(steering_.mode) + 1) % MODES.length];
1643
- steering_.mode = next;
1684
+ // The next mode in the service's own list, set by the service.
1685
+ const modes = steering_.modes;
1686
+ const next = modes[(modes.indexOf(steering_.mode) + 1) % modes.length];
1644
1687
  out();
1645
- out(ui.c.dim(` mode ${ui.c.bold(next)}, from the next job`));
1646
- prompt();
1688
+ void steer({ mode: next }).then((said) => {
1689
+ for (const line of said?.lines ?? [])
1690
+ out(ui.c.dim(line));
1691
+ prompt();
1692
+ });
1647
1693
  });
1648
1694
  async function handle(line) {
1649
1695
  const typed = line.trim();
@@ -1669,38 +1715,27 @@ async function runRepl(how = {}) {
1669
1715
  out();
1670
1716
  return prompt();
1671
1717
  }
1672
- const where = /^(project|workspace)(?:\s+(.+))?$/i.exec(bare);
1673
- const addFolder = /^folders\s+add\s+(.+)$/i.exec(bare);
1674
- if (where || addFolder || /^folders$/i.test(bare)) {
1675
- const { checkFolder, resolveProject } = await Promise.resolve().then(() => __importStar(require('../lib/project')));
1676
- const named = where ? where[2] : addFolder ? addFolder[1] : undefined;
1677
- if (named) {
1678
- const found = checkFolder(named.trim());
1679
- if (!found.ok) {
1680
- out(ui.fail(found.why));
1681
- out();
1682
- return prompt();
1683
- }
1684
- if (where) {
1685
- place.folder = found.path;
1686
- (await Promise.resolve().then(() => __importStar(require('../lib/project-ops')))).useSessionFolder(found.path);
1687
- }
1688
- else if (!place.added.includes(found.path))
1689
- place.added.push(found.path);
1690
- }
1691
- if (/^folders$/i.test(bare)) {
1692
- const facts = resolveProject(await sessionFolder(), place.added);
1693
- out();
1694
- out(` ${ui.c.bold(facts.root)} ${ui.c.dim('project')}`);
1695
- for (const f of facts.added)
1696
- out(` ${ui.c.bold(f)} ${ui.c.dim('added for this session')}`);
1697
- out();
1698
- return prompt();
1699
- }
1718
+ // Commands the service runs itself (web manual 13.2, 13.3): any word the
1719
+ // service lists as its own, and `project`, the old name for `workspace`.
1720
+ // What they mean and every line printed are the service's; this sends what
1721
+ // was typed, answers whether a folder exists, and carries out the action.
1722
+ const head = (bare.split(/\s+/)[0] ?? '').toLowerCase();
1723
+ const { waitingNextSteps } = await Promise.resolve().then(() => __importStar(require('../agent/session')));
1724
+ const serviceWord = head === 'project'
1725
+ || (/^\d+$/.test(bare) && waitingNextSteps > 0)
1726
+ || (listed?.items ?? []).some((i) => i.source === 'service' && i.name === head);
1727
+ if (serviceWord) {
1728
+ const words = head === 'project' ? bare.replace(/^project\b/i, 'workspace') : bare;
1729
+ const acted = await serviceCommand(words);
1700
1730
  out();
1701
- await showProjectLine();
1702
- // Another folder has other skills.
1703
- await refreshList();
1731
+ // A next step chosen: it runs as the request it stands for.
1732
+ if (typeof acted === 'string')
1733
+ return handle(`work ${acted}`);
1734
+ if (acted) {
1735
+ await showProjectLine();
1736
+ // Another folder has other skills.
1737
+ await refreshList();
1738
+ }
1704
1739
  return prompt();
1705
1740
  }
1706
1741
  // `pin <model>` and `effort <level>` (manual 4.17, 4.18), kept by the
@@ -1736,16 +1771,12 @@ async function runRepl(how = {}) {
1736
1771
  }
1737
1772
  const effortTo = /^effort\s+(\S+)$/.exec(word);
1738
1773
  if (effortTo) {
1739
- const level = effortTo[1];
1740
- if (!['low', 'medium', 'normal', 'high'].includes(level))
1741
- out(ui.fail('Effort is low, normal or high.'));
1742
- else {
1743
- const said = await steer({ effort: level === 'medium' ? 'normal' : level });
1744
- if (said) {
1745
- out(ui.c.dim(` effort ${ui.c.bold(said.effort)} for the next requests`));
1746
- if (said.effort_note)
1747
- out(ui.c.dim(` ${said.effort_note}`));
1748
- }
1774
+ // The service checks the word and says what is allowed.
1775
+ const said = await steer({ effort: effortTo[1] });
1776
+ if (said) {
1777
+ out(ui.c.dim(` effort ${ui.c.bold(said.effort)} for the next requests`));
1778
+ if (said.effort_note)
1779
+ out(ui.c.dim(` ${said.effort_note}`));
1749
1780
  }
1750
1781
  out();
1751
1782
  return prompt();
@@ -1753,20 +1784,16 @@ async function runRepl(how = {}) {
1753
1784
  // `mode <name>` and `plan off` (manual 4.1, 4.5).
1754
1785
  const modeTo = /^mode\s+(\S+)$/.exec(word);
1755
1786
  if (modeTo) {
1756
- const named = modeTo[1];
1757
- if (!MODES.includes(named)) {
1758
- out(ui.fail(`${named} is not a permission mode. One of: ${MODES.join(', ')}`));
1759
- }
1760
- else {
1761
- steering_.mode = named;
1762
- out(ui.c.dim(` mode ${ui.c.bold(named)}, from the next job`));
1763
- }
1787
+ const said = await steer({ mode: modeTo[1] });
1788
+ for (const line of said?.lines ?? [])
1789
+ out(ui.c.dim(line));
1764
1790
  out();
1765
1791
  return prompt();
1766
1792
  }
1767
1793
  if (word === 'plan off') {
1768
- steering_.plan = false;
1769
- out(ui.c.dim(' planning off: the next requests are carried out'));
1794
+ const said = await steer({ plan: false });
1795
+ for (const line of said?.lines ?? [])
1796
+ out(ui.c.dim(line));
1770
1797
  out();
1771
1798
  return prompt();
1772
1799
  }
@@ -1784,7 +1811,7 @@ async function runRepl(how = {}) {
1784
1811
  // `output 3`: a command's whole output, kept on this machine (5.12).
1785
1812
  const outputOf = /^output(?:\s+(\d+))?$/.exec(word);
1786
1813
  if (outputOf) {
1787
- const { keptOutput } = await Promise.resolve().then(() => __importStar(require('../executor/shell')));
1814
+ const { keptOutput } = await Promise.resolve().then(() => __importStar(require('../machine/executor/shell')));
1788
1815
  const kept = outputOf[1] ? keptOutput(Number(outputOf[1])) : undefined;
1789
1816
  if (!outputOf[1])
1790
1817
  out(ui.c.dim(' output N shows the whole output of command N, the number on its line.'));
@@ -1893,16 +1920,20 @@ async function runRepl(how = {}) {
1893
1920
  }
1894
1921
  if (COMMANDS.has(word)) {
1895
1922
  switch (word) {
1896
- case 'plan':
1897
- steering_.plan = true;
1898
- out(ui.c.dim(' planning on: the next requests are planned first and change nothing. `plan off` stops.'));
1923
+ case 'plan': {
1924
+ const said = await steer({ plan: true });
1925
+ for (const line of said?.lines ?? [])
1926
+ out(ui.c.dim(line));
1899
1927
  out();
1900
1928
  break;
1901
- case 'mode':
1902
- out(` ${ui.c.dim('mode')} ${ui.c.bold(steering_.mode)}${steering_.plan ? ui.c.dim(', planning first') : ''}`);
1903
- out(ui.c.dim(` one of ${MODES.join(', ')}. \`mode <name>\` or Shift+Tab changes it.`));
1929
+ }
1930
+ case 'mode': {
1931
+ const said = await steer({});
1932
+ for (const line of said?.lines ?? [])
1933
+ out(ui.c.dim(line));
1904
1934
  out();
1905
1935
  break;
1936
+ }
1906
1937
  case 'pin': {
1907
1938
  const said = await steer({});
1908
1939
  out(said?.pin
@@ -2096,17 +2127,10 @@ async function runRepl(how = {}) {
2096
2127
  // session the moment two are open, and this one is on the screen.
2097
2128
  case 'cost':
2098
2129
  case 'spend': {
2099
- // Nothing sent is nothing charged, and the service has no record of
2100
- // a session before its first job, so it would answer "no such
2101
- // session" to a person checking that a refusal cost them nothing
2102
- // (manual 6.1).
2103
- if (session.jobs.length === 0) {
2104
- out(` ${ui.c.dim('session')} ${ui.c.bold(session.id)} ${ui.c.dim('nothing has run yet, so it has cost')} $0.00`);
2105
- out();
2106
- break;
2107
- }
2130
+ // Nothing sent is nothing charged: the service answers even before
2131
+ // the first job, so a refusal can be checked as costing nothing (6.1).
2108
2132
  const { cmdCost } = await Promise.resolve().then(() => __importStar(require('./cost')));
2109
- await cmdCost([session.id]);
2133
+ await cmdCost([session.serverId || session.id]);
2110
2134
  break;
2111
2135
  }
2112
2136
  case 'model': {
@@ -52,8 +52,8 @@ const fs = __importStar(require("fs"));
52
52
  const path = __importStar(require("path"));
53
53
  const ui = __importStar(require("../lib/ui"));
54
54
  const gateway_1 = require("../lib/gateway");
55
- const project_1 = require("../lib/project");
56
- const project_2 = require("../lib/project");
55
+ const project_1 = require("../machine/folder/project");
56
+ const project_2 = require("../machine/folder/project");
57
57
  const out = (s = "") => process.stdout.write(`${s}\n`);
58
58
  const err = (s = "") => process.stderr.write(`${s}\n`);
59
59
  async function review(op, payload, cwd = process.cwd()) {
@@ -62,9 +62,9 @@ async function review(op, payload, cwd = process.cwd()) {
62
62
  }
63
63
  function refused(reply) {
64
64
  if (!reply.ok)
65
- return reply.message || "Your workspace could not be reached.";
65
+ return reply.message || "Your organization could not be reached.";
66
66
  if (reply.served === false)
67
- return "Your workspace is running an older build that does not answer this yet.";
67
+ return "Your organization is running an older build that does not answer this yet.";
68
68
  if (reply.granted === false)
69
69
  return reply.message || "Refused.";
70
70
  return null;
@@ -162,7 +162,7 @@ async function cmdRewind(args, confirmWith) {
162
162
  for (const item of items) {
163
163
  const where = inside(project.root, item.path);
164
164
  if (!where) {
165
- results.push({ path: item.path, result: "outside this project, not restored" });
165
+ results.push({ path: item.path, result: "outside this workspace, not restored" });
166
166
  continue;
167
167
  }
168
168
  // Your later changes are never overwritten (7.4): the file must still be
@@ -190,7 +190,7 @@ async function cmdRewind(args, confirmWith) {
190
190
  else if (item.action === "rename_back" && item.to) {
191
191
  const from = inside(project.root, item.to);
192
192
  if (!from)
193
- throw new Error("the new name is outside this project");
193
+ throw new Error("the new name is outside this workspace");
194
194
  fs.mkdirSync(path.dirname(where), { recursive: true });
195
195
  if (fs.existsSync(from))
196
196
  fs.renameSync(from, where);
@@ -41,29 +41,9 @@ exports.currentWorkspace = currentWorkspace;
41
41
  exports.cmdProviders = cmdProviders;
42
42
  exports.cmdModel = cmdModel;
43
43
  exports.cmdProject = cmdProject;
44
- /**
45
- * The three things a person sets once and then forgets: which model they are
46
- * compared against, which vendors they can reach, and which folder they work in.
47
- *
48
- * ── What is stored here, and what is not ──────────────────────────────────
49
- *
50
- * A PREFERENCE lives on this machine: the model you would otherwise have used,
51
- * and the folder you work in. Neither is a secret and neither is model logic;
52
- * they are two facts about you, and a round trip to ask us for them would be
53
- * slower and no safer.
54
- *
55
- * THE MODEL LIST does not live here. It comes from our server on every call,
56
- * because the models and their prices are ours, and because a copy on a
57
- * customer's laptop goes stale the day a vendor changes a price. A stale price
58
- * silently corrupts every figure downstream of it, which is the exact failure
59
- * this product exists to replace.
60
- */
61
- const node_fs_1 = __importDefault(require("node:fs"));
62
44
  const node_path_1 = __importDefault(require("node:path"));
63
- const prompt_1 = require("../lib/prompt");
64
45
  const gateway_1 = require("../lib/gateway");
65
46
  const config_1 = require("../lib/config");
66
- const project_1 = require("../lib/project");
67
47
  const ui = __importStar(require("../lib/ui"));
68
48
  const out = (s = '') => process.stdout.write(s + '\n');
69
49
  /** Where the chosen folder is remembered. Beside the rest of the settings. */
@@ -78,12 +58,10 @@ function workspaceFile() {
78
58
  * current one would be a trap.
79
59
  */
80
60
  function currentWorkspace() {
81
- try {
82
- const saved = JSON.parse(node_fs_1.default.readFileSync(workspaceFile(), 'utf8'));
83
- if (saved.path && node_fs_1.default.existsSync(saved.path))
84
- return { path: saved.path, source: 'saved' };
85
- }
86
- catch { /* nothing saved, which is the normal case */ }
61
+ // The folder you are standing in, as in every other terminal tool. A folder
62
+ // saved on this laptop used to override it; workspaces now live on the
63
+ // service, the same in every client, and `workspace <name>` opens another
64
+ // (web manual 13.2).
87
65
  return { path: process.cwd(), source: 'cwd' };
88
66
  }
89
67
  /**
@@ -107,8 +85,8 @@ async function cmdProviders() {
107
85
  // have, which is the fault reported on 17 September 2026.
108
86
  if (!reply.ok || reply.served === false || reply.complete === false
109
87
  || !reply.providers || reply.providers.length === 0) {
110
- out(ui.fail('Your workspace could not tell us which vendors it can reach.'));
111
- out(` ${ui.c.dim(reply.message || reply.decision.rationale || 'no answer from the workspace')}`);
88
+ out(ui.fail('Your organization could not tell us which vendors it can reach.'));
89
+ out(` ${ui.c.dim(reply.message || reply.decision.rationale || 'no answer from the organization')}`);
112
90
  out(` ${ui.c.dim('check the address with')} ${ui.c.bold('comprism status')}`);
113
91
  out();
114
92
  process.exitCode = 1;
@@ -136,111 +114,40 @@ async function cmdProviders() {
136
114
  * have used, which is the only thing a saving can honestly be measured against.
137
115
  */
138
116
  async function cmdModel(args) {
139
- const cfg = (0, config_1.loadConfig)();
140
- const named = args.find((a) => !a.startsWith('--'));
141
- out(ui.banner('Your comparison model'));
142
- out();
143
- out(ui.c.dim(' The model you would have used anyway. Savings are measured against it.'));
144
- out(` ${ui.c.dim('Now:')} ${ui.c.bold(cfg.defaultModel || 'not set')}`);
145
- out();
146
- const reply = await (0, gateway_1.ask)({ intent: 'catalog', prompt: '' });
147
- const models = (reply.providers || []).flatMap((p) => p.models);
148
- // Same rule as every other reader: an answer we did not get is not an answer
149
- // of none.
150
- if (!reply.ok || reply.served === false || reply.complete === false
151
- || models.length === 0) {
152
- out(ui.fail('Your workspace could not tell us which models it can reach.'));
153
- out(` ${ui.c.dim(reply.message || reply.decision.rationale || 'no answer from the workspace')}`);
154
- out();
155
- process.exitCode = 1;
156
- return;
157
- }
158
- const match = (value) => models.find((m) => m.id === value || m.key === value
159
- || m.label.toLowerCase() === value.toLowerCase());
160
- let chosen = named ? match(named) : undefined;
161
- if (named && !chosen) {
162
- out(ui.fail(`No model called "${named}".`));
163
- out(` ${ui.c.dim('see the list with')} ${ui.c.bold('comprism providers')}`);
164
- out();
117
+ // The comparison model is the person's own setting on the service, the same
118
+ // in every client (service catalog 14); the service lists, checks and words it.
119
+ const named = args.filter((a) => !a.startsWith('--')).join(' ');
120
+ const reply = await (0, gateway_1.ask)({
121
+ intent: 'command', prompt: '', payload: { words: `model ${named}`.trim() },
122
+ });
123
+ if (!reply.lines?.length) {
124
+ out(ui.fail(reply.message || 'Your organization could not answer that.'));
165
125
  process.exitCode = 1;
166
126
  return;
167
127
  }
168
- if (!chosen) {
169
- models.forEach((m, i) => {
170
- const n = String(i + 1).padStart(2);
171
- out(` ${n}. ${m.label.padEnd(24)} ${ui.c.dim(`${m.provider} ${m.tier}`)}`);
172
- });
173
- out();
174
- const answer = await (0, prompt_1.ask)(' number, or a model name: ');
175
- (0, prompt_1.closePrompt)();
176
- if (!answer) {
177
- out(ui.info('Left as it was.'));
178
- out();
179
- return;
180
- }
181
- const asNumber = Number(answer);
182
- chosen = Number.isInteger(asNumber) && asNumber >= 1 && asNumber <= models.length
183
- ? models[asNumber - 1]
184
- : match(answer);
185
- if (!chosen) {
186
- out(ui.fail(`"${answer}" is not on the list.`));
187
- out();
188
- process.exitCode = 1;
189
- return;
190
- }
191
- }
192
- (0, config_1.saveConfig)({ ...cfg, defaultModel: chosen.id });
193
128
  out();
194
- out(ui.ok(`Comparing against ${ui.c.bold(chosen.label)}.`));
195
- out(` ${ui.c.dim('every receipt from now on prices your work against this model')}`);
129
+ for (const line of reply.lines)
130
+ out(line);
196
131
  out();
132
+ if (reply.granted === false)
133
+ process.exitCode = 1;
197
134
  }
198
135
  async function cmdProject(args) {
199
- const named = args.find((a) => !a.startsWith('--'));
200
- const current = currentWorkspace();
201
- out(ui.banner('Project folder'));
202
- out();
203
- out(` ${ui.c.bold(current.path)}`);
204
- out(` ${ui.c.dim(current.source === 'cwd'
205
- ? 'the folder you are standing in'
206
- : 'saved, so it is used wherever you run the command from')}`);
207
- out();
208
- if (args.includes('--clear')) {
209
- try {
210
- node_fs_1.default.unlinkSync(workspaceFile());
211
- }
212
- catch { /* nothing was saved */ }
213
- out(ui.ok('Cleared. The folder you are standing in is used again.'));
214
- out();
215
- return;
216
- }
217
- // `comprism project` on its own shows the folder (manual 2.1). Asking only
218
- // when a person is at the keyboard and typed nothing, as before.
219
- let target = named;
220
- if (!target) {
221
- if (!process.stdin.isTTY)
222
- return;
223
- const answer = await (0, prompt_1.ask)(' new folder, or enter to keep it: ');
224
- (0, prompt_1.closePrompt)();
225
- if (!answer) {
226
- out(ui.info('Left as it was.'));
227
- out();
228
- return;
229
- }
230
- target = answer;
231
- }
232
- const found = (0, project_1.checkFolder)(target);
233
- if (!found.ok) {
234
- out(ui.fail(found.why));
235
- out();
236
- process.exitCode = 2;
136
+ // `comprism workspace ...` typed at the shell: the same service command a
137
+ // session runs (web manual 13.2). Opening one takes effect in a session.
138
+ const { runServiceCommand } = await Promise.resolve().then(() => __importStar(require('../lib/servicecommand')));
139
+ const said = await runServiceCommand(['workspace', ...args].join(' ').trim(), { cwd: process.cwd() });
140
+ if (!said.reached) {
141
+ out(ui.fail(said.message || 'Your organization could not answer that.'));
142
+ process.exitCode = 1;
237
143
  return;
238
144
  }
239
- node_fs_1.default.mkdirSync((0, config_1.homeDir)(), { recursive: true });
240
- node_fs_1.default.writeFileSync(workspaceFile(), JSON.stringify({ path: found.path }, null, 2), { mode: 0o600 });
241
- out(ui.ok(`Project folder set to ${ui.c.bold(found.path)}.`));
242
- out(` ${ui.c.dim('clear it with')} ${ui.c.bold('comprism project --clear')}`);
243
145
  out();
146
+ for (const line of said.lines)
147
+ out(line);
148
+ out();
149
+ if (!said.ok)
150
+ process.exitCode = 1;
244
151
  }
245
152
  /** The older name, kept so nothing that calls it breaks. */
246
153
  exports.cmdWorkspace = cmdProject;
@@ -50,7 +50,7 @@ const fs = __importStar(require("fs"));
50
50
  const path = __importStar(require("path"));
51
51
  const commandlist_1 = require("../lib/commandlist");
52
52
  const gateway_1 = require("../lib/gateway");
53
- const project_1 = require("../lib/project");
53
+ const project_1 = require("../machine/folder/project");
54
54
  const ui = __importStar(require("../lib/ui"));
55
55
  const ROUNDS = 6;
56
56
  /** What a folder sent with `add` may hold, beside its SKILL.md. The service
@@ -65,7 +65,7 @@ async function skillRows(folder, op = "list") {
65
65
  const reply = await (0, gateway_1.ask)({ intent: "skills", prompt: "", skillsPayload: { op, round, files, listings, project: root } });
66
66
  const body = reply.skills;
67
67
  if (!reply.ok || reply.served === false || !body) {
68
- return { rows: [], error: reply.message || "The skill list could not be read from your workspace." };
68
+ return { rows: [], error: reply.message || "The skill list could not be read from your organization." };
69
69
  }
70
70
  if (!body.wants) {
71
71
  return op === "check"
@@ -53,8 +53,8 @@ const path = __importStar(require("path"));
53
53
  const child_process_1 = require("child_process");
54
54
  const ui = __importStar(require("../lib/ui"));
55
55
  const queue_1 = require("../lib/queue");
56
- const project_1 = require("../lib/project");
57
- const self_1 = require("../lib/self");
56
+ const project_1 = require("../machine/folder/project");
57
+ const self_1 = require("../machine/runtime/self");
58
58
  const out = (s = "") => process.stdout.write(`${s}\n`);
59
59
  const err = (s = "") => process.stderr.write(`${s}\n`);
60
60
  /** Values typed after flags, so they are never read as the request. */
@@ -64,9 +64,9 @@ function words(args) {
64
64
  }
65
65
  function failed(reply) {
66
66
  if (!reply.ok)
67
- return reply.message || "Your workspace could not be reached.";
67
+ return reply.message || "Your organization could not be reached.";
68
68
  if (reply.served === false)
69
- return "Your workspace is running an older build that does not answer this yet.";
69
+ return "Your organization is running an older build that does not answer this yet.";
70
70
  if (reply.granted === false)
71
71
  return reply.message || "Refused.";
72
72
  return null;
@@ -216,7 +216,7 @@ async function runCloud(job) {
216
216
  }
217
217
  }
218
218
  const base = git(work, ["rev-parse", "HEAD"]).out.trim();
219
- const { availability } = await Promise.resolve().then(() => __importStar(require("../executor/sandbox")));
219
+ const { availability } = await Promise.resolve().then(() => __importStar(require("../machine/executor/sandbox")));
220
220
  const code = await runJob(job, work, availability().system ? ["--sandbox"] : []);
221
221
  git(work, ["add", "-A"]);
222
222
  const patch = git(work, ["diff", "--cached", "--binary", base]).out;
@@ -258,7 +258,7 @@ async function cmdWorker(args) {
258
258
  else {
259
259
  const folder = job.project_root && fs.existsSync(job.project_root) ? job.project_root : null;
260
260
  if (!folder) {
261
- await (0, queue_1.queue)("failed", { id: job.id, why: `the project folder ${job.project_root} is not on this machine` });
261
+ await (0, queue_1.queue)("failed", { id: job.id, why: `the workspace folder ${job.project_root} is not on this machine` });
262
262
  }
263
263
  else {
264
264
  const code = await runJob(job, folder);
@@ -50,7 +50,7 @@ const fs = __importStar(require("fs"));
50
50
  const path = __importStar(require("path"));
51
51
  const ui = __importStar(require("../lib/ui"));
52
52
  const gateway_1 = require("../lib/gateway");
53
- const self_1 = require("../lib/self");
53
+ const self_1 = require("../machine/runtime/self");
54
54
  const version_1 = require("../lib/version");
55
55
  const install_1 = require("./install");
56
56
  const out = (s = "") => process.stdout.write(`${s}\n`);