@lawaty/lacode 1.3.0-beta.1 → 1.3.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +44 -0
- package/dist/tui.js +76 -6
- package/package.json +12 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,50 @@ All notable changes to LaCode are recorded here. The format follows
|
|
|
7
7
|
Versions come from git release commits; the npm version is bumped in the same
|
|
8
8
|
commit as the changelog entry it describes.
|
|
9
9
|
|
|
10
|
+
## [1.3.0-beta.3] — the 1.3.0-beta.2 notes
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- **Republished so the published tarball carries the 1.3.0-beta.2 changelog
|
|
15
|
+
entry.** No runtime change: the code is identical to 1.3.0-beta.2.
|
|
16
|
+
|
|
17
|
+
## [1.3.0-beta.2] — a reason that survives, and a timeline that ships
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- **A durable failure journal.** Every failed or cancelled spawn appends one JSON
|
|
22
|
+
line to `failures.jsonl` in the pool state directory: timestamp, source, base,
|
|
23
|
+
slot, model, reason, elapsed time and the error text. `pool_status` prints the
|
|
24
|
+
last five under `recent failures:`, so a slot that dies without a cooldown is
|
|
25
|
+
no longer invisible afterwards.
|
|
26
|
+
|
|
27
|
+
### Changed
|
|
28
|
+
|
|
29
|
+
- **A spawn the pool did not abort now records why it died.** An unclassified
|
|
30
|
+
`session.error`, or an assistant message error matching no known class, used to
|
|
31
|
+
release the claim and say nothing. It now records the slot, model and error
|
|
32
|
+
text, and the cancelled task card is rewritten with that reason. A stop the
|
|
33
|
+
user presses still produces no record and no rewrite, because it raises no
|
|
34
|
+
session error.
|
|
35
|
+
|
|
36
|
+
### Fixed
|
|
37
|
+
|
|
38
|
+
- **The cancelled-task rewrite was unauthenticated.** It hand-rolled a `fetch`
|
|
39
|
+
PATCH and read `OPENCODE_SERVER_PASSWORD` from the plugin's own environment —
|
|
40
|
+
but that variable exists only in the server process, so the request always went
|
|
41
|
+
out unauthenticated and a password-protected server answered `401`. The reason
|
|
42
|
+
was then dropped and the caller saw a bare `Task cancelled`. The rewrite now
|
|
43
|
+
goes through the injected client's part update, which is already authenticated;
|
|
44
|
+
the raw request remains only as a fallback for a runtime without it.
|
|
45
|
+
- **The timeline sidebar was never bundled.** `src/tui/timeline.tsx` was added in
|
|
46
|
+
1.2.0 but never imported by the TUI entry point, so `dist/tui.js` contained no
|
|
47
|
+
reference to it and no published version shipped the panel: it worked only on a
|
|
48
|
+
machine whose `tui.json` pointed at the raw source file. The TUI entry now
|
|
49
|
+
composes it, `solid-js` and `@opentui/solid` are treated as host-provided peers
|
|
50
|
+
instead of being bundled, and the automatic JSX transform is enabled so the
|
|
51
|
+
`@opentui/solid` pragma is honoured rather than silently compiling to
|
|
52
|
+
`React.createElement`.
|
|
53
|
+
|
|
10
54
|
## [1.3.0-beta.0] — provider readiness, timeline roots, and a reason on cancelled tasks
|
|
11
55
|
|
|
12
56
|
### Added
|
package/dist/tui.js
CHANGED
|
@@ -85,17 +85,17 @@ function createRecorder(deps) {
|
|
|
85
85
|
const child = childHandle;
|
|
86
86
|
const filePath = currentPath;
|
|
87
87
|
if (!exited) {
|
|
88
|
-
await new Promise((
|
|
88
|
+
await new Promise((resolve2) => {
|
|
89
89
|
let done = false;
|
|
90
90
|
let timer;
|
|
91
91
|
const finish = () => {
|
|
92
92
|
if (done) return;
|
|
93
93
|
done = true;
|
|
94
94
|
if (timer) clearTimeout(timer);
|
|
95
|
-
if (resolveWait ===
|
|
96
|
-
|
|
95
|
+
if (resolveWait === resolve2) resolveWait = null;
|
|
96
|
+
resolve2();
|
|
97
97
|
};
|
|
98
|
-
resolveWait =
|
|
98
|
+
resolveWait = resolve2;
|
|
99
99
|
timer = setTimeout(() => {
|
|
100
100
|
try {
|
|
101
101
|
child.kill("SIGKILL");
|
|
@@ -821,6 +821,68 @@ function createVoiceClient(options, deps) {
|
|
|
821
821
|
return client;
|
|
822
822
|
}
|
|
823
823
|
|
|
824
|
+
// src/tui/timeline.tsx
|
|
825
|
+
import { createSignal, createEffect, onCleanup, For } from "solid-js";
|
|
826
|
+
import { readFileSync as readFileSync3 } from "node:fs";
|
|
827
|
+
import { homedir as homedir2 } from "node:os";
|
|
828
|
+
import { join as join3, resolve } from "node:path";
|
|
829
|
+
import { jsx, jsxs } from "@opentui/solid/jsx-runtime";
|
|
830
|
+
var registered = false;
|
|
831
|
+
var tui = async (api) => {
|
|
832
|
+
if (registered) return;
|
|
833
|
+
registered = true;
|
|
834
|
+
api.slots.register({
|
|
835
|
+
order: 150,
|
|
836
|
+
slots: {
|
|
837
|
+
sidebar_content(ctx, props) {
|
|
838
|
+
const [entries, setEntries] = createSignal([]);
|
|
839
|
+
const read = (id) => {
|
|
840
|
+
if (typeof id !== "string" || !/^[A-Za-z0-9_.-]+$/.test(id)) {
|
|
841
|
+
setEntries([]);
|
|
842
|
+
return;
|
|
843
|
+
}
|
|
844
|
+
const rawDir = process.env.LACODE_TIMELINE_DIR;
|
|
845
|
+
const dir = rawDir ? resolve(rawDir) : join3(homedir2(), ".local/share/opencode/lacode/timeline");
|
|
846
|
+
const file = join3(dir, id + ".jsonl");
|
|
847
|
+
try {
|
|
848
|
+
const raw = readFileSync3(file, "utf8");
|
|
849
|
+
const parsed = [];
|
|
850
|
+
for (const line of raw.split("\n")) {
|
|
851
|
+
const trimmed = line.trim();
|
|
852
|
+
if (!trimmed) continue;
|
|
853
|
+
try {
|
|
854
|
+
const obj = JSON.parse(trimmed);
|
|
855
|
+
if (obj && typeof obj.ts === "number" && typeof obj.text === "string") {
|
|
856
|
+
parsed.push(obj.text);
|
|
857
|
+
}
|
|
858
|
+
} catch {
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
setEntries(parsed.slice(-14).reverse());
|
|
862
|
+
} catch {
|
|
863
|
+
setEntries([]);
|
|
864
|
+
}
|
|
865
|
+
};
|
|
866
|
+
createEffect(() => {
|
|
867
|
+
const id = props.session_id;
|
|
868
|
+
read(id);
|
|
869
|
+
const timer = setInterval(() => read(id), 1e3);
|
|
870
|
+
onCleanup(() => clearInterval(timer));
|
|
871
|
+
});
|
|
872
|
+
return /* @__PURE__ */ jsxs("box", { flexDirection: "column", children: [
|
|
873
|
+
/* @__PURE__ */ jsx("text", { fg: ctx.theme.current.textMuted, children: "Timeline" }),
|
|
874
|
+
entries().length === 0 ? /* @__PURE__ */ jsx("text", { fg: ctx.theme.current.textMuted, children: "No timeline yet" }) : /* @__PURE__ */ jsx(For, { each: entries(), children: (text) => /* @__PURE__ */ jsx("text", { children: `\u2022 ${text}` }) })
|
|
875
|
+
] });
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
});
|
|
879
|
+
};
|
|
880
|
+
var plugin = {
|
|
881
|
+
id: "lacode.timeline",
|
|
882
|
+
tui
|
|
883
|
+
};
|
|
884
|
+
var timeline_default = plugin;
|
|
885
|
+
|
|
824
886
|
// src/tui/index.ts
|
|
825
887
|
var DEFAULT_MODEL = "whisper-large-v3-turbo";
|
|
826
888
|
var DEFAULT_LANGUAGE = "en";
|
|
@@ -1049,7 +1111,7 @@ async function answerWithText(api, opts, text, request) {
|
|
|
1049
1111
|
const labels = answers.map((answer) => answer.join(", ")).filter((answer) => answer.length > 0).join("; ");
|
|
1050
1112
|
toast(api, { variant: "success", message: labels });
|
|
1051
1113
|
}
|
|
1052
|
-
var
|
|
1114
|
+
var tui2 = async (api, options) => {
|
|
1053
1115
|
const opts = resolveOptions(options);
|
|
1054
1116
|
if (!opts.enabled) return;
|
|
1055
1117
|
daemonConnected = false;
|
|
@@ -1271,10 +1333,18 @@ var tui = async (api, options) => {
|
|
|
1271
1333
|
bindings.push({ key: opts.answerKey, cmd: "lacode.voice.answer", desc: "Voice answer" });
|
|
1272
1334
|
}
|
|
1273
1335
|
api.keymap.registerLayer({ mode: "base", commands, bindings });
|
|
1336
|
+
const timelineOpts = options ?? {};
|
|
1337
|
+
const timelineOff = timelineOpts.timeline === false || typeof timelineOpts.timeline === "object" && timelineOpts.timeline !== null && timelineOpts.timeline.enabled === false;
|
|
1338
|
+
if (!timelineOff) {
|
|
1339
|
+
try {
|
|
1340
|
+
await timeline_default.tui(api, options);
|
|
1341
|
+
} catch {
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1274
1344
|
};
|
|
1275
1345
|
var mod = {
|
|
1276
1346
|
id: "lacode.voice",
|
|
1277
|
-
tui
|
|
1347
|
+
tui: tui2
|
|
1278
1348
|
};
|
|
1279
1349
|
var index_default = mod;
|
|
1280
1350
|
export {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lawaty/lacode",
|
|
3
|
-
"version": "1.3.0-beta.
|
|
3
|
+
"version": "1.3.0-beta.3",
|
|
4
4
|
"description": "Ultimate opencode setup for Go users — cost-controlled pooled subagents, hang recovery, and notifications for opencode.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -64,7 +64,17 @@
|
|
|
64
64
|
"esbuild": "^0.28.2"
|
|
65
65
|
},
|
|
66
66
|
"peerDependencies": {
|
|
67
|
-
"@opencode-ai/plugin": "1.18.34"
|
|
67
|
+
"@opencode-ai/plugin": "1.18.34",
|
|
68
|
+
"solid-js": "*",
|
|
69
|
+
"@opentui/solid": "*"
|
|
70
|
+
},
|
|
71
|
+
"peerDependenciesMeta": {
|
|
72
|
+
"solid-js": {
|
|
73
|
+
"optional": true
|
|
74
|
+
},
|
|
75
|
+
"@opentui/solid": {
|
|
76
|
+
"optional": true
|
|
77
|
+
}
|
|
68
78
|
},
|
|
69
79
|
"optionalDependencies": {
|
|
70
80
|
"@picovoice/porcupine-node": "^4.0.2",
|