dotmd-cli 0.77.3 → 0.79.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/README.md +70 -60
- package/assets/opencode/plugin.js +45 -8
- package/bin/dotmd.mjs +274 -283
- package/package.json +2 -2
- package/scripts/postinstall.mjs +4 -4
- package/src/atomic-mutation.mjs +1 -1
- package/src/baton.mjs +86 -50
- package/src/check-collapse.mjs +5 -5
- package/src/claude-commands.mjs +6 -2
- package/src/commands.mjs +8 -8
- package/src/config.mjs +2 -2
- package/src/deps.mjs +1 -1
- package/src/doctor.mjs +17 -17
- package/src/fix-membership.mjs +1 -1
- package/src/frontmatter-fix.mjs +1 -1
- package/src/git.mjs +1 -1
- package/src/glossary.mjs +3 -3
- package/src/graph.mjs +1 -1
- package/src/guard.mjs +13 -10
- package/src/health.mjs +2 -2
- package/src/hints.mjs +7 -7
- package/src/host-integration.mjs +41 -22
- package/src/hub-membership.mjs +1 -1
- package/src/hud.mjs +14 -14
- package/src/index-file.mjs +2 -2
- package/src/init.mjs +24 -24
- package/src/install.mjs +4 -4
- package/src/journal.mjs +40 -7
- package/src/lifecycle.mjs +17 -17
- package/src/lint.mjs +1 -1
- package/src/migrate-prompts.mjs +1 -1
- package/src/migrate-template.mjs +2 -2
- package/src/migrate.mjs +1 -1
- package/src/misuse-read.mjs +4 -5
- package/src/modules.mjs +3 -3
- package/src/new.mjs +15 -12
- package/src/output-identity.mjs +7 -2
- package/src/pickup-card.mjs +2 -2
- package/src/pickup.mjs +2 -2
- package/src/prompts.mjs +18 -15
- package/src/query.mjs +9 -9
- package/src/rename.mjs +2 -2
- package/src/render.mjs +20 -20
- package/src/roadmap.mjs +5 -5
- package/src/runlist.mjs +11 -11
- package/src/ship.mjs +2 -2
- package/src/skill-drift.mjs +19 -6
- package/src/statuses.mjs +16 -16
- package/src/summary.mjs +1 -1
- package/src/surfaces.mjs +1 -1
- package/src/sync-status.mjs +4 -4
- package/src/update.mjs +11 -11
- package/src/use.mjs +6 -2
- package/src/validate.mjs +9 -9
- package/src/watch.mjs +1 -1
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
#
|
|
1
|
+
# runlist
|
|
2
2
|
|
|
3
3
|
CLI for managing Markdown documents with YAML frontmatter.
|
|
4
4
|
|
|
5
|
-
dotmd indexes, queries, validates, graphs, exports, and lifecycle-manages plans,
|
|
5
|
+
runlist (formerly dotmd) indexes, queries, validates, graphs, exports, and lifecycle-manages plans,
|
|
6
6
|
ADRs, RFCs, design docs, and other structured Markdown. It is built for
|
|
7
7
|
AI-assisted development workflows where documents need to remain current and
|
|
8
8
|
safe to mutate.
|
|
@@ -22,7 +22,9 @@ npx dotmd-cli init # try it without installing
|
|
|
22
22
|
|
|
23
23
|
`runlist` is the canonical executable, `rl` is its short convenience alias, and
|
|
24
24
|
`dotmd` remains supported during the compatibility window. All three invoke the
|
|
25
|
-
same CLI
|
|
25
|
+
same CLI. The package is still published as `dotmd-cli`, and the Claude Code
|
|
26
|
+
plugin is still `dotmd@dotmd`; those names change in a later release. Legacy
|
|
27
|
+
`dotmd.config.*` files, `DOTMD_*` variables and `.dotmd/` state keep working.
|
|
26
28
|
|
|
27
29
|
Maintainer release automation is POSIX-only because it uses Bash and POSIX
|
|
28
30
|
command-line tools. The published Node.js CLI remains cross-platform.
|
|
@@ -33,19 +35,19 @@ The CLI alone gives an agent no orientation and no session identity. Install the
|
|
|
33
35
|
integration for whichever host you run:
|
|
34
36
|
|
|
35
37
|
```bash
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
runlist install # what's installed for each host
|
|
39
|
+
runlist install claude # Claude Code plugin (marketplace + plugin)
|
|
40
|
+
runlist install opencode # OpenCode plugin (one auto-discovered file)
|
|
41
|
+
runlist doctor --session # what identity runlist sees here, and from where
|
|
40
42
|
```
|
|
41
43
|
|
|
42
|
-
Both are one-time and global; `
|
|
44
|
+
Both are one-time and global; `runlist update` keeps them in step with the CLI.
|
|
43
45
|
Codex needs no install for identity: it exports `CODEX_THREAD_ID` to every tool
|
|
44
|
-
shell, and
|
|
46
|
+
shell, and runlist reads it as a per-session identity automatically.
|
|
45
47
|
|
|
46
48
|
### Claude Code Plugin
|
|
47
49
|
|
|
48
|
-
`
|
|
50
|
+
`runlist install claude` runs the two steps below for you. From inside a session:
|
|
49
51
|
|
|
50
52
|
```text
|
|
51
53
|
/plugin marketplace add reowens/dotmd
|
|
@@ -58,32 +60,33 @@ guard, the canonical workflow skill, and `/plans`, `/docs`, `/prompts`, and
|
|
|
58
60
|
|
|
59
61
|
### OpenCode Plugin
|
|
60
62
|
|
|
61
|
-
`
|
|
63
|
+
`runlist install opencode` writes one plugin file into OpenCode's global config
|
|
62
64
|
directory, where OpenCode auto-discovers it — no `opencode.json` edit. It
|
|
63
65
|
supplies the two things the CLI cannot get on its own:
|
|
64
66
|
|
|
65
67
|
- **Per-session plan ownership.** OpenCode exports no session id to a tool
|
|
66
|
-
shell. Without the plugin,
|
|
68
|
+
shell. Without the plugin, runlist falls back to `OPENCODE_PID`, which names the
|
|
67
69
|
OpenCode *process* — so every session in one OpenCode instance shares an
|
|
68
70
|
identity and can release the others' in-session plans.
|
|
69
71
|
- **A session-start briefing**, the equivalent of Claude Code's SessionStart
|
|
70
72
|
hook. OpenCode's Claude Code compatibility covers skills and the system
|
|
71
|
-
prompt, not hooks, so nothing else runs `
|
|
73
|
+
prompt, not hooks, so nothing else runs `runlist hud`.
|
|
72
74
|
|
|
73
|
-
Restart OpenCode after installing. The file is version-stamped
|
|
74
|
-
|
|
75
|
+
Restart OpenCode after installing. The file is version-stamped (`runlist-generated:`, or
|
|
76
|
+
`dotmd-generated:` from older releases); a `dotmd.js` without either stamp is
|
|
77
|
+
treated as hand-authored and is never overwritten.
|
|
75
78
|
|
|
76
|
-
The plugin requires a global CLI install because its hooks resolve `dotmd` from
|
|
79
|
+
The plugin requires a global CLI install because its hooks resolve `runlist` (or `dotmd`) from
|
|
77
80
|
`PATH`. A project devDependency is useful for npm scripts but does not put the
|
|
78
81
|
CLI on the hook's `PATH`.
|
|
79
82
|
|
|
80
83
|
Keep the CLI and plugin aligned with:
|
|
81
84
|
|
|
82
85
|
```bash
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
86
|
+
runlist update
|
|
87
|
+
runlist update --check
|
|
88
|
+
runlist update --cli-only
|
|
89
|
+
runlist update --plugin-only
|
|
87
90
|
```
|
|
88
91
|
|
|
89
92
|
Restart Claude Code, or run `/reload-plugins`, after a plugin update.
|
|
@@ -91,29 +94,29 @@ Restart Claude Code, or run `/reload-plugins`, after a plugin update.
|
|
|
91
94
|
## Quick Start
|
|
92
95
|
|
|
93
96
|
```bash
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
97
|
+
runlist init # create config, docs/, and the generated index
|
|
98
|
+
runlist new plan auth-refresh # scaffold a typed document
|
|
99
|
+
runlist briefing # compact active-work orientation
|
|
100
|
+
runlist plans # live plan dashboard
|
|
101
|
+
runlist check # validate schema, references, and lifecycle shape
|
|
102
|
+
runlist doctor # preview repairs; add --apply to write
|
|
100
103
|
```
|
|
101
104
|
|
|
102
|
-
`
|
|
103
|
-
human/LLM briefing, while `
|
|
105
|
+
`runlist briefing` is the compact orientation view. `runlist context` is the fuller
|
|
106
|
+
human/LLM briefing, while `runlist agent-context` emits bounded structured JSON for
|
|
104
107
|
agent integrations.
|
|
105
108
|
|
|
106
109
|
## Core Workflow
|
|
107
110
|
|
|
108
111
|
```bash
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
112
|
+
runlist briefing
|
|
113
|
+
runlist use docs/plans/auth-refresh.md
|
|
114
|
+
runlist set awaiting docs/plans/auth-refresh.md --note "Need API owner decision"
|
|
115
|
+
runlist set active docs/plans/auth-refresh.md --note "Decision received"
|
|
116
|
+
runlist archive docs/plans/auth-refresh.md --note "Shipped and verified"
|
|
114
117
|
```
|
|
115
118
|
|
|
116
|
-
Use `
|
|
119
|
+
Use `runlist set <status> [<file>]` for lifecycle changes rather than editing a
|
|
117
120
|
`status:` line. It validates the status for the document type, updates history,
|
|
118
121
|
runs lifecycle hooks, repairs references after moves, and synchronizes the
|
|
119
122
|
index.
|
|
@@ -122,11 +125,18 @@ For unfinished session work, save the handoff and release the owned plan in one
|
|
|
122
125
|
operation:
|
|
123
126
|
|
|
124
127
|
```bash
|
|
125
|
-
|
|
128
|
+
runlist baton @/tmp/resume.md
|
|
126
129
|
```
|
|
127
130
|
|
|
128
|
-
|
|
129
|
-
|
|
131
|
+
Baton refuses when a handoff for the same work is already pending, so one piece
|
|
132
|
+
of work never has two resume prompts.
|
|
133
|
+
|
|
134
|
+
Saved prompts are local session state. Consume them with `runlist use`; inspect
|
|
135
|
+
without consuming via `runlist prompts show`. Consuming a baton prompt also claims
|
|
136
|
+
its plan; `runlist use --no-claim` reads and archives it without starting the plan.
|
|
137
|
+
|
|
138
|
+
New plans are created `planned`; `runlist use` starts one, and
|
|
139
|
+
`runlist new plan <name> --status <status>` sets a different starting status.
|
|
130
140
|
|
|
131
141
|
## Document Format
|
|
132
142
|
|
|
@@ -153,11 +163,11 @@ related_docs:
|
|
|
153
163
|
|
|
154
164
|
`status` is the only universally required field. A `type` enables type-specific
|
|
155
165
|
statuses, validation, templates, and briefing behavior. Explicit frontmatter
|
|
156
|
-
wins, but
|
|
166
|
+
wins, but runlist can also derive titles, summaries, state, next steps, checklist
|
|
157
167
|
progress, and Markdown links from the body.
|
|
158
168
|
|
|
159
169
|
Use plural `modules:` and `surfaces:` arrays. The old singular keys remain
|
|
160
|
-
readable for compatibility and can be migrated with `
|
|
170
|
+
readable for compatibility and can be migrated with `runlist lint --fix`.
|
|
161
171
|
|
|
162
172
|
### Built-In Types
|
|
163
173
|
|
|
@@ -176,19 +186,19 @@ A sprint runlist is an ordered `runlist:` array on a hub plan. Scaffold a hub
|
|
|
176
186
|
and children together:
|
|
177
187
|
|
|
178
188
|
```bash
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
189
|
+
runlist new plan auth-revamp --runlist extract,rewrite,cleanup
|
|
190
|
+
runlist runlist auth-revamp
|
|
191
|
+
runlist runlist next auth-revamp
|
|
182
192
|
```
|
|
183
193
|
|
|
184
194
|
Mutate the structure through the CLI so the array, child `parent_plan` refs, and
|
|
185
195
|
body order list remain synchronized:
|
|
186
196
|
|
|
187
197
|
```bash
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
198
|
+
runlist runlist add auth-revamp docs/plans/existing-plan.md
|
|
199
|
+
runlist runlist add auth-revamp follow-up
|
|
200
|
+
runlist runlist reorder auth-revamp follow-up --before cleanup
|
|
201
|
+
runlist runlist remove auth-revamp extract --clear-parent
|
|
192
202
|
```
|
|
193
203
|
|
|
194
204
|
Archived children count as complete. Parked children (`blocked`, `partial`,
|
|
@@ -198,16 +208,16 @@ pickup but do not count as done.
|
|
|
198
208
|
For a larger prose-first domain map, create a coordination runlist:
|
|
199
209
|
|
|
200
210
|
```bash
|
|
201
|
-
|
|
202
|
-
|
|
211
|
+
runlist new plan platform-work --coordination
|
|
212
|
+
runlist runlists
|
|
203
213
|
```
|
|
204
214
|
|
|
205
215
|
For progress across several runlists, create a roadmap:
|
|
206
216
|
|
|
207
217
|
```bash
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
218
|
+
runlist new plan platform-roadmap --roadmap
|
|
219
|
+
runlist roadmap platform-roadmap
|
|
220
|
+
runlist roadmap platform-roadmap next
|
|
211
221
|
```
|
|
212
222
|
|
|
213
223
|
Roadmaps roll up progress recursively and choose the first startable plan across
|
|
@@ -229,17 +239,17 @@ counts so dashboards do not double-count their children.
|
|
|
229
239
|
The CLI is the source of truth for command syntax and options:
|
|
230
240
|
|
|
231
241
|
```bash
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
242
|
+
runlist --help
|
|
243
|
+
runlist help all
|
|
244
|
+
runlist help statuses
|
|
245
|
+
runlist <command> --help
|
|
236
246
|
```
|
|
237
247
|
|
|
238
248
|
Shell completion is generated from the same command registry:
|
|
239
249
|
|
|
240
250
|
```bash
|
|
241
|
-
eval "$(
|
|
242
|
-
eval "$(
|
|
251
|
+
eval "$(runlist completions bash)"
|
|
252
|
+
eval "$(runlist completions zsh)"
|
|
243
253
|
```
|
|
244
254
|
|
|
245
255
|
This README intentionally documents onboarding and concepts instead of
|
|
@@ -247,7 +257,7 @@ duplicating the complete command catalog.
|
|
|
247
257
|
|
|
248
258
|
## Configuration
|
|
249
259
|
|
|
250
|
-
Run `
|
|
260
|
+
Run `runlist init` to create `runlist.config.mjs` (a legacy `dotmd.config.mjs` is still read). A minimal typed configuration:
|
|
251
261
|
|
|
252
262
|
```js
|
|
253
263
|
export const root = 'docs';
|
|
@@ -273,12 +283,12 @@ export const types = {
|
|
|
273
283
|
|
|
274
284
|
Configuration supports multiple roots, custom types and templates, taxonomy,
|
|
275
285
|
reference fields, presets, rendering, lifecycle hooks, validation hooks, and
|
|
276
|
-
AI summarization hooks. See [`
|
|
286
|
+
AI summarization hooks. See [`runlist.config.example.mjs`](runlist.config.example.mjs)
|
|
277
287
|
for the complete annotated reference.
|
|
278
288
|
|
|
279
289
|
## Hooks
|
|
280
290
|
|
|
281
|
-
Functions exported from `
|
|
291
|
+
Functions exported from `runlist.config.mjs` are detected as hooks. They can add
|
|
282
292
|
validation, customize rendering and summaries, or react to lifecycle events.
|
|
283
293
|
Hooks receive the resolved config and command context; mutation hooks participate
|
|
284
294
|
in the command's dry-run and failure contracts.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//
|
|
1
|
+
// runlist's OpenCode integration. Installed by `runlist install opencode`, which
|
|
2
2
|
// copies this file (with a version banner prepended) to the OpenCode plugin
|
|
3
3
|
// directory, where OpenCode auto-discovers it — it globs
|
|
4
4
|
// `{plugin,plugins}/*.{ts,js}` under `.opencode/` and the global config dir, so
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
//
|
|
14
14
|
// 2. NO HOOK MAY THROW. OpenCode awaits hook callbacks inside the request it
|
|
15
15
|
// is serving; a rejected promise fails the user's chat turn. Every hook
|
|
16
|
-
// body is wrapped, and a failure degrades to "
|
|
16
|
+
// body is wrapped, and a failure degrades to "runlist does nothing here"
|
|
17
17
|
// rather than to a broken session.
|
|
18
18
|
//
|
|
19
19
|
// Runs under Bun inside the OpenCode process. Node builtins only, no deps.
|
|
@@ -32,7 +32,9 @@ function cliExecutables() {
|
|
|
32
32
|
return process.platform === 'win32' ? ['runlist.cmd', 'dotmd.cmd'] : ['runlist', 'dotmd'];
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
// Runs the CLI and resolves its trimmed stdout, or '' on any failure. `input`,
|
|
36
|
+
// when given, is written to the child's stdin.
|
|
37
|
+
function runCli(directory, args, input = null) {
|
|
36
38
|
return new Promise(resolve => {
|
|
37
39
|
let settled = false;
|
|
38
40
|
const done = value => { if (!settled) { settled = true; resolve(value); } };
|
|
@@ -40,7 +42,7 @@ function runHud(directory) {
|
|
|
40
42
|
const attempt = index => {
|
|
41
43
|
if (index >= candidates.length) { done(''); return; }
|
|
42
44
|
try {
|
|
43
|
-
execFile(candidates[index],
|
|
45
|
+
const child = execFile(candidates[index], args, {
|
|
44
46
|
cwd: directory,
|
|
45
47
|
timeout: PRIMER_TIMEOUT_MS,
|
|
46
48
|
windowsHide: true,
|
|
@@ -49,12 +51,33 @@ function runHud(directory) {
|
|
|
49
51
|
if (error?.code === 'ENOENT') attempt(index + 1);
|
|
50
52
|
else done(error ? '' : (stdout ?? '').trim());
|
|
51
53
|
});
|
|
54
|
+
child.stdin?.on('error', () => {});
|
|
55
|
+
if (input !== null) child.stdin?.end(input);
|
|
56
|
+
else child.stdin?.end();
|
|
52
57
|
} catch { attempt(index + 1); }
|
|
53
58
|
};
|
|
54
59
|
attempt(0);
|
|
55
60
|
});
|
|
56
61
|
}
|
|
57
62
|
|
|
63
|
+
// OpenCode runs no Claude Code hooks, so `runlist guard` never sees its tool
|
|
64
|
+
// calls, and sessions opened pending prompts with the read tool, which prints a
|
|
65
|
+
// prompt without archiving it. The guard's answer for a prompt read is a
|
|
66
|
+
// warning, not a block, so it is applied after the call: the teaching text is
|
|
67
|
+
// appended to what the agent sees. Only calls that name a prompt file reach
|
|
68
|
+
// the CLI; everything else costs a regex.
|
|
69
|
+
const PROMPT_FILE = /(^|[\\/])prompts[\\/]\S*\.md\b/;
|
|
70
|
+
|
|
71
|
+
function guardPayload(tool, args) {
|
|
72
|
+
if (tool === 'read' && typeof args?.filePath === 'string' && PROMPT_FILE.test(args.filePath)) {
|
|
73
|
+
return { tool_name: 'Read', tool_input: { file_path: args.filePath } };
|
|
74
|
+
}
|
|
75
|
+
if (tool === 'bash' && typeof args?.command === 'string' && PROMPT_FILE.test(args.command)) {
|
|
76
|
+
return { tool_name: 'Bash', tool_input: { command: args.command } };
|
|
77
|
+
}
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
|
|
58
81
|
export default async function dotmdOpencodePlugin({ directory }) {
|
|
59
82
|
// Keyed by session so a subagent session primes independently, the way
|
|
60
83
|
// SubagentStart does under Claude Code.
|
|
@@ -68,14 +91,14 @@ export default async function dotmdOpencodePlugin({ directory }) {
|
|
|
68
91
|
// only the first request — and a never-refreshed one would keep announcing
|
|
69
92
|
// a pending prompt this session already consumed.
|
|
70
93
|
if (cached && Date.now() - cached.at < PRIMER_TTL_MS) return cached.text;
|
|
71
|
-
const text = await
|
|
94
|
+
const text = await runCli(directory, ['hud']);
|
|
72
95
|
primers.set(key, { text, at: Date.now() });
|
|
73
96
|
return text;
|
|
74
97
|
}
|
|
75
98
|
|
|
76
99
|
return {
|
|
77
100
|
// Ownership identity. OpenCode sets no session-id variable of its own, and
|
|
78
|
-
// `OPENCODE_PID` — what
|
|
101
|
+
// `OPENCODE_PID` — what runlist falls back to without this plugin — names the
|
|
79
102
|
// OpenCode *process*, so every session in one TUI shares it and can release
|
|
80
103
|
// the others' plans. This is the only place the real session id is
|
|
81
104
|
// available to a tool shell.
|
|
@@ -83,18 +106,32 @@ export default async function dotmdOpencodePlugin({ directory }) {
|
|
|
83
106
|
try {
|
|
84
107
|
if (input?.sessionID) {
|
|
85
108
|
output.env.RUNLIST_SESSION_ID = `opencode:${input.sessionID}`;
|
|
109
|
+
// Legacy name, kept for an older CLI (before 0.77.0) still on PATH.
|
|
86
110
|
output.env.DOTMD_SESSION_ID = `opencode:${input.sessionID}`;
|
|
87
111
|
}
|
|
88
112
|
// The OpenCode server process hosts the session and outlives every tool
|
|
89
113
|
// shell, so it is the process whose liveness answers "is this claim's
|
|
90
|
-
// owner still there?" — `
|
|
114
|
+
// owner still there?" — `runlist doctor --claims` probes exactly this.
|
|
91
115
|
output.env.RUNLIST_SESSION_PID = String(process.pid);
|
|
92
116
|
output.env.DOTMD_SESSION_PID = String(process.pid);
|
|
93
117
|
} catch { /* never break a shell over this */ }
|
|
94
118
|
},
|
|
95
119
|
|
|
120
|
+
// The guard's warnings, appended after the call ran. A `deny` from the
|
|
121
|
+
// guard is ignored here: the call has already happened, so there is
|
|
122
|
+
// nothing left to refuse.
|
|
123
|
+
'tool.execute.after': async (input, output) => {
|
|
124
|
+
try {
|
|
125
|
+
const payload = guardPayload(input?.tool, input?.args);
|
|
126
|
+
if (!payload || typeof output?.output !== 'string') return;
|
|
127
|
+
const raw = await runCli(directory, ['guard'], JSON.stringify(payload));
|
|
128
|
+
const note = raw ? JSON.parse(raw)?.hookSpecificOutput?.additionalContext : null;
|
|
129
|
+
if (typeof note === 'string' && note) output.output += `\n\n${note}`;
|
|
130
|
+
} catch { /* a guard failure never touches the tool result */ }
|
|
131
|
+
},
|
|
132
|
+
|
|
96
133
|
// Session priming — the equivalent of the SessionStart hook that runs
|
|
97
|
-
// `
|
|
134
|
+
// `runlist hud` under Claude Code. Silent outside a runlist repo (hud prints
|
|
98
135
|
// nothing and exits 0), so this is inert in unrelated projects.
|
|
99
136
|
'experimental.chat.system.transform': async (input, output) => {
|
|
100
137
|
try {
|