Repository navigation
feat(init): allow exactly the installed CLI in each agent's permission file - #510
Conversation
|
@claude /review |
|
Claude finished @theCodeDrift's task in 6m 57s —— View job Review completeReview mode: incremental — read 0 prior review thread(s) before reviewing.
[New] Likely type error:
|
| } else { | ||
| install.permissions = records; | ||
| } | ||
| manifest.install = install; |
There was a problem hiding this comment.
[New] manifest.install = install; assigns a Record<string, unknown> to a property typed TasklessInstallManifest | undefined (cliVersion?: string; targets?: ...; onboarded?: boolean; in filesystem/manifest.ts, no index signature and no permissions field). That direction of assignment requires every declared property of the target to be satisfiable from the source's unknown index signature, which doesn't hold — this should fail tsc --noEmit/pnpm typecheck as written.
Compare with install/state.ts:112-113, which merges { ...previousInstall, ...toInstallManifest(state) } without ever widening through an explicit Record<string, unknown> annotation, so it stays structurally assignable.
Suggest adding permissions?: Record<string, { rules: string[]; created: boolean }> to TasklessInstallManifest so this function can build a properly-typed value instead of casting through Record<string, unknown>.
It does typecheck ( — AI Coding Agent |
…n file init writes a version-pinned allow rule for each harness it installs the skill into: Claude Code, Cursor (editor and CLI), OpenCode (object and array forms), and Codex when present. Each rule uses its harness's word-bounded form. The manifest records what was written, so an upgrade replaces only Taskless's own rule; a file that denies the command or does not parse is left alone. Edits keep the file's formatting and comments. Every edit is announced as Created/Edited <file> with green ALLOW and red REMOVE lines; the wizard previews them and asks before writing, and init --json carries them under permissions. Archives the pinned-cli-permissions OpenSpec change.
df696d3 to
69f7196
Compare
Stack (root → tip):
Tip of a two-PR stack that merges forward, stacked on #509. It delivers the second half of
pinned-cli-permissionsand archives the change.What
initwrites, for each harness it installs the skill into, in the wizard and in--no-interactive:.claude/settings.jsonpermissions.allow:Bash(<inv> *).cursor/permissions.jsonterminalAllowlist:<inv>.cursor/cli.jsonShell(npx:<spec>),Shell(npx:<spec> *)opencode.json[c](root or.opencode/), else.opencode/opencode.json.codex/rules/taskless.rules, only when.agents/is selected and Codex is detectedprefix_rule(pattern = ["npx","<spec>"], decision = "allow")Every other harness, including everything that reads
.agents/skills, gets no rule and falls back to per-command approval in the skill.Guarantees
@0.13.0never matches@0.13.01. The Codex form was checked withcodex execpolicy check.install.permissionsin the manifest records exactly what was written, so the upgrade swaps that entry. A rule the user wrote, even one for Taskless, is never touched.jsonc-parser(new bundled devDependency, already in the lockfile). Entries are placed by hand, because the library's formatter reflowed lines: a user's trailing comment ended up describing our entry. Removals are computed from the parse tree, because the library's removal left a stray quote after an inline insert. Every hand-placed edit is checked to parse back to the value it wrote, and falls back to the formatter if it doesn't.Announced edits
Edited <file>orCreated <file>line, then a greenALLOW:line per rule added and a redREMOVE:line per old rule taken out. A skipped file gets a yellowSKIPPED:line with the reason.init --jsoncarries them underpermissions.Skill and recipe
Bash(<inv> *).initrecipe documentspermissionsand goes to topic v8.The changeset at the bottom of the stack grows to describe this PR. Typecheck, lint, and all 2329 CLI tests pass.
Verified against the real build in scratch projects:
.jsonckept its comments, with the rule placed after the"*": "ask"catch-all.Not verified by hand: Cursor CLI's
Shell(npx:<args> *)glob, specifically whether*crosses/in file arguments. The docs leave it open.