slidemind 0.3.20 → 0.4.0
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/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/AGENTS.md +591 -15
- package/README.md +202 -7
- package/bin/slidemind.mjs +50 -2
- package/package.json +2 -2
- package/skills/create-slides/SKILL.md +484 -886
- package/skills/search/SKILL.md +46 -23
- package/src/bridge/build-and-push.mjs +548 -73
- package/src/bridge/bundle.mjs +100 -31
- package/src/bridge/capture.mjs +14 -17
- package/src/bridge/client/brands.mjs +157 -18
- package/src/bridge/client/engine-routing.mjs +48 -13
- package/src/bridge/client/engine-search.mjs +24 -1
- package/src/bridge/client/render.mjs +27 -1
- package/src/bridge/client/transport.mjs +499 -23
- package/src/bridge/client.mjs +10 -0
- package/src/bridge/config.mjs +67 -6
- package/src/bridge/engine-download.mjs +0 -10
- package/src/bridge/graph-auth.mjs +55 -3
- package/src/bridge/image-intent-envelope.mjs +239 -0
- package/src/bridge/package-preview.mjs +67 -0
- package/src/bridge/sharepoint.mjs +914 -0
- package/src/builders/asset-fetch.mjs +203 -0
- package/src/builders/block-dividers.mjs +83 -0
- package/src/builders/build.mjs +171 -87
- package/src/builders/card-height.mjs +294 -0
- package/src/builders/chart-hole.mjs +183 -0
- package/src/builders/chart-jsx.mjs +410 -0
- package/src/builders/chart-labels.mjs +326 -0
- package/src/builders/concept-geometry.mjs +370 -0
- package/src/builders/concept-intent.mjs +200 -0
- package/src/builders/concept-layout.mjs +79 -0
- package/src/builders/concept-lines.mjs +509 -0
- package/src/builders/concept-lists.mjs +270 -0
- package/src/builders/concept-marks.mjs +84 -0
- package/src/builders/concept-relationships.mjs +12 -0
- package/src/builders/concept-spec.mjs +645 -0
- package/src/builders/concept-text.mjs +140 -0
- package/src/builders/concept-waves.mjs +57 -0
- package/src/builders/copy-fit.mjs +139 -0
- package/src/builders/design-tokens.mjs +347 -0
- package/src/builders/draft-check.mjs +552 -340
- package/src/builders/draft-lines.mjs +369 -0
- package/src/builders/edit-route.mjs +29 -0
- package/src/builders/figure-sketch.mjs +375 -0
- package/src/builders/fold-sets.mjs +639 -0
- package/src/builders/gate-server.mjs +9 -4
- package/src/builders/gate-session.js +273 -12
- package/src/builders/gate-shell.js +1494 -0
- package/src/builders/image-intent-check.mjs +308 -0
- package/src/builders/image-use-reconcile.mjs +107 -0
- package/src/builders/kit-helpers.mjs +121 -0
- package/src/builders/layout-names.mjs +32 -0
- package/src/builders/legacy-reference-uses.mjs +179 -0
- package/src/builders/line-fit.mjs +224 -0
- package/src/builders/line-native.mjs +895 -0
- package/src/builders/line-relations.mjs +230 -0
- package/src/builders/lint-fix.mjs +117 -9
- package/src/builders/lint.mjs +25 -20
- package/src/builders/list-jsx.mjs +88 -0
- package/src/builders/placement.mjs +133 -0
- package/src/builders/plan-checks.mjs +135 -0
- package/src/builders/plan-comments.mjs +19 -0
- package/src/builders/plan-handlers.mjs +95 -0
- package/src/builders/plan-markdown-edit.mjs +3 -3
- package/src/builders/plan-overlay.js +1530 -1608
- package/src/builders/plan.mjs +689 -186
- package/src/builders/preset-definitions.json +1 -0
- package/src/builders/preset-eval.mjs +244 -0
- package/src/builders/preview.html +51 -120
- package/src/builders/red-thread-backbone.mjs +135 -36
- package/src/builders/repair.mjs +205 -0
- package/src/builders/repeat-groups.mjs +540 -0
- package/src/builders/resolve-skill.mjs +5 -4
- package/src/builders/review-overlay.js +296 -293
- package/src/builders/review.mjs +305 -84
- package/src/builders/rule-shift.mjs +96 -0
- package/src/builders/seat.mjs +354 -0
- package/src/builders/settle-driver.mjs +236 -0
- package/src/builders/settle.mjs +1448 -0
- package/src/builders/slide-prep.mjs +67 -0
- package/src/builders/spec-assets.mjs +236 -0
- package/src/builders/spec-match.mjs +56 -0
- package/src/builders/stack.mjs +413 -0
- package/src/builders/storyboard-markdown.mjs +70 -27
- package/src/builders/storyboard-schema.mjs +54 -114
- package/src/builders/text-blocks.mjs +212 -0
- package/src/builders/text-card-fit.mjs +552 -0
- package/src/builders/text-stack.mjs +276 -0
- package/src/builders/transcribe.mjs +1069 -0
- package/src/cli/assets.mjs +164 -0
- package/src/cli/common.mjs +173 -12
- package/src/cli/concept-spec-support.mjs +76 -0
- package/src/cli/concepts.mjs +1002 -103
- package/src/cli/deck.mjs +401 -65
- package/src/cli/diagnose.mjs +4 -2
- package/src/cli/engine-helpers.mjs +17 -10
- package/src/cli/engine-results.mjs +76 -3
- package/src/cli/help.mjs +232 -28
- package/src/cli/install.mjs +9 -0
- package/src/cli/maintenance.mjs +104 -0
- package/src/cli/read.mjs +2 -1
- package/src/cli/ready.mjs +6 -3
- package/src/cli/record.mjs +522 -0
- package/src/cli/remote.mjs +818 -0
- package/src/cli/revision.mjs +686 -0
- package/src/cli/search.mjs +30 -11
- package/src/cli/session.mjs +56 -13
- package/src/cli/setup.mjs +46 -2
- package/src/cli/status.mjs +142 -33
- package/src/cli/tasks.mjs +246 -0
- package/src/cli/transcribe.mjs +854 -0
- package/src/cli/workspace-ui.mjs +260 -0
- package/src/cli/workspace.mjs +212 -34
- package/src/install-channel.mjs +64 -7
- package/src/lib/adopt.mjs +346 -25
- package/src/lib/concept-spec-binding.mjs +96 -0
- package/src/lib/conversions.mjs +70 -6
- package/src/lib/convert-folded.mjs +107 -0
- package/src/lib/deck-paths.mjs +418 -0
- package/src/lib/durable-ids.mjs +47 -0
- package/src/lib/edit-operations.mjs +316 -0
- package/src/lib/edit-state.mjs +1244 -0
- package/src/lib/edit-transitions.mjs +120 -0
- package/src/lib/extensions.mjs +501 -0
- package/src/lib/image-assets.mjs +465 -0
- package/src/lib/image-derivatives.mjs +234 -0
- package/src/lib/image-intent-fingerprint.mjs +70 -0
- package/src/lib/image-intent-tags.mjs +176 -0
- package/src/lib/image-intent.mjs +802 -0
- package/src/lib/image-use-overrides.mjs +279 -0
- package/src/lib/inline-components.mjs +613 -0
- package/src/lib/lint-converted.mjs +68 -4
- package/src/lib/merge-json.mjs +163 -0
- package/src/lib/overwrite-guard.mjs +3 -3
- package/src/lib/presentation-context.mjs +531 -0
- package/src/lib/preservation-tags.mjs +157 -0
- package/src/lib/preservation-verdict.mjs +1342 -0
- package/src/lib/publish.mjs +1557 -0
- package/src/lib/rebase.mjs +945 -0
- package/src/lib/reconcile-ack.mjs +4 -6
- package/src/lib/reconcile.mjs +62 -24
- package/src/lib/record-client.mjs +175 -0
- package/src/lib/record-state.mjs +151 -0
- package/src/lib/remote.mjs +661 -0
- package/src/lib/revision.mjs +1210 -0
- package/src/lib/slide-guids.mjs +4 -6
- package/src/lib/slide-preservation.mjs +423 -0
- package/src/lib/slide-selection.mjs +9 -0
- package/src/lib/workspace-transaction.mjs +117 -0
- package/src/pptx/content-digest.mjs +334 -0
- package/src/pptx/deck-assemble.mjs +1278 -0
- package/src/pptx/fill/engine.mjs +2 -3
- package/src/pptx/fill/freeform.mjs +6 -3
- package/src/pptx/ooxml.mjs +20 -0
- package/src/pptx/package-evidence.mjs +383 -0
- package/src/pptx/tags.mjs +163 -11
- package/src/update-check.mjs +22 -4
- package/src/workspace/adapters.mjs +222 -0
- package/src/workspace/auth.mjs +256 -0
- package/src/workspace/autostart.mjs +204 -0
- package/src/workspace/daemon.mjs +360 -0
- package/src/workspace/discovery.mjs +180 -0
- package/src/workspace/edit.mjs +167 -0
- package/src/workspace/events.mjs +52 -0
- package/src/workspace/gate-client.mjs +290 -0
- package/src/workspace/handback.mjs +73 -0
- package/src/workspace/lifecycle.mjs +635 -0
- package/src/workspace/operations.mjs +200 -0
- package/src/workspace/pick-folder.mjs +152 -0
- package/src/workspace/registry.mjs +359 -0
- package/src/workspace/remote-links.mjs +397 -0
- package/src/workspace/remote-status.mjs +359 -0
- package/src/workspace/routes.mjs +1331 -0
- package/src/workspace/server.mjs +159 -0
- package/src/workspace/sync.mjs +1119 -0
- package/src/workspace/task-actions.mjs +215 -0
- package/src/workspace/tasks.mjs +507 -0
- package/src/workspace/ui/app.js +1886 -0
- package/src/workspace/ui/index.html +141 -0
- package/src/workspace/ui/plan-bridge.js +120 -0
- package/src/workspace/ui/sharepoint.svg +59 -0
- package/src/workspace/ui/styles.css +423 -0
- package/src/builders/visual-families.mjs +0 -46
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
// `slidemind tasks …` — the agent's side of durable tasks (contracts §1).
|
|
2
|
+
//
|
|
3
|
+
// tasks list [<deck>] [--status pending] --json
|
|
4
|
+
// tasks request <deck> --kind <kind> --json derive the subject, dedupe → { task, link, say } — returns at once
|
|
5
|
+
// tasks get <deck> <id> --json the answer; records that the caller received it
|
|
6
|
+
// tasks wait <deck> <id> [--timeout 45] --json scripts only: saved answer first, bounded wait → { task, pending }
|
|
7
|
+
//
|
|
8
|
+
// An agent never waits: it ends its turn with `say`, and the user's pasted
|
|
9
|
+
// message names `tasks get` (doc 21 → *Tasks and agent continuation*).
|
|
10
|
+
//
|
|
11
|
+
// Exit codes: 0 done (a pending wait is a successful read), 1 operational,
|
|
12
|
+
// 2 blocked/busy/incompatible, 3 conflict/stale. One JSON value on stdout under
|
|
13
|
+
// --json; diagnostics on stderr. The code lands on process.exitCode so bin's
|
|
14
|
+
// post-command hooks still run.
|
|
15
|
+
|
|
16
|
+
import fs from "node:fs";
|
|
17
|
+
import path from "node:path";
|
|
18
|
+
|
|
19
|
+
import { deckRoot as rootOf, planPageOwner, resolveWorkspace } from "../lib/deck-paths.mjs";
|
|
20
|
+
import { resolveWorkspaceAdapter } from "../workspace/adapters.mjs";
|
|
21
|
+
import { daemonRequest, ensureRunning, registerDeck, workspaceStatus } from "../workspace/lifecycle.mjs";
|
|
22
|
+
import { askBlocker } from "../workspace/gate-client.mjs";
|
|
23
|
+
import { sayLine, viewOf } from "../workspace/handback.mjs";
|
|
24
|
+
import { browserUrl } from "./workspace-ui.mjs";
|
|
25
|
+
import { listDecks } from "../workspace/registry.mjs";
|
|
26
|
+
import { deriveTaskSubject } from "../workspace/task-actions.mjs";
|
|
27
|
+
import { KINDS, getTask, listTasks, markPickedUp, requestTask, waitTask } from "../workspace/tasks.mjs";
|
|
28
|
+
import { resolveDeckArg } from "./common.mjs";
|
|
29
|
+
|
|
30
|
+
const EXIT_BY_CODE = {
|
|
31
|
+
deck_busy: 2,
|
|
32
|
+
workspace_sandboxed: 2,
|
|
33
|
+
deck_not_writable: 2,
|
|
34
|
+
workspace_unavailable: 2,
|
|
35
|
+
extension_missing: 2,
|
|
36
|
+
extension_incompatible: 2,
|
|
37
|
+
recovery_required: 2,
|
|
38
|
+
workspace_upgrade_required: 2,
|
|
39
|
+
stale_subject: 3,
|
|
40
|
+
local_conflict: 3,
|
|
41
|
+
unknown_task: 1,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
function parse(rest) {
|
|
45
|
+
const flags = { json: false, status: null, kind: null, timeout: 45 };
|
|
46
|
+
const positional = [];
|
|
47
|
+
for (let i = 0; i < rest.length; i++) {
|
|
48
|
+
const a = rest[i];
|
|
49
|
+
if (a === "--json") flags.json = true;
|
|
50
|
+
else if (a === "--status") flags.status = rest[++i];
|
|
51
|
+
else if (a === "--kind") flags.kind = rest[++i];
|
|
52
|
+
else if (a === "--timeout") flags.timeout = Number(rest[++i]);
|
|
53
|
+
else if (a.startsWith("--")) throw usage(`unknown flag ${a}`);
|
|
54
|
+
else positional.push(a);
|
|
55
|
+
}
|
|
56
|
+
if (!Number.isFinite(flags.timeout) || flags.timeout < 0) throw usage("--timeout expects seconds");
|
|
57
|
+
return { flags, positional };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const usage = (msg) => Object.assign(new Error(msg), { code: "usage" });
|
|
61
|
+
|
|
62
|
+
function emit(flags, payload, human) {
|
|
63
|
+
process.stdout.write(flags.json ? JSON.stringify(payload) + "\n" : human + "\n");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** The registry entry for a deck path when it has one; the path alone otherwise. */
|
|
67
|
+
function registered(deckRoot) {
|
|
68
|
+
let real = deckRoot;
|
|
69
|
+
try {
|
|
70
|
+
real = fs.realpathSync(deckRoot);
|
|
71
|
+
} catch {}
|
|
72
|
+
return listDecks({ hidden: true, limit: Infinity }).decks.find((d) => d.path === real) ?? { id: null, path: real };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const taskLine = (t, deck = "") => `${t.status.padEnd(10)} ${t.kind.padEnd(15)} ${t.id}${deck ? ` ${deck}` : ""}`;
|
|
76
|
+
|
|
77
|
+
/** What a settled task says, in one human line (a superseded or dismissed task has no response). */
|
|
78
|
+
function outcomeLine(t) {
|
|
79
|
+
if (t.status === "completed") return `${t.response?.action ?? "answered"} by ${t.response?.actor ?? "the user"}${t.response?.comment ? `:\n${t.response.comment}` : ""}`;
|
|
80
|
+
if (t.status === "superseded") return "superseded — the content changed; ask again about the current version";
|
|
81
|
+
if (t.status === "cancelled") return "dismissed by the user without an answer — ask them in chat how to go on";
|
|
82
|
+
return t.status;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** The caller now holds the answer: record the receipt the workspace page reports. Best effort. */
|
|
86
|
+
async function received(deckRoot, task) {
|
|
87
|
+
if (task?.status !== "completed" || task.pickedUpAt) return task;
|
|
88
|
+
try {
|
|
89
|
+
return await markPickedUp(deckRoot, task.id);
|
|
90
|
+
} catch (err) {
|
|
91
|
+
process.stderr.write(`slidemind: could not record that the answer was received (${err.message})\n`);
|
|
92
|
+
return task;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* The page of the view the task is answered in, signing in whichever browser
|
|
98
|
+
* opens it, every time it is clicked; null when none is live. The agent pastes
|
|
99
|
+
* it for the user to click cold — it names the view, not the task, so a link
|
|
100
|
+
* from an earlier ask still opens the right place.
|
|
101
|
+
*/
|
|
102
|
+
export async function taskUrl(deckRoot, task) {
|
|
103
|
+
const s = await workspaceStatus();
|
|
104
|
+
if (!s.running) return null;
|
|
105
|
+
const entry = await registeredEntry(deckRoot);
|
|
106
|
+
return entry ? browserUrl({ deckId: entry.id, view: viewOf(task.kind) }) : null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** The deck's library entry (through the workspace when this process is sandboxed), or null with the reason on stderr. */
|
|
110
|
+
async function registeredEntry(deckRoot) {
|
|
111
|
+
try {
|
|
112
|
+
return await registerDeck(deckRoot);
|
|
113
|
+
} catch (err) {
|
|
114
|
+
process.stderr.write(`slidemind: the workspace could not list ${deckRoot}: ${err.message}\n`);
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** Tell an open workspace page about the question (SSE); best effort, never opens a browser. */
|
|
120
|
+
async function announce(deckRoot, task) {
|
|
121
|
+
const entry = await registeredEntry(deckRoot);
|
|
122
|
+
if (!entry?.id) return;
|
|
123
|
+
await daemonRequest(`/decks/${entry.id}/attention`, { method: "POST", body: { kind: task.kind, taskId: task.id }, timeoutMs: 3000 });
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** `tasks wait` as a long-poll on the daemon; null when it is not running or refuses. */
|
|
127
|
+
async function waitViaDaemon(deckRoot, taskId, timeoutS) {
|
|
128
|
+
const s = await workspaceStatus();
|
|
129
|
+
if (!s.running) return null;
|
|
130
|
+
const entry = await registeredEntry(deckRoot);
|
|
131
|
+
if (!entry?.id) return null;
|
|
132
|
+
try {
|
|
133
|
+
const { status, body } = await daemonRequest(`/decks/${entry.id}/tasks/${encodeURIComponent(taskId)}/wait?timeout=${Math.round(timeoutS)}`, {
|
|
134
|
+
timeoutMs: (timeoutS + 15) * 1000,
|
|
135
|
+
// an edit session's token rides along: the answer to this task re-enters it instead of meeting deck_busy
|
|
136
|
+
headers: process.env.SLIDEMIND_OWNER ? { "X-Slidemind-Owner": process.env.SLIDEMIND_OWNER } : {},
|
|
137
|
+
});
|
|
138
|
+
if (status !== 200 || !body?.ok || !body.task) return null;
|
|
139
|
+
return { task: body.task, pending: !!body.pending };
|
|
140
|
+
} catch {
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/** The task's subject, derived from the deck (task-actions.mjs) — never taken from the caller. */
|
|
146
|
+
async function deriveSubject(deckRoot, kind) {
|
|
147
|
+
const owner = planPageOwner(resolveWorkspace(deckRoot));
|
|
148
|
+
let adapter = null;
|
|
149
|
+
if (owner.owner !== "core") {
|
|
150
|
+
// `"extension"` is the generic marker for "a pack owns this page, but the deck
|
|
151
|
+
// never said which" — it is not an id. Passing it through named a pack that
|
|
152
|
+
// cannot exist in the blocker ("install the 'extension' pack"); null gets the
|
|
153
|
+
// honest `no adapter id`, which is what the other three call sites do.
|
|
154
|
+
adapter = resolveWorkspaceAdapter(owner.owner === "extension" ? null : owner.owner);
|
|
155
|
+
if (adapter.blocker) throw Object.assign(new Error(adapter.blocker.message), { code: adapter.blocker.code });
|
|
156
|
+
}
|
|
157
|
+
return deriveTaskSubject({ deckRoot, adapter, kind });
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export async function cmdTasks(rest) {
|
|
161
|
+
let flags;
|
|
162
|
+
try {
|
|
163
|
+
const parsed = parse(rest);
|
|
164
|
+
flags = parsed.flags;
|
|
165
|
+
const [sub, ...args] = parsed.positional;
|
|
166
|
+
const deckOf = (arg, what) => {
|
|
167
|
+
if (!arg) throw usage(`usage: slidemind tasks ${what}`);
|
|
168
|
+
return rootOf(resolveDeckArg(arg, { allowUnfinished: true }));
|
|
169
|
+
};
|
|
170
|
+
switch (sub) {
|
|
171
|
+
case "list": {
|
|
172
|
+
const decks = args[0] ? [registered(deckOf(args[0], "list [<deck>]"))] : listDecks().decks.filter((d) => !d.missing);
|
|
173
|
+
const tasks = [];
|
|
174
|
+
for (const d of decks) {
|
|
175
|
+
try {
|
|
176
|
+
for (const t of listTasks(d.path, { status: flags.status })) tasks.push({ ...t, deckId: d.id ?? null, deckPath: d.path });
|
|
177
|
+
} catch (err) {
|
|
178
|
+
process.stderr.write(`slidemind: ${d.path}: ${err.message}\n`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
emit(flags, { tasks }, tasks.map((t) => taskLine(t, t.deckPath)).join("\n") || "no tasks");
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
case "request": {
|
|
185
|
+
const deck = deckOf(args[0], "request <deck> --kind <kind>");
|
|
186
|
+
if (!KINDS[flags.kind]) throw usage(`--kind must be one of ${Object.keys(KINDS).join(", ")}`);
|
|
187
|
+
const { adapterId, subject } = await deriveSubject(deck, flags.kind);
|
|
188
|
+
// The human answers in the workspace, so a question needs one to answer in
|
|
189
|
+
// and a link into it; without them it is a blocker, never a linkless task.
|
|
190
|
+
let task;
|
|
191
|
+
let existing;
|
|
192
|
+
let url;
|
|
193
|
+
try {
|
|
194
|
+
await ensureRunning();
|
|
195
|
+
await registerDeck(deck);
|
|
196
|
+
({ task, existing } = await requestTask(deck, { kind: flags.kind, adapterId, subject }));
|
|
197
|
+
url = await taskUrl(deck, task);
|
|
198
|
+
} catch (err) {
|
|
199
|
+
const b = askBlocker(err, deck);
|
|
200
|
+
throw Object.assign(new Error(b.message), { code: b.code });
|
|
201
|
+
}
|
|
202
|
+
if (!url) {
|
|
203
|
+
const b = askBlocker(Object.assign(new Error("the workspace did not hand out a link to this deck (see above)"), { code: "workspace_unavailable" }), deck);
|
|
204
|
+
throw Object.assign(new Error(b.message), { code: b.code });
|
|
205
|
+
}
|
|
206
|
+
const say = sayLine(flags.kind, url);
|
|
207
|
+
// an open page shows the question at once; nothing opens a browser
|
|
208
|
+
await announce(deck, task).catch(() => {});
|
|
209
|
+
// `link` is the clickable one everywhere (`slidemind workspace` names it so too); `url` is kept for older callers
|
|
210
|
+
emit(flags, { task, existing, url, link: url, say }, `${existing ? "already open" : "requested"}: ${taskLine(task)}\nASK: ${url}\nSAY: ${say}\nEnd your turn now with the SAY line, word for word — do not wait or poll.`);
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
case "get": {
|
|
214
|
+
const deck = deckOf(args[0], "get <deck> <id>");
|
|
215
|
+
const found = args[1] && getTask(deck, args[1]);
|
|
216
|
+
if (!found) throw Object.assign(new Error(`no task ${args[1] ?? "<id>"} on this deck`), { code: "unknown_task" });
|
|
217
|
+
const task = await received(deck, found);
|
|
218
|
+
emit(flags, { task }, `${taskLine(task)}\n${outcomeLine(task)}`);
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
case "wait": {
|
|
222
|
+
const deck = deckOf(args[0], "wait <deck> <id> [--timeout 45]");
|
|
223
|
+
if (!args[1]) throw usage("usage: slidemind tasks wait <deck> <id>");
|
|
224
|
+
if (!getTask(deck, args[1])) throw Object.assign(new Error(`no task ${args[1]} on this deck`), { code: "unknown_task" });
|
|
225
|
+
// Through the running daemon when there is one, so the workspace page can
|
|
226
|
+
// SEE this wait (its "delivered" vs "tell your agent" wording rides on it);
|
|
227
|
+
// the file watcher is the fallback for a workspace that is not running.
|
|
228
|
+
const r = (await waitViaDaemon(deck, args[1], flags.timeout)) ?? (await waitTask(deck, args[1], { timeoutMs: flags.timeout * 1000 }));
|
|
229
|
+
if (!r.pending) r.task = await received(deck, r.task);
|
|
230
|
+
emit(flags, r, r.pending ? `still pending after ${flags.timeout}s: ${taskLine(r.task)}` : `${taskLine(r.task)}\n${outcomeLine(r.task)}`);
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
default:
|
|
234
|
+
throw usage("usage: slidemind tasks <list|request|get|wait> …");
|
|
235
|
+
}
|
|
236
|
+
} catch (err) {
|
|
237
|
+
const code = err?.code ?? "error";
|
|
238
|
+
const exit = code === "usage" ? 1 : EXIT_BY_CODE[code] ?? 1;
|
|
239
|
+
if (flags?.json) {
|
|
240
|
+
process.stdout.write(JSON.stringify({ ok: false, error: { code, message: err.message, retryable: exit === 2 } }) + "\n");
|
|
241
|
+
} else {
|
|
242
|
+
process.stderr.write(`slidemind: ${err.message}\n`);
|
|
243
|
+
}
|
|
244
|
+
process.exitCode = exit;
|
|
245
|
+
}
|
|
246
|
+
}
|