@metaphi-ai/hum 0.1.26 → 0.1.30

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.mjs CHANGED
@@ -1257,26 +1257,26 @@ var require_react_development = __commonJS({
1257
1257
  }
1258
1258
  return lazyType;
1259
1259
  }
1260
- function forwardRef3(render2) {
1260
+ function forwardRef3(render3) {
1261
1261
  {
1262
- if (render2 != null && render2.$$typeof === REACT_MEMO_TYPE) {
1262
+ if (render3 != null && render3.$$typeof === REACT_MEMO_TYPE) {
1263
1263
  error("forwardRef requires a render function but received a `memo` component. Instead of forwardRef(memo(...)), use memo(forwardRef(...)).");
1264
- } else if (typeof render2 !== "function") {
1265
- error("forwardRef requires a render function but was given %s.", render2 === null ? "null" : typeof render2);
1264
+ } else if (typeof render3 !== "function") {
1265
+ error("forwardRef requires a render function but was given %s.", render3 === null ? "null" : typeof render3);
1266
1266
  } else {
1267
- if (render2.length !== 0 && render2.length !== 2) {
1268
- error("forwardRef render functions accept exactly two parameters: props and ref. %s", render2.length === 1 ? "Did you forget to use the ref parameter?" : "Any additional parameter will be undefined.");
1267
+ if (render3.length !== 0 && render3.length !== 2) {
1268
+ error("forwardRef render functions accept exactly two parameters: props and ref. %s", render3.length === 1 ? "Did you forget to use the ref parameter?" : "Any additional parameter will be undefined.");
1269
1269
  }
1270
1270
  }
1271
- if (render2 != null) {
1272
- if (render2.defaultProps != null || render2.propTypes != null) {
1271
+ if (render3 != null) {
1272
+ if (render3.defaultProps != null || render3.propTypes != null) {
1273
1273
  error("forwardRef render functions do not support propTypes or defaultProps. Did you accidentally pass a React component?");
1274
1274
  }
1275
1275
  }
1276
1276
  }
1277
1277
  var elementType = {
1278
1278
  $$typeof: REACT_FORWARD_REF_TYPE,
1279
- render: render2
1279
+ render: render3
1280
1280
  };
1281
1281
  {
1282
1282
  var ownName;
@@ -1288,8 +1288,8 @@ var require_react_development = __commonJS({
1288
1288
  },
1289
1289
  set: function(name) {
1290
1290
  ownName = name;
1291
- if (!render2.name && !render2.displayName) {
1292
- render2.displayName = name;
1291
+ if (!render3.name && !render3.displayName) {
1292
+ render3.displayName = name;
1293
1293
  }
1294
1294
  }
1295
1295
  });
@@ -2249,7 +2249,7 @@ var require_signal_exit = __commonJS({
2249
2249
  } else {
2250
2250
  assert = __require("assert");
2251
2251
  signals = require_signals();
2252
- isWin = /^win/i.test(process13.platform);
2252
+ isWin2 = /^win/i.test(process13.platform);
2253
2253
  EE = __require("events");
2254
2254
  if (typeof EE !== "function") {
2255
2255
  EE = EE.EventEmitter;
@@ -2321,7 +2321,7 @@ var require_signal_exit = __commonJS({
2321
2321
  unload();
2322
2322
  emit("exit", null, sig);
2323
2323
  emit("afterexit", null, sig);
2324
- if (isWin && sig === "SIGHUP") {
2324
+ if (isWin2 && sig === "SIGHUP") {
2325
2325
  sig = "SIGINT";
2326
2326
  }
2327
2327
  process13.kill(process13.pid, sig);
@@ -2378,7 +2378,7 @@ var require_signal_exit = __commonJS({
2378
2378
  }
2379
2379
  var assert;
2380
2380
  var signals;
2381
- var isWin;
2381
+ var isWin2;
2382
2382
  var EE;
2383
2383
  var emitter;
2384
2384
  var unload;
@@ -13104,7 +13104,7 @@ var require_react_reconciler_development = __commonJS({
13104
13104
  }
13105
13105
  function pushStoreConsistencyCheck(fiber, getSnapshot, renderedSnapshot) {
13106
13106
  fiber.flags |= StoreConsistency;
13107
- var check = {
13107
+ var check2 = {
13108
13108
  getSnapshot,
13109
13109
  value: renderedSnapshot
13110
13110
  };
@@ -13112,13 +13112,13 @@ var require_react_reconciler_development = __commonJS({
13112
13112
  if (componentUpdateQueue === null) {
13113
13113
  componentUpdateQueue = createFunctionComponentUpdateQueue();
13114
13114
  currentlyRenderingFiber$1.updateQueue = componentUpdateQueue;
13115
- componentUpdateQueue.stores = [check];
13115
+ componentUpdateQueue.stores = [check2];
13116
13116
  } else {
13117
13117
  var stores = componentUpdateQueue.stores;
13118
13118
  if (stores === null) {
13119
- componentUpdateQueue.stores = [check];
13119
+ componentUpdateQueue.stores = [check2];
13120
13120
  } else {
13121
- stores.push(check);
13121
+ stores.push(check2);
13122
13122
  }
13123
13123
  }
13124
13124
  }
@@ -15465,7 +15465,7 @@ var require_react_reconciler_development = __commonJS({
15465
15465
  }
15466
15466
  }
15467
15467
  }
15468
- var render2 = Component.render;
15468
+ var render3 = Component.render;
15469
15469
  var ref = workInProgress2.ref;
15470
15470
  var nextChildren;
15471
15471
  var hasId;
@@ -15476,12 +15476,12 @@ var require_react_reconciler_development = __commonJS({
15476
15476
  {
15477
15477
  ReactCurrentOwner$1.current = workInProgress2;
15478
15478
  setIsRendering(true);
15479
- nextChildren = renderWithHooks(current2, workInProgress2, render2, nextProps, ref, renderLanes2);
15479
+ nextChildren = renderWithHooks(current2, workInProgress2, render3, nextProps, ref, renderLanes2);
15480
15480
  hasId = checkDidRenderIdHook();
15481
15481
  if (workInProgress2.mode & StrictLegacyMode) {
15482
15482
  setIsStrictModeForDevtools(true);
15483
15483
  try {
15484
- nextChildren = renderWithHooks(current2, workInProgress2, render2, nextProps, ref, renderLanes2);
15484
+ nextChildren = renderWithHooks(current2, workInProgress2, render3, nextProps, ref, renderLanes2);
15485
15485
  hasId = checkDidRenderIdHook();
15486
15486
  } finally {
15487
15487
  setIsStrictModeForDevtools(false);
@@ -16661,7 +16661,7 @@ var require_react_reconciler_development = __commonJS({
16661
16661
  }
16662
16662
  }
16663
16663
  }
16664
- function initSuspenseListRenderState(workInProgress2, isBackwards, tail2, lastContentRow, tailMode) {
16664
+ function initSuspenseListRenderState(workInProgress2, isBackwards, tail3, lastContentRow, tailMode) {
16665
16665
  var renderState = workInProgress2.memoizedState;
16666
16666
  if (renderState === null) {
16667
16667
  workInProgress2.memoizedState = {
@@ -16669,7 +16669,7 @@ var require_react_reconciler_development = __commonJS({
16669
16669
  rendering: null,
16670
16670
  renderingStartTime: 0,
16671
16671
  last: lastContentRow,
16672
- tail: tail2,
16672
+ tail: tail3,
16673
16673
  tailMode
16674
16674
  };
16675
16675
  } else {
@@ -16677,7 +16677,7 @@ var require_react_reconciler_development = __commonJS({
16677
16677
  renderState.rendering = null;
16678
16678
  renderState.renderingStartTime = 0;
16679
16679
  renderState.last = lastContentRow;
16680
- renderState.tail = tail2;
16680
+ renderState.tail = tail3;
16681
16681
  renderState.tailMode = tailMode;
16682
16682
  }
16683
16683
  }
@@ -16709,19 +16709,19 @@ var require_react_reconciler_development = __commonJS({
16709
16709
  switch (revealOrder) {
16710
16710
  case "forwards": {
16711
16711
  var lastContentRow = findLastContentRow(workInProgress2.child);
16712
- var tail2;
16712
+ var tail3;
16713
16713
  if (lastContentRow === null) {
16714
- tail2 = workInProgress2.child;
16714
+ tail3 = workInProgress2.child;
16715
16715
  workInProgress2.child = null;
16716
16716
  } else {
16717
- tail2 = lastContentRow.sibling;
16717
+ tail3 = lastContentRow.sibling;
16718
16718
  lastContentRow.sibling = null;
16719
16719
  }
16720
16720
  initSuspenseListRenderState(
16721
16721
  workInProgress2,
16722
16722
  false,
16723
16723
  // isBackwards
16724
- tail2,
16724
+ tail3,
16725
16725
  lastContentRow,
16726
16726
  tailMode
16727
16727
  );
@@ -16835,9 +16835,9 @@ var require_react_reconciler_development = __commonJS({
16835
16835
  }
16836
16836
  }
16837
16837
  var newProps = workInProgress2.pendingProps;
16838
- var render2 = newProps.children;
16838
+ var render3 = newProps.children;
16839
16839
  {
16840
- if (typeof render2 !== "function") {
16840
+ if (typeof render3 !== "function") {
16841
16841
  error("A context consumer was rendered with multiple children, or a child that isn't a function. A context consumer expects a single child that is a function. If you did pass a function, make sure there is no trailing or leading whitespace around it.");
16842
16842
  }
16843
16843
  }
@@ -16850,7 +16850,7 @@ var require_react_reconciler_development = __commonJS({
16850
16850
  {
16851
16851
  ReactCurrentOwner$1.current = workInProgress2;
16852
16852
  setIsRendering(true);
16853
- newChildren = render2(newValue);
16853
+ newChildren = render3(newValue);
16854
16854
  setIsRendering(false);
16855
16855
  }
16856
16856
  {
@@ -20619,9 +20619,9 @@ var require_react_reconciler_development = __commonJS({
20619
20619
  var checks = updateQueue.stores;
20620
20620
  if (checks !== null) {
20621
20621
  for (var i = 0; i < checks.length; i++) {
20622
- var check = checks[i];
20623
- var getSnapshot = check.getSnapshot;
20624
- var renderedValue = check.value;
20622
+ var check2 = checks[i];
20623
+ var getSnapshot = check2.getSnapshot;
20624
+ var renderedValue = check2.value;
20625
20625
  try {
20626
20626
  if (!objectIs(getSnapshot(), renderedValue)) {
20627
20627
  return false;
@@ -22744,10 +22744,10 @@ var require_react_reconciler_development = __commonJS({
22744
22744
  var setErrorHandler = null;
22745
22745
  var setSuspenseHandler = null;
22746
22746
  {
22747
- var copyWithDeleteImpl = function(obj, path4, index2) {
22748
- var key = path4[index2];
22747
+ var copyWithDeleteImpl = function(obj, path6, index2) {
22748
+ var key = path6[index2];
22749
22749
  var updated = isArray(obj) ? obj.slice() : assign({}, obj);
22750
- if (index2 + 1 === path4.length) {
22750
+ if (index2 + 1 === path6.length) {
22751
22751
  if (isArray(updated)) {
22752
22752
  updated.splice(key, 1);
22753
22753
  } else {
@@ -22755,11 +22755,11 @@ var require_react_reconciler_development = __commonJS({
22755
22755
  }
22756
22756
  return updated;
22757
22757
  }
22758
- updated[key] = copyWithDeleteImpl(obj[key], path4, index2 + 1);
22758
+ updated[key] = copyWithDeleteImpl(obj[key], path6, index2 + 1);
22759
22759
  return updated;
22760
22760
  };
22761
- var copyWithDelete = function(obj, path4) {
22762
- return copyWithDeleteImpl(obj, path4, 0);
22761
+ var copyWithDelete = function(obj, path6) {
22762
+ return copyWithDeleteImpl(obj, path6, 0);
22763
22763
  };
22764
22764
  var copyWithRenameImpl = function(obj, oldPath, newPath, index2) {
22765
22765
  var oldKey = oldPath[index2];
@@ -22797,17 +22797,17 @@ var require_react_reconciler_development = __commonJS({
22797
22797
  }
22798
22798
  return copyWithRenameImpl(obj, oldPath, newPath, 0);
22799
22799
  };
22800
- var copyWithSetImpl = function(obj, path4, index2, value) {
22801
- if (index2 >= path4.length) {
22800
+ var copyWithSetImpl = function(obj, path6, index2, value) {
22801
+ if (index2 >= path6.length) {
22802
22802
  return value;
22803
22803
  }
22804
- var key = path4[index2];
22804
+ var key = path6[index2];
22805
22805
  var updated = isArray(obj) ? obj.slice() : assign({}, obj);
22806
- updated[key] = copyWithSetImpl(obj[key], path4, index2 + 1, value);
22806
+ updated[key] = copyWithSetImpl(obj[key], path6, index2 + 1, value);
22807
22807
  return updated;
22808
22808
  };
22809
- var copyWithSet = function(obj, path4, value) {
22810
- return copyWithSetImpl(obj, path4, 0, value);
22809
+ var copyWithSet = function(obj, path6, value) {
22810
+ return copyWithSetImpl(obj, path6, 0, value);
22811
22811
  };
22812
22812
  var findHook = function(fiber, id) {
22813
22813
  var currentHook2 = fiber.memoizedState;
@@ -22817,10 +22817,10 @@ var require_react_reconciler_development = __commonJS({
22817
22817
  }
22818
22818
  return currentHook2;
22819
22819
  };
22820
- overrideHookState = function(fiber, id, path4, value) {
22820
+ overrideHookState = function(fiber, id, path6, value) {
22821
22821
  var hook = findHook(fiber, id);
22822
22822
  if (hook !== null) {
22823
- var newState = copyWithSet(hook.memoizedState, path4, value);
22823
+ var newState = copyWithSet(hook.memoizedState, path6, value);
22824
22824
  hook.memoizedState = newState;
22825
22825
  hook.baseState = newState;
22826
22826
  fiber.memoizedProps = assign({}, fiber.memoizedProps);
@@ -22830,10 +22830,10 @@ var require_react_reconciler_development = __commonJS({
22830
22830
  }
22831
22831
  }
22832
22832
  };
22833
- overrideHookStateDeletePath = function(fiber, id, path4) {
22833
+ overrideHookStateDeletePath = function(fiber, id, path6) {
22834
22834
  var hook = findHook(fiber, id);
22835
22835
  if (hook !== null) {
22836
- var newState = copyWithDelete(hook.memoizedState, path4);
22836
+ var newState = copyWithDelete(hook.memoizedState, path6);
22837
22837
  hook.memoizedState = newState;
22838
22838
  hook.baseState = newState;
22839
22839
  fiber.memoizedProps = assign({}, fiber.memoizedProps);
@@ -22856,8 +22856,8 @@ var require_react_reconciler_development = __commonJS({
22856
22856
  }
22857
22857
  }
22858
22858
  };
22859
- overrideProps = function(fiber, path4, value) {
22860
- fiber.pendingProps = copyWithSet(fiber.memoizedProps, path4, value);
22859
+ overrideProps = function(fiber, path6, value) {
22860
+ fiber.pendingProps = copyWithSet(fiber.memoizedProps, path6, value);
22861
22861
  if (fiber.alternate) {
22862
22862
  fiber.alternate.pendingProps = fiber.pendingProps;
22863
22863
  }
@@ -22866,8 +22866,8 @@ var require_react_reconciler_development = __commonJS({
22866
22866
  scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp);
22867
22867
  }
22868
22868
  };
22869
- overridePropsDeletePath = function(fiber, path4) {
22870
- fiber.pendingProps = copyWithDelete(fiber.memoizedProps, path4);
22869
+ overridePropsDeletePath = function(fiber, path6) {
22870
+ fiber.pendingProps = copyWithDelete(fiber.memoizedProps, path6);
22871
22871
  if (fiber.alternate) {
22872
22872
  fiber.alternate.pendingProps = fiber.pendingProps;
22873
22873
  }
@@ -29446,7 +29446,7 @@ var require_has_flag = __commonJS({
29446
29446
  var require_supports_colors = __commonJS({
29447
29447
  "node_modules/@colors/colors/lib/system/supports-colors.js"(exports, module) {
29448
29448
  "use strict";
29449
- var os6 = __require("os");
29449
+ var os8 = __require("os");
29450
29450
  var hasFlag2 = require_has_flag();
29451
29451
  var env3 = process.env;
29452
29452
  var forceColor = void 0;
@@ -29484,7 +29484,7 @@ var require_supports_colors = __commonJS({
29484
29484
  }
29485
29485
  var min = forceColor ? 1 : 0;
29486
29486
  if (process.platform === "win32") {
29487
- var osRelease = os6.release().split(".");
29487
+ var osRelease = os8.release().split(".");
29488
29488
  if (Number(process.versions.node.split(".")[0]) >= 8 && Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
29489
29489
  return Number(osRelease[2]) >= 14931 ? 3 : 2;
29490
29490
  }
@@ -31587,7 +31587,7 @@ var require_core = __commonJS({
31587
31587
  function close(node) {
31588
31588
  result += "</" + tag2(node) + ">";
31589
31589
  }
31590
- function render2(event) {
31590
+ function render3(event) {
31591
31591
  (event.event === "start" ? open : close)(event.node);
31592
31592
  }
31593
31593
  while (original.length || highlighted.length) {
@@ -31597,7 +31597,7 @@ var require_core = __commonJS({
31597
31597
  if (stream === original) {
31598
31598
  nodeStack.reverse().forEach(close);
31599
31599
  do {
31600
- render2(stream.splice(0, 1)[0]);
31600
+ render3(stream.splice(0, 1)[0]);
31601
31601
  stream = selectStream();
31602
31602
  } while (stream === original && stream.length && stream[0].offset === processed);
31603
31603
  nodeStack.reverse().forEach(open);
@@ -31607,7 +31607,7 @@ var require_core = __commonJS({
31607
31607
  } else {
31608
31608
  nodeStack.pop();
31609
31609
  }
31610
- render2(stream.splice(0, 1)[0]);
31610
+ render3(stream.splice(0, 1)[0]);
31611
31611
  }
31612
31612
  }
31613
31613
  return result + escapeHTML(value.substr(processed));
@@ -73569,15 +73569,15 @@ var require_route = __commonJS({
73569
73569
  };
73570
73570
  }
73571
73571
  function wrapConversion(toModel, graph) {
73572
- const path4 = [graph[toModel].parent, toModel];
73572
+ const path6 = [graph[toModel].parent, toModel];
73573
73573
  let fn = conversions[graph[toModel].parent][toModel];
73574
73574
  let cur = graph[toModel].parent;
73575
73575
  while (graph[cur].parent) {
73576
- path4.unshift(graph[cur].parent);
73576
+ path6.unshift(graph[cur].parent);
73577
73577
  fn = link3(conversions[graph[cur].parent][cur], fn);
73578
73578
  cur = graph[cur].parent;
73579
73579
  }
73580
- fn.conversion = path4;
73580
+ fn.conversion = path6;
73581
73581
  return fn;
73582
73582
  }
73583
73583
  module.exports = function(fromModel) {
@@ -73817,7 +73817,7 @@ var require_has_flag2 = __commonJS({
73817
73817
  var require_supports_color = __commonJS({
73818
73818
  "node_modules/supports-color/index.js"(exports, module) {
73819
73819
  "use strict";
73820
- var os6 = __require("os");
73820
+ var os8 = __require("os");
73821
73821
  var tty2 = __require("tty");
73822
73822
  var hasFlag2 = require_has_flag2();
73823
73823
  var { env: env3 } = process;
@@ -73865,7 +73865,7 @@ var require_supports_color = __commonJS({
73865
73865
  return min;
73866
73866
  }
73867
73867
  if (process.platform === "win32") {
73868
- const osRelease = os6.release().split(".");
73868
+ const osRelease = os8.release().split(".");
73869
73869
  if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
73870
73870
  return Number(osRelease[2]) >= 14931 ? 3 : 2;
73871
73871
  }
@@ -74575,6 +74575,246 @@ var require_dist = __commonJS({
74575
74575
  }
74576
74576
  });
74577
74577
 
74578
+ // src/install.js
74579
+ import { spawnSync } from "node:child_process";
74580
+ import fs2 from "node:fs";
74581
+ import os3 from "node:os";
74582
+ import path from "node:path";
74583
+ function importedVersion(env3 = process.env, runImpl = run) {
74584
+ const r = runImpl(enginePython(env3), ASK_VERSION);
74585
+ return r && r.status === 0 ? String(r.stdout).trim() : null;
74586
+ }
74587
+ function installedVersion(env3 = process.env, runImpl = run) {
74588
+ try {
74589
+ return fs2.readFileSync(stampPath(env3), "utf8").trim() || null;
74590
+ } catch {
74591
+ }
74592
+ if (!fs2.existsSync(enginePython(env3))) return null;
74593
+ const v = importedVersion(env3, runImpl);
74594
+ if (v) {
74595
+ try {
74596
+ fs2.writeFileSync(stampPath(env3), `${v}
74597
+ `);
74598
+ } catch {
74599
+ }
74600
+ }
74601
+ return v;
74602
+ }
74603
+ function needsInstall(version, { env: env3 = process.env, installed = () => installedVersion(env3), now = Date.now(), state = readInstallState(env3) } = {}) {
74604
+ if (!version || env3.HUM_ENGINE || env3.HUM_ENGINE_PORT) return false;
74605
+ if (installed() === version) return false;
74606
+ if (state && !state.ok && state.version === version && now - (state.at || 0) < 10 * 60 * 1e3) return false;
74607
+ return true;
74608
+ }
74609
+ function installEngine(version, { env: env3 = process.env, say = (m) => console.log(`hum: ${m}`), runImpl = run, now = Date.now() } = {}) {
74610
+ const home = humHome(env3);
74611
+ const dir = engineDir(env3);
74612
+ const python = enginePython(env3);
74613
+ const localBin = path.join(os3.homedir(), ".local", "bin");
74614
+ const uvNames = ["uv", path.join(localBin, win ? "uv.exe" : "uv")];
74615
+ const uv = () => uvNames.find((u) => {
74616
+ const r = runImpl(u, ["--version"]);
74617
+ return r && r.status === 0;
74618
+ });
74619
+ const spec = env3.HUM_ENGINE_SPEC || `hum-cli==${version}`;
74620
+ const outcome = (ok, error = null, got = version) => {
74621
+ writeInstallState({ version: got, wanted: version, ok, error, at: now }, env3);
74622
+ return { ok, version: got, error };
74623
+ };
74624
+ try {
74625
+ let u = uv();
74626
+ if (!u) {
74627
+ say("installing uv (it creates the Python environment for the part of hum that does the work) \u2026");
74628
+ const r = win ? runImpl("powershell", ["-ExecutionPolicy", "ByPass", "-c", "irm https://astral.sh/uv/install.ps1 | iex"], { stdio: "inherit" }) : runImpl("sh", ["-c", "curl -LsSf https://astral.sh/uv/install.sh | sh"], { stdio: "inherit" });
74629
+ u = r && r.status === 0 ? uv() : null;
74630
+ if (!u) return outcome(false, `could not install uv; install it from https://astral.sh/uv and run: ${npmFix(version)}`);
74631
+ }
74632
+ say(`installing ${env3.HUM_ENGINE_SPEC ? spec : `hum ${version}`} into ${dir} \u2026`);
74633
+ fs2.mkdirSync(home, { recursive: true });
74634
+ try {
74635
+ fs2.unlinkSync(stampPath(env3));
74636
+ } catch {
74637
+ }
74638
+ if (!fs2.existsSync(python)) {
74639
+ const args2 = ["venv", "--quiet", "--python", "3.12", ...fs2.existsSync(dir) ? ["--clear"] : [], dir];
74640
+ if ((runImpl(u, args2, { stdio: "inherit" }) || {}).status !== 0) return outcome(false, "uv venv failed");
74641
+ }
74642
+ if ((runImpl(u, ["pip", "install", "--quiet", "--python", python, spec], { stdio: "inherit" }) || {}).status !== 0) return outcome(false, `uv pip install ${spec} failed`);
74643
+ const got = importedVersion(env3, runImpl);
74644
+ if (!got) return outcome(false, "hum did not import after the install");
74645
+ if (got !== version && !env3.HUM_ENGINE_SPEC) return outcome(false, `installed ${got}, wanted ${version}`, got);
74646
+ fs2.mkdirSync(dir, { recursive: true });
74647
+ fs2.writeFileSync(stampPath(env3), `${got}
74648
+ `);
74649
+ const list2 = runImpl(u, ["tool", "list"]);
74650
+ if (list2 && list2.status === 0 && /^hum-cli\b/m.test(list2.stdout)) {
74651
+ const rm = runImpl(u, ["tool", "uninstall", "hum-cli"]);
74652
+ if (rm && rm.status === 0) say(`removed the uv install of hum-cli and its shims in ${localBin}; hum lives in ${dir} now`);
74653
+ }
74654
+ say(`hum ${got} ready`);
74655
+ return outcome(true, null, got);
74656
+ } catch (e) {
74657
+ return outcome(false, e && e.message ? e.message : String(e));
74658
+ }
74659
+ }
74660
+ var win, npmFix, NPM_FIX, humHome, engineDir, enginePython, stampPath, statePath, run, ASK_VERSION, readInstallState, writeInstallState;
74661
+ var init_install = __esm({
74662
+ "src/install.js"() {
74663
+ win = process.platform === "win32";
74664
+ npmFix = (version = "") => `npm i -g @metaphi-ai/hum@${version || "latest"} --foreground-scripts`;
74665
+ NPM_FIX = npmFix("latest");
74666
+ humHome = (env3 = process.env) => env3.HUM_HOME || path.join(os3.homedir(), ".hum");
74667
+ engineDir = (env3 = process.env) => path.join(humHome(env3), "engine");
74668
+ enginePython = (env3 = process.env) => win ? path.join(engineDir(env3), "Scripts", "python.exe") : path.join(engineDir(env3), "bin", "python");
74669
+ stampPath = (env3) => path.join(engineDir(env3), "version");
74670
+ statePath = (env3) => path.join(humHome(env3), "engine-install.json");
74671
+ run = (cmd, args2, opts = {}) => spawnSync(cmd, args2, { encoding: "utf8", windowsHide: true, ...opts });
74672
+ ASK_VERSION = ["-I", "-c", "import hum; print(hum.__version__)"];
74673
+ readInstallState = (env3 = process.env) => {
74674
+ try {
74675
+ return JSON.parse(fs2.readFileSync(statePath(env3), "utf8"));
74676
+ } catch {
74677
+ return null;
74678
+ }
74679
+ };
74680
+ writeInstallState = (s, env3) => {
74681
+ try {
74682
+ fs2.mkdirSync(humHome(env3), { recursive: true });
74683
+ fs2.writeFileSync(statePath(env3), JSON.stringify(s));
74684
+ } catch {
74685
+ }
74686
+ };
74687
+ }
74688
+ });
74689
+
74690
+ // src/update.js
74691
+ import fs3 from "node:fs";
74692
+ import os4 from "node:os";
74693
+ import path2 from "node:path";
74694
+ import { spawn, spawnSync as spawnSync2 } from "node:child_process";
74695
+ async function latestVersion(fetchImpl = globalThis.fetch, env3 = process.env) {
74696
+ if (env3.HUM_NO_UPDATE_CHECK || typeof fetchImpl !== "function") return "";
74697
+ try {
74698
+ const r = await fetchImpl(`${dist(env3)}/releases/latest`, { signal: AbortSignal.timeout(2500) });
74699
+ if (!r.ok) return "";
74700
+ const v = (await r.text()).trim();
74701
+ return /^\d+\.\d+\.\d+$/.test(v) ? v : "";
74702
+ } catch {
74703
+ return "";
74704
+ }
74705
+ }
74706
+ function installLayout(execPath = process.execPath, env3 = process.env) {
74707
+ const exe = String(execPath).split(/[\\/]/).pop();
74708
+ if (/^(node|bun)(\.exe)?$/i.test(exe)) return { kind: env3.HUM_ENGINE_PORT ? "python" : "npm" };
74709
+ let real = execPath;
74710
+ try {
74711
+ real = fs3.realpathSync(execPath);
74712
+ } catch {
74713
+ }
74714
+ return { kind: "native", exe, dir: path2.dirname(real), base: path2.dirname(path2.dirname(real)) };
74715
+ }
74716
+ function installerArgv(version, platform2 = process.platform) {
74717
+ const base = dist();
74718
+ if (platform2 === "win32") return ["powershell", ["-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", `irm ${base}/install.ps1 | iex`]];
74719
+ return ["/bin/sh", ["-c", `curl -fsSL "${base}/install.sh" | sh`]];
74720
+ }
74721
+ function startBackgroundUpdate(version, { env: env3 = process.env, now = Date.now(), spawnImpl = spawn } = {}) {
74722
+ if (env3.HUM_NO_AUTO_UPDATE) return false;
74723
+ const s = readState(env3);
74724
+ if (s.version === version && now - (s.started || 0) < 30 * 60 * 1e3) return false;
74725
+ const log = path2.join(humHome2(env3), "update.log");
74726
+ let out = "ignore";
74727
+ try {
74728
+ fs3.mkdirSync(humHome2(env3), { recursive: true });
74729
+ out = fs3.openSync(log, "w");
74730
+ } catch {
74731
+ }
74732
+ const [bin, args2] = installerArgv(version);
74733
+ try {
74734
+ const child = spawnImpl(bin, args2, {
74735
+ detached: true,
74736
+ stdio: ["ignore", out, out],
74737
+ windowsHide: true,
74738
+ env: { ...env3, HUM_VERSION: version, HUM_DIST: dist(env3) }
74739
+ });
74740
+ child.unref();
74741
+ writeState({ version, started: now }, env3);
74742
+ return true;
74743
+ } catch {
74744
+ return false;
74745
+ }
74746
+ }
74747
+ function mismatchLine(mine, running, { env: env3 = process.env, layout: layout2 = installLayout(process.execPath, env3), state = readInstallState(env3) } = {}) {
74748
+ if (!mine || !running || mine === running) return "";
74749
+ const head = `hum ${mine} is installed but ${running} is what runs`;
74750
+ if (env3.HUM_ENGINE) return `${head}: HUM_ENGINE points at it \xB7 unset HUM_ENGINE to use ${mine}`;
74751
+ const fix = layout2.kind === "npm" ? npmFix(mine) : updateCommand(layout2);
74752
+ if (state && !state.ok && state.wanted === mine && state.error) return `${head}: the update did not finish (${state.error}) \xB7 ${fix}`;
74753
+ return `${head} \xB7 ${fix}`;
74754
+ }
74755
+ async function updateNotice(mine, { running = "", env: env3 = process.env, fetchImpl = globalThis.fetch, layout: layout2 = installLayout(process.execPath, env3), spawnImpl = spawn } = {}) {
74756
+ const drift = mismatchLine(mine, running, { env: env3, layout: layout2 });
74757
+ if (drift) return drift;
74758
+ const latest = await latestVersion(fetchImpl, env3);
74759
+ if (!latest || !newer(latest, mine)) return "";
74760
+ if (layout2.kind !== "native") return `hum ${latest} is out (this is ${mine}) \xB7 ${updateCommand(layout2)}`;
74761
+ if (readyVersion(layout2, latest)) return `hum ${latest} is ready \xB7 restart hum to use it`;
74762
+ if (startBackgroundUpdate(latest, { env: env3, spawnImpl })) return `hum ${latest} is downloading in the background \xB7 it takes effect the next time you start hum`;
74763
+ const s = readState(env3);
74764
+ if (s.version === latest && !env3.HUM_NO_AUTO_UPDATE) return `hum ${latest} is still installing in the background (${path2.join(humHome2(env3), "update.log")} has the details)`;
74765
+ return `hum ${latest} is out (this is ${mine}) \xB7 ${updateCommand(layout2)}`;
74766
+ }
74767
+ function updateNow(layout2 = installLayout()) {
74768
+ if (layout2.kind === "native") {
74769
+ const [bin, args2] = installerArgv();
74770
+ return spawnSync2(bin, args2, { stdio: "inherit", env: { ...process.env, HUM_DIST: dist() } }).status ?? 1;
74771
+ }
74772
+ if (layout2.kind === "python") {
74773
+ process.stdout.write(`update with your package manager: ${updateCommand(layout2)}
74774
+ `);
74775
+ return 0;
74776
+ }
74777
+ const r = spawnSync2(win2() ? "npm.cmd" : "npm", ["i", "-g", "@metaphi-ai/hum@latest"], { stdio: "inherit", shell: win2() });
74778
+ return r.status ?? 1;
74779
+ }
74780
+ var dist, humHome2, win2, newer, updateCommand, readyVersion, stateFile, readState, writeState;
74781
+ var init_update = __esm({
74782
+ "src/update.js"() {
74783
+ init_install();
74784
+ dist = (env3 = process.env) => (env3.HUM_DIST || "https://metaphi.ai/hum").replace(/\/+$/, "");
74785
+ humHome2 = (env3 = process.env) => env3.HUM_HOME || path2.join(os4.homedir(), ".hum");
74786
+ win2 = () => process.platform === "win32";
74787
+ newer = (a, b) => {
74788
+ const pa = String(a).split(".").map(Number), pb = String(b).split(".").map(Number);
74789
+ for (let i = 0; i < 3; i += 1) {
74790
+ if ((pa[i] || 0) !== (pb[i] || 0)) return (pa[i] || 0) > (pb[i] || 0);
74791
+ }
74792
+ return false;
74793
+ };
74794
+ updateCommand = (layout2 = installLayout(), platform2 = process.platform) => {
74795
+ if (layout2.kind === "native") return platform2 === "win32" ? `irm ${dist()}/install.ps1 | iex` : `curl -fsSL ${dist()}/install.sh | sh`;
74796
+ if (layout2.kind === "python") return "uv tool upgrade hum-cli (or: pip install -U hum-cli)";
74797
+ return "npm i -g @metaphi-ai/hum@latest";
74798
+ };
74799
+ readyVersion = (layout2, version) => layout2.kind === "native" && version && fs3.existsSync(path2.join(layout2.base, version, layout2.exe)) ? version : "";
74800
+ stateFile = (env3 = process.env) => path2.join(humHome2(env3), "update.json");
74801
+ readState = (env3 = process.env) => {
74802
+ try {
74803
+ return JSON.parse(fs3.readFileSync(stateFile(env3), "utf8"));
74804
+ } catch {
74805
+ return {};
74806
+ }
74807
+ };
74808
+ writeState = (s, env3 = process.env) => {
74809
+ try {
74810
+ fs3.mkdirSync(humHome2(env3), { recursive: true });
74811
+ fs3.writeFileSync(stateFile(env3), JSON.stringify(s));
74812
+ } catch {
74813
+ }
74814
+ };
74815
+ }
74816
+ });
74817
+
74578
74818
  // node_modules/react/cjs/react-jsx-runtime.production.min.js
74579
74819
  var require_react_jsx_runtime_production_min = __commonJS({
74580
74820
  "node_modules/react/cjs/react-jsx-runtime.production.min.js"(exports) {
@@ -75505,6 +75745,571 @@ var require_jsx_runtime = __commonJS({
75505
75745
  }
75506
75746
  });
75507
75747
 
75748
+ // src/engine.js
75749
+ import fs5 from "node:fs";
75750
+ import net from "node:net";
75751
+ import os6 from "node:os";
75752
+ import path4 from "node:path";
75753
+ import crypto from "node:crypto";
75754
+ import { spawn as spawn2, spawnSync as spawnSync3 } from "node:child_process";
75755
+ function uvToolDirs() {
75756
+ const dirs = [];
75757
+ if (process.env.UV_TOOL_DIR) dirs.push(process.env.UV_TOOL_DIR);
75758
+ if (win3) {
75759
+ for (const base of [process.env.APPDATA, process.env.LOCALAPPDATA]) if (base) dirs.push(path4.join(base, "uv", "tools"));
75760
+ } else dirs.push(path4.join(process.env.XDG_DATA_HOME || path4.join(os6.homedir(), ".local", "share"), "uv", "tools"));
75761
+ if (!dirs.some(exists)) {
75762
+ for (const uv of ["uv", path4.join(os6.homedir(), ".local", "bin", win3 ? "uv.exe" : "uv")]) {
75763
+ try {
75764
+ const r = spawnSync3(uv, ["tool", "dir"], { encoding: "utf8", windowsHide: true });
75765
+ if (r.status === 0 && r.stdout.trim()) {
75766
+ dirs.push(r.stdout.trim());
75767
+ break;
75768
+ }
75769
+ } catch {
75770
+ }
75771
+ }
75772
+ }
75773
+ return dirs;
75774
+ }
75775
+ function enginePython2(dirs = uvToolDirs()) {
75776
+ for (const dir of dirs) for (const name of ["hum-cli", "hum"]) {
75777
+ const py = win3 ? path4.join(dir, name, "Scripts", "python.exe") : path4.join(dir, name, "bin", "python");
75778
+ if (exists(py)) return py;
75779
+ }
75780
+ return null;
75781
+ }
75782
+ function siblingEngine(execPath = process.execPath) {
75783
+ let dir;
75784
+ try {
75785
+ dir = path4.dirname(fs5.realpathSync(execPath));
75786
+ } catch {
75787
+ return null;
75788
+ }
75789
+ const p = path4.join(dir, "engine", win3 ? "hum-engine.exe" : "hum-engine");
75790
+ return exists(p) ? p : null;
75791
+ }
75792
+ function homeEngine(env3 = process.env) {
75793
+ const home = env3.HUM_HOME || path4.join(os6.homedir(), ".hum");
75794
+ const py = win3 ? path4.join(home, "engine", "Scripts", "python.exe") : path4.join(home, "engine", "bin", "python");
75795
+ return exists(py) ? py : null;
75796
+ }
75797
+ function engineCandidates(env3 = process.env) {
75798
+ const out = [];
75799
+ if (env3.HUM_ENGINE) {
75800
+ const [bin, ...args2] = env3.HUM_ENGINE.split(" ");
75801
+ out.push({ bin, args: args2, where: "HUM_ENGINE" });
75802
+ }
75803
+ const sib = siblingEngine();
75804
+ if (sib) out.push({ bin: sib, args: ["engine"], where: "beside hum" });
75805
+ const home = homeEngine(env3);
75806
+ if (home) out.push({ bin: home, args: ["-m", "hum.cli", "engine"], where: "HUM_HOME/engine" });
75807
+ const py = enginePython2();
75808
+ if (py) out.push({ bin: py, args: ["-m", "hum.cli", "engine"], where: "the interpreter beside it" });
75809
+ out.push({ bin: "hum-engine", args: [], where: "PATH" });
75810
+ out.push({ bin: path4.join(os6.homedir(), ".local", "bin", win3 ? "hum-engine.exe" : "hum-engine"), args: [], where: "uv's bin dir" });
75811
+ return out;
75812
+ }
75813
+ function engineCommand(argv, candidates = engineCandidates()) {
75814
+ for (const c of candidates) {
75815
+ if (c.args[c.args.length - 1] !== "engine") continue;
75816
+ return { bin: c.bin, args: [...c.args.slice(0, -1), ...argv], where: c.where };
75817
+ }
75818
+ return null;
75819
+ }
75820
+ function candidateVersion(c, { env: env3 = process.env, runImpl = spawnSync3 } = {}) {
75821
+ if (!c || !c.bin) return null;
75822
+ if (c.where === "HUM_HOME/engine") return installedVersion(env3);
75823
+ const interp = c.args.length >= 3 && c.args[c.args.length - 3] === "-m" && c.args[c.args.length - 2] === "hum.cli";
75824
+ let r;
75825
+ try {
75826
+ r = runImpl(c.bin, interp ? ASK_VERSION : ["--version"], { encoding: "utf8", windowsHide: true, timeout: 2e4 });
75827
+ } catch {
75828
+ return null;
75829
+ }
75830
+ if (!r || r.status !== 0) return null;
75831
+ const m = String(r.stdout || "").match(/(\d+\.\d+\.\d+)/);
75832
+ return m ? m[1] : null;
75833
+ }
75834
+ function runningVersion(candidates = engineCandidates(), opts = {}) {
75835
+ for (const c of candidates) {
75836
+ const v = candidateVersion(c, opts);
75837
+ if (v) return { version: v, where: c.where };
75838
+ }
75839
+ return null;
75840
+ }
75841
+ function startFailure(failures, { npm = /^(node|bun)(\.exe)?$/i.test(String(process.execPath).split(/[\\/]/).pop()), platform: platform2 = process.platform, version = true ? "0.1.30" : "" } = {}) {
75842
+ const refused = failures.find((f) => f.error && f.error.code !== "ENOENT");
75843
+ const fix = npm ? npmFix(version) : updateCommand({ kind: "native" }, platform2);
75844
+ if (!refused) {
75845
+ return `Hum is not fully installed here \u2014 the half that does the work is missing. Run: ${fix} (or set HUM_ENGINE to the command that runs it)`;
75846
+ }
75847
+ const what = refused.error.code || refused.error.message;
75848
+ const lines = [
75849
+ `Hum is installed (${refused.bin}) but this machine would not run it: ${what}.`
75850
+ ];
75851
+ if (win3) {
75852
+ lines.push("On a managed Windows machine that is usually Device Guard / WDAC refusing an executable it does not know.");
75853
+ lines.push(`To see the policy's own message, run: "${refused.bin}" --help`);
75854
+ const dir = uvToolDirs()[0];
75855
+ lines.push(`If uv's environment is elsewhere, point Hum at its interpreter: set HUM_ENGINE=${path4.join(dir || "<uv tool dir>", "hum-cli", "Scripts", "python.exe")} -m hum.cli engine`);
75856
+ } else {
75857
+ lines.push('Set HUM_ENGINE to a command that starts it, e.g. HUM_ENGINE="python -m hum.cli engine"');
75858
+ }
75859
+ return lines.join("\n");
75860
+ }
75861
+ function attempt({ bin, args: args2 }, cwd2, { task, images, resume }) {
75862
+ return new Promise((resolve, reject) => {
75863
+ const runId = crypto.randomBytes(6).toString("hex");
75864
+ fs5.mkdirSync(runDir(), { recursive: true });
75865
+ const logPath = path4.join(runDir(), `${runId}.log`);
75866
+ const log = fs5.openSync(logPath, "a");
75867
+ const argv = [...args2, "-C", cwd2, "--run-id", runId];
75868
+ if (task) argv.push("--task", task);
75869
+ for (const p of images) argv.push("--image", p);
75870
+ if (resume) argv.push("--resume", resume);
75871
+ let settled = false;
75872
+ const settle = (fn) => {
75873
+ if (!settled) {
75874
+ settled = true;
75875
+ fn();
75876
+ }
75877
+ };
75878
+ let child;
75879
+ try {
75880
+ child = spawn2(bin, argv, { stdio: ["ignore", log, log], detached: true, windowsHide: true });
75881
+ } catch (e) {
75882
+ fs5.closeSync(log);
75883
+ reject({ spawn: e });
75884
+ return;
75885
+ }
75886
+ fs5.closeSync(log);
75887
+ let died = false;
75888
+ child.on("error", (e) => settle(() => reject({ spawn: e })));
75889
+ child.on("exit", () => {
75890
+ died = true;
75891
+ });
75892
+ const t0 = Date.now();
75893
+ const poll = () => {
75894
+ if (settled) return;
75895
+ const rec = readRun(runId);
75896
+ if (rec && rec.port) {
75897
+ child.unref();
75898
+ settle(() => resolve(rec));
75899
+ return;
75900
+ }
75901
+ if (rec && rec.error) {
75902
+ settle(() => reject({ failed: rec.error }));
75903
+ return;
75904
+ }
75905
+ if (died && !rec) {
75906
+ settle(() => reject({ died: logPath }));
75907
+ return;
75908
+ }
75909
+ if (Date.now() - t0 > 9e4) {
75910
+ settle(() => reject({ timeout: true }));
75911
+ return;
75912
+ }
75913
+ setTimeout(poll, 50);
75914
+ };
75915
+ poll();
75916
+ });
75917
+ }
75918
+ function failureMessage(error) {
75919
+ return error.message + (error.hint ? `
75920
+ ${error.hint}` : "");
75921
+ }
75922
+ function diedMessage(logPath, text = null) {
75923
+ let tail3 = "";
75924
+ try {
75925
+ tail3 = (text ?? fs5.readFileSync(logPath, "utf8")).trim().split("\n").slice(-3).join("\n").trim();
75926
+ } catch {
75927
+ }
75928
+ return `the session did not start${tail3 ? `:
75929
+ ${tail3}` : ""}
75930
+ (its log: ${logPath})`;
75931
+ }
75932
+ async function spawnEngine(cwd2, { task = null, images = [], resume = null, candidates = engineCandidates() } = {}) {
75933
+ const failures = [];
75934
+ for (const cand of candidates) {
75935
+ if (!cand.bin) continue;
75936
+ try {
75937
+ return await attempt(cand, cwd2, { task, images, resume });
75938
+ } catch (f) {
75939
+ if (f && f.spawn) {
75940
+ failures.push({ ...cand, error: f.spawn });
75941
+ continue;
75942
+ }
75943
+ if (f && f.failed) throw new EngineError(failureMessage(f.failed));
75944
+ if (f && f.died) throw new EngineError(diedMessage(f.died));
75945
+ if (f && f.timeout) throw new EngineError("the session did not start in time");
75946
+ throw f;
75947
+ }
75948
+ }
75949
+ throw new EngineError(startFailure(failures));
75950
+ }
75951
+ var runDir, readRun, EngineError, win3, exists, Engine;
75952
+ var init_engine = __esm({
75953
+ "src/engine.js"() {
75954
+ init_install();
75955
+ init_update();
75956
+ runDir = () => path4.join(process.env.HUM_HOME || path4.join(os6.homedir(), ".hum"), "run");
75957
+ readRun = (id) => {
75958
+ try {
75959
+ return JSON.parse(fs5.readFileSync(path4.join(runDir(), `${id}.json`), "utf8"));
75960
+ } catch {
75961
+ return null;
75962
+ }
75963
+ };
75964
+ EngineError = class extends Error {
75965
+ };
75966
+ win3 = process.platform === "win32";
75967
+ exists = (p) => {
75968
+ try {
75969
+ fs5.accessSync(p);
75970
+ return true;
75971
+ } catch {
75972
+ return false;
75973
+ }
75974
+ };
75975
+ Engine = class {
75976
+ constructor(port2) {
75977
+ this.port = port2;
75978
+ this.handlers = [];
75979
+ this.closed = false;
75980
+ }
75981
+ connect() {
75982
+ return new Promise((resolve, reject) => {
75983
+ const sock = net.createConnection({ host: "127.0.0.1", port: this.port }, () => resolve());
75984
+ this.sock = sock;
75985
+ sock.on("error", (e) => {
75986
+ if (!this.closed && this.sock === sock) reject(new EngineError(`could not reach the session: ${e.message}`));
75987
+ });
75988
+ let buf = "";
75989
+ sock.on("data", (d) => {
75990
+ if (this.sock !== sock) return;
75991
+ buf += d.toString();
75992
+ const lines = buf.split("\n");
75993
+ buf = lines.pop();
75994
+ for (const line of lines) {
75995
+ if (!line.trim()) continue;
75996
+ let ev;
75997
+ try {
75998
+ ev = JSON.parse(line);
75999
+ } catch {
76000
+ continue;
76001
+ }
76002
+ for (const h of this.handlers) h(ev);
76003
+ }
76004
+ });
76005
+ sock.on("close", () => {
76006
+ if (this.sock !== sock) return;
76007
+ this.closed = true;
76008
+ for (const h of this.handlers) h({ type: "bye", gone: true });
76009
+ });
76010
+ });
76011
+ }
76012
+ // Attach to another engine (a session running elsewhere on this machine): the old
76013
+ // socket is dropped quietly, the new one greets us with hello and a replay.
76014
+ async reconnect(port2) {
76015
+ const old = this.sock;
76016
+ this.sock = null;
76017
+ this.port = port2;
76018
+ this.closed = false;
76019
+ try {
76020
+ old.destroy();
76021
+ } catch {
76022
+ }
76023
+ await this.connect();
76024
+ }
76025
+ on(handler) {
76026
+ this.handlers.push(handler);
76027
+ }
76028
+ send(cmd) {
76029
+ if (this.closed) return;
76030
+ try {
76031
+ this.sock.write(JSON.stringify(cmd) + "\n");
76032
+ } catch {
76033
+ }
76034
+ }
76035
+ close() {
76036
+ this.closed = true;
76037
+ try {
76038
+ this.sock.end();
76039
+ } catch {
76040
+ }
76041
+ }
76042
+ };
76043
+ }
76044
+ });
76045
+
76046
+ // src/doctor.js
76047
+ var doctor_exports = {};
76048
+ __export(doctor_exports, {
76049
+ diagnose: () => diagnose,
76050
+ doctor: () => doctor,
76051
+ onPath: () => onPath,
76052
+ render: () => render2
76053
+ });
76054
+ import fs6 from "node:fs";
76055
+ import os7 from "node:os";
76056
+ import path5 from "node:path";
76057
+ import { spawnSync as spawnSync4 } from "node:child_process";
76058
+ function jsonError(text, e) {
76059
+ const msg = e.message || "";
76060
+ const lc = /\(line (\d+) column \d+\)/.exec(msg);
76061
+ if (lc) return `line ${lc[1]}: ${msg.replace(/ in JSON.*$/, "")}`;
76062
+ const m = /position (\d+)/.exec(msg);
76063
+ if (!m) return msg;
76064
+ const line = text.slice(0, Number(m[1])).split("\n").length;
76065
+ return `line ${line}: ${msg.replace(/ in JSON.*$/, "")}`;
76066
+ }
76067
+ function onPath(env3, { platform: platform2 = process.platform } = {}) {
76068
+ const names = isWin(platform2) ? ["hum.cmd", "hum.exe", "hum", "hum-engine.exe", "hum-engine.cmd"] : ["hum", "hum-engine"];
76069
+ const seen = /* @__PURE__ */ new Set();
76070
+ const hits = [];
76071
+ for (const dir of String(env3.PATH || env3.Path || "").split(path5.delimiter).filter(Boolean)) {
76072
+ for (const n of names) {
76073
+ const p = path5.join(dir, n);
76074
+ if (!exists2(p) || seen.has(p)) continue;
76075
+ seen.add(p);
76076
+ hits.push({ path: p, name: n, real: realpath(p) });
76077
+ }
76078
+ }
76079
+ return hits;
76080
+ }
76081
+ async function diagnose({
76082
+ env: env3 = process.env,
76083
+ mine = "0.0.0",
76084
+ platform: platform2 = process.platform,
76085
+ execPath = process.execPath,
76086
+ homedir = os7.homedir(),
76087
+ cwd: cwd2 = process.cwd(),
76088
+ layout: layout2 = installLayout(execPath, env3),
76089
+ candidates = engineCandidates(env3),
76090
+ runImpl = spawnSync4,
76091
+ fetchImpl = globalThis.fetch
76092
+ } = {}) {
76093
+ const home = env3.HUM_HOME || path5.join(homedir, ".hum");
76094
+ const sections = [];
76095
+ {
76096
+ const checks = [];
76097
+ const from = layout2.kind === "native" ? path5.join(layout2.dir, layout2.exe) : realpath(execPath);
76098
+ const how = { native: "the native install", npm: "npm", python: "Python (uv or pip)" }[layout2.kind] || layout2.kind;
76099
+ checks.push(check("ok", `hum ${mine} \xB7 installed with ${how} \xB7 runs from ${from}`));
76100
+ if (layout2.kind === "native") {
76101
+ const launcher = isWin(platform2) ? path5.join(env3.LOCALAPPDATA || path5.join(homedir, "AppData", "Local"), "hum", "bin", "hum.cmd") : path5.join(homedir, ".local", "bin", "hum");
76102
+ if (!exists2(launcher)) checks.push(check("warn", `no launcher at ${launcher}`, updateCommand(layout2, platform2)));
76103
+ else {
76104
+ const target = isWin(platform2) ? (fs6.readFileSync(launcher, "utf8").match(new RegExp('"([^"]+)"')) || [])[1] || "" : realpath(launcher);
76105
+ const insideVersions = target && realpath(target).startsWith(realpath(layout2.base));
76106
+ checks.push(insideVersions ? check("ok", `launcher ${launcher} \u2192 ${target}`) : check("warn", `launcher ${launcher} is not the installer's (it points at ${target || "?"})`, updateCommand(layout2, platform2)));
76107
+ }
76108
+ }
76109
+ const hits = onPath(env3, { platform: platform2 });
76110
+ const hums = hits.filter((h) => !h.name.startsWith("hum-engine"));
76111
+ const stale = hits.filter((h) => h.name.startsWith("hum-engine"));
76112
+ const targets = new Set(hums.map((h) => h.real));
76113
+ if (hums.length === 0) checks.push(check("warn", "no hum on PATH: a new terminal may not find it", layout2.kind === "native" ? isWin(platform2) ? "open a new terminal" : 'export PATH="$HOME/.local/bin:$PATH"' : "npm bin -g, and put that directory on PATH"));
76114
+ else if (targets.size > 1) checks.push(check("warn", `more than one hum on PATH; the first wins: ${hums.map((h) => h.path).join(" \xB7 ")}`, "remove the ones you did not mean to keep"));
76115
+ else checks.push(check("ok", `hum on PATH: ${hums[0].path}`));
76116
+ for (const s of stale) checks.push(check("warn", `an older install left ${s.path} on PATH`, "uv tool uninstall hum-cli"));
76117
+ sections.push({ key: "install", title: "Install", checks });
76118
+ }
76119
+ let running = null;
76120
+ {
76121
+ const checks = [];
76122
+ if (env3.HUM_ENGINE_PORT) checks.push(check("ok", `started by Python for this hum (HUM_ENGINE_PORT=${env3.HUM_ENGINE_PORT})`));
76123
+ for (const c of candidates) {
76124
+ const v = candidateVersion(c, { env: env3, runImpl });
76125
+ if (v) {
76126
+ running = { ...c, version: v };
76127
+ break;
76128
+ }
76129
+ }
76130
+ if (!running) checks.push(check("fail", "nothing answers: the part of hum that does the work is missing", layout2.kind === "npm" ? npmFix2(mine) : updateCommand(layout2, platform2)));
76131
+ else if (running.version === mine) checks.push(check("ok", `${running.version} runs from ${running.where} (${running.bin})`));
76132
+ else if (env3.HUM_ENGINE) checks.push(check("fail", `${running.version} is what runs: HUM_ENGINE points at it (${env3.HUM_ENGINE}); you installed ${mine}`, "unset HUM_ENGINE"));
76133
+ else checks.push(check("fail", `${running.version} is what runs (${running.where}: ${running.bin}); you installed ${mine}`, layout2.kind === "npm" ? npmFix2(mine) : updateCommand(layout2, platform2)));
76134
+ if (env3.HUM_ENGINE && running && running.version === mine) checks.push(check("warn", `HUM_ENGINE is set (${env3.HUM_ENGINE}): it decides what runs, ahead of any install`, "unset HUM_ENGINE"));
76135
+ if (layout2.kind === "npm") {
76136
+ const st = readInstallState(env3);
76137
+ const stamp = installedVersion(env3, runImpl);
76138
+ if (st && !st.ok) checks.push(check(stamp === mine ? "warn" : "fail", `the last install attempt (wanted ${st.wanted || st.version}) did not finish: ${st.error}`, npmFix2(mine)));
76139
+ else if (!stamp) checks.push(check("fail", `nothing installed under ${engineDir(env3)}`, npmFix2(mine)));
76140
+ else checks.push(check(stamp === mine ? "ok" : "warn", `${engineDir(env3)} holds ${stamp}`, stamp === mine ? "" : npmFix2(mine)));
76141
+ }
76142
+ if (layout2.kind === "native") {
76143
+ const sib = path5.join(layout2.dir, "engine", isWin(platform2) ? "hum-engine.exe" : "hum-engine");
76144
+ checks.push(exists2(sib) ? check("ok", `the working half is beside hum: ${sib}`) : check("fail", `nothing beside hum at ${sib}: the install is incomplete`, updateCommand(layout2, platform2)));
76145
+ }
76146
+ sections.push({ key: "runtime", title: "The part of hum that does the work", checks });
76147
+ }
76148
+ {
76149
+ const checks = [];
76150
+ const st = readState(env3);
76151
+ if (st && st.version) {
76152
+ const ready = readyVersion(layout2, st.version);
76153
+ checks.push(check("ok", `last background update: ${st.version}, started ${st.started ? new Date(st.started).toISOString() : "?"}${ready ? " \xB7 ready, takes effect on restart" : ""}`));
76154
+ const last = tail2(path5.join(home, "update.log"));
76155
+ if (last) checks.push(check("ok", `update.log: ${last}`));
76156
+ } else checks.push(check("ok", "no background update recorded"));
76157
+ if (env3.HUM_NO_UPDATE_CHECK) checks.push(check("warn", "HUM_NO_UPDATE_CHECK is set: hum does not look for releases", "unset HUM_NO_UPDATE_CHECK"));
76158
+ if (env3.HUM_NO_AUTO_UPDATE) checks.push(check("warn", "HUM_NO_AUTO_UPDATE is set: hum tells you about releases but does not fetch them", "unset HUM_NO_AUTO_UPDATE"));
76159
+ const latest = env3.HUM_NO_UPDATE_CHECK ? "" : await latestVersion(fetchImpl, env3);
76160
+ if (!latest && !env3.HUM_NO_UPDATE_CHECK) checks.push(check("warn", `could not reach ${dist(env3)} (offline, or a proxy in the way)`, "try again with a connection"));
76161
+ else if (latest && newer(latest, mine)) checks.push(check("warn", `${latest} is out \xB7 this is ${mine}`, updateCommand(layout2, platform2)));
76162
+ else if (latest) checks.push(check("ok", `${mine} is the latest release`));
76163
+ sections.push({ key: "updates", title: "Updates", checks });
76164
+ }
76165
+ const interp = running && running.args.length >= 3 && running.args[running.args.length - 2] === "hum.cli" ? running.bin : exists2(enginePython(env3)) ? enginePython(env3) : null;
76166
+ let toolServers = null;
76167
+ {
76168
+ const checks = [];
76169
+ try {
76170
+ fs6.accessSync(home, fs6.constants.W_OK);
76171
+ checks.push(check("ok", `HUM_HOME ${home} is writable`));
76172
+ } catch {
76173
+ checks.push(exists2(home) ? check("fail", `${home} is not writable`, `chmod u+w ${home}`) : check("warn", `${home} does not exist yet: it is made on first run`));
76174
+ }
76175
+ const configPath = env3.HUM_CONFIG || path5.join(home, "config.toml");
76176
+ if (!exists2(configPath)) checks.push(check("ok", `no ${configPath}: defaults`));
76177
+ else if (!interp) checks.push(check("warn", `${configPath} not checked: nothing here can parse TOML`, layout2.kind === "npm" ? npmFix2(mine) : updateCommand(layout2, platform2)));
76178
+ else {
76179
+ const r = runImpl(interp, ["-I", "-c", PARSE_CONFIG, configPath], { encoding: "utf8", windowsHide: true, timeout: 2e4 });
76180
+ let parsed = null;
76181
+ try {
76182
+ parsed = JSON.parse(String(r && r.stdout || ""));
76183
+ } catch {
76184
+ }
76185
+ if (!parsed) checks.push(check("warn", `${configPath} not checked: ${interp} did not answer`));
76186
+ else if (parsed.error) checks.push(check("fail", `${configPath}: ${parsed.error}`, `fix ${configPath}`));
76187
+ else {
76188
+ checks.push(check("ok", `${configPath} parses`));
76189
+ toolServers = parsed.mcp;
76190
+ }
76191
+ }
76192
+ for (const f of [path5.join(home, "hooks.json"), path5.join(cwd2, ".hum", "hooks.json"), path5.join(home, "autonomy.json"), path5.join(home, "update.json"), path5.join(home, "engine-install.json")]) {
76193
+ if (!exists2(f)) continue;
76194
+ const text = fs6.readFileSync(f, "utf8");
76195
+ try {
76196
+ JSON.parse(text);
76197
+ checks.push(check("ok", `${f} parses`));
76198
+ } catch (e) {
76199
+ checks.push(check("fail", `${f}: ${jsonError(text, e)}`, `fix ${f}`));
76200
+ }
76201
+ }
76202
+ const credPath = path5.join(home, "credentials.json");
76203
+ let cred = null;
76204
+ if (exists2(credPath)) {
76205
+ const text = fs6.readFileSync(credPath, "utf8");
76206
+ try {
76207
+ cred = JSON.parse(text);
76208
+ } catch (e) {
76209
+ checks.push(check("fail", `${credPath}: ${jsonError(text, e)}`, "hum login"));
76210
+ }
76211
+ }
76212
+ if (cred && cred.access_token) checks.push(check("ok", `signed in${cred.email ? ` as ${cred.email}` : ""}`));
76213
+ else if (!cred) checks.push(check("warn", "not signed in", "hum login"));
76214
+ checks.push(sandboxCheck(platform2, env3));
76215
+ sections.push({ key: "configuration", title: "Configuration", checks });
76216
+ }
76217
+ {
76218
+ const checks = [];
76219
+ const local = Array.isArray(toolServers) ? toolServers : null;
76220
+ if (local) for (const s of local) checks.push(check("ok", `${s.name} \xB7 ${s.transport}${s.at ? ` \xB7 ${s.at}` : ""} \xB7 from config.toml`));
76221
+ else if (toolServers === null && exists2(env3.HUM_CONFIG || path5.join(home, "config.toml"))) checks.push(check("warn", "config.toml servers not listed (it did not parse, or nothing here can read it)"));
76222
+ let cred = null;
76223
+ try {
76224
+ cred = JSON.parse(fs6.readFileSync(path5.join(home, "credentials.json"), "utf8"));
76225
+ } catch {
76226
+ }
76227
+ for (const s of cred && Array.isArray(cred.mcp) ? cred.mcp : []) if (s && s.name) checks.push(check("ok", `${s.name} \xB7 http \xB7 via the server`));
76228
+ if (checks.length === 0) checks.push(check("ok", "none configured"));
76229
+ sections.push({ key: "tool_servers", title: "Tool servers", checks });
76230
+ }
76231
+ const summary = { ok: 0, warn: 0, fail: 0 };
76232
+ for (const s of sections) for (const c of s.checks) summary[c.status] += 1;
76233
+ return { hum: mine, platform: platform2, layout: layout2.kind, sections, summary };
76234
+ }
76235
+ function sandboxCheck(platform2, env3) {
76236
+ if (isWin(platform2)) return check("ok", "no sandbox on Windows: commands run as you, in your account");
76237
+ if (platform2 === "darwin") return exists2("/usr/bin/sandbox-exec") ? check("ok", "sandbox: macOS Seatbelt (/usr/bin/sandbox-exec)") : check("warn", "/usr/bin/sandbox-exec is missing: commands run unsandboxed");
76238
+ const dirs = String(env3.PATH || "").split(path5.delimiter);
76239
+ const bwrap = dirs.map((d) => path5.join(d, "bwrap")).find(exists2);
76240
+ if (!bwrap) return check("warn", "bubblewrap is not installed: commands run unsandboxed", "sudo apt install bubblewrap");
76241
+ const restricted = (() => {
76242
+ try {
76243
+ return fs6.readFileSync("/proc/sys/kernel/apparmor_restrict_unprivileged_userns", "utf8").trim() === "1";
76244
+ } catch {
76245
+ return false;
76246
+ }
76247
+ })();
76248
+ if (restricted) return check("warn", "bubblewrap is installed but unprivileged user namespaces are restricted", "sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0");
76249
+ return check("ok", `sandbox: bubblewrap (${bwrap})`);
76250
+ }
76251
+ function render2(report) {
76252
+ const out = [];
76253
+ for (const s of report.sections) {
76254
+ out.push(s.title);
76255
+ for (const c of s.checks) out.push(` ${MARK[c.status]} ${c.text}${c.fix ? `
76256
+ \u2192 ${c.fix}` : ""}`);
76257
+ out.push("");
76258
+ }
76259
+ out.push(`${report.summary.ok} ok \xB7 ${report.summary.warn} warn \xB7 ${report.summary.fail} fail`);
76260
+ return out.join("\n") + "\n";
76261
+ }
76262
+ async function doctor({ json = false, mine, write = (t) => process.stdout.write(t), ...opts } = {}) {
76263
+ const report = await diagnose({ mine, ...opts });
76264
+ write(json ? JSON.stringify(report, null, 2) + "\n" : render2(report));
76265
+ return report.summary.fail ? 1 : 0;
76266
+ }
76267
+ var isWin, npmFix2, exists2, realpath, tail2, check, PARSE_CONFIG, MARK;
76268
+ var init_doctor = __esm({
76269
+ "src/doctor.js"() {
76270
+ init_engine();
76271
+ init_install();
76272
+ init_update();
76273
+ isWin = (platform2) => platform2 === "win32";
76274
+ npmFix2 = (version) => `npm i -g @metaphi-ai/hum@${version || "latest"} --foreground-scripts`;
76275
+ exists2 = (p) => {
76276
+ try {
76277
+ fs6.accessSync(p);
76278
+ return true;
76279
+ } catch {
76280
+ return false;
76281
+ }
76282
+ };
76283
+ realpath = (p) => {
76284
+ try {
76285
+ return fs6.realpathSync(p);
76286
+ } catch {
76287
+ return p;
76288
+ }
76289
+ };
76290
+ tail2 = (p) => {
76291
+ try {
76292
+ const lines = fs6.readFileSync(p, "utf8").trim().split("\n");
76293
+ return lines[lines.length - 1] || "";
76294
+ } catch {
76295
+ return "";
76296
+ }
76297
+ };
76298
+ check = (status, text, fix = "") => ({ status, text, ...fix ? { fix } : {} });
76299
+ PARSE_CONFIG = [
76300
+ "import json, sys, tomllib",
76301
+ "p = sys.argv[1]",
76302
+ "try:",
76303
+ ' d = tomllib.loads(open(p, "rb").read().decode("utf-8"))',
76304
+ "except Exception as e:",
76305
+ ' print(json.dumps({"error": str(e)})); sys.exit(0)',
76306
+ 'mcp = [{"name": s.get("name", "?"), "transport": "http" if s.get("url") else "stdio", "at": s.get("url") or s.get("command") or ""} for s in d.get("mcp", [])]',
76307
+ 'print(json.dumps({"mcp": mcp}))'
76308
+ ].join("\n");
76309
+ MARK = { ok: "ok ", warn: "warn", fail: "FAIL" };
76310
+ }
76311
+ });
76312
+
75508
76313
  // src/cli.jsx
75509
76314
  var import_react25 = __toESM(require_react(), 1);
75510
76315
 
@@ -80199,7 +81004,7 @@ var create = (stream, { showCursor = false } = {}) => {
80199
81004
  let previousLineCount = 0;
80200
81005
  let previousOutput = "";
80201
81006
  let hasHiddenCursor = false;
80202
- const render2 = (str) => {
81007
+ const render3 = (str) => {
80203
81008
  if (!showCursor && !hasHiddenCursor) {
80204
81009
  cli_cursor_default.hide();
80205
81010
  hasHiddenCursor = true;
@@ -80212,12 +81017,12 @@ var create = (stream, { showCursor = false } = {}) => {
80212
81017
  stream.write(base_exports.eraseLines(previousLineCount) + output);
80213
81018
  previousLineCount = output.split("\n").length;
80214
81019
  };
80215
- render2.clear = () => {
81020
+ render3.clear = () => {
80216
81021
  stream.write(base_exports.eraseLines(previousLineCount));
80217
81022
  previousOutput = "";
80218
81023
  previousLineCount = 0;
80219
81024
  };
80220
- render2.done = () => {
81025
+ render3.done = () => {
80221
81026
  previousOutput = "";
80222
81027
  previousLineCount = 0;
80223
81028
  if (!showCursor) {
@@ -80225,7 +81030,7 @@ var create = (stream, { showCursor = false } = {}) => {
80225
81030
  hasHiddenCursor = false;
80226
81031
  }
80227
81032
  };
80228
- return render2;
81033
+ return render3;
80229
81034
  };
80230
81035
  var logUpdate = { create };
80231
81036
  var log_update_default = logUpdate;
@@ -80406,8 +81211,8 @@ function Text({ color, backgroundColor, dimColor = false, bold = false, italic =
80406
81211
  }
80407
81212
 
80408
81213
  // node_modules/ink/build/components/ErrorOverview.js
80409
- var cleanupPath = (path4) => {
80410
- return path4?.replace(`file://${cwd()}/`, "");
81214
+ var cleanupPath = (path6) => {
81215
+ return path6?.replace(`file://${cwd()}/`, "");
80411
81216
  };
80412
81217
  var stackUtils = new import_stack_utils.default({
80413
81218
  cwd: cwd(),
@@ -81042,7 +81847,7 @@ var getInstance = (stdout, createInstance) => {
81042
81847
  // node_modules/ink/build/components/Static.js
81043
81848
  var import_react11 = __toESM(require_react(), 1);
81044
81849
  function Static(props) {
81045
- const { items, children: render2, style: customStyle } = props;
81850
+ const { items, children: render3, style: customStyle } = props;
81046
81851
  const [index, setIndex] = (0, import_react11.useState)(0);
81047
81852
  const itemsToRender = (0, import_react11.useMemo)(() => {
81048
81853
  return items.slice(index);
@@ -81051,7 +81856,7 @@ function Static(props) {
81051
81856
  setIndex(items.length);
81052
81857
  }, [items.length]);
81053
81858
  const children = itemsToRender.map((item, itemIndex) => {
81054
- return render2(item, index + itemIndex);
81859
+ return render3(item, index + itemIndex);
81055
81860
  });
81056
81861
  const style = (0, import_react11.useMemo)(() => ({
81057
81862
  position: "absolute",
@@ -81353,9 +82158,9 @@ var import_react21 = __toESM(require_react(), 1);
81353
82158
 
81354
82159
  // src/app.jsx
81355
82160
  var import_react24 = __toESM(require_react(), 1);
81356
- import fs3 from "node:fs";
81357
- import os4 from "node:os";
81358
- import path2 from "node:path";
82161
+ import fs4 from "node:fs";
82162
+ import os5 from "node:os";
82163
+ import path3 from "node:path";
81359
82164
 
81360
82165
  // node_modules/ink-spinner/build/index.js
81361
82166
  var import_react22 = __toESM(require_react(), 1);
@@ -83584,124 +84389,16 @@ var MASCOT = [
83584
84389
  var MASCOT_WIDTH = 10;
83585
84390
 
83586
84391
  // src/banner.js
83587
- function bannerLines(ev, homeRel2 = (p) => p) {
84392
+ function bannerLines(ev, homeRel2 = (p) => p, mine = "") {
83588
84393
  const state = ev.state && ev.state !== "new" && ev.state !== "idle" ? ` \xB7 ${ev.state}` : "";
84394
+ const drift = mine && ev.version && mine !== ev.version ? ` \xB7 you installed ${mine}` : "";
83589
84395
  const where = `${homeRel2(ev.cwd || "")}${ev.workspace ? ` \xB7 ${ev.workspace}` : ""}`;
83590
84396
  const agents = ev.agents_model ? ` \xB7 agents on ${ev.agents_model}` : "";
83591
- return [`hum ${ev.version || ""}`.trim() + state, `${ev.model || ""}${agents}${ev.user ? ` \xB7 ${ev.user}` : ""}`, where];
84397
+ return [`hum ${ev.version || ""}`.trim() + drift + state, `${ev.model || ""}${agents}${ev.user ? ` \xB7 ${ev.user}` : ""}`, where];
83592
84398
  }
83593
84399
 
83594
- // src/update.js
83595
- import fs2 from "node:fs";
83596
- import os3 from "node:os";
83597
- import path from "node:path";
83598
- import { spawn, spawnSync } from "node:child_process";
83599
- var dist = (env3 = process.env) => (env3.HUM_DIST || "https://storage.googleapis.com/hum-dist").replace(/\/+$/, "");
83600
- var humHome = (env3 = process.env) => env3.HUM_HOME || path.join(os3.homedir(), ".hum");
83601
- var win = () => process.platform === "win32";
83602
- async function latestVersion(fetchImpl = globalThis.fetch, env3 = process.env) {
83603
- if (env3.HUM_NO_UPDATE_CHECK || typeof fetchImpl !== "function") return "";
83604
- try {
83605
- const r = await fetchImpl(`${dist(env3)}/releases/latest`, { signal: AbortSignal.timeout(2500) });
83606
- if (!r.ok) return "";
83607
- const v = (await r.text()).trim();
83608
- return /^\d+\.\d+\.\d+$/.test(v) ? v : "";
83609
- } catch {
83610
- return "";
83611
- }
83612
- }
83613
- var newer = (a, b) => {
83614
- const pa = String(a).split(".").map(Number), pb = String(b).split(".").map(Number);
83615
- for (let i = 0; i < 3; i += 1) {
83616
- if ((pa[i] || 0) !== (pb[i] || 0)) return (pa[i] || 0) > (pb[i] || 0);
83617
- }
83618
- return false;
83619
- };
83620
- function installLayout(execPath = process.execPath, env3 = process.env) {
83621
- const exe = String(execPath).split(/[\\/]/).pop();
83622
- if (/^(node|bun)(\.exe)?$/i.test(exe)) return { kind: env3.HUM_ENGINE_PORT ? "python" : "npm" };
83623
- let real = execPath;
83624
- try {
83625
- real = fs2.realpathSync(execPath);
83626
- } catch {
83627
- }
83628
- return { kind: "native", exe, dir: path.dirname(real), base: path.dirname(path.dirname(real)) };
83629
- }
83630
- var updateCommand = (layout = installLayout(), platform2 = process.platform) => {
83631
- if (layout.kind === "native") return platform2 === "win32" ? `irm ${dist()}/install.ps1 | iex` : `curl -fsSL ${dist()}/install.sh | sh`;
83632
- if (layout.kind === "python") return "uv tool upgrade hum-cli (or: pip install -U hum-cli)";
83633
- return "npm i -g @metaphi-ai/hum@latest";
83634
- };
83635
- var readyVersion = (layout, version) => layout.kind === "native" && version && fs2.existsSync(path.join(layout.base, version, layout.exe)) ? version : "";
83636
- var stateFile = (env3 = process.env) => path.join(humHome(env3), "update.json");
83637
- var readState = (env3 = process.env) => {
83638
- try {
83639
- return JSON.parse(fs2.readFileSync(stateFile(env3), "utf8"));
83640
- } catch {
83641
- return {};
83642
- }
83643
- };
83644
- var writeState = (s, env3 = process.env) => {
83645
- try {
83646
- fs2.mkdirSync(humHome(env3), { recursive: true });
83647
- fs2.writeFileSync(stateFile(env3), JSON.stringify(s));
83648
- } catch {
83649
- }
83650
- };
83651
- function installerArgv(version, platform2 = process.platform) {
83652
- const base = dist();
83653
- if (platform2 === "win32") return ["powershell", ["-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", `irm ${base}/install.ps1 | iex`]];
83654
- return ["/bin/sh", ["-c", `curl -fsSL "${base}/install.sh" | sh`]];
83655
- }
83656
- function startBackgroundUpdate(version, { env: env3 = process.env, now = Date.now(), spawnImpl = spawn } = {}) {
83657
- if (env3.HUM_NO_AUTO_UPDATE) return false;
83658
- const s = readState(env3);
83659
- if (s.version === version && now - (s.started || 0) < 30 * 60 * 1e3) return false;
83660
- const log = path.join(humHome(env3), "update.log");
83661
- let out = "ignore";
83662
- try {
83663
- fs2.mkdirSync(humHome(env3), { recursive: true });
83664
- out = fs2.openSync(log, "w");
83665
- } catch {
83666
- }
83667
- const [bin, args2] = installerArgv(version);
83668
- try {
83669
- const child = spawnImpl(bin, args2, {
83670
- detached: true,
83671
- stdio: ["ignore", out, out],
83672
- windowsHide: true,
83673
- env: { ...env3, HUM_VERSION: version, HUM_DIST: dist(env3) }
83674
- });
83675
- child.unref();
83676
- writeState({ version, started: now }, env3);
83677
- return true;
83678
- } catch {
83679
- return false;
83680
- }
83681
- }
83682
- async function updateNotice(mine, { env: env3 = process.env, fetchImpl = globalThis.fetch, layout = installLayout(process.execPath, env3), spawnImpl = spawn } = {}) {
83683
- const latest = await latestVersion(fetchImpl, env3);
83684
- if (!latest || !newer(latest, mine)) return "";
83685
- if (layout.kind !== "native") return `hum ${latest} is out (this is ${mine}) \xB7 ${updateCommand(layout)}`;
83686
- if (readyVersion(layout, latest)) return `hum ${latest} is ready \xB7 restart hum to use it`;
83687
- if (startBackgroundUpdate(latest, { env: env3, spawnImpl })) return `hum ${latest} is downloading in the background \xB7 it takes effect the next time you start hum`;
83688
- const s = readState(env3);
83689
- if (s.version === latest && !env3.HUM_NO_AUTO_UPDATE) return `hum ${latest} is still installing in the background (${path.join(humHome(env3), "update.log")} has the details)`;
83690
- return `hum ${latest} is out (this is ${mine}) \xB7 ${updateCommand(layout)}`;
83691
- }
83692
- function updateNow(layout = installLayout()) {
83693
- if (layout.kind === "native") {
83694
- const [bin, args2] = installerArgv();
83695
- return spawnSync(bin, args2, { stdio: "inherit", env: { ...process.env, HUM_DIST: dist() } }).status ?? 1;
83696
- }
83697
- if (layout.kind === "python") {
83698
- process.stdout.write(`update with your package manager: ${updateCommand(layout)}
83699
- `);
83700
- return 0;
83701
- }
83702
- const r = spawnSync(win() ? "npm.cmd" : "npm", ["i", "-g", "@metaphi-ai/hum@latest"], { stdio: "inherit", shell: win() });
83703
- return r.status ?? 1;
83704
- }
84400
+ // src/app.jsx
84401
+ init_update();
83705
84402
 
83706
84403
  // src/input.jsx
83707
84404
  var import_react23 = __toESM(require_react(), 1);
@@ -83844,6 +84541,7 @@ var input_default = MultilineInput;
83844
84541
 
83845
84542
  // src/app.jsx
83846
84543
  var import_jsx_runtime2 = __toESM(require_jsx_runtime(), 1);
84544
+ var MINE = true ? "0.1.30" : "";
83847
84545
  var fmtDur = (s) => s < 60 ? `${Math.max(1, Math.round(s))}s` : `${Math.floor(s / 60)}m ${Math.round(s % 60)}s`;
83848
84546
  var plural = (n, w) => `${n} ${w}${n === 1 ? "" : "s"}`;
83849
84547
  var firstResp = (e) => e.first_response_s ? ` \xB7 first response ${e.first_response_s.toFixed(1)}s` : "";
@@ -83851,7 +84549,7 @@ var shortSession = (name) => (name || "").replace(/\.jsonl$/, "");
83851
84549
  var PICKER_ROWS = 8;
83852
84550
  var sessionRows = (p, here) => {
83853
84551
  const q = p.query.trim().toLowerCase();
83854
- const all = p.all.map((it) => ({ ...it, dir: it.cwd ? path2.basename(it.cwd) : "" }));
84552
+ const all = p.all.map((it) => ({ ...it, dir: it.cwd ? path3.basename(it.cwd) : "" }));
83855
84553
  const inHere = all.filter((it) => it.cwd && here && it.cwd === here);
83856
84554
  const scope = p.scope === "here" && inHere.length ? "here" : "all";
83857
84555
  let rows = all;
@@ -83865,8 +84563,15 @@ var sessionRows = (p, here) => {
83865
84563
  if (q) rows = rows.filter((it) => [it.instruction, it.dir, it.name, it.model].some((v) => (v || "").toLowerCase().includes(q)));
83866
84564
  return { rows, scope };
83867
84565
  };
84566
+ var ago = (at) => {
84567
+ const secs = Math.max(0, Date.now() / 1e3 - (at || 0));
84568
+ if (secs < 90) return "just now";
84569
+ if (secs < 3600) return `${Math.floor(secs / 60)}m ago`;
84570
+ if (secs < 86400) return `${Math.floor(secs / 3600)}h ago`;
84571
+ return `${Math.floor(secs / 86400)}d ago`;
84572
+ };
83868
84573
  var homeRel = (p) => {
83869
- const h = os4.homedir();
84574
+ const h = os5.homedir();
83870
84575
  return p && h && p.startsWith(h) ? "~" + p.slice(h.length) : p;
83871
84576
  };
83872
84577
  var handEdit = (stat) => {
@@ -83877,11 +84582,11 @@ var handEdit = (stat) => {
83877
84582
  ${lines.join("\n ")}`;
83878
84583
  };
83879
84584
  var fmtCost = (c) => c >= 0.01 ? `$${c.toFixed(2)}` : c > 0 ? `$${c.toFixed(4)}` : "$0";
83880
- var HISTORY_PATH = path2.join(os4.homedir(), ".hum", "history.json");
84585
+ var HISTORY_PATH = path3.join(os5.homedir(), ".hum", "history.json");
83881
84586
  var HISTORY_MAX = 300;
83882
84587
  var loadHistory = () => {
83883
84588
  try {
83884
- const a = JSON.parse(fs3.readFileSync(HISTORY_PATH, "utf8"));
84589
+ const a = JSON.parse(fs4.readFileSync(HISTORY_PATH, "utf8"));
83885
84590
  return Array.isArray(a) ? a.filter((x) => typeof x === "string") : [];
83886
84591
  } catch {
83887
84592
  return [];
@@ -83889,8 +84594,8 @@ var loadHistory = () => {
83889
84594
  };
83890
84595
  var saveHistory = (arr) => {
83891
84596
  try {
83892
- fs3.mkdirSync(path2.dirname(HISTORY_PATH), { recursive: true });
83893
- fs3.writeFileSync(HISTORY_PATH, JSON.stringify(arr.slice(-HISTORY_MAX)));
84597
+ fs4.mkdirSync(path3.dirname(HISTORY_PATH), { recursive: true });
84598
+ fs4.writeFileSync(HISTORY_PATH, JSON.stringify(arr.slice(-HISTORY_MAX)));
83894
84599
  } catch {
83895
84600
  }
83896
84601
  };
@@ -83901,8 +84606,10 @@ var tail = (s, n) => {
83901
84606
  };
83902
84607
  var COMMANDS = [
83903
84608
  { name: "/resume", desc: "pick a past session to continue (this machine or any other)" },
83904
- { name: "/compact", desc: "summarise and restart the context now" },
84609
+ { name: "/compact", desc: "summarise and restart the context now (/compact <what the note should attend to>)" },
83905
84610
  { name: "/model", desc: "switch between the models you can use; /model <name> switches straight away" },
84611
+ { name: "/diff", desc: "what has changed since this session began (/diff last: the last exchange; /diff <path>: one file)" },
84612
+ { name: "/rewind", desc: "go back to something you said: the files, the conversation, or both (esc esc opens it too)" },
83906
84613
  { name: "/cost", desc: "tokens and cost so far" },
83907
84614
  { name: "/approve", desc: "approvals on|off \u2014 whether every change and command waits for you first (leaving the sandbox always asks)" },
83908
84615
  { name: "/continue", desc: "after a pause: let the agent carry on" },
@@ -83916,8 +84623,16 @@ var COMMANDS = [
83916
84623
  { name: "/quit", desc: "leave; the session keeps running (hum resume brings you back)" },
83917
84624
  { name: "/stop", desc: "end this session for good (the record is saved)" }
83918
84625
  ];
83919
- var HELP = "!cmd runs a command as you \xB7 esc interrupts the model (what it had is kept) \xB7 type while it works to steer \xB7 edit files in your editor any time (recorded as your turn) \xB7 ctrl+o shows the full output of the last tool result \xB7 ctrl+v pastes a screenshot from the clipboard \xB7 @path.png or /image <path> attaches an image file \xB7 commands run in a sandbox (writes in the working directory, no network); leaving it asks you first (enter approves, a typed reason rejects) \xB7 /approve makes every change and command wait for you; at the panel, a allows that shape for the session and p writes it into the project \xB7 /permissions lists the rules in force \xB7 /mcp lists the tool servers \xB7 /resume picks a past session (a running one attaches) \xB7 /compact restarts the context from a summary \xB7 ctrl+c twice leaves and the session keeps running (`hum resume` brings you back) \xB7 /stop ends it";
84626
+ var HELP = "!cmd runs a command as you \xB7 esc interrupts the model (what it had is kept) \xB7 esc twice while it is idle opens the rewind picker \xB7 type while it works to steer \xB7 edit files in your editor any time (recorded as your turn) \xB7 ctrl+o shows the full output of the last tool result \xB7 ctrl+v pastes a screenshot from the clipboard \xB7 @path.png or /image <path> attaches an image file \xB7 commands run in a sandbox (writes in the working directory, no network); leaving it asks you first (enter approves, a typed reason rejects) \xB7 /approve makes every change and command wait for you; at the panel, a allows that shape for the session and p writes it into the project \xB7 /permissions lists the rules in force \xB7 /diff shows what has changed since the session began \xB7 /rewind takes the files or the conversation back to something you said \xB7 /mcp lists the tool servers \xB7 /resume picks a past session (a running one attaches) \xB7 /compact restarts the context from a summary \xB7 ctrl+c twice leaves and the session keeps running (`hum resume` brings you back) \xB7 /stop ends it";
83920
84627
  var DIFF_TAIL_LINES = 20;
84628
+ var PATCH_LINES = 200;
84629
+ var ESC_ESC_MS = 800;
84630
+ var REWIND_ROWS = 8;
84631
+ var REWIND_CHOICES = [
84632
+ { key: "files", label: "restore the files", desc: "the workspace goes back to how it was then" },
84633
+ { key: "chat", label: "restore the conversation", desc: "hum carries on from what you said, on a new branch; nothing is deleted" },
84634
+ { key: "both", label: "both", desc: "" }
84635
+ ];
83921
84636
  var OUTPUT_MAX_LINES = 200;
83922
84637
  var ERR_TAIL_LINES = 5;
83923
84638
  function App2({ engine: engine2, task, resume, images = [] }) {
@@ -83944,6 +84659,7 @@ function App2({ engine: engine2, task, resume, images = [] }) {
83944
84659
  const [qAnswers, setQAnswers] = (0, import_react24.useState)({});
83945
84660
  const [qPicks, setQPicks] = (0, import_react24.useState)([]);
83946
84661
  const [qCursor, setQCursor] = (0, import_react24.useState)(0);
84662
+ const [confirm, setConfirm] = (0, import_react24.useState)(null);
83947
84663
  const [gate, setGate] = (0, import_react24.useState)("off");
83948
84664
  const [paused, setPaused] = (0, import_react24.useState)(false);
83949
84665
  const attachRef = (0, import_react24.useRef)([]);
@@ -83961,6 +84677,9 @@ function App2({ engine: engine2, task, resume, images = [] }) {
83961
84677
  const lastOutRef = (0, import_react24.useRef)(null);
83962
84678
  const helloRef = (0, import_react24.useRef)(false);
83963
84679
  const startedRef = (0, import_react24.useRef)(false);
84680
+ const escRef = (0, import_react24.useRef)(0);
84681
+ const rewindRef = (0, import_react24.useRef)({ files: true, conversation: true });
84682
+ const wantRow = (0, import_react24.useRef)(null);
83964
84683
  const preHello = (0, import_react24.useRef)([]);
83965
84684
  const [meter, setMeter] = (0, import_react24.useState)({ tokens: 0, cap: 0, input: 0, output: 0 });
83966
84685
  const setPhaseBoth = (p) => {
@@ -84005,6 +84724,7 @@ function App2({ engine: engine2, task, resume, images = [] }) {
84005
84724
  setQCursor(0);
84006
84725
  setPaused(false);
84007
84726
  setPicker(null);
84727
+ setConfirm(null);
84008
84728
  setSpend(0);
84009
84729
  setGoal(null);
84010
84730
  setSession(null);
@@ -84070,7 +84790,7 @@ function App2({ engine: engine2, task, resume, images = [] }) {
84070
84790
  setGate(ev.gate === "approve" ? "approve" : "off");
84071
84791
  if (ev.session) setSession(ev.session);
84072
84792
  if (ev.fresh) append({ kind: "wordmark" });
84073
- append({ kind: "banner", lines: bannerLines(ev, homeRel), instruction: ev.session ? ev.instruction : null });
84793
+ append({ kind: "banner", lines: bannerLines(ev, homeRel, MINE), instruction: ev.session ? ev.instruction : null });
84074
84794
  if (ev.note) append({ kind: "warn", text: ev.note });
84075
84795
  setGoal(ev.goal || null);
84076
84796
  if (ev.goal) append({ kind: "info", text: `goal: ${ev.goal}` });
@@ -84299,6 +85019,39 @@ function App2({ engine: engine2, task, resume, images = [] }) {
84299
85019
  setProposal(null);
84300
85020
  append({ kind: "info", text: "approvals off: the waiting proposal ran" });
84301
85021
  break;
85022
+ case "diff": {
85023
+ const text = String(ev.text || "");
85024
+ if (!text.trim()) {
85025
+ append({ kind: "info", text: ev.scope === "last" ? "nothing changed in the last exchange" : ev.scope ? `nothing changed in ${ev.scope}` : "nothing has changed since this session began" });
85026
+ break;
85027
+ }
85028
+ const ls = text.split("\n");
85029
+ const stat = String(ev.stat || "").split("\n").filter((l) => l.trim()).pop() || "";
85030
+ append({ kind: "patch", lines: ls.slice(0, PATCH_LINES), more: Math.max(0, ls.length - PATCH_LINES), stat });
85031
+ break;
85032
+ }
85033
+ case "rewind_list": {
85034
+ const items2 = ev.items || [];
85035
+ if (!items2.length) {
85036
+ append({ kind: "info", text: "nothing to go back to yet" });
85037
+ break;
85038
+ }
85039
+ const want = items2.findIndex((it) => it.n === wantRow.current);
85040
+ wantRow.current = null;
85041
+ setPicker({ kind: "rewind", items: items2, index: want >= 0 ? want : items2.length - 1, top: 0, choice: null });
85042
+ break;
85043
+ }
85044
+ case "rewind_confirm":
85045
+ setPicker(null);
85046
+ setConfirm({ node: ev.node, said: ev.said || "", stat: ev.stat || "", why: ev.why || "" });
85047
+ break;
85048
+ case "rewind": {
85049
+ setConfirm(null);
85050
+ const did = [ev.files ? "the files" : null, ev.conversation ? "the conversation" : null].filter(Boolean).join(" and ");
85051
+ append({ kind: "info", text: `back to \u201C${(ev.said || "").slice(0, 60)}\u201D \xB7 ${did} restored` });
85052
+ if (ev.stat) append({ kind: "info", text: ` ${String(ev.stat).split("\n").filter((l) => l.trim()).join("\n ")}` });
85053
+ break;
85054
+ }
84302
85055
  case "goal":
84303
85056
  setGoal(ev.text || null);
84304
85057
  append({ kind: "info", text: ev.text ? `goal: ${ev.text}` : "goal cleared" });
@@ -84375,7 +85128,7 @@ function App2({ engine: engine2, task, resume, images = [] }) {
84375
85128
  (0, import_react24.useEffect)(() => {
84376
85129
  if (!hello) return void 0;
84377
85130
  let live = true;
84378
- updateNotice(true ? "0.1.26" : hello.version || "0.0.0").then((line) => {
85131
+ updateNotice(MINE || hello.version || "0.0.0", { running: hello.version || "" }).then((line) => {
84379
85132
  if (live && line) append({ kind: "info", text: line });
84380
85133
  }).catch(() => {
84381
85134
  });
@@ -84423,6 +85176,47 @@ function App2({ engine: engine2, task, resume, images = [] }) {
84423
85176
  }
84424
85177
  return;
84425
85178
  }
85179
+ if (confirm && !picker) {
85180
+ if (key.return) {
85181
+ setConfirm(null);
85182
+ engine2.send({ cmd: "rewind", to: confirm.node, ...rewindRef.current, confirm: true });
85183
+ return;
85184
+ }
85185
+ if (key.escape) {
85186
+ setConfirm(null);
85187
+ append({ kind: "info", text: "left as it is" });
85188
+ return;
85189
+ }
85190
+ return;
85191
+ }
85192
+ if (picker && picker.kind === "rewind") {
85193
+ if (picker.choice === null) {
85194
+ const n = picker.items.length;
85195
+ const move = (d) => setPicker((pk) => {
85196
+ const index = (pk.index + d + n) % n;
85197
+ const top = index < pk.top ? index : index >= pk.top + REWIND_ROWS ? index - REWIND_ROWS + 1 : pk.top;
85198
+ return { ...pk, index, top };
85199
+ });
85200
+ if (key.upArrow) move(-1);
85201
+ else if (key.downArrow || key.tab) move(1);
85202
+ else if (key.escape) setPicker(null);
85203
+ else if (key.return) setPicker((pk) => ({ ...pk, choice: 0 }));
85204
+ return;
85205
+ }
85206
+ const pick = (c) => {
85207
+ const it = picker.items[picker.index];
85208
+ setPicker(null);
85209
+ if (!it) return;
85210
+ rewindRef.current = { files: c !== "chat", conversation: c !== "files" };
85211
+ engine2.send({ cmd: "rewind", to: it.node, ...rewindRef.current });
85212
+ };
85213
+ if (key.upArrow) setPicker((pk) => ({ ...pk, choice: (pk.choice + REWIND_CHOICES.length - 1) % REWIND_CHOICES.length }));
85214
+ else if (key.downArrow || key.tab) setPicker((pk) => ({ ...pk, choice: (pk.choice + 1) % REWIND_CHOICES.length }));
85215
+ else if (key.escape) setPicker((pk) => ({ ...pk, choice: null }));
85216
+ else if (key.return) pick(REWIND_CHOICES[picker.choice].key);
85217
+ else if (/^[1-3]$/.test(input)) pick(REWIND_CHOICES[Number(input) - 1].key);
85218
+ return;
85219
+ }
84426
85220
  if (proposal && !picker) {
84427
85221
  if (key.return && !value.trim()) {
84428
85222
  decide("accept");
@@ -84519,7 +85313,20 @@ function App2({ engine: engine2, task, resume, images = [] }) {
84519
85313
  else if (key.tab) setValue(menu[Math.min(menuIndex, menu.length - 1)].name + " ");
84520
85314
  return;
84521
85315
  }
84522
- if (key.escape && phaseRef.current === "busy") engine2.send({ cmd: "interrupt" });
85316
+ if (key.escape) {
85317
+ if (phaseRef.current === "busy") {
85318
+ engine2.send({ cmd: "interrupt" });
85319
+ escRef.current = 0;
85320
+ return;
85321
+ }
85322
+ const now = Date.now();
85323
+ if (now - escRef.current < ESC_ESC_MS) {
85324
+ escRef.current = 0;
85325
+ engine2.send({ cmd: "rewind_list" });
85326
+ return;
85327
+ }
85328
+ escRef.current = now;
85329
+ }
84523
85330
  });
84524
85331
  (0, import_react24.useEffect)(() => {
84525
85332
  setMenuIndex(0);
@@ -84587,7 +85394,7 @@ function App2({ engine: engine2, task, resume, images = [] }) {
84587
85394
  engine2.send({ cmd: "sessions" });
84588
85395
  break;
84589
85396
  case "/compact":
84590
- engine2.send({ cmd: "compact" });
85397
+ engine2.send(arg ? { cmd: "compact", text: arg } : { cmd: "compact" });
84591
85398
  break;
84592
85399
  case "/model":
84593
85400
  if (arg) {
@@ -84595,6 +85402,13 @@ function App2({ engine: engine2, task, resume, images = [] }) {
84595
85402
  engine2.send({ cmd: "model", name: arg });
84596
85403
  } else engine2.send({ cmd: "model" });
84597
85404
  break;
85405
+ case "/diff":
85406
+ engine2.send({ cmd: "diff", scope: arg });
85407
+ break;
85408
+ case "/rewind":
85409
+ wantRow.current = /^\d+$/.test(arg) ? Number(arg) : null;
85410
+ engine2.send({ cmd: "rewind_list" });
85411
+ break;
84598
85412
  case "/cost": {
84599
85413
  const ctx = ctxPct > 0 ? ` \xB7 context ${ctxPct}% of the compaction threshold` : "";
84600
85414
  append({ kind: "info", text: `${fmtCost(spend)} this session \xB7 ${meter.input.toLocaleString()}+${meter.output.toLocaleString()} tokens${ctx}` });
@@ -84772,6 +85586,19 @@ function App2({ engine: engine2, task, resume, images = [] }) {
84772
85586
  )),
84773
85587
  item.more > 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: `\u2026 +${item.more} more diff lines` }) : null
84774
85588
  ] }),
85589
+ item.kind === "patch" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { flexDirection: "column", paddingLeft: 2, children: [
85590
+ item.lines.map((l, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
85591
+ Text,
85592
+ {
85593
+ color: l.startsWith("+") ? "green" : l.startsWith("-") ? "red" : l.startsWith("@@") ? "cyan" : void 0,
85594
+ dimColor: !l.startsWith("+") && !l.startsWith("-"),
85595
+ children: l || " "
85596
+ },
85597
+ i
85598
+ )),
85599
+ item.more > 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: `\u2026 +${item.more} more lines \xB7 /diff <path> narrows it` }) : null,
85600
+ item.stat ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: item.stat.trim() }) : null
85601
+ ] }),
84775
85602
  item.kind === "errtail" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box_default, { flexDirection: "column", paddingLeft: 6, children: item.lines.map((l, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: "red", dimColor: true, children: l }, i)) }),
84776
85603
  item.kind === "output" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { flexDirection: "column", paddingLeft: 4, children: [
84777
85604
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: `full output \xB7 ${item.name}` }),
@@ -84909,6 +85736,73 @@ function App2({ engine: engine2, task, resume, images = [] }) {
84909
85736
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { children: " " }),
84910
85737
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: "Enter to switch \xB7 Esc to cancel" })
84911
85738
  ] }),
85739
+ confirm && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, marginTop: 1, children: [
85740
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { color: "yellow", bold: true, children: [
85741
+ "\u23EE ",
85742
+ confirm.why || "the workspace has changed since hum last looked"
85743
+ ] }),
85744
+ String(confirm.stat || "").split("\n").filter((l) => l.trim()).slice(0, 8).map((l, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { dimColor: true, children: [
85745
+ " ",
85746
+ l
85747
+ ] }, i)),
85748
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: "they are kept in this session's history and can be found again \xB7 enter goes back anyway \xB7 esc leaves it as it is" })
85749
+ ] }),
85750
+ picker && picker.kind === "rewind" && (() => {
85751
+ const it = picker.items[picker.index];
85752
+ if (picker.choice !== null) {
85753
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { flexDirection: "column", paddingX: 1, marginTop: 1, children: [
85754
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { color: ACCENT, bold: true, children: [
85755
+ "Rewind to ",
85756
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: "white", children: `\u201C${(it?.said || "").slice(0, width - 24)}\u201D` })
85757
+ ] }),
85758
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { children: " " }),
85759
+ REWIND_CHOICES.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { children: [
85760
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: ACCENT, children: i === picker.choice ? "\u276F " : " " }),
85761
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { bold: i === picker.choice, children: [
85762
+ i + 1,
85763
+ ". ",
85764
+ c.label.padEnd(26)
85765
+ ] }),
85766
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: c.desc })
85767
+ ] }, c.key)),
85768
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { children: " " }),
85769
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: "Enter to go back \xB7 Esc for the list again" })
85770
+ ] });
85771
+ }
85772
+ const top = Math.min(picker.top, Math.max(0, picker.items.length - REWIND_ROWS));
85773
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { flexDirection: "column", paddingX: 1, marginTop: 1, children: [
85774
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { color: ACCENT, bold: true, children: [
85775
+ "Rewind ",
85776
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: `(${picker.index + 1} of ${picker.items.length})` })
85777
+ ] }),
85778
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: "Every checkpoint is something you said. Nothing is deleted: what you go back past stays in the session." }),
85779
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { children: " " }),
85780
+ picker.items.slice(top, top + REWIND_ROWS).map((c, j) => {
85781
+ const i = top + j;
85782
+ const sel = i === picker.index;
85783
+ const meta = [`${c.steps} ${c.steps === 1 ? "step" : "steps"}`, c.files ? `${c.files} ${c.files === 1 ? "file" : "files"} changed since` : null].filter(Boolean).join(" \xB7 ");
85784
+ const said = (c.said || "(nothing said)").replace(/\s+/g, " ");
85785
+ const room = Math.max(16, width - 26);
85786
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { flexDirection: "column", children: [
85787
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { children: [
85788
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: ACCENT, children: sel ? "\u276F " : " " }),
85789
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { dimColor: true, children: [
85790
+ String(ago(c.at)).padStart(9),
85791
+ " "
85792
+ ] }),
85793
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { bold: sel, color: sel ? ACCENT : void 0, children: said.length > room ? said.slice(0, room - 1) + "\u2026" : said })
85794
+ ] }),
85795
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { dimColor: true, children: [
85796
+ " ",
85797
+ meta
85798
+ ] })
85799
+ ] }, c.node);
85800
+ }),
85801
+ top + REWIND_ROWS < picker.items.length ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: `\u2193 ${picker.items.length - top - REWIND_ROWS} more` }) : null,
85802
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { children: " " }),
85803
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: "Enter to choose what comes back \xB7 Esc to cancel" })
85804
+ ] });
85805
+ })(),
84912
85806
  picker && picker.kind === "session" && (() => {
84913
85807
  const { rows, scope } = sessionRows(picker, hello?.cwd);
84914
85808
  const top = Math.min(picker.top, Math.max(0, rows.length - PICKER_ROWS));
@@ -84970,7 +85864,7 @@ function App2({ engine: engine2, task, resume, images = [] }) {
84970
85864
  value,
84971
85865
  onChange: setValue,
84972
85866
  onSubmit,
84973
- focus: phase !== "dead" && !picker,
85867
+ focus: phase !== "dead" && !picker && !confirm,
84974
85868
  navActive: menu.length === 0,
84975
85869
  history: historyRef.current,
84976
85870
  mask: !!(step && step.secret),
@@ -84999,293 +85893,48 @@ function App2({ engine: engine2, task, resume, images = [] }) {
84999
85893
  ] });
85000
85894
  }
85001
85895
 
85002
- // src/engine.js
85003
- import fs4 from "node:fs";
85004
- import net from "node:net";
85005
- import os5 from "node:os";
85006
- import path3 from "node:path";
85007
- import crypto from "node:crypto";
85008
- import { spawn as spawn2, spawnSync as spawnSync2 } from "node:child_process";
85009
- var runDir = () => path3.join(process.env.HUM_HOME || path3.join(os5.homedir(), ".hum"), "run");
85010
- var readRun = (id) => {
85011
- try {
85012
- return JSON.parse(fs4.readFileSync(path3.join(runDir(), `${id}.json`), "utf8"));
85013
- } catch {
85014
- return null;
85015
- }
85016
- };
85017
- var EngineError = class extends Error {
85018
- };
85019
- var win2 = process.platform === "win32";
85020
- var exists = (p) => {
85021
- try {
85022
- fs4.accessSync(p);
85023
- return true;
85024
- } catch {
85025
- return false;
85026
- }
85027
- };
85028
- function uvToolDirs() {
85029
- const dirs = [];
85030
- if (process.env.UV_TOOL_DIR) dirs.push(process.env.UV_TOOL_DIR);
85031
- if (win2) {
85032
- for (const base of [process.env.APPDATA, process.env.LOCALAPPDATA]) if (base) dirs.push(path3.join(base, "uv", "tools"));
85033
- } else dirs.push(path3.join(process.env.XDG_DATA_HOME || path3.join(os5.homedir(), ".local", "share"), "uv", "tools"));
85034
- if (!dirs.some(exists)) {
85035
- for (const uv of ["uv", path3.join(os5.homedir(), ".local", "bin", win2 ? "uv.exe" : "uv")]) {
85036
- try {
85037
- const r = spawnSync2(uv, ["tool", "dir"], { encoding: "utf8", windowsHide: true });
85038
- if (r.status === 0 && r.stdout.trim()) {
85039
- dirs.push(r.stdout.trim());
85040
- break;
85041
- }
85042
- } catch {
85043
- }
85044
- }
85045
- }
85046
- return dirs;
85047
- }
85048
- function enginePython(dirs = uvToolDirs()) {
85049
- for (const dir of dirs) for (const name of ["hum-cli", "hum"]) {
85050
- const py = win2 ? path3.join(dir, name, "Scripts", "python.exe") : path3.join(dir, name, "bin", "python");
85051
- if (exists(py)) return py;
85052
- }
85053
- return null;
85054
- }
85055
- function siblingEngine(execPath = process.execPath) {
85056
- let dir;
85057
- try {
85058
- dir = path3.dirname(fs4.realpathSync(execPath));
85059
- } catch {
85060
- return null;
85061
- }
85062
- const p = path3.join(dir, "engine", win2 ? "hum-engine.exe" : "hum-engine");
85063
- return exists(p) ? p : null;
85064
- }
85065
- function homeEngine(env3 = process.env) {
85066
- const home = env3.HUM_HOME || path3.join(os5.homedir(), ".hum");
85067
- const py = win2 ? path3.join(home, "engine", "Scripts", "python.exe") : path3.join(home, "engine", "bin", "python");
85068
- return exists(py) ? py : null;
85069
- }
85070
- function engineCandidates(env3 = process.env) {
85071
- const out = [];
85072
- if (env3.HUM_ENGINE) {
85073
- const [bin, ...args2] = env3.HUM_ENGINE.split(" ");
85074
- out.push({ bin, args: args2, where: "HUM_ENGINE" });
85075
- }
85076
- const sib = siblingEngine();
85077
- if (sib) out.push({ bin: sib, args: ["engine"], where: "beside hum" });
85078
- const home = homeEngine(env3);
85079
- if (home) out.push({ bin: home, args: ["-m", "hum.cli", "engine"], where: "HUM_HOME/engine" });
85080
- const py = enginePython();
85081
- if (py) out.push({ bin: py, args: ["-m", "hum.cli", "engine"], where: "the engine's interpreter" });
85082
- out.push({ bin: "hum-engine", args: [], where: "PATH" });
85083
- out.push({ bin: path3.join(os5.homedir(), ".local", "bin", win2 ? "hum-engine.exe" : "hum-engine"), args: [], where: "uv's bin dir" });
85084
- return out;
85085
- }
85086
- function engineCommand(argv, candidates = engineCandidates()) {
85087
- for (const c of candidates) {
85088
- if (c.args[c.args.length - 1] !== "engine") continue;
85089
- return { bin: c.bin, args: [...c.args.slice(0, -1), ...argv], where: c.where };
85090
- }
85091
- return null;
85092
- }
85093
- function startFailure(failures) {
85094
- const refused = failures.find((f) => f.error && f.error.code !== "ENOENT");
85095
- if (!refused) {
85096
- return "Hum's engine is not installed. Run: uv tool install hum-cli (or set HUM_ENGINE to the command that starts it)";
85097
- }
85098
- const what = refused.error.code || refused.error.message;
85099
- const lines = [
85100
- `Hum's engine is installed (${refused.bin}) but this machine would not start it: ${what}.`
85101
- ];
85102
- if (win2) {
85103
- lines.push("On a managed Windows machine that is usually Device Guard / WDAC refusing an executable it does not know.");
85104
- lines.push(`To see the policy's own message, run: "${refused.bin}" --help`);
85105
- const dir = uvToolDirs()[0];
85106
- lines.push(`If uv's environment is elsewhere, point Hum at its interpreter: set HUM_ENGINE=${path3.join(dir || "<uv tool dir>", "hum-cli", "Scripts", "python.exe")} -m hum.cli engine`);
85107
- } else {
85108
- lines.push('Set HUM_ENGINE to a command that starts it, e.g. HUM_ENGINE="python -m hum.cli engine"');
85109
- }
85110
- return lines.join("\n");
85111
- }
85112
- function attempt({ bin, args: args2 }, cwd2, { task, images, resume }) {
85113
- return new Promise((resolve, reject) => {
85114
- const runId = crypto.randomBytes(6).toString("hex");
85115
- fs4.mkdirSync(runDir(), { recursive: true });
85116
- const logPath = path3.join(runDir(), `${runId}.log`);
85117
- const log = fs4.openSync(logPath, "a");
85118
- const argv = [...args2, "-C", cwd2, "--run-id", runId];
85119
- if (task) argv.push("--task", task);
85120
- for (const p of images) argv.push("--image", p);
85121
- if (resume) argv.push("--resume", resume);
85122
- let settled = false;
85123
- const settle = (fn) => {
85124
- if (!settled) {
85125
- settled = true;
85126
- fn();
85127
- }
85128
- };
85129
- let child;
85130
- try {
85131
- child = spawn2(bin, argv, { stdio: ["ignore", log, log], detached: true, windowsHide: true });
85132
- } catch (e) {
85133
- fs4.closeSync(log);
85134
- reject({ spawn: e });
85135
- return;
85136
- }
85137
- fs4.closeSync(log);
85138
- let died = false;
85139
- child.on("error", (e) => settle(() => reject({ spawn: e })));
85140
- child.on("exit", () => {
85141
- died = true;
85142
- });
85143
- const t0 = Date.now();
85144
- const poll = () => {
85145
- if (settled) return;
85146
- const rec = readRun(runId);
85147
- if (rec && rec.port) {
85148
- child.unref();
85149
- settle(() => resolve(rec));
85150
- return;
85151
- }
85152
- if (rec && rec.error) {
85153
- settle(() => reject({ failed: rec.error }));
85154
- return;
85155
- }
85156
- if (died && !rec) {
85157
- settle(() => reject({ died: logPath }));
85158
- return;
85159
- }
85160
- if (Date.now() - t0 > 9e4) {
85161
- settle(() => reject({ timeout: true }));
85162
- return;
85163
- }
85164
- setTimeout(poll, 50);
85165
- };
85166
- poll();
85167
- });
85168
- }
85169
- function failureMessage(error) {
85170
- return error.message + (error.hint ? `
85171
- ${error.hint}` : "");
85172
- }
85173
- function diedMessage(logPath, text = null) {
85174
- let tail2 = "";
85175
- try {
85176
- tail2 = (text ?? fs4.readFileSync(logPath, "utf8")).trim().split("\n").slice(-3).join("\n").trim();
85177
- } catch {
85178
- }
85179
- return `the engine did not start${tail2 ? `:
85180
- ${tail2}` : ""}
85181
- (its log: ${logPath})`;
85182
- }
85183
- async function spawnEngine(cwd2, { task = null, images = [], resume = null, candidates = engineCandidates() } = {}) {
85184
- const failures = [];
85185
- for (const cand of candidates) {
85186
- if (!cand.bin) continue;
85187
- try {
85188
- return await attempt(cand, cwd2, { task, images, resume });
85189
- } catch (f) {
85190
- if (f && f.spawn) {
85191
- failures.push({ ...cand, error: f.spawn });
85192
- continue;
85193
- }
85194
- if (f && f.failed) throw new EngineError(failureMessage(f.failed));
85195
- if (f && f.died) throw new EngineError(diedMessage(f.died));
85196
- if (f && f.timeout) throw new EngineError("the engine did not start in time");
85197
- throw f;
85198
- }
85199
- }
85200
- throw new EngineError(startFailure(failures));
85201
- }
85202
- var Engine = class {
85203
- constructor(port2) {
85204
- this.port = port2;
85205
- this.handlers = [];
85206
- this.closed = false;
85207
- }
85208
- connect() {
85209
- return new Promise((resolve, reject) => {
85210
- const sock = net.createConnection({ host: "127.0.0.1", port: this.port }, () => resolve());
85211
- this.sock = sock;
85212
- sock.on("error", (e) => {
85213
- if (!this.closed && this.sock === sock) reject(new EngineError(`engine: ${e.message}`));
85214
- });
85215
- let buf = "";
85216
- sock.on("data", (d) => {
85217
- if (this.sock !== sock) return;
85218
- buf += d.toString();
85219
- const lines = buf.split("\n");
85220
- buf = lines.pop();
85221
- for (const line of lines) {
85222
- if (!line.trim()) continue;
85223
- let ev;
85224
- try {
85225
- ev = JSON.parse(line);
85226
- } catch {
85227
- continue;
85228
- }
85229
- for (const h of this.handlers) h(ev);
85230
- }
85231
- });
85232
- sock.on("close", () => {
85233
- if (this.sock !== sock) return;
85234
- this.closed = true;
85235
- for (const h of this.handlers) h({ type: "bye", gone: true });
85236
- });
85237
- });
85238
- }
85239
- // Attach to another engine (a session running elsewhere on this machine): the old
85240
- // socket is dropped quietly, the new one greets us with hello and a replay.
85241
- async reconnect(port2) {
85242
- const old = this.sock;
85243
- this.sock = null;
85244
- this.port = port2;
85245
- this.closed = false;
85246
- try {
85247
- old.destroy();
85248
- } catch {
85249
- }
85250
- await this.connect();
85251
- }
85252
- on(handler) {
85253
- this.handlers.push(handler);
85254
- }
85255
- send(cmd) {
85256
- if (this.closed) return;
85257
- try {
85258
- this.sock.write(JSON.stringify(cmd) + "\n");
85259
- } catch {
85260
- }
85261
- }
85262
- close() {
85263
- this.closed = true;
85264
- try {
85265
- this.sock.end();
85266
- } catch {
85267
- }
85268
- }
85269
- };
85270
-
85271
85896
  // src/cli.jsx
85897
+ init_engine();
85898
+ init_update();
85899
+ init_install();
85272
85900
  var import_jsx_runtime3 = __toESM(require_jsx_runtime(), 1);
85273
- import { spawnSync as spawnSync3 } from "node:child_process";
85901
+ import { spawnSync as spawnSync5 } from "node:child_process";
85902
+ var MINE2 = true ? "0.1.30" : "0.0.0";
85903
+ var layout = installLayout();
85904
+ function completeInstall() {
85905
+ if (layout.kind !== "npm" || !needsInstall(MINE2)) return;
85906
+ const say = (m) => process.stderr.write(`hum: ${m}
85907
+ `);
85908
+ say(`updating to ${MINE2} \u2026`);
85909
+ const r = installEngine(MINE2, { say });
85910
+ if (!r.ok) say(`the update did not finish: ${r.error} \xB7 ${npmFix(MINE2)}`);
85911
+ }
85274
85912
  var ENGINE_COMMANDS = /* @__PURE__ */ new Set(["run", "login", "logout", "whoami", "model", "key", "sessions", "show", "sync", "skill", "ps", "stop", "hooks", "engine"]);
85275
85913
  var argv0 = process.argv.slice(2);
85276
85914
  if (argv0[0] === "--version" || argv0[0] === "-V") {
85277
- process.stdout.write(`hum ${true ? "0.1.26" : "0.0.0"}
85915
+ process.stdout.write(`hum ${MINE2}
85916
+ `);
85917
+ if (layout.kind === "npm") {
85918
+ const r = runningVersion();
85919
+ const drift = mismatchLine(MINE2, r ? r.version : "", { layout });
85920
+ if (drift) process.stdout.write(`${drift}
85278
85921
  `);
85922
+ }
85279
85923
  process.exit(0);
85280
85924
  }
85281
85925
  if (argv0[0] === "update") process.exit(updateNow());
85926
+ if (argv0[0] === "doctor") {
85927
+ const { doctor: doctor2 } = await Promise.resolve().then(() => (init_doctor(), doctor_exports));
85928
+ process.exit(await doctor2({ json: argv0.includes("--json"), mine: MINE2, layout }));
85929
+ }
85282
85930
  if (ENGINE_COMMANDS.has(argv0[0])) {
85931
+ completeInstall();
85283
85932
  const cmd = engineCommand(argv0);
85284
85933
  if (!cmd) {
85285
85934
  process.stderr.write(startFailure([]) + "\n");
85286
85935
  process.exit(1);
85287
85936
  }
85288
- const r = spawnSync3(cmd.bin, cmd.args, { stdio: "inherit", windowsHide: true });
85937
+ const r = spawnSync5(cmd.bin, cmd.args, { stdio: "inherit", windowsHide: true });
85289
85938
  if (r.error) {
85290
85939
  process.stderr.write(startFailure([{ bin: cmd.bin, error: r.error }]) + "\n");
85291
85940
  process.exit(1);
@@ -85303,7 +85952,7 @@ function parseArgs(argv) {
85303
85952
  } else if (x === "--image" && argv[i + 1]) {
85304
85953
  a.images.push(argv[++i]);
85305
85954
  } else if (x === "-h" || x === "--help") {
85306
- process.stdout.write("usage: hum [task] [--image path] | hum resume [name]\nIn a session: type to talk, !cmd runs a command, esc stops the model, ctrl+v pastes a screenshot, / for commands.\n");
85955
+ process.stdout.write("usage: hum [task] [--image path] | hum resume [name]\nIn a session: type to talk, !cmd runs a command, esc stops the model (twice, while it waits: go back), ctrl+v pastes a screenshot, / for commands.\n");
85307
85956
  process.exit(0);
85308
85957
  } else if (!x.startsWith("-")) {
85309
85958
  a.task = a.task ? `${a.task} ${x}` : x;
@@ -85320,6 +85969,7 @@ var port = Number(process.env.HUM_ENGINE_PORT || 0);
85320
85969
  var startedHere = false;
85321
85970
  try {
85322
85971
  if (!port) {
85972
+ completeInstall();
85323
85973
  const rec = await spawnEngine(args.cwd, { task: args.task, images: args.images, resume: args.resume && args.resume !== "pick" ? args.resume : null });
85324
85974
  startedHere = true;
85325
85975
  port = rec.port;