@rse/ase 2.0.7 → 2.0.8
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/dst/ase-agent-relay-client.js +3 -4
- package/dst/ase-config-schema.js +4 -1
- package/dst/ase-lib-fetch.js +12 -0
- package/dst/ase-lib-server-cli.js +8 -5
- package/dst/ase-task-board-diff.js +120 -0
- package/dst/ase-task-board-tui-control.js +8 -5
- package/dst/ase-task-board-tui-model.js +54 -14
- package/dst/ase-task-board-tui-popup.js +41 -8
- package/dst/ase-task-board-tui.js +42 -27
- package/dst/ase-task-board-web-client.css +1 -1
- package/dst/ase-task-board-web-client.html +16 -0
- package/dst/ase-task-board-web-client.js +33 -33
- package/dst/ase-task-board-web-server.js +44 -9
- package/dst/ase-task-board.js +12 -4
- package/dst/ase-task-store-client.js +4 -5
- package/dst/man/ase-config-init.md +2 -1
- package/dst/man/ase-config.md +5 -0
- package/dst/man/ase-task-board.md +44 -2
- package/package.json +7 -6
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/plugin/.github/plugin/plugin.json +1 -1
- package/plugin/meta/ase-common-task.md +24 -0
- package/plugin/mods/ase-mods-common.ts +73 -42
- package/plugin/mods/ase-mods-task-edit.ts +427 -0
- package/plugin/mods/ase-mods.ts +45 -14
- package/plugin/skills/ase-help-intent/data.md +78 -8
- package/plugin/skills/ase-task-edit/SKILL.md +114 -9
- package/plugin/skills/ase-task-edit/help.md +60 -0
- package/plugin/skills/ase-task-grill/SKILL.md +35 -20
- package/plugin/skills/ase-task-grill/help.md +18 -8
- /package/plugin/mods/{ase-mods-evaluate.ts → ase-mods-meta-evaluate.ts} +0 -0
- /package/plugin/mods/{ase-mods-grill.ts → ase-mods-task-grill.ts} +0 -0
|
@@ -13,6 +13,7 @@ import { userId } from "./ase-service-otel.js";
|
|
|
13
13
|
import { Config } from "./ase-config-core.js";
|
|
14
14
|
import { configSchema, webColorDefaults, webColorNames } from "./ase-config-schema.js";
|
|
15
15
|
import { buildBoard, watchTasks, toneOf, laneMoves, cardMoves, BoardState, attachmentTabs, isDiff, diffTones, dataLang, dataLoad, dataSpans, newTaskText, createTask, saveTask, TaskConflict, watchAgents } from "./ase-task-board-core.js";
|
|
16
|
+
import { diffHunks, diffMarkdown, diffMarksToHTML } from "./ase-task-board-diff.js";
|
|
16
17
|
import { layoutGraph, drawGraphSVG } from "./ase-task-board-graph.js";
|
|
17
18
|
import { flowOf, layoutFlow, drawFlowSVG } from "./ase-task-board-flow.js";
|
|
18
19
|
import { filterBoard, dropStandalone } from "./ase-task-board-filter.js";
|
|
@@ -94,9 +95,9 @@ const markedLoad = async (remote) => {
|
|
|
94
95
|
(title ? ` title="${escapeHTML(title)}"` : "") + ">" : escapeHTML(text);
|
|
95
96
|
},
|
|
96
97
|
code({ text, lang }) {
|
|
97
|
-
if (lang === "mermaid") {
|
|
98
|
+
if (lang === "mermaid" && !text.includes("⟦chg:")) {
|
|
98
99
|
try {
|
|
99
|
-
return `<div class="diagram">${renderMermaidSVG(text)}</div>`;
|
|
100
|
+
return `<div class="diagram">${renderMermaidSVG(text, { bg: "var(--c-paper)", fg: "var(--c-text)" })}</div>`;
|
|
100
101
|
}
|
|
101
102
|
catch {
|
|
102
103
|
/* fall through to the plain rendering of the source */
|
|
@@ -119,12 +120,12 @@ const renderPlan = async (body, remote = false) => {
|
|
|
119
120
|
const outside = fence === "";
|
|
120
121
|
fence = TaskFormat.fenceTrack(fence, line);
|
|
121
122
|
return !outside || fence !== "" ? line : line
|
|
122
|
-
.replace(/^(\s*(?:[-*]|\d+[.)])\s+)\[([ x/?\->])\]/, (_m, lead, box) => `${lead}⟦box:${boxes[box]}⟧`);
|
|
123
|
+
.replace(/^(\s*(?:[-*]|\d+[.)])\s+(?:⟦chg:[a-z-]+⟧)?)\[([ x/?\->])\]/, (_m, lead, box) => `${lead}⟦box:${boxes[box]}⟧`);
|
|
123
124
|
}).join("\n");
|
|
124
125
|
if (!marked.has(remote))
|
|
125
126
|
marked.set(remote, markedLoad(remote));
|
|
126
127
|
const html = (await marked.get(remote)).parse(prepared, { async: false });
|
|
127
|
-
return html.replace(/⟦box:([a-z]+)⟧/g, (_m, state) => `<span class="box ${state}" title="[${escapeHTML(boxChars[state] ?? " ")}]"></span>`);
|
|
128
|
+
return diffMarksToHTML(html.replace(/⟦box:([a-z]+)⟧/g, (_m, state) => `<span class="box ${state}" title="[${escapeHTML(boxChars[state] ?? " ")}]"></span>`));
|
|
128
129
|
};
|
|
129
130
|
const colorRoles = Object.keys(webColorDefaults);
|
|
130
131
|
const colorBases = (log) => {
|
|
@@ -154,10 +155,18 @@ const editorKeymap = (log) => {
|
|
|
154
155
|
const value = cfg.get("board.web.editor.keymap");
|
|
155
156
|
return value === "vim" || value === "emacs" ? value : "default";
|
|
156
157
|
};
|
|
157
|
-
/*
|
|
158
|
-
|
|
158
|
+
/* the color theme of the web board, resolved from the
|
|
159
|
+
"board.web.theme" configuration (on each page load) */
|
|
160
|
+
const boardTheme = (log) => {
|
|
161
|
+
const cfg = new Config("config", configSchema, log);
|
|
162
|
+
cfg.read();
|
|
163
|
+
const value = cfg.get("board.web.theme");
|
|
164
|
+
return value === "light" || value === "dark" ? value : "auto";
|
|
165
|
+
};
|
|
166
|
+
/* render a standalone document (styled by the client stylesheet) out of key/value
|
|
167
|
+
fields (optionally marked as added or removed), separated by a line from the content */
|
|
159
168
|
const fieldsDocument = (fields, content) => {
|
|
160
|
-
const rows = fields.map(([k, v]) => `<tr><td class="k">${escapeHTML(k)}</td><td>${escapeHTML(v)}</td></tr>`).join("");
|
|
169
|
+
const rows = fields.map(([k, v, mark]) => `<tr${mark !== undefined ? ` class="${mark}"` : ""}><td class="k">${escapeHTML(k)}</td><td>${escapeHTML(v)}</td></tr>`).join("");
|
|
161
170
|
return "<!DOCTYPE html><html><head><meta charset=\"utf-8\">" +
|
|
162
171
|
"<link rel=\"stylesheet\" href=\"/task-board/colors.css\">" +
|
|
163
172
|
"<link rel=\"stylesheet\" href=\"/task-board/ase-task-board-web-client.css\"></head><body class=\"plan\"><article>" +
|
|
@@ -166,6 +175,16 @@ const fieldsDocument = (fields, content) => {
|
|
|
166
175
|
};
|
|
167
176
|
/* render a task plan as a standalone document: frontmatter fields and the numbered plan sections */
|
|
168
177
|
const taskDocument = async (keys, body) => fieldsDocument([...keys].filter(([k]) => k !== "Type"), await renderPlan(body));
|
|
178
|
+
const isPlanText = (value) => {
|
|
179
|
+
const plan = value;
|
|
180
|
+
return typeof plan?.body === "string" && Array.isArray(plan.keys) && plan.keys.every((field) => Array.isArray(field) && field.length === 2 && field.every((text) => typeof text === "string"));
|
|
181
|
+
};
|
|
182
|
+
/* render the diff of two task plans as a standalone document, in the look of a task plan */
|
|
183
|
+
const diffDocument = async (before, after) => fieldsDocument(diffHunks(before.keys, after.keys, (field) => JSON.stringify(field)).flatMap(({ kept, removed, added }) => [
|
|
184
|
+
...kept,
|
|
185
|
+
...removed.map(([k, v]) => [k, v, "del"]),
|
|
186
|
+
...added.map(([k, v]) => [k, v, "add"])
|
|
187
|
+
]), await renderPlan(diffMarkdown(before.body, after.body)));
|
|
169
188
|
/* render a task plan attachment as a standalone document: its fields and
|
|
170
189
|
its content, with images embedded, Markdown rendered, YAML or JSON data syntax-highlighted, a diff
|
|
171
190
|
colored per line, binary content as a placeholder, and else verbatim text */
|
|
@@ -335,11 +354,13 @@ const guarded = (handler) => async (request, h) => {
|
|
|
335
354
|
};
|
|
336
355
|
/* register the page routes of the web board: its client assets and its colors */
|
|
337
356
|
const registerPageRoutes = (server, log) => {
|
|
338
|
-
/* the single page of the web board, with its stylesheet and browser-side code
|
|
357
|
+
/* the single page of the web board, with its stylesheet and browser-side code,
|
|
358
|
+
and with its color theme (resolved on each page load) on its root element */
|
|
339
359
|
server.route({
|
|
340
360
|
method: "GET",
|
|
341
361
|
path: "/task-board",
|
|
342
|
-
handler: (_request, h) => h.response(clientAsset("html")
|
|
362
|
+
handler: (_request, h) => h.response(clientAsset("html")
|
|
363
|
+
.replace(/<html\b/, `<html data-theme="${boardTheme(log)}"`)).type("text/html; charset=utf-8")
|
|
343
364
|
});
|
|
344
365
|
server.route({
|
|
345
366
|
method: "GET",
|
|
@@ -439,12 +460,26 @@ const registerViewRoutes = (server, log) => {
|
|
|
439
460
|
group: board.groups.find((g) => g.lanes.some((l) => l.status === card.status))?.title ?? "",
|
|
440
461
|
epic: card.group,
|
|
441
462
|
doc: await taskDocument(parts.keys, parts.body),
|
|
463
|
+
plan: { keys: [...parts.keys].filter(([k]) => k !== "Type"), body: parts.body },
|
|
442
464
|
tabs: attachmentTabs(await Task.attachments(log, id), parts.keys.get("Modified") ?? ""),
|
|
443
465
|
pred: ref(board.pred.get(id) ?? []),
|
|
444
466
|
succ: ref(board.succ.get(id) ?? [])
|
|
445
467
|
});
|
|
446
468
|
})
|
|
447
469
|
});
|
|
470
|
+
/* the diff of two states of a task plan, rendered statelessly out of the states
|
|
471
|
+
kept by the client, as the changes are followed per task dialog */
|
|
472
|
+
server.route({
|
|
473
|
+
method: "POST",
|
|
474
|
+
path: "/task-board/api/diff",
|
|
475
|
+
options: { payload: { parse: true, allow: "application/json" } },
|
|
476
|
+
handler: guarded(async (request, h) => {
|
|
477
|
+
const p = request.payload;
|
|
478
|
+
if (!isPlanText(p?.before) || !isPlanText(p.after))
|
|
479
|
+
return h.response({ error: "invalid diff request" }).code(400);
|
|
480
|
+
return h.response({ doc: await diffDocument(p.before, p.after) });
|
|
481
|
+
})
|
|
482
|
+
});
|
|
448
483
|
/* one task plan as text for editing, with the entity tag it is based on and the editor key bindings */
|
|
449
484
|
server.route({
|
|
450
485
|
method: "GET",
|
package/dst/ase-task-board.js
CHANGED
|
@@ -108,27 +108,35 @@ export default class TaskBoardCommand {
|
|
|
108
108
|
.option("--agent-relay <url>", "agent relay to receive the live presence of the agents from, " +
|
|
109
109
|
"as \"ase[s]://<addr>:<port>[/<token>]\" (default: the configured \"project.relay.url\", else none; " +
|
|
110
110
|
"the web board always follows the configured one)")
|
|
111
|
+
.option("-T, --task <id>", "show only the task dialog of the given task as a task viewer, " +
|
|
112
|
+
"following all its changes live (with --text or without a terminal: print its plan and exit)")
|
|
111
113
|
.action(async (opts) => {
|
|
114
|
+
/* refuse the task viewer on an unknown task */
|
|
115
|
+
const plan = opts.task !== undefined ? await Task.load(this.log, opts.task) : "";
|
|
116
|
+
if (opts.task !== undefined && plan === "")
|
|
117
|
+
throw new Error(`board: no task "${opts.task}"`);
|
|
112
118
|
/* serve and open the web board */
|
|
113
119
|
if (opts.web === true) {
|
|
114
120
|
if (opts.agentRelay !== undefined)
|
|
115
121
|
this.log.write("warning", "board: \"--agent-relay\" is ignored by the web board, " +
|
|
116
122
|
"which follows the configured \"project.relay.url\"");
|
|
117
|
-
const url = `http://${SERVICE_HOST}:${await this.servicePort()}/task-board
|
|
123
|
+
const url = `http://${SERVICE_HOST}:${await this.servicePort()}/task-board` +
|
|
124
|
+
(opts.task !== undefined ? `?task=${encodeURIComponent(opts.task)}` : "");
|
|
118
125
|
await writeStdout(`${url}\n`);
|
|
119
126
|
await this.openBrowser(url);
|
|
120
127
|
return;
|
|
121
128
|
}
|
|
122
|
-
/* print the plain text overview
|
|
129
|
+
/* print the plain text overview (resp. the plan of the task
|
|
130
|
+
of the task viewer) if requested or without a terminal */
|
|
123
131
|
if (opts.text === true || !process.stdout.isTTY || !process.stdin.isTTY) {
|
|
124
|
-
await writeStdout(await textOverview(this.log, opts.agentRelay));
|
|
132
|
+
await writeStdout(opts.task !== undefined ? plan : await textOverview(this.log, opts.agentRelay));
|
|
125
133
|
return;
|
|
126
134
|
}
|
|
127
135
|
/* run the interactive terminal board, with the production build of React
|
|
128
136
|
(its development build records a never cleared performance measure per render) */
|
|
129
137
|
process.env.NODE_ENV ??= "production";
|
|
130
138
|
const { runTUI } = await import("./ase-task-board-tui.js");
|
|
131
|
-
await runTUI(this.log, opts.agentRelay);
|
|
139
|
+
await runTUI(this.log, opts.agentRelay, opts.task);
|
|
132
140
|
});
|
|
133
141
|
}
|
|
134
142
|
}
|
|
@@ -5,10 +5,9 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import path from "node:path";
|
|
7
7
|
import fs from "node:fs";
|
|
8
|
-
import { ofetch } from "ofetch";
|
|
9
|
-
import { Agent } from "undici";
|
|
10
8
|
import { WebSocket } from "ws";
|
|
11
9
|
import { LRUCache } from "lru-cache";
|
|
10
|
+
import { dispatchFetch, insecureAgent } from "./ase-lib-fetch.js";
|
|
12
11
|
import { Config } from "./ase-config-core.js";
|
|
13
12
|
import { configSchema } from "./ase-config-schema.js";
|
|
14
13
|
import { parseScope, userStateDir } from "./ase-config-scope.js";
|
|
@@ -217,7 +216,7 @@ export class RemoteTaskStoreClient {
|
|
|
217
216
|
this.insecure = insecure;
|
|
218
217
|
this.lifecycle = configured;
|
|
219
218
|
this.idscheme = configuredIdScheme;
|
|
220
|
-
this.dispatcher = insecure ?
|
|
219
|
+
this.dispatcher = insecure ? insecureAgent() : undefined;
|
|
221
220
|
}
|
|
222
221
|
/* raise a failed connection as an unreachable store error,
|
|
223
222
|
reporting the innermost cause (like "connect ECONNREFUSED") */
|
|
@@ -232,7 +231,7 @@ export class RemoteTaskStoreClient {
|
|
|
232
231
|
a null result, any other error response is raised as a problem carrying
|
|
233
232
|
its status, and a failed connection is raised as an unreachable store error */
|
|
234
233
|
async request(method, url, body, headers = {}, tolerated = []) {
|
|
235
|
-
const r = await
|
|
234
|
+
const r = await dispatchFetch.raw(`${this.base}${url}`, {
|
|
236
235
|
method,
|
|
237
236
|
headers: {
|
|
238
237
|
Authorization: `Bearer ${this.token}`,
|
|
@@ -408,7 +407,7 @@ export class RemoteTaskStoreClient {
|
|
|
408
407
|
return await this.task(await this.request("POST", `${this.tasks}/${encodeURIComponent(id)}/attachment${append ? "?append=true" : ""}`, attachment)) !== null;
|
|
409
408
|
}
|
|
410
409
|
async content(id, index) {
|
|
411
|
-
const r = await
|
|
410
|
+
const r = await dispatchFetch.raw(`${this.base}${this.tasks}/${encodeURIComponent(id)}/attachment/${index}/content`, {
|
|
412
411
|
headers: { Authorization: `Bearer ${this.token}` },
|
|
413
412
|
responseType: "arrayBuffer",
|
|
414
413
|
dispatcher: this.dispatcher,
|
|
@@ -63,7 +63,8 @@ file lock and atomically.
|
|
|
63
63
|
`project.task.effort.line` `0.025`,
|
|
64
64
|
`project.task.effort.iteration` `2.5`, the full set of
|
|
65
65
|
`project.artifact.*` globs, the `board.tui.color.*`,
|
|
66
|
-
`board.web.color.*`,
|
|
66
|
+
`board.web.color.*`, `board.web.editor.keymap`, and
|
|
67
|
+
`board.web.theme` defaults, and
|
|
67
68
|
`telemetry.enabled` `false`, `telemetry.prices.ai`
|
|
68
69
|
`*=4.00/20.00/0.20/5.00`, and `telemetry.prices.hr` `*=110`.
|
|
69
70
|
- `vibe`:
|
package/dst/man/ase-config.md
CHANGED
|
@@ -361,6 +361,11 @@ Task board (all writable on the `user` and `project` scopes only, see
|
|
|
361
361
|
The key bindings of the task plan editor of the web board (default:
|
|
362
362
|
`default`).
|
|
363
363
|
|
|
364
|
+
- `board.web.theme` (`auto`, `light`, or `dark`):
|
|
365
|
+
The color theme of the web board, where `auto` follows the light or
|
|
366
|
+
dark preference of the operating system resp. browser (default:
|
|
367
|
+
`auto`).
|
|
368
|
+
|
|
364
369
|
## ENVIRONMENT
|
|
365
370
|
|
|
366
371
|
- `EDITOR`, `VISUAL`:
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
\[`-w`|`--web`\]
|
|
8
8
|
\[`-t`|`--text`\]
|
|
9
9
|
\[`--agent-relay` *url*\]
|
|
10
|
+
\[`-T`|`--task` *id*\]
|
|
10
11
|
|
|
11
12
|
## DESCRIPTION
|
|
12
13
|
|
|
@@ -89,6 +90,11 @@ set snapshot `kind="changeset"` of the `implementer` and `integrator`
|
|
|
89
90
|
agents) is colored per line, YAML and JSON data are syntax-highlighted,
|
|
90
91
|
and a change set snapshot older than the plan is marked `(stale)`.
|
|
91
92
|
|
|
93
|
+
While the task dialog is open, the last change of the shown plan is displayed
|
|
94
|
+
as a diff in the plan tab, with the removed and added lines colored (in the
|
|
95
|
+
terminal board also signed) and their changed words shown inverse, until `#` clears it or a next change
|
|
96
|
+
replaces it. Closing the task dialog or switching to another task drops it.
|
|
97
|
+
|
|
92
98
|
A task is moved into another state (changing its `Status:`) either by
|
|
93
99
|
picking it up with `SPACE` and dropping it with a second `SPACE` onto
|
|
94
100
|
the selected lane (only lanes whose state is reachable from the current
|
|
@@ -214,6 +220,26 @@ waiting) with their status and their last processing log line, and
|
|
|
214
220
|
finally all warnings of the board (behind `⚠`, e.g. on dependency
|
|
215
221
|
cycles).
|
|
216
222
|
|
|
223
|
+
### Task Viewer
|
|
224
|
+
|
|
225
|
+
With `--task`, the terminal and the web board act as a *task viewer*:
|
|
226
|
+
instead of the board, they show only the task dialog of the given task,
|
|
227
|
+
spanning the entire window and following all changes of the task live.
|
|
228
|
+
All actions of the task dialog stay available, and a click onto a
|
|
229
|
+
predecessor or successor shows that task instead. The shown view of the
|
|
230
|
+
board stays untouched. An unknown task is refused with an error.
|
|
231
|
+
|
|
232
|
+
The terminal board quits on `q` or `Ctrl`+`C` only, and with a warning
|
|
233
|
+
once the shown task no longer exists (e.g. as it was deleted or renamed
|
|
234
|
+
elsewhere).
|
|
235
|
+
|
|
236
|
+
The web board has no closing keys, as a page cannot close its browser
|
|
237
|
+
tab. Once the shown task no longer exists, it shows only a notice, and
|
|
238
|
+
shows the task again as soon as it exists again.
|
|
239
|
+
|
|
240
|
+
With `--text`, and also without an interactive terminal, the plan of the
|
|
241
|
+
task is printed as plain text and the command exits.
|
|
242
|
+
|
|
217
243
|
### Statistics View
|
|
218
244
|
|
|
219
245
|
The third view *statistics* shows the statistics of the tasks matching the
|
|
@@ -410,6 +436,10 @@ relay, the agent graph view is skipped.
|
|
|
410
436
|
board always follows the configured `project.relay.url` (and hence
|
|
411
437
|
warns about the option).
|
|
412
438
|
|
|
439
|
+
- \[`-T`|`--task` *id*\]:
|
|
440
|
+
Show only the task dialog of the task *id* instead of the board, as a
|
|
441
|
+
viewer and watcher of the task (see **Task Viewer**).
|
|
442
|
+
|
|
413
443
|
## KEYS
|
|
414
444
|
|
|
415
445
|
The following keys are supported by the terminal board (and, unless
|
|
@@ -426,6 +456,9 @@ letter under the kitty keyboard protocol.
|
|
|
426
456
|
views).
|
|
427
457
|
- `?`: Hide or show the key hint lines (persisted); while hidden, the
|
|
428
458
|
information line ends with `?: show key hints`.
|
|
459
|
+
- `L`: Cycle the color theme through `auto`, `light`, and `dark`,
|
|
460
|
+
overriding `board.web.theme` in the current browser until cycled back
|
|
461
|
+
to its value (web board only).
|
|
429
462
|
- `D`: Delete the selected task, after a confirmation (not in the
|
|
430
463
|
agent logs and statistics views).
|
|
431
464
|
- `T`: Transfer the selected task to another state via the transfer
|
|
@@ -515,7 +548,8 @@ letter under the kitty keyboard protocol.
|
|
|
515
548
|
- `↑`/`↓`: Scroll the content.
|
|
516
549
|
- `PgUp`/`PgDn`: Scroll the content by one page.
|
|
517
550
|
- `e`: Edit the task plan.
|
|
518
|
-
-
|
|
551
|
+
- `#`: Clear the diff of the last change of the task plan.
|
|
552
|
+
- `D`, `T`, `A`, `E`, `R`, `M`, `L`: As in every view.
|
|
519
553
|
- `⏎`, `ESC`: Close the task dialog.
|
|
520
554
|
|
|
521
555
|
### Filter Field
|
|
@@ -594,6 +628,11 @@ The following configuration keys (on scope `user` or `project`, see
|
|
|
594
628
|
The key bindings of the task plan editor of the web board: `default`,
|
|
595
629
|
`vim`, or `emacs` (default: `default`).
|
|
596
630
|
|
|
631
|
+
- `board.web.theme`:
|
|
632
|
+
The color theme of the web board: `light`, `dark`, or `auto`, which
|
|
633
|
+
follows the light or dark preference of the operating system resp.
|
|
634
|
+
browser (default: `auto`).
|
|
635
|
+
|
|
597
636
|
- `project.relay.url`:
|
|
598
637
|
The default agent relay of the boards (see `--agent-relay`).
|
|
599
638
|
|
|
@@ -625,7 +664,7 @@ The following configuration keys (on scope `user` or `project`, see
|
|
|
625
664
|
The command exits with status `0` once the terminal board is quit, the
|
|
626
665
|
text overview is printed, resp. the web board is opened, and with
|
|
627
666
|
status `1` on any error (e.g. an *ASE* service without web board on
|
|
628
|
-
`--web`).
|
|
667
|
+
`--web`, or an unknown task on `--task`).
|
|
629
668
|
|
|
630
669
|
## EXAMPLES
|
|
631
670
|
|
|
@@ -636,6 +675,9 @@ $ ase task board
|
|
|
636
675
|
# show the web board in the browser
|
|
637
676
|
$ ase task board --web
|
|
638
677
|
|
|
678
|
+
# view and watch a single task in the terminal
|
|
679
|
+
$ ase task board --task T1
|
|
680
|
+
|
|
639
681
|
# print the lane overview, including the agents of a remote agent relay
|
|
640
682
|
$ ase task board --text --agent-relay ase://relay.example.com:42043
|
|
641
683
|
```
|
package/package.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"homepage": "https://ase.tools",
|
|
7
7
|
"repository": { "url": "git+https://github.com/rse/ase.git", "type": "git" },
|
|
8
8
|
"bugs": { "url": "https://github.com/rse/ase/issues" },
|
|
9
|
-
"version": "2.0.
|
|
9
|
+
"version": "2.0.8",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"author": {
|
|
12
12
|
"name": "Dr. Ralf S. Engelschall",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"globals": "17.14.0",
|
|
32
32
|
"typescript": "6.0.3",
|
|
33
33
|
"eslint-plugin-vue": "10.12.0",
|
|
34
|
-
"vue-eslint-parser": "10.4.
|
|
34
|
+
"vue-eslint-parser": "10.4.2",
|
|
35
35
|
"vue-tsc": "3.3.14",
|
|
36
36
|
|
|
37
37
|
"@rse/stx": "1.1.7",
|
|
@@ -39,9 +39,9 @@
|
|
|
39
39
|
"shx": "0.4.0",
|
|
40
40
|
"sync-directory": "6.0.6",
|
|
41
41
|
"stylus": "0.64.0",
|
|
42
|
-
"vite": "8.3.
|
|
42
|
+
"vite": "8.3.6",
|
|
43
43
|
"@vitejs/plugin-vue": "6.0.10",
|
|
44
|
-
"vue": "3.5.
|
|
44
|
+
"vue": "3.5.45",
|
|
45
45
|
"mousetrap": "1.6.5",
|
|
46
46
|
"@codemirror/view": "6.43.15",
|
|
47
47
|
"@codemirror/state": "6.7.6",
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
"valibot": "1.5.0",
|
|
79
79
|
"execa": "10.2.1",
|
|
80
80
|
"mkdirp": "3.0.1",
|
|
81
|
-
"@hapi/hapi": "21.4.
|
|
81
|
+
"@hapi/hapi": "21.4.13",
|
|
82
82
|
"beautiful-mermaid": "1.1.3",
|
|
83
83
|
"@d2lang/d2": "0.1.34",
|
|
84
84
|
"elkjs": "0.12.1",
|
|
@@ -87,6 +87,7 @@
|
|
|
87
87
|
"react": "19.3.1",
|
|
88
88
|
"chokidar": "6.0.0",
|
|
89
89
|
"marked": "18.1.3",
|
|
90
|
+
"diff": "9.0.0",
|
|
90
91
|
"shiki": "4.6.0",
|
|
91
92
|
"cli-table3": "0.6.5",
|
|
92
93
|
"chalk": "6.0.1",
|
|
@@ -105,7 +106,7 @@
|
|
|
105
106
|
"p-queue": "10.0.0",
|
|
106
107
|
"pacote": "22.0.1",
|
|
107
108
|
"ofetch": "1.5.1",
|
|
108
|
-
"undici": "8.12.
|
|
109
|
+
"undici": "8.12.4",
|
|
109
110
|
"picomatch": "4.0.7",
|
|
110
111
|
"lru-cache": "11.5.3",
|
|
111
112
|
"@rse/specbook": "1.6.2",
|
|
@@ -58,6 +58,30 @@ Task Skill Common Steps
|
|
|
58
58
|
|
|
59
59
|
</define>
|
|
60
60
|
|
|
61
|
+
<define name="task-focus">
|
|
62
|
+
|
|
63
|
+
Resolve the plan sections under focus: treat <getopt-option-focus/> as a
|
|
64
|
+
comma-separated list of *section tokens*. Trim every token, then expand
|
|
65
|
+
the synonyms `SPEC` and `WHAT` to `SPECIFICATION`, the synonyms `DES` and
|
|
66
|
+
`HOW` to `DESIGN`, and the synonyms `VERIFY`, `VER`, and `WHEN` to
|
|
67
|
+
`VERIFICATION`, and expand the sentinel `all` (the default) to
|
|
68
|
+
`SPECIFICATION,DESIGN,VERIFICATION`. Set <sections/> to the resulting
|
|
69
|
+
list, *keeping the given order*. The getopt parser validates only the
|
|
70
|
+
*first* token, so you *MUST* validate each token yourself: if any token
|
|
71
|
+
is *empty*, *not* one of the recognized sections or synonyms (matched
|
|
72
|
+
*case-sensitively*), or results in a section already present in
|
|
73
|
+
<sections/>, bind <token/> to that offending token, then only output the
|
|
74
|
+
following <template/> and immediately *STOP* processing the entire
|
|
75
|
+
current skill:
|
|
76
|
+
|
|
77
|
+
<template>
|
|
78
|
+
⧉ **ASE**: ☻ skill: **<arg1/>**, ▶ ERROR: invalid `--focus` token: **<token/>**
|
|
79
|
+
</template>
|
|
80
|
+
|
|
81
|
+
Do not output anything else.
|
|
82
|
+
|
|
83
|
+
</define>
|
|
84
|
+
|
|
61
85
|
<define name="task-load-content">
|
|
62
86
|
|
|
63
87
|
<if condition="
|