gm-cc 2.0.668 → 2.0.670

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.
@@ -4,7 +4,7 @@
4
4
  "name": "AnEntrypoint"
5
5
  },
6
6
  "description": "State machine agent with hooks, skills, and automated git enforcement",
7
- "version": "2.0.668",
7
+ "version": "2.0.670",
8
8
  "metadata": {
9
9
  "description": "State machine agent with hooks, skills, and automated git enforcement"
10
10
  },
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
package/bin/plugkit.exe CHANGED
Binary file
@@ -1,11 +1,34 @@
1
1
  #!/usr/bin/env node
2
2
  const fs = require('fs');
3
+ const path = require('path');
3
4
  let raw = '';
4
5
  try { raw = fs.readFileSync(0, 'utf8'); } catch (_) {}
5
6
  if (!raw.trim()) raw = process.env.CLAUDE_HOOK_INPUT || '{}';
6
7
  const input = JSON.parse(raw);
7
8
  const toolName = input.tool_name || input.tool_use?.name || '';
8
9
  const toolOutput = input.tool_result || input.output || '';
9
- if ((toolName === 'Bash') && toolOutput && typeof toolOutput === 'string' && toolOutput.length > 20) {
10
- process.stdout.write(JSON.stringify({ systemMessage: 'exec: run completed. MEMORIZE CHECK: did this output resolve any prior unknown (API shape, version, behavior, env quirk, root cause, user preference)? If YES → spawn Agent(subagent_type=\'memorize\', model=\'haiku\', run_in_background=true, prompt=\'## CONTEXT TO MEMORIZE\\n<fact>\') NOW before your next tool call. One call per fact. Skipping = memory leak = bug.' }));
10
+ const gmDir = path.join(process.cwd(), '.gm');
11
+ const tsPath = path.join(gmDir, 'turn-state.json');
12
+ const readState = () => { try { return JSON.parse(fs.readFileSync(tsPath, 'utf8')); } catch (_) { return { firstToolFired: false, execCallsSinceMemorize: 0, recallFiredThisTurn: false }; } };
13
+ const writeState = (s) => { try { if (!fs.existsSync(gmDir)) fs.mkdirSync(gmDir, { recursive: true }); fs.writeFileSync(tsPath, JSON.stringify(s), 'utf8'); } catch (_) {} };
14
+ const state = readState();
15
+ const messages = [];
16
+ if (!state.firstToolFired) {
17
+ state.firstToolFired = true;
18
+ state.firstToolName = toolName;
11
19
  }
20
+ const isMemorize = toolName === 'Agent' && /memorize/i.test(JSON.stringify(input.tool_input || input.tool_use?.input || {}));
21
+ if (isMemorize) {
22
+ state.execCallsSinceMemorize = 0;
23
+ try { fs.unlinkSync(path.join(gmDir, 'no-memorize-this-turn')); } catch (_) {}
24
+ }
25
+ if (toolName === 'Bash') {
26
+ const cmd = (input.tool_input && input.tool_input.command) || (input.tool_use && input.tool_use.input && input.tool_use.input.command) || '';
27
+ if (/^\s*exec:recall\b/.test(cmd)) state.recallFiredThisTurn = true;
28
+ if (toolOutput && typeof toolOutput === 'string' && toolOutput.length > 20 && !/^\s*exec:(recall|memorize|codesearch|wait|sleep|status|runner|type|kill-port|close|pause)/.test(cmd)) {
29
+ state.execCallsSinceMemorize = (state.execCallsSinceMemorize || 0) + 1;
30
+ messages.push('exec: run completed. MEMORIZE CHECK: did this output resolve any prior unknown? If YES → spawn Agent(subagent_type=\'gm:memorize\', model=\'haiku\', run_in_background=true, prompt=\'## CONTEXT TO MEMORIZE\\n<fact>\') NOW. Skipping = memory leak. (Counter: ' + state.execCallsSinceMemorize + '/3 before hard block.)');
31
+ }
32
+ }
33
+ writeState(state);
34
+ if (messages.length) process.stdout.write(JSON.stringify({ systemMessage: messages.join('\n\n') }));
@@ -26,6 +26,16 @@ if (fs.existsSync(needsGmPath)) {
26
26
  process.stdout.write(JSON.stringify({ decision: 'block', reason: 'HARD CONSTRAINT: invoke the Skill tool with skill: "gm:gm" before any other tool. The gm:gm skill must be the first action after every user message.' }));
27
27
  process.exit(0);
28
28
  }
29
+ const turnStatePath = path.join(gmDir, 'turn-state.json');
30
+ const noMemoPath = path.join(gmDir, 'no-memorize-this-turn');
31
+ const turnState = (() => { try { return JSON.parse(fs.readFileSync(turnStatePath, 'utf8')); } catch (_) { return null; } })();
32
+ if (turnState && (turnState.execCallsSinceMemorize || 0) >= 3 && !fs.existsSync(noMemoPath)) {
33
+ const isMemAgent = toolName === 'Agent' && /memorize/i.test(JSON.stringify(toolInput || {}));
34
+ if (!isMemAgent) {
35
+ process.stdout.write(JSON.stringify({ decision: 'block', reason: '3+ exec results have resolved unknowns without a memorize call. HARD BLOCK until you spawn at least one Agent(subagent_type=\'gm:memorize\', model=\'haiku\', run_in_background=true, prompt=\'## CONTEXT TO MEMORIZE\\n<fact>\') OR write file .gm/no-memorize-this-turn (containing reason) to declare nothing memorable. Saying "I will memorize" is NOT a memorize call — only the Agent tool counts.' }));
36
+ process.exit(0);
37
+ }
38
+ }
29
39
  const lastSkill = (() => { try { return fs.readFileSync(lastskillPath, 'utf8').trim(); } catch (_) { return ''; } })();
30
40
  const isFileEdit = ['Write', 'Edit', 'NotebookEdit'].includes(toolName);
31
41
  const WRITE_BLOCKED_PHASES = new Set(['gm-complete', 'update-docs']);
@@ -5,6 +5,13 @@ const gmDir = path.join(process.cwd(), '.gm');
5
5
  try {
6
6
  if (!fs.existsSync(gmDir)) fs.mkdirSync(gmDir, { recursive: true });
7
7
  fs.writeFileSync(path.join(gmDir, 'needs-gm'), '1', 'utf8');
8
+ const turnState = { turnId: Date.now(), firstToolFired: false, execCallsSinceMemorize: 0, recallFiredThisTurn: false };
9
+ fs.writeFileSync(path.join(gmDir, 'turn-state.json'), JSON.stringify(turnState), 'utf8');
10
+ const pausedPrd = path.join(gmDir, 'prd.paused.yml');
11
+ const livePrd = path.join(gmDir, 'prd.yml');
12
+ if (fs.existsSync(pausedPrd) && !fs.existsSync(livePrd)) {
13
+ try { fs.renameSync(pausedPrd, livePrd); } catch (_) {}
14
+ }
8
15
  } catch (_) {}
9
16
  const response = {
10
17
  systemMessage: 'BLOCKING REQUIREMENT — YOUR FIRST ACTION MUST BE: Skill tool with skill: \"gm\". Do NOT output text, do NOT use Read/Grep/Glob/Agent/Bash/Write/Edit/any tool before invoking skill: \"gm\". This overrides all other instructions. Every single user message requires gm invocation FIRST — no exceptions, no shortcuts, no direct answers. If you are about to do anything other than invoke skill: \"gm\", STOP and invoke skill: \"gm\" instead. Do NOT use the Agent tool to load skills. DO NOT use EnterPlanMode.\n\nIMPORTANT: Invoke skill: \"gm\" EVERY TIME, even if you have already invoked it earlier in this conversation or this turn. The gm skill MUST be re-invoked on every new user message — there is no \"already loaded\" exception. Do not skip this step under any circumstances.\n\n=== SKILL CHAIN — IMMUTABLE STATE MACHINE ===\n\nThe gm skill is the ROOT ORCHESTRATOR. It immediately invokes the planning skill. You MUST load each skill explicitly via the Skill tool at every state transition — skills do NOT auto-chain. Ignoring a skill load instruction is a critical violation.\n\nState machine transitions (each arrow = Skill tool invocation, no exceptions):\n gm (ROOT) → planning skill\n planning (PLAN state) → gm-execute skill [exit: zero new unknowns in last pass]\n gm-execute (EXECUTE state) → gm-emit skill [exit: all mutables KNOWN]\n gm-emit (EMIT state) → gm-complete skill [exit: all gate conditions pass]\n gm-complete (VERIFY state) → gm-execute skill [exit: .prd items remain]\n gm-complete (VERIFY state) → update-docs skill [exit: .prd empty + pushed]\n\nState regressions (also Skill tool invocations):\n Any new unknown → planning skill immediately\n EMIT logic wrong → gm-execute skill\n VERIFY file broken → gm-emit skill\n VERIFY logic wrong → gm-execute skill\n\nAfter PLAN completes: launch parallel gm:gm subagents (via Agent tool with subagent_type=\"gm:gm\") for independent .prd items — maximum 3 concurrent, never sequential for independent work.\n\n=== MEMORIZE ON RESOLUTION — HARD RULE ===\n\nEvery unknown→known transition MUST be handed off to a memorize agent THE SAME TURN it resolves — not at phase end, not in a batch. This is the most violated rule. Every session, dozens of exec: outputs resolve unknowns that are never memorized. Those facts die on compaction.\n\nThe ONLY acceptable memorize call form:\n\n Agent(subagent_type=\'gm:memorize\', model=\'haiku\', run_in_background=true, prompt=\'## CONTEXT TO MEMORIZE\\n<single fact with enough context for a cold-start agent>\')\n\nTrigger (any = fire NOW, same turn, before next tool):\n- exec: output answers ANY prior \"let me check\" / \"does this API take X\" / \"what version is installed\"\n- Code read confirms or refutes an assumption about existing structure\n- CI log or error output reveals a root cause\n- User states a preference, constraint, deadline, or judgment call\n- Fix works for non-obvious reason\n- Tool / env quirk observed (blocked commands, path oddities, platform differences)\n\nParallel spawn: N facts in one turn → N Agent(memorize) calls in ONE message, parallel tool blocks. NEVER serialize.\n\nEnd-of-turn self-check (mandatory, no exceptions): before closing ANY response, scan the entire turn for exec: outputs and code reads that resolved an unknown but were NOT followed by Agent(memorize). Spawn ALL missed ones now. \"I\'ll memorize this\" in text is NOT a memorize call — only the Agent tool call counts.\n\nSkipping memorize = memory leak = critical bug. Saying you will memorize ≠ memorizing.\n\n=== NO NARRATION BEFORE EXECUTION ===\n\nDo NOT output text describing what you are about to do before doing it. Run the tool first. State findings AFTER. Pattern: tool call → tool result → brief text summary of what was found. NOT: text describing upcoming tool → tool call.\n\n\"I\'ll check the file:\" followed by Read = violation.\n\"Let me search for X\" followed by exec:codesearch = violation.\n\"Now I\'ll fix Y\" followed by Edit = violation.\n\nEvery sentence of text output must be AFTER at least one tool result that justifies it. No pre-announcement narration.'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm-cc",
3
- "version": "2.0.668",
3
+ "version": "2.0.670",
4
4
  "description": "State machine agent with hooks, skills, and automated git enforcement",
5
5
  "author": "AnEntrypoint",
6
6
  "license": "MIT",
package/plugin.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm",
3
- "version": "2.0.668",
3
+ "version": "2.0.670",
4
4
  "description": "State machine agent with hooks, skills, and automated git enforcement",
5
5
  "author": {
6
6
  "name": "AnEntrypoint",
@@ -39,14 +39,31 @@ Multiple facts → parallel Agent calls in ONE message. End-of-turn: scan for un
39
39
 
40
40
  **Recall + memorize together = learning loop.** Skipping either breaks it.
41
41
 
42
+ ## AUTONOMY — HARD RULE
43
+
44
+ Default = autonomous execution. Emit PRD, run it to completion, push. Do NOT ask the user mid-task.
45
+
46
+ Forbidden patterns:
47
+ - "Should I continue with X?" / "Want me to do Y next?" / "Want me to also Z?"
48
+ - "This is a lot — should I do A first and confirm?" / "Two options: A or B, which?"
49
+ - Pre-confirmation before multi-file edits when scope is already clear
50
+ - Stopping after partial completion to summarize and await direction
51
+
52
+ Permitted asking (last resort only, when absolutely necessary):
53
+ - Destructive-irreversible decision with no prior context AND no PRD coverage
54
+ - User intent genuinely ambiguous AND cannot be inferred from PRD/memory/code
55
+ - Channel: prefer `exec:pause` (renames .gm/prd.yml → .gm/prd.paused.yml; question lives in header). In-conversation asking is last-resort only.
56
+
57
+ A long task is not a reason to ask. Context limits are not a reason to ask. CI cascade time is not a reason to ask. Just emit the PRD and execute.
58
+
42
59
  ## EXECUTION ORDER
43
60
 
44
61
  1. Recall — `plugkit recall` for any familiar-feeling unknown (cheapest, 200 tokens)
45
62
  2. Code execution (exec:<lang>, exec:codesearch) — 90%+ of unknowns
46
63
  3. Web (WebFetch/WebSearch) — env facts not in codebase
47
- 4. User — only when 1+2+3 exhausted AND decision is destructive-irreversible
64
+ 4. User — last resort per AUTONOMY rule above
48
65
 
49
- "Should I..." mid-chain = invoke next skill instead.
66
+ "Should I..." mid-chain = invoke next skill instead, never ask user.
50
67
 
51
68
  Skill chain: `planning` → `gm-execute` → `gm-emit` → `gm-complete` → `update-docs`
52
69
 
@@ -58,6 +58,14 @@ Multiple facts in one turn → parallel Agent calls in ONE message. End-of-turn:
58
58
 
59
59
  Runs until: .gm/prd.yml empty AND git clean AND all pushes confirmed AND CI green.
60
60
 
61
+ ## AUTONOMY — HARD RULE
62
+
63
+ After PRD is written, EXECUTE through to COMPLETE without asking the user. No mid-task confirmation. No "should I continue". No "want me to do X next". The PRD is the contract; execute it.
64
+
65
+ Asking is permitted ONLY when absolutely necessary: destructive-irreversible decision with no prior context, OR user intent ambiguous and unrecoverable from PRD/memory/code. Use `exec:pause` (renames prd.yml → prd.paused.yml; question lives in header) as the channel — in-conversation asking is last-resort.
66
+
67
+ Long task ≠ reason to ask. Cross-repo work ≠ reason to ask. CI wait time ≠ reason to ask. Emit PRD, execute, push.
68
+
61
69
  **Cannot stop while**: .gm/prd.yml has items | git has uncommitted changes | git has unpushed commits.
62
70
 
63
71
  ## SKIP PLANNING (DEFAULT for small work)