gcf-harness-aif-ext 0.8.0 → 0.8.1

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 CHANGED
@@ -33,7 +33,7 @@ This installs the `gcf-run` and `gcf-run-ingest` skills and registers the `gcf-h
33
33
  ai-factory gcf-harness init # per project: .claude/settings.json + .gitignore
34
34
  ```
35
35
 
36
- It is **per project**, not global — run it again in every game repository: it adds the readset-guard `PreToolUse` entry to the project's `.claude/settings.json` (never `~/.claude`) and `.gcf-session/` to `.gitignore`. It is idempotent — a re-run after moving or cloning the project repoints the hook at the new path — refuses when the `gcf` command is not registered, and refuses to rewrite a `settings.json` it cannot parse. It is a separate step for the same reason as `gcf hooks-install`: an AI Factory manifest cannot install Claude Code hooks.
36
+ It is **per project**, not global — run it again in every game repository: it adds the readset-guard `PreToolUse` entry to the project's `.claude/settings.json` (never `~/.claude`) and `.gcf-session/` to `.gitignore`. It also allows what an unattended `claude -p` run needs at least — `Edit`, `Write`, `Bash(git *)`, `Bash(ai-factory *)` — because print mode cannot ask and denies the rest; add your engine's tools yourself (for example `mcp__<editor-server>` for an editor driven over MCP). Commit `.claude/settings.json`: the rules apply to every Claude session in the project. It is idempotent — a re-run after moving or cloning the project repoints the hook at the new path — refuses when the `gcf` command is not registered, and refuses to rewrite a `settings.json` it cannot parse. It is a separate step for the same reason as `gcf hooks-install`: an AI Factory manifest cannot install Claude Code hooks.
37
37
 
38
38
  ## Upgrade
39
39
 
@@ -1,6 +1,7 @@
1
1
  // `ai-factory gcf-harness init` — registers the readset-guard PreToolUse hook in the
2
2
  // project's .claude/settings.json (the AIF manifest cannot install Claude Code hooks —
3
- // same decision as gcf hooks-install for git hooks). Idempotent by marker comment.
3
+ // same decision as gcf hooks-install for git hooks). Idempotent by marker comment. It also
4
+ // allows what a headless agent run needs (AGENT_ALLOW).
4
5
  // `ai-factory gcf-harness gate <ids…>` — the /gcf-run gate as code (Harness-PRD §4.3).
5
6
  import { readFile, writeFile, mkdir, appendFile } from 'node:fs/promises';
6
7
  import { existsSync, readFileSync } from 'node:fs';
@@ -210,6 +211,20 @@ function registerGuard(settings, command) {
210
211
  return stale.length ? 'repointed' : null;
211
212
  }
212
213
 
214
+ // What a headless `claude -p` run needs at least: it cannot ask, so anything not allowed is
215
+ // denied. The engine's own tools (an editor's MCP server) are the project's to add.
216
+ const AGENT_ALLOW = ['Edit', 'Write', 'Bash(git *)', 'Bash(ai-factory *)'];
217
+
218
+ /** Adds the rules the settings do not hold yet; returns the ones added. */
219
+ function allowAgent(settings) {
220
+ settings.permissions ??= {};
221
+ settings.permissions.allow ??= [];
222
+ const added = AGENT_ALLOW.filter((r) => !settings.permissions.allow.includes(r));
223
+ settings.permissions.allow.push(...added);
224
+
225
+ return added;
226
+ }
227
+
213
228
  /**
214
229
  * Only an active rule ignoring the root .gcf-session/ counts — not a comment or a pattern
215
230
  * for some other directory that happens to contain the name.
@@ -235,14 +250,17 @@ async function init(program) {
235
250
  const guard = path.join(EXT_ROOT, 'hooks', 'readset-guard.js').replaceAll('\\', '/');
236
251
  const settings = await readSettings(settingsFile);
237
252
  const change = registerGuard(settings, `node "${guard}" # ${MARKER}`);
238
- if (change) {
253
+ const allowed = allowAgent(settings);
254
+ if (change || allowed.length) {
239
255
  await mkdir(path.dirname(settingsFile), { recursive: true });
240
256
  await writeFile(settingsFile, `${JSON.stringify(settings, null, 2)}\n`, 'utf8');
241
- console.log(`readset-guard ${change} → ${settingsFile}`);
242
- } else {
243
- console.log('readset-guard already registered');
244
257
  }
245
258
 
259
+ console.log(
260
+ change ? `readset-guard ${change} → ${settingsFile}` : 'readset-guard already registered',
261
+ );
262
+ if (allowed.length) console.log(`agent runs may now: ${allowed.join(', ')}`);
263
+
246
264
  await ignoreSession(projectDir);
247
265
  }
248
266
 
@@ -261,7 +279,9 @@ export function register(program) {
261
279
 
262
280
  harness
263
281
  .command('init')
264
- .description('Initialize the harness in this project: readset-guard hook (idempotent)')
282
+ .description(
283
+ 'Initialize the harness in this project: readset-guard hook, agent permissions (idempotent)',
284
+ )
265
285
  .action(() => init(program));
266
286
 
267
287
  harness
package/extension.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://raw.githubusercontent.com/lee-to/ai-factory/2.x/schemas/extension.schema.json",
3
3
  "name": "gcf-harness-aif-ext",
4
- "version": "0.8.0",
4
+ "version": "0.8.1",
5
5
  "description": "GCF orchestration harness for Claude Code: one-command card pipeline, readset guard",
6
6
  "skills": [
7
7
  "skills/gcf-run",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gcf-harness-aif-ext",
3
- "version": "0.8.0",
3
+ "version": "0.8.1",
4
4
  "description": "GCF orchestration harness for Claude Code: one-command card pipeline, readset guard",
5
5
  "type": "module",
6
6
  "license": "MIT",