castle-web-cli 0.4.34 → 0.4.36
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/agent-prompts.js
CHANGED
|
@@ -36,6 +36,7 @@ comma-separated titles or ids of the finished tasks
|
|
|
36
36
|
\`\`\`
|
|
37
37
|
|
|
38
38
|
- NEVER check a task off on your own judgment -- only a clear user statement that it works (or an explicit ask to clear it) counts. When in doubt, leave the row on the board.
|
|
39
|
+
- The background-tasks list below IS the board the user sees -- every row, with its id. To clear the WHOLE board at once (e.g. "clear all the tasks"), use \`all\` instead of listing ids: a \`castle-done\` with body \`all\` checks off every finished row, and a \`castle-stop\` with body \`all\` stops everything still running. Never claim the board is cleared without actually emitting the fence.
|
|
39
40
|
- To STOP tasks (running or waiting) when the user asks or their work is clearly no longer wanted, include:
|
|
40
41
|
|
|
41
42
|
\`\`\`castle-stop
|
package/dist/agent.js
CHANGED
|
@@ -543,13 +543,14 @@ function createTaskStore(opts) {
|
|
|
543
543
|
});
|
|
544
544
|
}
|
|
545
545
|
function spawnFromDirective(directive, originMessageId) {
|
|
546
|
-
// A fix/redo task sweeps the rows it obsoletes off the user's board.
|
|
547
|
-
// superseded task that
|
|
546
|
+
// A fix/redo task sweeps the rows it obsoletes off the user's board. Halt
|
|
547
|
+
// first -- a superseded task that is still running must have its process
|
|
548
|
+
// killed (not just hidden, which left an invisible zombie the rest of the
|
|
549
|
+
// board could depend on), and a waiting one must not start later.
|
|
548
550
|
for (const id of resolveDeps(tasks, directive.supersedes)) {
|
|
549
551
|
const old = tasks.get(id);
|
|
550
552
|
if (old && !old.acknowledged) {
|
|
551
|
-
|
|
552
|
-
old.status = 'interrupted';
|
|
553
|
+
haltTask(old);
|
|
553
554
|
old.acknowledged = true;
|
|
554
555
|
touch(old);
|
|
555
556
|
opts.onSuperseded(old);
|
|
@@ -602,38 +603,58 @@ function createTaskStore(opts) {
|
|
|
602
603
|
}
|
|
603
604
|
}
|
|
604
605
|
}
|
|
605
|
-
//
|
|
606
|
+
// True when a fence body is the special token "all" / "*" (clear/stop
|
|
607
|
+
// everything, no per-task enumeration).
|
|
608
|
+
function meansAll(tokens) {
|
|
609
|
+
return tokens.some((t) => t.toLowerCase() === 'all' || t === '*');
|
|
610
|
+
}
|
|
611
|
+
// The router checks finished tasks off by title or id (castle-done fence),
|
|
612
|
+
// or "all" to clear every finished row off the board at once.
|
|
606
613
|
function checkOff(tokens) {
|
|
607
|
-
|
|
614
|
+
const ids = meansAll(tokens)
|
|
615
|
+
? [...tasks.values()].filter((t) => isTerminal(t.status) && !t.acknowledged).map((t) => t.id)
|
|
616
|
+
: resolveDeps(tasks, tokens);
|
|
617
|
+
for (const id of ids)
|
|
608
618
|
acknowledge(id, false);
|
|
609
619
|
}
|
|
610
|
-
// The router stops tasks by title or id (castle-stop fence)
|
|
611
|
-
//
|
|
612
|
-
//
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
}
|
|
620
|
+
// The router stops tasks by title or id (castle-stop fence), or "all" to
|
|
621
|
+
// stop everything still active. Waiting tasks are cancelled outright;
|
|
622
|
+
// running ones get their agent process killed and finalize as interrupted
|
|
623
|
+
// via the stopRequested path.
|
|
624
|
+
// Halt an active task: a waiting one is cancelled (-> interrupted); a
|
|
625
|
+
// running one gets its agent process killed and finalizes as interrupted
|
|
626
|
+
// via the stopRequested path. No-op on terminal tasks.
|
|
627
|
+
function haltTask(task) {
|
|
628
|
+
if (task.status === 'waiting') {
|
|
629
|
+
task.status = 'interrupted';
|
|
630
|
+
touch(task);
|
|
631
|
+
}
|
|
632
|
+
else if (task.status === 'running') {
|
|
633
|
+
stopRequested.add(task.id);
|
|
634
|
+
for (const child of children) {
|
|
635
|
+
if (child.pid === task.pid) {
|
|
636
|
+
try {
|
|
637
|
+
child.kill('SIGKILL');
|
|
638
|
+
}
|
|
639
|
+
catch {
|
|
640
|
+
/* already gone */
|
|
632
641
|
}
|
|
633
642
|
}
|
|
634
643
|
}
|
|
635
644
|
}
|
|
636
645
|
}
|
|
646
|
+
function stop(tokens) {
|
|
647
|
+
const ids = meansAll(tokens)
|
|
648
|
+
? [...tasks.values()]
|
|
649
|
+
.filter((t) => t.status === 'running' || t.status === 'waiting')
|
|
650
|
+
.map((t) => t.id)
|
|
651
|
+
: resolveDeps(tasks, tokens);
|
|
652
|
+
for (const id of ids) {
|
|
653
|
+
const task = tasks.get(id);
|
|
654
|
+
if (task)
|
|
655
|
+
haltTask(task);
|
|
656
|
+
}
|
|
657
|
+
}
|
|
637
658
|
return { sorted, get: (id) => tasks.get(id), spawnFromDirective, acknowledge, checkOff, stop, shutdown };
|
|
638
659
|
}
|
|
639
660
|
// -- attachments ----------------------------------------------------------------
|
|
@@ -764,7 +785,13 @@ function runRouterTurnIn(ctx, instruction) {
|
|
|
764
785
|
messages: ctx.log.messages
|
|
765
786
|
.filter((m) => m.role !== 'log' && m.id !== message.id && m.status !== 'streaming')
|
|
766
787
|
.map((m) => ({ role: m.role, text: m.text })),
|
|
767
|
-
tasks
|
|
788
|
+
// Only the live board -- match what the user sees. Hide tasks that are
|
|
789
|
+
// BOTH acknowledged AND finished; an active (running/waiting) task always
|
|
790
|
+
// shows even if somehow acked, so nothing can ever go invisible mid-work.
|
|
791
|
+
tasks: ctx.taskStore
|
|
792
|
+
.sorted()
|
|
793
|
+
.filter((t) => !(t.acknowledged && isTerminal(t.status)))
|
|
794
|
+
.map(asPromptTask),
|
|
768
795
|
instruction,
|
|
769
796
|
});
|
|
770
797
|
const backend = ctx.backend();
|
package/dist/chat-client.js
CHANGED
|
@@ -227,7 +227,10 @@ function TaskRow(props) {
|
|
|
227
227
|
expanded && task.status !== 'running' ? (React.createElement("div", { className: "task-notes", dangerouslySetInnerHTML: renderMarkdown(notes) })) : null));
|
|
228
228
|
}
|
|
229
229
|
function TaskBoard(props) {
|
|
230
|
-
|
|
230
|
+
// Hide only tasks that are acknowledged AND finished. An active
|
|
231
|
+
// (running/waiting) task always shows, even if somehow acked -- a running
|
|
232
|
+
// task must never go invisible while it (and its dependents) are live.
|
|
233
|
+
const visible = props.tasks.filter((t) => !(t.acknowledged && TERMINAL_TASK_STATUSES.includes(t.status)));
|
|
231
234
|
if (visible.length === 0)
|
|
232
235
|
return null;
|
|
233
236
|
return (React.createElement("div", { id: "chat-strip" }, visible.map((task) => (React.createElement(TaskRow, { key: task.id, task: task, feed: props.feeds[task.id], onAck: props.onAck })))));
|
|
@@ -127,6 +127,7 @@ function buildFileTree(paths) {
|
|
|
127
127
|
}
|
|
128
128
|
}
|
|
129
129
|
pruneChildMaps(root);
|
|
130
|
+
sortRootChildren(root);
|
|
130
131
|
return root;
|
|
131
132
|
}
|
|
132
133
|
function pruneChildMaps(node) {
|
|
@@ -134,6 +135,17 @@ function pruneChildMaps(node) {
|
|
|
134
135
|
for (const child of node.children) pruneChildMaps(child);
|
|
135
136
|
delete node.childMap;
|
|
136
137
|
}
|
|
138
|
+
// Top-level folders list in a fixed order: drawings, then scenes, then
|
|
139
|
+
// behaviors, then anything else alphabetically.
|
|
140
|
+
function sortRootChildren(root) {
|
|
141
|
+
const rank = (name) => {
|
|
142
|
+
if (name === 'drawings') return 0;
|
|
143
|
+
if (name === 'scenes') return 1;
|
|
144
|
+
if (name === 'behaviors') return 2;
|
|
145
|
+
return 3;
|
|
146
|
+
};
|
|
147
|
+
root.children.sort((a, b) => rank(a.name) - rank(b.name) || a.name.localeCompare(b.name));
|
|
148
|
+
}
|
|
137
149
|
function collectDirectoryPaths(node) {
|
|
138
150
|
if (node.type !== 'directory') return [];
|
|
139
151
|
return [
|
|
@@ -44,6 +44,15 @@
|
|
|
44
44
|
box-sizing: border-box;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
/* Hide scrollbars across the whole editor while keeping scroll functional. */
|
|
48
|
+
:global(*) {
|
|
49
|
+
scrollbar-width: none;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
:global(*)::-webkit-scrollbar {
|
|
53
|
+
display: none;
|
|
54
|
+
}
|
|
55
|
+
|
|
47
56
|
:global(html),
|
|
48
57
|
:global(body),
|
|
49
58
|
:global(#root) {
|