kaizen-agent 1.34.3 → 1.34.5
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/cli/state.test.ts +4 -0
- package/package.json +1 -1
- package/web/board/cards.ts +39 -3
- package/web/board/icebox.ts +2 -1
- package/web/board.html +3 -1
- package/web/board.js +12 -12
- package/web/notebook.js +1 -1
- package/web/term.js +16 -16
- package/web/term.ts +47 -24
package/cli/state.test.ts
CHANGED
|
@@ -250,6 +250,10 @@ test("notes log: append to a run and to an idea; attachments saved and made abso
|
|
|
250
250
|
const rel = saveAttachment(state, null, "../evil name.png", new Uint8Array([1]));
|
|
251
251
|
expect(rel).toMatch(/^attachments\/\w+-_evil_name\.png$/);
|
|
252
252
|
expect(requestOf("x", ``, state)).toBe(`x\n\n})`);
|
|
253
|
+
// The New idea form's path: idea first, then its files as a note; a plain file reaches the run by absolute path.
|
|
254
|
+
const doc = saveAttachment(state, null, "spec.pdf", new Uint8Array([3]));
|
|
255
|
+
expect(appendNote(state, { text: "chatty zq6" }, `[spec.pdf](${doc})`)).toBeNull();
|
|
256
|
+
expect(requestOf("/kaizen chatty zq6", readInbox(state)[0]!.notes, state)).toContain(`[spec.pdf](${join(state, doc)})`);
|
|
253
257
|
expect(saveAttachment(state, "2026-09-01-waiting", "b.txt", new Uint8Array([2]))).toMatch(/^runs\/2026-09-01-waiting\/attachments\//);
|
|
254
258
|
});
|
|
255
259
|
|
package/package.json
CHANGED
package/web/board/cards.ts
CHANGED
|
@@ -507,9 +507,10 @@ export function render() {
|
|
|
507
507
|
if (ci === 0 && store.mode === "new") {
|
|
508
508
|
const f = document.createElement("li");
|
|
509
509
|
f.className = "inl";
|
|
510
|
-
f.innerHTML = `${store.all ? `<div class="combo" id="ndc"><button class="sel" id="newdir" aria-label="Project for this idea" aria-haspopup="listbox" aria-expanded="false"></button><div class="menu-pop" hidden><input class="sel" aria-label="Search projects" placeholder="Search projects…" spellcheck="false" autocomplete="off"><div id="nds" role="listbox"></div></div></div>` : ""}<input id="newidea" placeholder="What would you like done?"><textarea id="newnotes" placeholder="Notes: links, paths, background (optional)"></textarea><div class="row"><button class="btn ghost" id="nc">Cancel</button><button class="btn pri" id="ns">Add idea</button></div>`;
|
|
510
|
+
f.innerHTML = `${store.all ? `<div class="combo" id="ndc"><button class="sel" id="newdir" aria-label="Project for this idea" aria-haspopup="listbox" aria-expanded="false"></button><div class="menu-pop" hidden><input class="sel" aria-label="Search projects" placeholder="Search projects…" spellcheck="false" autocomplete="off"><div id="nds" role="listbox"></div></div></div>` : ""}<input id="newidea" placeholder="What would you like done?"><textarea id="newnotes" placeholder="Notes: links, paths, background (optional)"></textarea><div class="att" id="newatt"></div><input type="file" id="newfile" multiple hidden><div class="row"><button class="btn ghost" id="newpick">Attach</button><button class="btn ghost" id="nc">Cancel</button><button class="btn pri" id="ns">Add idea</button></div>`;
|
|
511
511
|
ul.appendChild(f);
|
|
512
|
-
const inp = f.querySelector("#newidea")
|
|
512
|
+
const inp = f.querySelector("#newidea"),
|
|
513
|
+
files = [];
|
|
513
514
|
draft(inp, "f:new:0");
|
|
514
515
|
draft(f.querySelector("textarea"), "f:new:1");
|
|
515
516
|
const save = async () => {
|
|
@@ -519,9 +520,44 @@ export function render() {
|
|
|
519
520
|
store.mode = null;
|
|
520
521
|
const dir = store.all ? newDir : null;
|
|
521
522
|
const r = await post("/inbox", dir ? { op: "add", dir, text, notes } : { op: "add", text, notes });
|
|
522
|
-
if (r.ok)
|
|
523
|
+
if (r.ok) {
|
|
524
|
+
toast("Idea added");
|
|
525
|
+
// The idea exists first: a failed upload leaves it as plain text.
|
|
526
|
+
if (files.length) {
|
|
527
|
+
const enc = await Promise.all(
|
|
528
|
+
files.map(
|
|
529
|
+
(x) =>
|
|
530
|
+
new Promise((res) => {
|
|
531
|
+
const rd = new FileReader();
|
|
532
|
+
rd.onload = () => res({ name: x.name, data: rd.result });
|
|
533
|
+
rd.readAsDataURL(x);
|
|
534
|
+
}),
|
|
535
|
+
),
|
|
536
|
+
);
|
|
537
|
+
const n = await post("/note", { dir, for: text, text: "", files: enc });
|
|
538
|
+
if (!n.ok) toast("Idea added, files not attached");
|
|
539
|
+
}
|
|
540
|
+
}
|
|
523
541
|
load();
|
|
524
542
|
};
|
|
543
|
+
const add = (x) => {
|
|
544
|
+
files.push(x);
|
|
545
|
+
f.querySelector("#newatt").textContent = files.map((y) => y.name).join(" · ");
|
|
546
|
+
};
|
|
547
|
+
f.querySelector("#newpick").onclick = () => f.querySelector("#newfile").click();
|
|
548
|
+
f.querySelector("#newfile").onchange = (e) => {
|
|
549
|
+
[...e.target.files].forEach(add);
|
|
550
|
+
e.target.value = "";
|
|
551
|
+
};
|
|
552
|
+
for (const el of [inp, f.querySelector("textarea")])
|
|
553
|
+
el.onpaste = (e) => {
|
|
554
|
+
for (const it of e.clipboardData.items)
|
|
555
|
+
if (it.kind === "file") {
|
|
556
|
+
const x = it.getAsFile();
|
|
557
|
+
add(new File([x], x.name === "image.png" ? `paste-${Date.now()}.png` : x.name, { type: x.type }));
|
|
558
|
+
e.preventDefault();
|
|
559
|
+
}
|
|
560
|
+
};
|
|
525
561
|
if (store.all) ideaCombo(f);
|
|
526
562
|
f.querySelector("#ns").onclick = save;
|
|
527
563
|
f.querySelector("#nc").onclick = () => {
|
package/web/board/icebox.ts
CHANGED
|
@@ -236,7 +236,8 @@ export async function openSources() {
|
|
|
236
236
|
const pick = (id, label, xs) =>
|
|
237
237
|
`<select class="sel ice-sel" id="${id}" aria-label="${label}">${xs.join("")}</select>`;
|
|
238
238
|
const chips =
|
|
239
|
-
|
|
239
|
+
// Dismissed and Done are hidden until picked, so even a lone one is a choice.
|
|
240
|
+
(byCat.size > 1 || byCat.has("Dismissed") || byCat.has("Done")
|
|
240
241
|
? pick("ice-fc", "Category", [
|
|
241
242
|
opt("", !iceCat, "All categories"),
|
|
242
243
|
...[...byCat.keys()].map((k) => opt(k, iceCat === k, k)),
|
package/web/board.html
CHANGED
|
@@ -189,7 +189,7 @@ section h2 .clear{margin-left:auto;min-height:22px;padding:0 8px}
|
|
|
189
189
|
.notes{display:flex;flex-direction:column;gap:8px}
|
|
190
190
|
#pbody img{max-width:100%;border-radius:var(--r-s)}
|
|
191
191
|
/* the in-card agent: a wider panel, and the terminal filling its body */
|
|
192
|
-
aside.wide{width:100%;border-left:0}#pbody:has(.term){display:flex;flex-direction:column}#pbody .term{flex:1;min-height:0;min-height:320px;background:var(--bg);border-radius:var(--r-s)}#pbody .term .xterm{height:100%;padding:4px}#pbody .term .xterm-viewport{background:transparent!important}.termkeys{
|
|
192
|
+
aside.wide{width:100%;border-left:0}#pbody:has(.term){display:flex;flex-direction:column}#pbody .term{flex:1;min-height:0;min-height:320px;background:var(--bg);border-radius:var(--r-s)}#pbody .term .xterm{height:100%;padding:4px}#pbody .term .xterm-viewport{background:transparent!important}.termkeys{padding:6px 0}.termkeys button{height:52px;padding:0;border:1px solid var(--line);border-bottom-width:4px;border-radius:10px;background:var(--bg-2);color:var(--ink-hi);font:600 17px var(--mono);touch-action:manipulation}.termkeys button:active{transform:translateY(2px);border-bottom-width:2px;background:var(--hover)}.termkeys button.on{color:var(--on-accent);background:var(--accent);border-color:var(--accent)}.keygrid{display:grid;grid-template-columns:repeat(6,1fr);gap:8px}.ctrlpad{margin-bottom:8px}.ctrlpad div{display:flex;gap:4px;margin-bottom:5px}.ctrlpad div:nth-child(2){padding:0 5%}.ctrlpad div:nth-child(3){padding:0 10%}.ctrlpad button{flex:1;min-width:0;height:44px;font-size:15px}.termkeys [hidden]{display:none}.termkeys .keyhide{display:block;width:100%;height:30px;margin-bottom:6px;border-bottom-width:1px;font-size:14px}
|
|
193
193
|
.desc{border-bottom:1px solid var(--line);padding-bottom:6px;margin-bottom:14px}.desc h3{margin-top:14px}
|
|
194
194
|
.chat{display:flex;flex-direction:column;gap:10px;margin:0 0 14px}.msg{border:1px solid var(--line);border-radius:var(--r);padding:10px 12px;background:var(--bg)}.msg time{display:block;font-size:11px;color:var(--dim);margin-bottom:4px}.msg p:last-child{margin-bottom:0}.msg img{max-width:100%;max-height:260px;border-radius:var(--r-s);display:block;margin:4px 0}
|
|
195
195
|
.notes .tools{display:flex;gap:6px;align-items:center}.notes .tools span{flex:1;font-size:11px;color:var(--dim)}.notes .att{font-size:11px;color:var(--dim)}
|
|
@@ -413,6 +413,8 @@ body:not(.paged) .src-sec,body:not(.paged) .src-scrim{display:none}
|
|
|
413
413
|
.src-add .acts .btn{flex-shrink:0}
|
|
414
414
|
@media(max-width:480px){.src-add .two,.src-add .two.plat{grid-template-columns:1fr}}
|
|
415
415
|
@media(max-width:900px){main{grid-template-columns:1fr;padding-inline:16px;gap:8px}.hdr,.ftr,aside.docked>header,aside.docked>.body{padding-inline:16px}.more{display:grid}.card:hover .age{display:inline}.toast{left:16px;max-width:calc(100% - 32px)}}
|
|
416
|
+
@media(max-width:640px){.hdr{gap:8px 12px}.hdr h1{order:0;flex:1 0 50%}#newtop{order:1}.hdr .combo{order:2;flex:1 1 calc(50% - 6px);min-width:0}.hdr .combo>.sel{width:100%;max-width:none}.hdr .sp{display:none}.ftr{gap:6px 12px}}
|
|
417
|
+
@media(hover:none){#kbd{display:none}}
|
|
416
418
|
@media(prefers-reduced-motion:reduce){*,*::before,*::after{transition:none!important;animation:none!important}}
|
|
417
419
|
</style>
|
|
418
420
|
</head>
|