@cmodjs/core 0.2.3 → 0.3.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/docs/commands.md +8 -0
- package/docs/hooks.md +2 -1
- package/docs/jobs.md +2 -2
- package/docs/options.md +1 -1
- package/docs/permissions.md +1 -1
- package/docs/testing.md +1 -1
- package/package.json +1 -1
- package/register.js +1 -1
- package/runtime/claude.d.ts +0 -1
- package/runtime/claude.d.ts.map +1 -1
- package/runtime/grants.d.ts.map +1 -1
- package/runtime/grants.js +0 -7
- package/runtime/lifecycle.js +2 -2
- package/src/register.ts +1 -1
- package/src/runtime/claude.ts +1 -1
- package/src/runtime/grants.ts +0 -7
- package/src/runtime/lifecycle.ts +2 -2
- package/src/testing/fake-claude.ts +1 -2
- package/src/utils/parse-shell.ts +16 -9
- package/testing/fake-claude.d.ts +0 -1
- package/testing/fake-claude.d.ts.map +1 -1
- package/testing/fake-claude.js +0 -1
- package/utils/parse-shell.d.ts +1 -0
- package/utils/parse-shell.d.ts.map +1 -1
- package/utils/parse-shell.js +14 -7
package/docs/commands.md
CHANGED
|
@@ -209,3 +209,11 @@ cmod permission <mod> <name> [value] on|off
|
|
|
209
209
|
```
|
|
210
210
|
|
|
211
211
|
Turns one permission of a set-up mod on or off, such as `cmod permission ci-watch model off` or `cmod permission ci-watch network api.github.com on`. A toggle in `/mods` runs it. It refuses a permission the mod's `package.json` `cmod.permissions` does not list, and the mod sees the change before its next call, with no reload ([permissions.md](permissions.md)).
|
|
212
|
+
|
|
213
|
+
### cmod option
|
|
214
|
+
|
|
215
|
+
```text
|
|
216
|
+
cmod option <name> <key> <value>
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Sets one option of an installed plugin through `claude plugin configure`, the way `/config` sets it, such as `cmod option ci-watch branch main`. A list option takes its items separated by commas. It refuses a key the plugin's `plugin.json` `userConfig` does not declare. A field in `/mods` and the option questions a mod asks at its first start run it, and the mod reads the new value at its next start ([options.md](options.md)).
|
package/docs/hooks.md
CHANGED
|
@@ -107,7 +107,7 @@ The input of `PreToolUse`, `PostToolUse`, and `PostToolUseFailure` has `files: {
|
|
|
107
107
|
parseShell(line: string): ParsedShell
|
|
108
108
|
|
|
109
109
|
type ParsedShell = { commands: ShellCommand[]; reads: string[]; writes: string[]; fetches: string[]; isFullyParsed: boolean }
|
|
110
|
-
type ShellCommand = { argv: [string, ...string[]]; folder: string }
|
|
110
|
+
type ShellCommand = { argv: [string, ...string[]]; folder: string; input?: number }
|
|
111
111
|
|
|
112
112
|
resolve(...paths): string join(...paths): string dirname(path): string basename(path, suffix?): string
|
|
113
113
|
extname(path): string relative(from, to): string isAbsolute(path): boolean normalize(path): string
|
|
@@ -115,6 +115,7 @@ extname(path): string relative(from, to): string isAbsolute(path): bool
|
|
|
115
115
|
|
|
116
116
|
- `commands` lists every command the line runs, those inside `sudo`, `bash -c`, `$(…)`, and heredocs included, with flags such as `-rf` split into `-r` and `-f`.
|
|
117
117
|
- `folder` is where a command runs, as the line wrote it: `''` for the folder the line starts in, `src` after `cd src`, `/tmp` after `cd /tmp`, and `~/p` after `cd ~/p`. `resolve(input.cwd, folder)` makes it absolute.
|
|
118
|
+
- `input` is the index in `commands` of the command whose output this one reads through `|` or `|&`, and is absent for a command that reads no pipe. `trace read a.ts | head -5` gives `head` the `input` `0`. A wrapper such as `timeout 5 trace read a.ts` writes the output of the command it runs, so `input` names `trace`, not `timeout`.
|
|
118
119
|
- `reads`, `writes`, and `fetches` are the paths and URLs the commands name, as written. A path that holds a shell expansion makes `isFullyParsed` false, and so does a line the parser cannot read.
|
|
119
120
|
- `resolve` has no working folder to start from in Claude Code's hooks, so pass an absolute folder first, such as `resolve(mod.cwd, path)`.
|
|
120
121
|
|
package/docs/jobs.md
CHANGED
|
@@ -448,7 +448,7 @@ export const timer = defineMod({
|
|
|
448
448
|
|
|
449
449
|
Each member calls the member of the same name in Claude Code's hooks API, `$`, with the same arguments. The `env` members read `$.env.get` instead. `mod.claude.on` adds a handler, as [Write a job of your own](#write-a-job-of-your-own) shows.
|
|
450
450
|
|
|
451
|
-
A member that does what a permission covers checks it first and rejects with the fix: `process` needs `run`, `http.fetch` needs `network`, `fs.write` outside the project and the data folder needs `files` or, for Claude Code's own settings files, `config`, `fs.read` of a transcript needs `conversation`, `session.messages` needs `conversation`, `session.append` and `prompt.submit` need `prompt`, `model.complete` needs `model`, `agent.spawn` needs `agents`,
|
|
451
|
+
A member that does what a permission covers checks it first and rejects with the fix: `process` needs `run`, `http.fetch` needs `network`, `fs.write` outside the project and the data folder needs `files` or, for Claude Code's own settings files, `config`, `fs.read` of a transcript needs `conversation`, `session.messages` needs `conversation`, `session.append` and `prompt.submit` need `prompt`, `model.complete` needs `model`, `agent.spawn` needs `agents`, and `tool.call` needs `tools`, except `CronCreate`, which needs `prompt`, and `CronList` and `CronDelete`, which need nothing ([permissions.md](permissions.md)).
|
|
452
452
|
|
|
453
453
|
| Member | What it does |
|
|
454
454
|
| --- | --- |
|
|
@@ -470,7 +470,7 @@ A member that does what a permission covers checks it first and rejects with the
|
|
|
470
470
|
| `fs.read`, `fs.write`, `fs.list`, `fs.exists`, `fs.stat` | What `mod.fs` calls. A relative path is under the session's working folder. |
|
|
471
471
|
| `http.fetch(url, init?)` | What `mod.http.fetch` calls. |
|
|
472
472
|
| `settings.read(args?)` | Reads Claude Code's own `settings.json` files. Without `{ source }` it answers every source merged. `user`, `project`, `local`, `flag`, and `policy` each answer one. |
|
|
473
|
-
| `config.list()
|
|
473
|
+
| `config.list()` | Lists the rows `/config` shows, such as `<mod>.<option>`. A mod sets an option through `cmod option <mod> <key> <value>`, as `/mods` does. |
|
|
474
474
|
| `store.get`, `store.set`, `store.delete`, `store.keys` | The plugin's key-value store, where cmod also keeps `mod.state`. |
|
|
475
475
|
| `clock.now()` | Resolves milliseconds since the epoch. |
|
|
476
476
|
| `clock.after(ms, fn)` | Calls `fn` once after `ms` milliseconds, and returns `{ cancel() }`. |
|
package/docs/options.md
CHANGED
|
@@ -49,7 +49,7 @@ Each value is, in order of precedence:
|
|
|
49
49
|
3. The value the person set in `/config`.
|
|
50
50
|
4. The `default` in the declaration.
|
|
51
51
|
|
|
52
|
-
An option with no default and no value is asked before `setup` runs, on a page of the installer pane: one field per option, each saved to `/config` as the person submits it. A secret is set in `/config` itself, where Claude Code keeps it in the keychain, and the page says so. When the person chooses Not now, or no one can answer, as in `claude -p`, the mod does not start: its progress line says `it needs <title>` and `Set it in /config.`, and Claude Code reloads the mod once the value is set.
|
|
52
|
+
An option with no default and no value is asked before `setup` runs, on a page of the installer pane: one field per option, each saved to `/config` through `cmod option` as the person submits it. A secret is set in `/config` itself, where Claude Code keeps it in the keychain, and the page says so. When the person chooses Not now, or no one can answer, as in `claude -p`, the mod does not start: its progress line says `it needs <title>` and `Set it in /config.`, and Claude Code reloads the mod once the value is set.
|
|
53
53
|
|
|
54
54
|
`cmod install`, `cmod link`, and `cmod try` set options from the terminal with `--option key=value`, once per option ([commands.md](commands.md)).
|
|
55
55
|
|
package/docs/permissions.md
CHANGED
|
@@ -24,7 +24,7 @@ They sit in the `package.json` `cmod` key, beside `install` and `keys`, because
|
|
|
24
24
|
| `"model": true` | Ask a model, which uses your plan | `mod.model.complete` |
|
|
25
25
|
| `"agents": true` | Start agents | `mod.agent.spawn` |
|
|
26
26
|
| `"tools": true` | Use and change Claude's tool calls | `mod.claude.tool.call`, and a hook that changes a tool call's input |
|
|
27
|
-
| `"config": true` | Change your Claude Code settings |
|
|
27
|
+
| `"config": true` | Change your Claude Code settings | writes to `.claude/settings.json`, `.claude/settings.local.json`, and `.mcp.json` |
|
|
28
28
|
| `"approve": true` | Approve Claude's tool calls for you | an allow or an ask from the mod's permission rules or hooks, and a `retry`. A deny needs no permission |
|
|
29
29
|
|
|
30
30
|
Reading files, drawing panes and slot renders, toasts, slash commands, tools of the mod's own, and hooks need no permission.
|
package/docs/testing.md
CHANGED
|
@@ -241,7 +241,7 @@ Set a fake to answer a call:
|
|
|
241
241
|
- `clock.after(ms, fn)` and `clock.every(ms, fn)` each return `{ cancel() }`, and so must a fake of either. `clock.after` runs a real timer by default. `clock.every` never fires unless a fake keeps `fn` for the test to call, so a test of `mod.every` keeps it and calls it once per tick.
|
|
242
242
|
- `session.append` and `prompt.submit` take every note and prompt by default, into `shown.notes` and `shown.prompts`. A fake that answers `{ deny }` or `{ drop }` refuses one.
|
|
243
243
|
- `model.complete` has no default: set it to the answer the model gives, such as `async () => ({ isAnswered: true, text: 'no', usage })`.
|
|
244
|
-
- `config.list` answers no `/config` rows by default
|
|
244
|
+
- `config.list` answers no `/config` rows by default. A `config.list` fake that answers a row with `isLocked: true` locks that option as managed settings do.
|
|
245
245
|
- `tool.call` answers `CronCreate`, `CronDelete`, and `CronList` by default, keeping the crons a `schedule` makes in `shown.schedules`. A call to any other tool needs a fake.
|
|
246
246
|
- `files` takes symbolic links too: `testMod(mod, { files, links: { '/work/skills': '/shared/skills' } })` makes `/work/skills` a link to `/shared/skills`, so a test of `mod.fs.find` or `mod.metadata.update` follows it as a real file system does.
|
|
247
247
|
- `testMod` runs no installer pane: an option with no default and no value fails `start()` with its fix, and the `installer` steps are not shown. Test a step's `render` and `isDone` by calling them with the started `mod`.
|
package/package.json
CHANGED
package/register.js
CHANGED
|
@@ -34,7 +34,7 @@ async function startMod($, eventInput, passOn) {
|
|
|
34
34
|
},
|
|
35
35
|
http: { fetch: (url, init) => $.http.fetch(url, init) },
|
|
36
36
|
settings: { read: (args) => $.settings.read(args) },
|
|
37
|
-
config: { list: () => $.config.list()
|
|
37
|
+
config: { list: () => $.config.list() },
|
|
38
38
|
store: {
|
|
39
39
|
get: (key) => $.store.get(key),
|
|
40
40
|
set: (key, value) => $.store.set(key, value),
|
package/runtime/claude.d.ts
CHANGED
package/runtime/claude.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../src/runtime/claude.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../src/runtime/claude.ts"],"names":[],"mappings":"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"}
|
package/runtime/grants.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grants.d.ts","sourceRoot":"","sources":["../src/runtime/grants.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAE7C,MAAM,MAAM,MAAM,GAAG;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;IACpC,QAAQ,CAAC,OAAO,EAAE,MAAM,WAAW,CAAC,MAAM,CAAC,CAAA;IAC3C,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAA;IACjC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAA;IACvC,QAAQ,CAAC,WAAW,EAAE,MAAM,MAAM,CAAA;IAClC,QAAQ,CAAC,WAAW,EAAE,MAAM,SAAS,MAAM,EAAE,CAAA;CAC9C,CAAA;AAED,qBAAa,iBAAkB,SAAQ,KAAK;CAAG;AAc/C,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEpF;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"grants.d.ts","sourceRoot":"","sources":["../src/runtime/grants.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAE7C,MAAM,MAAM,MAAM,GAAG;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;IACpC,QAAQ,CAAC,OAAO,EAAE,MAAM,WAAW,CAAC,MAAM,CAAC,CAAA;IAC3C,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAA;IACjC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAA;IACvC,QAAQ,CAAC,WAAW,EAAE,MAAM,MAAM,CAAA;IAClC,QAAQ,CAAC,WAAW,EAAE,MAAM,SAAS,MAAM,EAAE,CAAA;CAC9C,CAAA;AAED,qBAAa,iBAAkB,SAAQ,KAAK;CAAG;AAc/C,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEpF;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAsErE;AAmBD,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED,wBAAgB,SAAS,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAUvG;AAcD,wBAAgB,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAI9G;AA4BD,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;IAChC,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAC1C,CAAA;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAEzD;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAa9G;AAED,wBAAsB,aAAa,CAAC,KAAK,EAAE,WAAW,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CA+BxJ"}
|
package/runtime/grants.js
CHANGED
|
@@ -46,13 +46,6 @@ export function checkingGrants(claude, grants) {
|
|
|
46
46
|
return claude.http.fetch(url, init);
|
|
47
47
|
},
|
|
48
48
|
},
|
|
49
|
-
config: {
|
|
50
|
-
...claude.config,
|
|
51
|
-
set: (async (args) => {
|
|
52
|
-
await gate('config.set', 'config');
|
|
53
|
-
return claude.config.set(args);
|
|
54
|
-
}),
|
|
55
|
-
},
|
|
56
49
|
session: {
|
|
57
50
|
...claude.session,
|
|
58
51
|
messages: (async (...args) => {
|
package/runtime/lifecycle.js
CHANGED
|
@@ -153,8 +153,8 @@ export function createLifecycle(definition, checksPermissions = () => true, opti
|
|
|
153
153
|
const misfit = option.kind === 'toggle' && !['true', 'false'].includes(text.trim()) ? 'takes true or false' : fitsOption(option, value);
|
|
154
154
|
if (misfit !== undefined)
|
|
155
155
|
return `${option.title} ${misfit}.`;
|
|
156
|
-
const saved = await claude().
|
|
157
|
-
return saved.
|
|
156
|
+
const saved = await claude().process.run(['cmod', 'option', plugin.name, key, Array.isArray(value) ? value.join(',') : String(value)]);
|
|
157
|
+
return saved.exitCode === 0 ? undefined : lastLineOf(saved.stderr) ?? `cmod option exited ${saved.exitCode}.`;
|
|
158
158
|
};
|
|
159
159
|
const askOptions = async (missing) => {
|
|
160
160
|
if (!asksPerson || plugin === undefined || (await claude().session.surfaces()).length === 0)
|
package/src/register.ts
CHANGED
|
@@ -44,7 +44,7 @@ async function startMod($: EngineInterface, eventInput: Frozen<Args<'session.sta
|
|
|
44
44
|
},
|
|
45
45
|
http: { fetch: (url, init) => $.http.fetch(url, init) },
|
|
46
46
|
settings: { read: (args) => $.settings.read(args) },
|
|
47
|
-
config: { list: () => $.config.list()
|
|
47
|
+
config: { list: () => $.config.list() },
|
|
48
48
|
store: {
|
|
49
49
|
get: (key) => $.store.get(key),
|
|
50
50
|
set: (key, value) => $.store.set(key, value),
|
package/src/runtime/claude.ts
CHANGED
|
@@ -65,7 +65,7 @@ export type Claude = {
|
|
|
65
65
|
}
|
|
66
66
|
readonly http: { fetch(url: string, init?: HttpInit): Promise<HttpResponse> }
|
|
67
67
|
readonly settings: { read(args?: SettingsReadArgs): Promise<Settings> }
|
|
68
|
-
readonly config: { list(): Promise<ConfigRow[]
|
|
68
|
+
readonly config: { list(): Promise<ConfigRow[]> }
|
|
69
69
|
readonly store: {
|
|
70
70
|
get(key: string): Promise<unknown>
|
|
71
71
|
set(key: string, value: unknown): Promise<void>
|
package/src/runtime/grants.ts
CHANGED
|
@@ -63,13 +63,6 @@ export function checkingGrants(claude: Claude, grants: Grants): Claude {
|
|
|
63
63
|
return claude.http.fetch(url, init)
|
|
64
64
|
},
|
|
65
65
|
},
|
|
66
|
-
config: {
|
|
67
|
-
...claude.config,
|
|
68
|
-
set: (async (args: Parameters<Claude['config']['set']>[0]) => {
|
|
69
|
-
await gate('config.set', 'config')
|
|
70
|
-
return claude.config.set(args)
|
|
71
|
-
}) as Claude['config']['set'],
|
|
72
|
-
},
|
|
73
66
|
session: {
|
|
74
67
|
...claude.session,
|
|
75
68
|
messages: (async (...args: Parameters<Claude['session']['messages']>) => {
|
package/src/runtime/lifecycle.ts
CHANGED
|
@@ -209,8 +209,8 @@ export function createLifecycle<State extends object, Declared extends Options =
|
|
|
209
209
|
const value = option.kind === 'number' ? Number(text) : option.kind === 'toggle' ? text.trim() === 'true' : option.kind === 'list' ? text.split(',').map((item) => item.trim()).filter((item) => item !== '') : text
|
|
210
210
|
const misfit = option.kind === 'toggle' && !['true', 'false'].includes(text.trim()) ? 'takes true or false' : fitsOption(option, value)
|
|
211
211
|
if (misfit !== undefined) return `${option.title} ${misfit}.`
|
|
212
|
-
const saved = await claude().
|
|
213
|
-
return saved.
|
|
212
|
+
const saved = await claude().process.run(['cmod', 'option', plugin.name, key, Array.isArray(value) ? value.join(',') : String(value)])
|
|
213
|
+
return saved.exitCode === 0 ? undefined : lastLineOf(saved.stderr) ?? `cmod option exited ${saved.exitCode}.`
|
|
214
214
|
}
|
|
215
215
|
|
|
216
216
|
const askOptions = async (missing: MissingOptions): Promise<boolean> => {
|
|
@@ -12,7 +12,7 @@ export type Fakes = {
|
|
|
12
12
|
fs: { read?: Claude['fs']['read']; write?: Claude['fs']['write']; list?: Claude['fs']['list']; exists?: Claude['fs']['exists']; stat?: Claude['fs']['stat'] }
|
|
13
13
|
http: { fetch?: Claude['http']['fetch'] }
|
|
14
14
|
settings: { read?: Claude['settings']['read'] }
|
|
15
|
-
config: { list?: Claude['config']['list']
|
|
15
|
+
config: { list?: Claude['config']['list'] }
|
|
16
16
|
ui: { ask?: Claude['ui']['ask']; open?: Claude['ui']['open']; scroll?: Claude['ui']['scroll'] }
|
|
17
17
|
session: { messages?: Claude['session']['messages']; append?: Claude['session']['append'] }
|
|
18
18
|
prompt: { submit?: Claude['prompt']['submit'] }
|
|
@@ -151,7 +151,6 @@ export function fakeClaude(plugin: { readonly name: string; readonly root: strin
|
|
|
151
151
|
settings: { read: rejected('settings.read', () => fakes.settings.read) },
|
|
152
152
|
config: {
|
|
153
153
|
list: rejected('config.list', () => fakes.config.list ?? (async () => [])),
|
|
154
|
-
set: rejected('config.set', () => fakes.config.set ?? (async ({ value }) => ({ value }))) as Claude['config']['set'],
|
|
155
154
|
},
|
|
156
155
|
agent: {
|
|
157
156
|
list: rejected('agent.list', () => fakes.agent.list),
|
package/src/utils/parse-shell.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { basename, parse, type GlobPattern, type ParseEntry } from '../vendor.js'
|
|
2
2
|
|
|
3
|
-
export type ShellCommand = { argv: [string, ...string[]]; folder: string }
|
|
3
|
+
export type ShellCommand = { argv: [string, ...string[]]; folder: string; input?: number }
|
|
4
4
|
|
|
5
5
|
export type ParsedShell = {
|
|
6
6
|
commands: ShellCommand[]
|
|
@@ -16,7 +16,8 @@ type Expansion = Marker & { end: number }
|
|
|
16
16
|
type Heredoc = { delimiter: string; stripsTabs: boolean; isQuoted: boolean; marker: Marker; end: number }
|
|
17
17
|
type Scan = { text: string; markers: Marker[]; end: number }
|
|
18
18
|
type Redirect = { operator: string; target: Word }
|
|
19
|
-
type
|
|
19
|
+
type Pipe = { writer: number | undefined }
|
|
20
|
+
type Command = { words: Word[]; redirects: Redirect[]; pipe: Pipe | undefined }
|
|
20
21
|
type Stdin = { kind: 'text'; text: string } | { kind: 'pipe' }
|
|
21
22
|
type Access = 'reads' | 'writes'
|
|
22
23
|
type OptionSpec = { valued?: string; optional?: string; longValued?: readonly string[] }
|
|
@@ -470,7 +471,7 @@ function readHeredocBodies(source: string, from: number, heredocs: Heredoc[]): n
|
|
|
470
471
|
function walk(tokens: ParseEntry[], markers: Marker[], start: string, result: ParsedShell): void {
|
|
471
472
|
let folder = start
|
|
472
473
|
const subshells: string[] = []
|
|
473
|
-
let command = newCommand(
|
|
474
|
+
let command = newCommand(undefined)
|
|
474
475
|
let caseState: 'header' | 'pattern' | undefined
|
|
475
476
|
for (let index = 0; index < tokens.length; index += 1) {
|
|
476
477
|
const token = tokens[index]!
|
|
@@ -500,12 +501,14 @@ function walk(tokens: ParseEntry[], markers: Marker[], start: string, result: Pa
|
|
|
500
501
|
}
|
|
501
502
|
const following = tokens[index + 1]
|
|
502
503
|
if (operator === '(' && command.words.length === 1 && following !== undefined && !isWordToken(following) && 'op' in following && following.op === ')') {
|
|
503
|
-
command = newCommand(
|
|
504
|
+
command = newCommand(undefined)
|
|
504
505
|
index += 1
|
|
505
506
|
continue
|
|
506
507
|
}
|
|
508
|
+
const before = result.commands.length
|
|
507
509
|
folder = finish(command, operator, folder, result)
|
|
508
|
-
|
|
510
|
+
const writer = result.commands.length > before ? result.commands.length - 1 : undefined
|
|
511
|
+
command = newCommand(operator === '|' || operator === '|&' ? { writer } : undefined)
|
|
509
512
|
if (operator === '(') subshells.push(folder)
|
|
510
513
|
else if (operator === ')') {
|
|
511
514
|
const outer = subshells.pop()
|
|
@@ -517,8 +520,8 @@ function walk(tokens: ParseEntry[], markers: Marker[], start: string, result: Pa
|
|
|
517
520
|
finish(command, ';', folder, result)
|
|
518
521
|
}
|
|
519
522
|
|
|
520
|
-
function newCommand(
|
|
521
|
-
return { words: [], redirects: [],
|
|
523
|
+
function newCommand(pipe: Pipe | undefined): Command {
|
|
524
|
+
return { words: [], redirects: [], pipe }
|
|
522
525
|
}
|
|
523
526
|
|
|
524
527
|
function isWordToken(token: ParseEntry): token is string | GlobPattern {
|
|
@@ -543,9 +546,13 @@ function finish(command: Command, operator: string, folder: string, result: Pars
|
|
|
543
546
|
const [first, ...args] = words
|
|
544
547
|
if (first === undefined || first.text === 'for' || first.text === 'select') return folder
|
|
545
548
|
const here = command.redirects.findLast((redirect) => redirect.operator === '<<<')
|
|
546
|
-
const stdin: Stdin | undefined = here !== undefined ? { kind: 'text', text: here.target.text } : command.
|
|
549
|
+
const stdin: Stdin | undefined = here !== undefined ? { kind: 'text', text: here.target.text } : command.pipe !== undefined ? { kind: 'pipe' } : undefined
|
|
550
|
+
const reader = result.commands.length
|
|
547
551
|
const changed = addCommand(first, args, folder, stdin, result)
|
|
548
|
-
const
|
|
552
|
+
const read = result.commands[reader]
|
|
553
|
+
const writer = command.pipe?.writer
|
|
554
|
+
if (read !== undefined && writer !== undefined && here === undefined) result.commands[reader] = { ...read, input: writer }
|
|
555
|
+
const isPiped = command.pipe !== undefined || operator === '|' || operator === '|&' || operator === '&'
|
|
549
556
|
return changed === undefined || isPiped ? folder : changed
|
|
550
557
|
}
|
|
551
558
|
|
package/testing/fake-claude.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fake-claude.d.ts","sourceRoot":"","sources":["../src/testing/fake-claude.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAGlD,MAAM,MAAM,QAAQ,GAAG;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,SAAS,OAAO,EAAE,CAAA;CAClC,CAAA;AAED,MAAM,MAAM,KAAK,GAAG;IAClB,OAAO,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAA;KAAE,CAAA;IAC/E,EAAE,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAA;KAAE,CAAA;IAC7J,IAAI,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAA;KAAE,CAAA;IACzC,QAAQ,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAA;KAAE,CAAA;IAC/C,MAAM,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"fake-claude.d.ts","sourceRoot":"","sources":["../src/testing/fake-claude.ts"],"names":[],"mappings":"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"}
|
package/testing/fake-claude.js
CHANGED
|
@@ -105,7 +105,6 @@ export function fakeClaude(plugin) {
|
|
|
105
105
|
settings: { read: rejected('settings.read', () => fakes.settings.read) },
|
|
106
106
|
config: {
|
|
107
107
|
list: rejected('config.list', () => fakes.config.list ?? (async () => [])),
|
|
108
|
-
set: rejected('config.set', () => fakes.config.set ?? (async ({ value }) => ({ value }))),
|
|
109
108
|
},
|
|
110
109
|
agent: {
|
|
111
110
|
list: rejected('agent.list', () => fakes.agent.list),
|
package/utils/parse-shell.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse-shell.d.ts","sourceRoot":"","sources":["../src/utils/parse-shell.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,YAAY,GAAG;IAAE,IAAI,EAAE,CAAC,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;
|
|
1
|
+
{"version":3,"file":"parse-shell.d.ts","sourceRoot":"","sources":["../src/utils/parse-shell.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,YAAY,GAAG;IAAE,IAAI,EAAE,CAAC,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAE1F,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,EAAE,YAAY,EAAE,CAAA;IACxB,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,aAAa,EAAE,OAAO,CAAA;CACvB,CAAA;AA4BD,eAAO,MAAM,cAAc,QAAS,CAAA;AAiKpC,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAIpD"}
|
package/utils/parse-shell.js
CHANGED
|
@@ -453,7 +453,7 @@ function readHeredocBodies(source, from, heredocs) {
|
|
|
453
453
|
function walk(tokens, markers, start, result) {
|
|
454
454
|
let folder = start;
|
|
455
455
|
const subshells = [];
|
|
456
|
-
let command = newCommand(
|
|
456
|
+
let command = newCommand(undefined);
|
|
457
457
|
let caseState;
|
|
458
458
|
for (let index = 0; index < tokens.length; index += 1) {
|
|
459
459
|
const token = tokens[index];
|
|
@@ -492,12 +492,14 @@ function walk(tokens, markers, start, result) {
|
|
|
492
492
|
}
|
|
493
493
|
const following = tokens[index + 1];
|
|
494
494
|
if (operator === '(' && command.words.length === 1 && following !== undefined && !isWordToken(following) && 'op' in following && following.op === ')') {
|
|
495
|
-
command = newCommand(
|
|
495
|
+
command = newCommand(undefined);
|
|
496
496
|
index += 1;
|
|
497
497
|
continue;
|
|
498
498
|
}
|
|
499
|
+
const before = result.commands.length;
|
|
499
500
|
folder = finish(command, operator, folder, result);
|
|
500
|
-
|
|
501
|
+
const writer = result.commands.length > before ? result.commands.length - 1 : undefined;
|
|
502
|
+
command = newCommand(operator === '|' || operator === '|&' ? { writer } : undefined);
|
|
501
503
|
if (operator === '(')
|
|
502
504
|
subshells.push(folder);
|
|
503
505
|
else if (operator === ')') {
|
|
@@ -513,8 +515,8 @@ function walk(tokens, markers, start, result) {
|
|
|
513
515
|
}
|
|
514
516
|
finish(command, ';', folder, result);
|
|
515
517
|
}
|
|
516
|
-
function newCommand(
|
|
517
|
-
return { words: [], redirects: [],
|
|
518
|
+
function newCommand(pipe) {
|
|
519
|
+
return { words: [], redirects: [], pipe };
|
|
518
520
|
}
|
|
519
521
|
function isWordToken(token) {
|
|
520
522
|
return typeof token === 'string' || ('op' in token && token.op === 'glob');
|
|
@@ -539,9 +541,14 @@ function finish(command, operator, folder, result) {
|
|
|
539
541
|
if (first === undefined || first.text === 'for' || first.text === 'select')
|
|
540
542
|
return folder;
|
|
541
543
|
const here = command.redirects.findLast((redirect) => redirect.operator === '<<<');
|
|
542
|
-
const stdin = here !== undefined ? { kind: 'text', text: here.target.text } : command.
|
|
544
|
+
const stdin = here !== undefined ? { kind: 'text', text: here.target.text } : command.pipe !== undefined ? { kind: 'pipe' } : undefined;
|
|
545
|
+
const reader = result.commands.length;
|
|
543
546
|
const changed = addCommand(first, args, folder, stdin, result);
|
|
544
|
-
const
|
|
547
|
+
const read = result.commands[reader];
|
|
548
|
+
const writer = command.pipe?.writer;
|
|
549
|
+
if (read !== undefined && writer !== undefined && here === undefined)
|
|
550
|
+
result.commands[reader] = { ...read, input: writer };
|
|
551
|
+
const isPiped = command.pipe !== undefined || operator === '|' || operator === '|&' || operator === '&';
|
|
545
552
|
return changed === undefined || isPiped ? folder : changed;
|
|
546
553
|
}
|
|
547
554
|
function withoutPrefixes(words) {
|