@metaphi-ai/hum 0.1.19 → 0.1.21
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 +194 -102
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -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,
|
|
22748
|
-
var key =
|
|
22747
|
+
var copyWithDeleteImpl = function(obj, path4, index2) {
|
|
22748
|
+
var key = path4[index2];
|
|
22749
22749
|
var updated = isArray(obj) ? obj.slice() : assign({}, obj);
|
|
22750
|
-
if (index2 + 1 ===
|
|
22750
|
+
if (index2 + 1 === path4.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],
|
|
22758
|
+
updated[key] = copyWithDeleteImpl(obj[key], path4, index2 + 1);
|
|
22759
22759
|
return updated;
|
|
22760
22760
|
};
|
|
22761
|
-
var copyWithDelete = function(obj,
|
|
22762
|
-
return copyWithDeleteImpl(obj,
|
|
22761
|
+
var copyWithDelete = function(obj, path4) {
|
|
22762
|
+
return copyWithDeleteImpl(obj, path4, 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,
|
|
22801
|
-
if (index2 >=
|
|
22800
|
+
var copyWithSetImpl = function(obj, path4, index2, value) {
|
|
22801
|
+
if (index2 >= path4.length) {
|
|
22802
22802
|
return value;
|
|
22803
22803
|
}
|
|
22804
|
-
var key =
|
|
22804
|
+
var key = path4[index2];
|
|
22805
22805
|
var updated = isArray(obj) ? obj.slice() : assign({}, obj);
|
|
22806
|
-
updated[key] = copyWithSetImpl(obj[key],
|
|
22806
|
+
updated[key] = copyWithSetImpl(obj[key], path4, index2 + 1, value);
|
|
22807
22807
|
return updated;
|
|
22808
22808
|
};
|
|
22809
|
-
var copyWithSet = function(obj,
|
|
22810
|
-
return copyWithSetImpl(obj,
|
|
22809
|
+
var copyWithSet = function(obj, path4, value) {
|
|
22810
|
+
return copyWithSetImpl(obj, path4, 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,
|
|
22820
|
+
overrideHookState = function(fiber, id, path4, value) {
|
|
22821
22821
|
var hook = findHook(fiber, id);
|
|
22822
22822
|
if (hook !== null) {
|
|
22823
|
-
var newState = copyWithSet(hook.memoizedState,
|
|
22823
|
+
var newState = copyWithSet(hook.memoizedState, path4, 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,
|
|
22833
|
+
overrideHookStateDeletePath = function(fiber, id, path4) {
|
|
22834
22834
|
var hook = findHook(fiber, id);
|
|
22835
22835
|
if (hook !== null) {
|
|
22836
|
-
var newState = copyWithDelete(hook.memoizedState,
|
|
22836
|
+
var newState = copyWithDelete(hook.memoizedState, path4);
|
|
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,
|
|
22860
|
-
fiber.pendingProps = copyWithSet(fiber.memoizedProps,
|
|
22859
|
+
overrideProps = function(fiber, path4, value) {
|
|
22860
|
+
fiber.pendingProps = copyWithSet(fiber.memoizedProps, path4, 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,
|
|
22870
|
-
fiber.pendingProps = copyWithDelete(fiber.memoizedProps,
|
|
22869
|
+
overridePropsDeletePath = function(fiber, path4) {
|
|
22870
|
+
fiber.pendingProps = copyWithDelete(fiber.memoizedProps, path4);
|
|
22871
22871
|
if (fiber.alternate) {
|
|
22872
22872
|
fiber.alternate.pendingProps = fiber.pendingProps;
|
|
22873
22873
|
}
|
|
@@ -73569,15 +73569,15 @@ var require_route = __commonJS({
|
|
|
73569
73569
|
};
|
|
73570
73570
|
}
|
|
73571
73571
|
function wrapConversion(toModel, graph) {
|
|
73572
|
-
const
|
|
73572
|
+
const path4 = [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
|
-
|
|
73576
|
+
path4.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 =
|
|
73580
|
+
fn.conversion = path4;
|
|
73581
73581
|
return fn;
|
|
73582
73582
|
}
|
|
73583
73583
|
module.exports = function(fromModel) {
|
|
@@ -80406,8 +80406,8 @@ function Text({ color, backgroundColor, dimColor = false, bold = false, italic =
|
|
|
80406
80406
|
}
|
|
80407
80407
|
|
|
80408
80408
|
// node_modules/ink/build/components/ErrorOverview.js
|
|
80409
|
-
var cleanupPath = (
|
|
80410
|
-
return
|
|
80409
|
+
var cleanupPath = (path4) => {
|
|
80410
|
+
return path4?.replace(`file://${cwd()}/`, "");
|
|
80411
80411
|
};
|
|
80412
80412
|
var stackUtils = new import_stack_utils.default({
|
|
80413
80413
|
cwd: cwd(),
|
|
@@ -83844,6 +83844,23 @@ var fmtDur = (s) => s < 60 ? `${Math.max(1, Math.round(s))}s` : `${Math.floor(s
|
|
|
83844
83844
|
var plural = (n, w) => `${n} ${w}${n === 1 ? "" : "s"}`;
|
|
83845
83845
|
var firstResp = (e) => e.first_response_s ? ` \xB7 first response ${e.first_response_s.toFixed(1)}s` : "";
|
|
83846
83846
|
var shortSession = (name) => (name || "").replace(/\.jsonl$/, "");
|
|
83847
|
+
var PICKER_ROWS = 8;
|
|
83848
|
+
var sessionRows = (p, here) => {
|
|
83849
|
+
const q = p.query.trim().toLowerCase();
|
|
83850
|
+
const all = p.all.map((it) => ({ ...it, dir: it.cwd ? path2.basename(it.cwd) : "" }));
|
|
83851
|
+
const inHere = all.filter((it) => it.cwd && here && it.cwd === here);
|
|
83852
|
+
const scope = p.scope === "here" && inHere.length ? "here" : "all";
|
|
83853
|
+
let rows = all;
|
|
83854
|
+
if (scope === "here") rows = inHere;
|
|
83855
|
+
else {
|
|
83856
|
+
const order = [];
|
|
83857
|
+
for (const it of all) if (!order.includes(it.cwd || "")) order.push(it.cwd || "");
|
|
83858
|
+
if (here && order.includes(here)) order.splice(0, 0, ...order.splice(order.indexOf(here), 1));
|
|
83859
|
+
rows = [...all].sort((a, b) => order.indexOf(a.cwd || "") - order.indexOf(b.cwd || ""));
|
|
83860
|
+
}
|
|
83861
|
+
if (q) rows = rows.filter((it) => [it.instruction, it.dir, it.name, it.model].some((v) => (v || "").toLowerCase().includes(q)));
|
|
83862
|
+
return { rows, scope };
|
|
83863
|
+
};
|
|
83847
83864
|
var homeRel = (p) => {
|
|
83848
83865
|
const h = os4.homedir();
|
|
83849
83866
|
return p && h && p.startsWith(h) ? "~" + p.slice(h.length) : p;
|
|
@@ -83881,7 +83898,7 @@ var tail = (s, n) => {
|
|
|
83881
83898
|
var COMMANDS = [
|
|
83882
83899
|
{ name: "/resume", desc: "pick a past session to continue (this machine or any other)" },
|
|
83883
83900
|
{ name: "/compact", desc: "summarise and restart the context now" },
|
|
83884
|
-
{ name: "/model", desc: "the
|
|
83901
|
+
{ name: "/model", desc: "pick the model \u2014 enter makes it the default, s for this session only; /model <name> switches here" },
|
|
83885
83902
|
{ name: "/cost", desc: "tokens and cost so far" },
|
|
83886
83903
|
{ name: "/approve", desc: "approvals on|off \u2014 whether every change and command waits for you first (leaving the sandbox always asks)" },
|
|
83887
83904
|
{ name: "/continue", desc: "after a pause: let the agent carry on" },
|
|
@@ -83891,10 +83908,10 @@ var COMMANDS = [
|
|
|
83891
83908
|
{ name: "/tools", desc: "the tools the model has, and the sandbox they run in" },
|
|
83892
83909
|
{ name: "/hooks", desc: "the lifecycle hooks in scope (~/.hum/hooks.json, <repo>/.hum/hooks.json; Claude Code and Codex hook files too)" },
|
|
83893
83910
|
{ name: "/help", desc: "keys and commands" },
|
|
83894
|
-
{ name: "/quit", desc: "leave; the session keeps running (hum brings you back)" },
|
|
83911
|
+
{ name: "/quit", desc: "leave; the session keeps running (hum resume brings you back)" },
|
|
83895
83912
|
{ name: "/stop", desc: "end this session's engine (the record is saved)" }
|
|
83896
83913
|
];
|
|
83897
|
-
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 \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` brings you back) \xB7 /stop ends it";
|
|
83914
|
+
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 \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";
|
|
83898
83915
|
var DIFF_TAIL_LINES = 20;
|
|
83899
83916
|
var OUTPUT_MAX_LINES = 200;
|
|
83900
83917
|
var ERR_TAIL_LINES = 5;
|
|
@@ -83927,6 +83944,8 @@ function App2({ engine: engine2, task, resume, images = [] }) {
|
|
|
83927
83944
|
const turnT0 = (0, import_react24.useRef)(null);
|
|
83928
83945
|
const thinkT0 = (0, import_react24.useRef)(null);
|
|
83929
83946
|
const thinkChars = (0, import_react24.useRef)(0);
|
|
83947
|
+
const draftRef = (0, import_react24.useRef)("");
|
|
83948
|
+
const thoughtRef = (0, import_react24.useRef)(null);
|
|
83930
83949
|
const toolsRef = (0, import_react24.useRef)({});
|
|
83931
83950
|
const historyRef = (0, import_react24.useRef)(loadHistory());
|
|
83932
83951
|
const modelRef = (0, import_react24.useRef)("");
|
|
@@ -83951,17 +83970,21 @@ function App2({ engine: engine2, task, resume, images = [] }) {
|
|
|
83951
83970
|
const foldThinking = () => {
|
|
83952
83971
|
if (thinkChars.current > 0) {
|
|
83953
83972
|
const secs = thinkT0.current ? (Date.now() - thinkT0.current) / 1e3 : 0;
|
|
83954
|
-
|
|
83973
|
+
thoughtRef.current = { kind: "thought", text: `thought for ${fmtDur(secs)}` };
|
|
83955
83974
|
}
|
|
83956
83975
|
setThinking("");
|
|
83957
83976
|
thinkChars.current = 0;
|
|
83958
83977
|
thinkT0.current = null;
|
|
83959
83978
|
};
|
|
83960
83979
|
const flushDraft = () => {
|
|
83961
|
-
|
|
83962
|
-
|
|
83963
|
-
|
|
83964
|
-
|
|
83980
|
+
const d = draftRef.current.trim();
|
|
83981
|
+
draftRef.current = "";
|
|
83982
|
+
if (d) append({ kind: "hum", text: d });
|
|
83983
|
+
if (thoughtRef.current) {
|
|
83984
|
+
append(thoughtRef.current);
|
|
83985
|
+
thoughtRef.current = null;
|
|
83986
|
+
}
|
|
83987
|
+
setDraft("");
|
|
83965
83988
|
};
|
|
83966
83989
|
const handle = (ev) => {
|
|
83967
83990
|
if (ev.agent) {
|
|
@@ -84021,7 +84044,7 @@ function App2({ engine: engine2, task, resume, images = [] }) {
|
|
|
84021
84044
|
} else setPhaseBoth("idle");
|
|
84022
84045
|
if (resume === "pick") engine2.send({ cmd: "sessions" });
|
|
84023
84046
|
} else if (task) {
|
|
84024
|
-
if (images.length && !ev.images) append({ kind: "warn", text: "this
|
|
84047
|
+
if (images.length && !ev.images) append({ kind: "warn", text: "this version of hum does not take images; update hum" });
|
|
84025
84048
|
engine2.send({ cmd: "start", task, images: ev.images ? images : [] });
|
|
84026
84049
|
} else if (resume === "pick") {
|
|
84027
84050
|
setPhaseBoth("idle");
|
|
@@ -84030,12 +84053,18 @@ function App2({ engine: engine2, task, resume, images = [] }) {
|
|
|
84030
84053
|
else {
|
|
84031
84054
|
setPhaseBoth("idle");
|
|
84032
84055
|
if (ev.images) images.forEach((p) => engine2.send({ cmd: "attach", path: p }));
|
|
84033
|
-
else if (images.length) append({ kind: "warn", text: "this
|
|
84056
|
+
else if (images.length) append({ kind: "warn", text: "this version of hum does not take images; update hum" });
|
|
84034
84057
|
}
|
|
84035
84058
|
break;
|
|
84036
84059
|
}
|
|
84037
84060
|
case "replay":
|
|
84061
|
+
const ordered = [];
|
|
84038
84062
|
for (const it of ev.items || []) {
|
|
84063
|
+
const prev = ordered[ordered.length - 1];
|
|
84064
|
+
if (it.type === "text" && prev && prev.type === "thought") ordered.splice(ordered.length - 1, 0, it);
|
|
84065
|
+
else ordered.push(it);
|
|
84066
|
+
}
|
|
84067
|
+
for (const it of ordered) {
|
|
84039
84068
|
switch (it.type) {
|
|
84040
84069
|
case "you":
|
|
84041
84070
|
append({ kind: "you", text: it.text, images: it.images || [] });
|
|
@@ -84044,7 +84073,7 @@ function App2({ engine: engine2, task, resume, images = [] }) {
|
|
|
84044
84073
|
append({ kind: "hum", text: it.text });
|
|
84045
84074
|
break;
|
|
84046
84075
|
case "thought":
|
|
84047
|
-
append({ kind: "thought", text: `thought for ${fmtDur(it.secs || 0)}
|
|
84076
|
+
append({ kind: "thought", text: `thought for ${fmtDur(it.secs || 0)}` });
|
|
84048
84077
|
break;
|
|
84049
84078
|
case "tool_call": {
|
|
84050
84079
|
toolsRef.current[it.id] = it;
|
|
@@ -84110,8 +84139,17 @@ function App2({ engine: engine2, task, resume, images = [] }) {
|
|
|
84110
84139
|
append({ kind: "info", text: "no sessions yet" });
|
|
84111
84140
|
break;
|
|
84112
84141
|
}
|
|
84113
|
-
setPicker({
|
|
84142
|
+
setPicker({ kind: "session", all: ev.items, index: 0, top: 0, query: "", scope: "here" });
|
|
84114
84143
|
break;
|
|
84144
|
+
case "models": {
|
|
84145
|
+
if (!ev.items || ev.items.length === 0) {
|
|
84146
|
+
append({ kind: "info", text: "no models to pick from \u2014 sign in (hum login) or bring a key (hum key <provider> <key>)" });
|
|
84147
|
+
break;
|
|
84148
|
+
}
|
|
84149
|
+
const cur = Math.max(0, ev.items.findIndex((m) => m.current));
|
|
84150
|
+
setPicker({ kind: "model", items: ev.items, index: cur, via: ev.via, byo: ev.byo || [] });
|
|
84151
|
+
break;
|
|
84152
|
+
}
|
|
84115
84153
|
case "session":
|
|
84116
84154
|
setSession(ev.name);
|
|
84117
84155
|
setSpend(0);
|
|
@@ -84136,7 +84174,8 @@ function App2({ engine: engine2, task, resume, images = [] }) {
|
|
|
84136
84174
|
setThinking((t) => t + ev.text);
|
|
84137
84175
|
break;
|
|
84138
84176
|
case "text_delta":
|
|
84139
|
-
if (thinkChars.current > 0
|
|
84177
|
+
if (thinkChars.current > 0) foldThinking();
|
|
84178
|
+
draftRef.current += ev.text;
|
|
84140
84179
|
setDraft((d) => d + ev.text);
|
|
84141
84180
|
break;
|
|
84142
84181
|
case "tool_pending":
|
|
@@ -84263,7 +84302,7 @@ function App2({ engine: engine2, task, resume, images = [] }) {
|
|
|
84263
84302
|
setStatus("");
|
|
84264
84303
|
break;
|
|
84265
84304
|
case "bye":
|
|
84266
|
-
if (ev.gone && phaseRef.current !== "dead") append({ kind: "error", text: "
|
|
84305
|
+
if (ev.gone && phaseRef.current !== "dead") append({ kind: "error", text: "the session's process went away \xB7 `hum resume` brings it back" });
|
|
84267
84306
|
setPhaseBoth("dead");
|
|
84268
84307
|
exit();
|
|
84269
84308
|
break;
|
|
@@ -84277,7 +84316,7 @@ function App2({ engine: engine2, task, resume, images = [] }) {
|
|
|
84277
84316
|
(0, import_react24.useEffect)(() => {
|
|
84278
84317
|
if (!hello) return void 0;
|
|
84279
84318
|
let live = true;
|
|
84280
|
-
updateNotice(true ? "0.1.
|
|
84319
|
+
updateNotice(true ? "0.1.21" : hello.version || "0.0.0").then((line) => {
|
|
84281
84320
|
if (live && line) append({ kind: "info", text: line });
|
|
84282
84321
|
}).catch(() => {
|
|
84283
84322
|
});
|
|
@@ -84288,12 +84327,10 @@ function App2({ engine: engine2, task, resume, images = [] }) {
|
|
|
84288
84327
|
const quit = () => {
|
|
84289
84328
|
if (phaseRef.current === "dead") return;
|
|
84290
84329
|
const busy = phaseRef.current === "busy";
|
|
84291
|
-
append({ kind: "info", text: !session ? "bye" : busy ? "still working \xB7 `hum` brings you back" : `saved \xB7 \`hum\` brings you back` });
|
|
84330
|
+
append({ kind: "info", text: !session ? "bye" : busy ? "still working \xB7 `hum resume` brings you back" : `saved \xB7 \`hum resume\` brings you back` });
|
|
84292
84331
|
engine2.send({ cmd: "quit" });
|
|
84293
|
-
|
|
84294
|
-
|
|
84295
|
-
exit();
|
|
84296
|
-
}, 400);
|
|
84332
|
+
setPhaseBoth("dead");
|
|
84333
|
+
setTimeout(() => exit(), 400);
|
|
84297
84334
|
};
|
|
84298
84335
|
const stop = () => {
|
|
84299
84336
|
if (phaseRef.current === "dead") return;
|
|
@@ -84344,16 +84381,44 @@ function App2({ engine: engine2, task, resume, images = [] }) {
|
|
|
84344
84381
|
return;
|
|
84345
84382
|
}
|
|
84346
84383
|
}
|
|
84347
|
-
if (picker) {
|
|
84384
|
+
if (picker && picker.kind === "model") {
|
|
84385
|
+
const it = picker.items[picker.index];
|
|
84386
|
+
const pick = (isDefault) => {
|
|
84387
|
+
setPicker(null);
|
|
84388
|
+
if (it.current && !isDefault) return;
|
|
84389
|
+
modelRef.current = it.name;
|
|
84390
|
+
engine2.send({ cmd: "model", name: it.name, default: isDefault });
|
|
84391
|
+
};
|
|
84348
84392
|
if (key.upArrow) setPicker((p) => ({ ...p, index: (p.index + p.items.length - 1) % p.items.length }));
|
|
84349
84393
|
else if (key.downArrow || key.tab) setPicker((p) => ({ ...p, index: (p.index + 1) % p.items.length }));
|
|
84394
|
+
else if (key.escape) setPicker(null);
|
|
84395
|
+
else if (key.return) pick(true);
|
|
84396
|
+
else if (input === "s") pick(false);
|
|
84397
|
+
else if (/^[1-9]$/.test(input) && Number(input) <= picker.items.length) setPicker((p) => ({ ...p, index: Number(input) - 1 }));
|
|
84398
|
+
return;
|
|
84399
|
+
}
|
|
84400
|
+
if (picker && picker.kind === "session") {
|
|
84401
|
+
const { rows } = sessionRows(picker, hello?.cwd);
|
|
84402
|
+
const move = (d) => setPicker((p) => {
|
|
84403
|
+
const n = rows.length;
|
|
84404
|
+
if (!n) return p;
|
|
84405
|
+
const index = (p.index + d + n) % n;
|
|
84406
|
+
const top = index < p.top ? index : index >= p.top + PICKER_ROWS ? index - PICKER_ROWS + 1 : p.top;
|
|
84407
|
+
return { ...p, index, top };
|
|
84408
|
+
});
|
|
84409
|
+
if (key.upArrow) move(-1);
|
|
84410
|
+
else if (key.downArrow || key.tab) move(1);
|
|
84411
|
+
else if (key.escape) setPicker(null);
|
|
84350
84412
|
else if (key.return) {
|
|
84351
|
-
const it =
|
|
84413
|
+
const it = rows[picker.index];
|
|
84414
|
+
if (!it) return;
|
|
84352
84415
|
setPicker(null);
|
|
84353
84416
|
if (it.live && it.live.here) {
|
|
84354
84417
|
} else if (it.live && it.live.port) attachTo(it.live.port);
|
|
84355
84418
|
else engine2.send({ cmd: "resume", name: it.name });
|
|
84356
|
-
} else if (key.
|
|
84419
|
+
} else if (key.ctrl && input === "a") setPicker((p) => ({ ...p, scope: p.scope === "here" ? "all" : "here", index: 0, top: 0 }));
|
|
84420
|
+
else if (key.backspace || key.delete) setPicker((p) => ({ ...p, query: p.query.slice(0, -1), index: 0, top: 0 }));
|
|
84421
|
+
else if (input && !key.ctrl && !key.meta && input >= " ") setPicker((p) => ({ ...p, query: p.query + input, index: 0, top: 0 }));
|
|
84357
84422
|
return;
|
|
84358
84423
|
}
|
|
84359
84424
|
if (menu.length > 0) {
|
|
@@ -84370,6 +84435,8 @@ function App2({ engine: engine2, task, resume, images = [] }) {
|
|
|
84370
84435
|
const attachTo = (port2) => {
|
|
84371
84436
|
setItems([]);
|
|
84372
84437
|
setDraft("");
|
|
84438
|
+
draftRef.current = "";
|
|
84439
|
+
thoughtRef.current = null;
|
|
84373
84440
|
setThinking("");
|
|
84374
84441
|
thinkChars.current = 0;
|
|
84375
84442
|
setProposal(null);
|
|
@@ -84426,7 +84493,7 @@ function App2({ engine: engine2, task, resume, images = [] }) {
|
|
|
84426
84493
|
break;
|
|
84427
84494
|
}
|
|
84428
84495
|
case "/image":
|
|
84429
|
-
if (!hello?.images) append({ kind: "warn", text: "this
|
|
84496
|
+
if (!hello?.images) append({ kind: "warn", text: "this version of hum does not take images; update hum" });
|
|
84430
84497
|
else if (!arg) append({ kind: "info", text: "/image <path> attaches the file to your next message \xB7 ctrl+v pastes a screenshot \xB7 @path.png in a message works too" });
|
|
84431
84498
|
else engine2.send({ cmd: "attach", path: arg });
|
|
84432
84499
|
break;
|
|
@@ -84502,7 +84569,7 @@ function App2({ engine: engine2, task, resume, images = [] }) {
|
|
|
84502
84569
|
setPhaseBoth("busy");
|
|
84503
84570
|
}
|
|
84504
84571
|
};
|
|
84505
|
-
const statusLine = phase === "connecting" ? "starting
|
|
84572
|
+
const statusLine = phase === "connecting" ? "starting \u2026" : `${modelRef.current || ""} \xB7 ${fmtCost(spend)}` + (ctxPct >= 10 ? ` \xB7 ctx ${ctxPct}%` : "") + (gate === "approve" ? " \xB7 approvals on" : "") + (ctrlc ? " \xB7 ctrl+c again to quit" : " \xB7 / for commands");
|
|
84506
84573
|
const spinnerLabel = phase === "connecting" ? " starting \u2026" : ` ${status || "working"}${elapsed >= 2 ? ` \xB7 ${fmtDur(elapsed)}` : ""}` + (thinkChars.current > 4e3 ? ` \xB7 ${(thinkChars.current / 1e3).toFixed(0)}k thinking` : "");
|
|
84507
84574
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { flexDirection: "column", children: [
|
|
84508
84575
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Static, { items, children: (item) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { flexDirection: "column", marginBottom: ["hum", "you", "banner", "turn"].includes(item.kind) ? 1 : 0, children: [
|
|
@@ -84689,33 +84756,87 @@ function App2({ engine: engine2, task, resume, images = [] }) {
|
|
|
84689
84756
|
c.diff && c.diff.split("\n").length > DIFF_TAIL_LINES ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: ` \u2026 +${c.diff.split("\n").length - DIFF_TAIL_LINES} more diff lines` }) : null
|
|
84690
84757
|
] }, c.id))
|
|
84691
84758
|
] }),
|
|
84692
|
-
picker && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { flexDirection: "column", paddingX: 1, marginTop: 1, children: [
|
|
84693
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.
|
|
84694
|
-
|
|
84695
|
-
|
|
84696
|
-
|
|
84697
|
-
|
|
84698
|
-
|
|
84699
|
-
|
|
84700
|
-
|
|
84701
|
-
|
|
84702
|
-
|
|
84703
|
-
|
|
84704
|
-
|
|
84705
|
-
|
|
84706
|
-
|
|
84707
|
-
|
|
84708
|
-
|
|
84709
|
-
|
|
84710
|
-
|
|
84759
|
+
picker && picker.kind === "model" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { flexDirection: "column", paddingX: 1, marginTop: 1, children: [
|
|
84760
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: ACCENT, bold: true, children: "Select model" }),
|
|
84761
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: `Your pick becomes the default for new sessions.${picker.via ? ` Served via ${picker.via}.` : ""}${picker.byo.length ? ` Your own keys: ${picker.byo.join(", ")} \u2014 /model <provider>/<model> uses one.` : ""}` }),
|
|
84762
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { children: " " }),
|
|
84763
|
+
(() => {
|
|
84764
|
+
const nameW = Math.max(...picker.items.map((m) => m.name.length + (m.current ? 2 : 0)));
|
|
84765
|
+
return picker.items.map((m, i) => {
|
|
84766
|
+
const price = m.price_per_m && m.price_per_m.length === 2 && (m.price_per_m[0] || m.price_per_m[1]) ? `$${m.price_per_m[0]}/$${m.price_per_m[1]} per M` : "";
|
|
84767
|
+
const about = [m.note, price].filter(Boolean).join(" \xB7 ") + (m.default ? (m.note || price ? " \xB7 " : "") + "default" : "");
|
|
84768
|
+
const label = `${i + 1}. ${m.name}${m.current ? " \u2713" : ""}`.padEnd(nameW + 4);
|
|
84769
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { children: [
|
|
84770
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: ACCENT, children: i === picker.index ? "\u276F " : " " }),
|
|
84771
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: m.current ? "green" : void 0, bold: i === picker.index, children: label }),
|
|
84772
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { dimColor: i !== picker.index, children: [
|
|
84773
|
+
" ",
|
|
84774
|
+
about
|
|
84775
|
+
] })
|
|
84776
|
+
] }, m.name);
|
|
84777
|
+
});
|
|
84778
|
+
})(),
|
|
84779
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { children: " " }),
|
|
84780
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: "Enter to set as default \xB7 s to use this session only \xB7 Esc to cancel" })
|
|
84711
84781
|
] }),
|
|
84782
|
+
picker && picker.kind === "session" && (() => {
|
|
84783
|
+
const { rows, scope } = sessionRows(picker, hello?.cwd);
|
|
84784
|
+
const top = Math.min(picker.top, Math.max(0, rows.length - PICKER_ROWS));
|
|
84785
|
+
const shown = rows.slice(top, top + PICKER_ROWS);
|
|
84786
|
+
const out = [];
|
|
84787
|
+
let lastDir = null;
|
|
84788
|
+
shown.forEach((it, j) => {
|
|
84789
|
+
const i = top + j;
|
|
84790
|
+
if (it.dir !== lastDir) {
|
|
84791
|
+
out.push(/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { dimColor: true, children: [
|
|
84792
|
+
" ",
|
|
84793
|
+
it.dir || "(no directory)"
|
|
84794
|
+
] }, `dir${i}`));
|
|
84795
|
+
lastDir = it.dir;
|
|
84796
|
+
}
|
|
84797
|
+
const sel = i === picker.index;
|
|
84798
|
+
const state = it.live ? it.live.here ? "this window" : it.live.state || "running" : null;
|
|
84799
|
+
const what = (it.instruction || "(untitled)").replace(/\s+/g, " ");
|
|
84800
|
+
const room = Math.max(16, width - 6 - (state ? state.length + 4 : 0));
|
|
84801
|
+
const meta = [it.when, it.steps != null ? plural(it.steps, "step") : "on the server", it.cost_usd ? fmtCost(it.cost_usd) : null, it.model].filter(Boolean).join(" \xB7 ");
|
|
84802
|
+
out.push(
|
|
84803
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { flexDirection: "column", marginBottom: 1, children: [
|
|
84804
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { children: [
|
|
84805
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: ACCENT, children: sel ? "\u276F " : " " }),
|
|
84806
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { bold: sel, color: sel ? ACCENT : void 0, children: what.length > room ? what.slice(0, room - 1) + "\u2026" : what }),
|
|
84807
|
+
state ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { color: "magenta", children: [
|
|
84808
|
+
" \xB7 ",
|
|
84809
|
+
state
|
|
84810
|
+
] }) : null
|
|
84811
|
+
] }),
|
|
84812
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { dimColor: true, children: [
|
|
84813
|
+
" ",
|
|
84814
|
+
meta
|
|
84815
|
+
] })
|
|
84816
|
+
] }, it.name)
|
|
84817
|
+
);
|
|
84818
|
+
});
|
|
84819
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { flexDirection: "column", paddingX: 1, marginTop: 1, children: [
|
|
84820
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { color: ACCENT, bold: true, children: [
|
|
84821
|
+
"Resume session ",
|
|
84822
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: `(${rows.length ? picker.index + 1 : 0} of ${rows.length})` })
|
|
84823
|
+
] }),
|
|
84824
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box_default, { borderStyle: "round", borderColor: "gray", paddingX: 1, marginBottom: 1, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Text, { children: [
|
|
84825
|
+
"\u2315 ",
|
|
84826
|
+
picker.query ? picker.query : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: "Search\u2026" })
|
|
84827
|
+
] }) }),
|
|
84828
|
+
rows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: " nothing matches" }) : out,
|
|
84829
|
+
top + PICKER_ROWS < rows.length ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: `\u2193 ${rows.length - top - PICKER_ROWS} more` }) : null,
|
|
84830
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { dimColor: true, children: `Enter to continue \xB7 Ctrl+A to show ${scope === "here" ? "all directories" : "only this directory"} \xB7 Type to search \xB7 Esc to cancel` })
|
|
84831
|
+
] });
|
|
84832
|
+
})(),
|
|
84712
84833
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { borderStyle: "single", borderColor: "gray", borderLeft: false, borderRight: false, paddingX: 1, marginTop: 1, children: [
|
|
84713
84834
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: "cyan", children: "\u276F " }),
|
|
84714
84835
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
84715
84836
|
input_default,
|
|
84716
84837
|
{
|
|
84717
84838
|
ref: inputRef,
|
|
84718
|
-
onPasteImage: () => hello?.images ? engine2.send({ cmd: "paste_image" }) : append({ kind: "warn", text: "this
|
|
84839
|
+
onPasteImage: () => hello?.images ? engine2.send({ cmd: "paste_image" }) : append({ kind: "warn", text: "this version of hum does not take images; update hum" }),
|
|
84719
84840
|
value,
|
|
84720
84841
|
onChange: setValue,
|
|
84721
84842
|
onSubmit,
|
|
@@ -85011,13 +85132,11 @@ var Engine = class {
|
|
|
85011
85132
|
|
|
85012
85133
|
// src/cli.jsx
|
|
85013
85134
|
var import_jsx_runtime3 = __toESM(require_jsx_runtime(), 1);
|
|
85014
|
-
import fs5 from "node:fs";
|
|
85015
|
-
import path4 from "node:path";
|
|
85016
85135
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
85017
85136
|
var ENGINE_COMMANDS = /* @__PURE__ */ new Set(["run", "login", "logout", "whoami", "model", "key", "sessions", "show", "sync", "skill", "ps", "stop", "hooks", "engine"]);
|
|
85018
85137
|
var argv0 = process.argv.slice(2);
|
|
85019
85138
|
if (argv0[0] === "--version" || argv0[0] === "-V") {
|
|
85020
|
-
process.stdout.write(`hum ${true ? "0.1.
|
|
85139
|
+
process.stdout.write(`hum ${true ? "0.1.21" : "0.0.0"}
|
|
85021
85140
|
`);
|
|
85022
85141
|
process.exit(0);
|
|
85023
85142
|
}
|
|
@@ -85059,39 +85178,12 @@ if (!process.stdin.isTTY) {
|
|
|
85059
85178
|
process.stderr.write('hum needs an interactive terminal; use `hum run "task"` when piping.\n');
|
|
85060
85179
|
process.exit(1);
|
|
85061
85180
|
}
|
|
85062
|
-
var liveRuns = () => {
|
|
85063
|
-
let out = [];
|
|
85064
|
-
try {
|
|
85065
|
-
for (const f of fs5.readdirSync(runDir())) {
|
|
85066
|
-
if (!f.endsWith(".json")) continue;
|
|
85067
|
-
try {
|
|
85068
|
-
const r = JSON.parse(fs5.readFileSync(path4.join(runDir(), f), "utf8"));
|
|
85069
|
-
if (r.port && r.session) out.push(r);
|
|
85070
|
-
} catch {
|
|
85071
|
-
}
|
|
85072
|
-
}
|
|
85073
|
-
} catch {
|
|
85074
|
-
}
|
|
85075
|
-
out.sort((a, b) => (b.updated || 0) - (a.updated || 0));
|
|
85076
|
-
for (const r of out) {
|
|
85077
|
-
try {
|
|
85078
|
-
process.kill(r.pid, 0);
|
|
85079
|
-
} catch {
|
|
85080
|
-
r.dead = true;
|
|
85081
|
-
}
|
|
85082
|
-
}
|
|
85083
|
-
return out.filter((r) => !r.dead);
|
|
85084
|
-
};
|
|
85085
85181
|
var port = Number(process.env.HUM_ENGINE_PORT || 0);
|
|
85086
85182
|
var startedHere = false;
|
|
85087
85183
|
try {
|
|
85088
85184
|
if (!port) {
|
|
85089
|
-
|
|
85090
|
-
|
|
85091
|
-
if (!rec) {
|
|
85092
|
-
rec = await spawnEngine(args.cwd, { task: args.task, images: args.images, resume: args.resume && args.resume !== "pick" ? args.resume : null });
|
|
85093
|
-
startedHere = true;
|
|
85094
|
-
}
|
|
85185
|
+
const rec = await spawnEngine(args.cwd, { task: args.task, images: args.images, resume: args.resume && args.resume !== "pick" ? args.resume : null });
|
|
85186
|
+
startedHere = true;
|
|
85095
85187
|
port = rec.port;
|
|
85096
85188
|
}
|
|
85097
85189
|
} catch (exc) {
|