castle-web-cli 0.4.36 → 0.4.37

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.
@@ -20,7 +20,6 @@ Hard rules:
20
20
  \`\`\`castle-task
21
21
  short imperative title on the first line
22
22
  after: comma-separated titles or ids this task must wait for (optional line)
23
- supersedes: comma-separated titles or ids this task replaces (optional line)
24
23
  Then a SHORT self-contained prompt -- one tight paragraph (aim under 100
25
24
  words): what to build or fix and what "done" looks like. Task agents read
26
25
  the deck's own docs for framework/API detail, so never restate recipes,
@@ -28,23 +27,22 @@ file layouts, or implementation steps.
28
27
  \`\`\`
29
28
 
30
29
  - Use \`after:\` only when a task truly builds on or would conflict with another (it may reference tasks spawned in this same reply, by title). Independent tasks must NOT wait on each other.
31
- - Use \`supersedes:\` whenever the new task fixes, redoes, or makes obsolete an earlier task -- the old row is checked off the user's board automatically. Keep the board meaning "what to look at right now".
32
- - When the user clearly confirms something works (or tells you to clear items), check those finished tasks off the board by including:
30
+
31
+ Keeping the board clean. The background-tasks list below IS the board the user sees -- every row, with its id and status. Be diligent about removing rows that no longer belong, using these two fences:
33
32
 
34
33
  \`\`\`castle-done
35
- comma-separated titles or ids of the finished tasks
34
+ comma-separated finished-task titles or ids, or \`all\`
36
35
  \`\`\`
37
-
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.
40
- - To STOP tasks (running or waiting) when the user asks or their work is clearly no longer wanted, include:
41
-
42
36
  \`\`\`castle-stop
43
- comma-separated titles or ids of the tasks to stop
37
+ comma-separated active-task titles or ids, or \`all\`
44
38
  \`\`\`
45
39
 
46
- Stopped tasks show as interrupted on the board. If a new task replaces the stopped work, prefer \`supersedes:\` on the new task instead.
47
- - Tasks are one-and-done -- when the user gives feedback on a finished task, spawn a new fix task rather than reopening the old one.
40
+ - \`castle-done\` removes FINISHED rows (done/failed). Use it when the user confirms a task works, or to clear a finished task that has become obsolete (replaced by newer work). \`all\` clears every finished row.
41
+ - \`castle-stop\` stops AND removes ACTIVE rows (running/waiting) -- a running task's agent is killed. Use it when the user asks to stop something, or when you spawn a fix/replacement that makes an in-flight task obsolete. \`all\` stops everything active.
42
+ - When you spawn a task that fixes, redoes, or replaces an earlier one, remove the earlier one in the SAME reply: \`castle-done\` if it already finished, \`castle-stop\` if it is still running or waiting. Keep the board meaning "what to look at right now".
43
+ - Do not mark a task done to imply YOU verified its quality -- the user playtests and confirms that. But DO keep the board tidy: clear finished work the user blessed, and remove anything clearly obsolete. When genuinely unsure, leave the row.
44
+ - Never claim the board is cleared without actually emitting the fence.
45
+ - Tasks are one-and-done -- when the user gives feedback on a finished task, spawn a new fix task (and \`castle-done\` the old row) rather than reopening it.
48
46
  - Task agents are capable coding agents working in this same deck directory, but they know nothing about this conversation beyond your prompt.
49
47
 
50
48
  Conversation style:
package/dist/agent.js CHANGED
@@ -113,8 +113,7 @@ function visibleLength(raw) {
113
113
  return raw.length;
114
114
  }
115
115
  // Pull ```castle-task fenced directives out of a finished router reply.
116
- // Block format: title line, then optional "after:" / "supersedes:" lines (in
117
- // either order), then the task prompt.
116
+ // Block format: title line, then an optional "after:" line, then the prompt.
118
117
  function extractDirectives(full) {
119
118
  const directives = [];
120
119
  const checkoffs = [];
@@ -135,9 +134,9 @@ function extractDirectives(full) {
135
134
  const cleaned = withoutDone.replace(fenceRe, (_match, body) => {
136
135
  const lines = String(body).replace(/\r/g, '').split('\n');
137
136
  const title = (lines.shift() ?? '').trim();
138
- const headers = { after: [], supersedes: [] };
137
+ const headers = { after: [] };
139
138
  while (lines.length > 0) {
140
- const headerMatch = /^(after|supersedes):\s*(.*)$/i.exec((lines[0] ?? '').trim());
139
+ const headerMatch = /^(after):\s*(.*)$/i.exec((lines[0] ?? '').trim());
141
140
  if (!headerMatch)
142
141
  break;
143
142
  lines.shift();
@@ -148,7 +147,7 @@ function extractDirectives(full) {
148
147
  }
149
148
  const prompt = lines.join('\n').trim();
150
149
  if (title) {
151
- directives.push({ title, after: headers.after, supersedes: headers.supersedes, prompt });
150
+ directives.push({ title, after: headers.after, prompt });
152
151
  }
153
152
  return '';
154
153
  });
@@ -528,6 +527,9 @@ function createTaskStore(opts) {
528
527
  refreshTaskFiles(tasksDir, task);
529
528
  const wasStopped = stopRequested.delete(task.id);
530
529
  task.status = wasStopped ? 'interrupted' : result.ok ? 'done' : 'failed';
530
+ // A stopped task is cleared off the board (castle-stop = halt + remove).
531
+ if (wasStopped)
532
+ task.acknowledged = true;
531
533
  if (result.ok && !wasStopped)
532
534
  task.progress = 100;
533
535
  task.finishedAt = nowIso();
@@ -543,19 +545,6 @@ function createTaskStore(opts) {
543
545
  });
544
546
  }
545
547
  function spawnFromDirective(directive, originMessageId) {
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.
550
- for (const id of resolveDeps(tasks, directive.supersedes)) {
551
- const old = tasks.get(id);
552
- if (old && !old.acknowledged) {
553
- haltTask(old);
554
- old.acknowledged = true;
555
- touch(old);
556
- opts.onSuperseded(old);
557
- }
558
- }
559
548
  const task = {
560
549
  id: nanoid(8),
561
550
  title: directive.title,
@@ -621,12 +610,14 @@ function createTaskStore(opts) {
621
610
  // stop everything still active. Waiting tasks are cancelled outright;
622
611
  // running ones get their agent process killed and finalize as interrupted
623
612
  // 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.
613
+ // Halt + remove an active task (castle-stop): a waiting one is cancelled and
614
+ // cleared off the board immediately; a running one gets its agent process
615
+ // killed and is cleared when it finalizes (the stopRequested path acks it).
616
+ // No-op on terminal tasks.
627
617
  function haltTask(task) {
628
618
  if (task.status === 'waiting') {
629
619
  task.status = 'interrupted';
620
+ task.acknowledged = true;
630
621
  touch(task);
631
622
  }
632
623
  else if (task.status === 'running') {
@@ -992,7 +983,6 @@ export function createAgentServer(opts) {
992
983
  onStarted: () => undefined,
993
984
  onRetry: (task, attempt) => addLog(`agent died, retrying (${attempt}/${MAX_TASK_ATTEMPTS}): ${task.title}`),
994
985
  onFinished: (task) => taskFeeds.map.delete(task.id),
995
- onSuperseded: () => undefined,
996
986
  onFeed: (task, entry) => taskFeeds.push(task, entry),
997
987
  });
998
988
  // A new user message interrupts the in-flight router reply: its partial
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "castle-web-cli",
3
- "version": "0.4.36",
3
+ "version": "0.4.37",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "castle-web": "./dist/index.js"