gm-cc 2.0.727 → 2.0.1064

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.
Files changed (44) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/agents/gm.md +1 -3
  3. package/agents/memorize.md +22 -2
  4. package/agents/research-worker.md +36 -0
  5. package/agents/textprocessing.md +47 -0
  6. package/bin/bootstrap.js +624 -34
  7. package/bin/plugkit.js +95 -53
  8. package/bin/plugkit.sha256 +6 -6
  9. package/bin/plugkit.version +1 -1
  10. package/bin/rtk.sha256 +6 -0
  11. package/bin/rtk.version +1 -0
  12. package/hooks/hooks.json +2 -46
  13. package/hooks/hooks.spec.json +48 -0
  14. package/package.json +2 -2
  15. package/plugin.json +1 -1
  16. package/skills/browser/SKILL.md +18 -16
  17. package/skills/code-search/SKILL.md +15 -15
  18. package/skills/create-lang-plugin/SKILL.md +22 -26
  19. package/skills/gm/SKILL.md +31 -66
  20. package/skills/gm-cc/SKILL.md +19 -0
  21. package/skills/gm-codex/SKILL.md +19 -0
  22. package/skills/gm-complete/SKILL.md +52 -69
  23. package/skills/gm-copilot-cli/SKILL.md +19 -0
  24. package/skills/gm-cursor/SKILL.md +19 -0
  25. package/skills/gm-emit/SKILL.md +44 -61
  26. package/skills/gm-execute/SKILL.md +42 -84
  27. package/skills/gm-gc/SKILL.md +19 -0
  28. package/skills/gm-jetbrains/SKILL.md +19 -0
  29. package/skills/gm-kilo/SKILL.md +19 -0
  30. package/skills/gm-oc/SKILL.md +19 -0
  31. package/skills/gm-vscode/SKILL.md +19 -0
  32. package/skills/gm-zed/SKILL.md +19 -0
  33. package/skills/governance/SKILL.md +24 -23
  34. package/skills/pages/SKILL.md +42 -92
  35. package/skills/planning/SKILL.md +83 -80
  36. package/skills/research/SKILL.md +43 -0
  37. package/skills/ssh/SKILL.md +15 -9
  38. package/skills/textprocessing/SKILL.md +40 -0
  39. package/skills/update-docs/SKILL.md +27 -21
  40. package/.github/workflows/publish-npm.yml +0 -44
  41. package/hooks/post-tool-use-hook.js +0 -34
  42. package/hooks/pre-tool-use-hook.js +0 -45
  43. package/hooks/prompt-submit-hook.js +0 -19
  44. package/hooks/session-start-hook.js +0 -23
@@ -0,0 +1,40 @@
1
+ ---
2
+ name: textprocessing
3
+ description: The required surface for any text task whose correctness depends on understanding. Code does mechanics; this skill does meaning. Invoked via Agent(subagent_type='gm:textprocessing', model='haiku', ...).
4
+ allowed-tools: Skill
5
+ ---
6
+
7
+ # Textprocessing — Meaning goes through Haiku
8
+
9
+ ## Invocation
10
+
11
+ ```
12
+ Agent(subagent_type='gm:textprocessing', model='haiku', prompt='## INPUT\n<body>\n\n## INSTRUCTION\n<task>')
13
+ ```
14
+
15
+ Background fire-and-forget: add `run_in_background=true`. Batch: N parallel `Agent` calls in one message, one per item.
16
+
17
+ ## The split
18
+
19
+ Mechanics stay in code: char/word/token/line counts, byte length, split on delimiter, exact-string find/replace, regex match/extract, sort, group-by-key, dedup-by-equality, lower/uppercase, JSON parse/stringify, base64, URL encode, hash, diff, format/pretty-print.
20
+
21
+ Meaning goes through this skill: summarize, classify, extract entities or intents, rewrite for tone or audience, translate, semantic dedup (same meaning, different words), rank or score by quality, label by topic, decide whether two texts are about the same thing, paraphrase, simplify, expand outline → prose, headline-from-body, body-from-headline, fact-from-passage, sentiment, toxicity, relevance, similarity-by-meaning.
22
+
23
+ The bar: would a human have to *read and understand* the text to do this correctly? Yes → skill. No → code. A keyword-list, a regex on phrases like "important", or a string-similarity ratio loop deciding meaning is a stub of this skill. Replace it with one (or N parallel) Agent calls.
24
+
25
+ ## Batch
26
+
27
+ Independent items run in parallel — one Agent call per item, all in one message. The runner Promise-allSettles. Sequential calls are wasteful when items don't depend on each other.
28
+
29
+ For one large body exceeding a single-prompt budget, the *caller* chunks deterministically (paragraph, section, fixed token count), fans out one Agent per chunk, and merges with a final reducer Agent if cross-chunk synthesis is needed. The agent itself never chunks — it processes whatever it receives in one shot.
30
+
31
+ ## Output contract
32
+
33
+ Plain-text instruction → plain-text output, no fences, no labels. JSON instruction → exactly that JSON, parseable by `JSON.parse`. Multi-document input requested as a list → one entry per input doc in the same order. Ambiguous shape → defaults to plain text. Empty input → empty output.
34
+
35
+ ## Constraints
36
+
37
+ - Model fixed at `haiku`. Escalate to opus only when haiku output fails an acceptance check.
38
+ - One transform per call. Three parallel calls beats one prompt asking for "summarize AND classify AND translate".
39
+ - Idempotent: same input + same instruction → same output, modulo sampling. Strict determinism callers specify `temperature=0` in the prompt.
40
+ - Output is the deliverable. No commentary, no "here is your output".
@@ -5,24 +5,22 @@ description: UPDATE-DOCS phase. Refresh README.md, AGENTS.md, and docs/index.htm
5
5
 
6
6
  # GM UPDATE-DOCS
7
7
 
8
- GRAPH: `PLAN EXECUTE EMIT VERIFY[UPDATE-DOCS]COMPLETE`
9
- Entry: feature verified, committed, pushed. From `gm-complete`.
8
+ Entry: feature verified, committed, pushed. Exit: docs match disk, committed, pushed COMPLETE. Unknown architecture change → `planning`.
10
9
 
11
- **FORWARD**: docs updated + committed + pushed COMPLETE
12
- **BACKWARD**: unknown architecture change → `planning`
10
+ Every claim in docs is verifiable against disk. Phase names match frontmatter, platform names match `platforms/`, file paths exist, constraint counts are accurate. An unverifiable section is removed, not speculated.
13
11
 
14
12
  ## Sequence
15
13
 
16
- **1What changed**:
14
+ What changed run directly via Bash:
15
+
17
16
  ```
18
- exec:bash
19
17
  git log -5 --oneline
20
18
  git diff HEAD~1 --stat
21
19
  ```
22
20
 
23
- **2 Read current docs**:
21
+ Read current docs via Read tool, or via a nodejs spool file (`in/nodejs/<N>.js`):
22
+
24
23
  ```
25
- exec:nodejs
26
24
  const fs = require('fs');
27
25
  ['README.md', 'AGENTS.md', 'docs/index.html', 'gm-starter/agents/gm.md'].forEach(f => {
28
26
  try { console.log(`=== ${f} ===\n` + fs.readFileSync(f, 'utf8')); }
@@ -30,31 +28,39 @@ const fs = require('fs');
30
28
  });
31
29
  ```
32
30
 
33
- **3 — Write changed sections only**:
31
+ Write changed sections only:
32
+
33
+ - **README.md** — platform count, skill tree diagram, quick-start commands
34
+ - **AGENTS.md** — via `Agent(subagent_type='gm:memorize', model='haiku', run_in_background=true, prompt='## CONTEXT TO MEMORIZE\n<learnings>')`. Never inline-edit.
35
+ - **docs/index.html** — `PHASES` array, platform lists, state machine diagram
36
+ - **gm-starter/agents/gm.md** — skill chain line if new skills added
34
37
 
35
- - **README.md**: platform count, skill tree diagram, quick start commands
36
- - **AGENTS.md**: via memorize sub-agent only — never inline-edit. `Agent(subagent_type='gm:memorize', model='haiku', run_in_background=true, prompt='## CONTEXT TO MEMORIZE\n<learnings>')`
37
- - **docs/index.html**: `PHASES` array, platform lists, state machine diagram
38
- - **gm-starter/agents/gm.md**: skill chain line if new skills added
38
+ Verify from disk (Read tool, or a nodejs spool file):
39
39
 
40
- **4 — Verify from disk**:
41
40
  ```
42
- exec:nodejs
43
41
  const content = require('fs').readFileSync('/abs/path/file.md', 'utf8');
44
42
  console.log(content.includes('expectedString'), content.length);
45
43
  ```
46
44
 
47
- **5 — Commit and push**:
45
+ Commit and push directly via Bash:
46
+
48
47
  ```
49
- exec:bash
50
48
  git add README.md docs/index.html gm-starter/agents/gm.md
51
49
  git commit -m "docs: update documentation to reflect session changes"
52
50
  git push -u origin HEAD
53
51
  ```
54
52
 
55
- ## Fidelity Rules
53
+ ## Exit: browser cleanup
54
+
55
+ After docs push succeeds, close any browser sessions spawned during this or prior skill phases. Write a nodejs spool file calling rs-exec:
56
56
 
57
- Every claim verifiable against disk: phase names match frontmatter, platform names match `platforms/`, file paths exist, constraint counts accurate. Unverifiable section → remove, don't speculate.
57
+ ```javascript
58
+ const sessionId = process.env.CLAUDE_SESSION_ID;
59
+ if (!sessionId) return;
60
+ const rs = require('rs-exec');
61
+ try {
62
+ rs.client().close_sessions_for(sessionId).catch(() => {});
63
+ } catch (e) {}
64
+ ```
58
65
 
59
- **Never**: write from memory | push without disk verify | add comments | claim done without witnessed push
60
- **Always**: git diff first | read before overwriting | verify after write | push
66
+ Best-effort: session context or rs-exec unavailable skip gracefully. No error thrown.
@@ -1,44 +0,0 @@
1
- name: Publish to npm
2
-
3
- on:
4
- push:
5
- branches:
6
- - main
7
- workflow_dispatch:
8
-
9
- jobs:
10
- publish:
11
- runs-on: ubuntu-latest
12
- steps:
13
- - uses: actions/checkout@v4
14
-
15
- - uses: actions/setup-node@v4
16
- with:
17
- node-version: '22'
18
- registry-url: 'https://registry.npmjs.org'
19
-
20
- - name: Publish to npm
21
- run: |
22
- PACKAGE=$(jq -r '.name' package.json)
23
- VERSION=$(jq -r '.version' package.json)
24
- echo "Package: $PACKAGE@$VERSION"
25
-
26
- # Skip if this exact version is already on npm
27
- PUBLISHED=$(npm view "$PACKAGE@$VERSION" version 2>/dev/null || echo "")
28
- if [ "$PUBLISHED" = "$VERSION" ]; then
29
- echo "✅ $PACKAGE@$VERSION already published - skipping"
30
- exit 0
31
- fi
32
-
33
- echo "Publishing $PACKAGE@$VERSION..."
34
- npm publish --access public 2>&1 | tee /tmp/npm-out.log; EXIT=${PIPESTATUS[0]}
35
- if [ "$EXIT" != "0" ]; then
36
- if grep -q "cannot publish over\|previously published" /tmp/npm-out.log; then
37
- echo "⚠️ Version already published, skipping"
38
- else
39
- exit "$EXIT"
40
- fi
41
- fi
42
- echo "✅ Published $PACKAGE@$VERSION"
43
- env:
44
- NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
@@ -1,34 +0,0 @@
1
- #!/usr/bin/env node
2
- const fs = require('fs');
3
- const path = require('path');
4
- let raw = '';
5
- try { raw = fs.readFileSync(0, 'utf8'); } catch (_) {}
6
- if (!raw.trim()) raw = process.env.CLAUDE_HOOK_INPUT || '{}';
7
- const input = JSON.parse(raw);
8
- const toolName = input.tool_name || input.tool_use?.name || '';
9
- const toolOutput = input.tool_result || input.output || '';
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;
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') }));
@@ -1,45 +0,0 @@
1
- #!/usr/bin/env node
2
- const fs = require('fs');
3
- const path = require('path');
4
- let raw = '';
5
- try { raw = fs.readFileSync(0, 'utf8'); } catch (_) {}
6
- if (!raw.trim()) raw = process.env.CLAUDE_HOOK_INPUT || '{}';
7
- const input = JSON.parse(raw);
8
- const toolName = input.tool_name || input.tool_use?.name || '';
9
- const toolInput = input.tool_input || input.tool_use?.input || {};
10
- const skillName = toolInput.skill || toolInput.name || '';
11
- const gmDir = path.join(process.cwd(), '.gm');
12
- const needsGmPath = path.join(gmDir, 'needs-gm');
13
- const lastskillPath = path.join(gmDir, 'lastskill');
14
- const isSkillTool = toolName === 'Skill' || toolName === 'skill';
15
- if (isSkillTool && skillName) {
16
- try {
17
- if (!fs.existsSync(gmDir)) fs.mkdirSync(gmDir, { recursive: true });
18
- fs.writeFileSync(lastskillPath, skillName, 'utf8');
19
- if (skillName === 'gm' || skillName === 'gm:gm') {
20
- try { fs.unlinkSync(needsGmPath); } catch (_) {}
21
- }
22
- } catch (_) {}
23
- process.exit(0);
24
- }
25
- if (fs.existsSync(needsGmPath)) {
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
- process.exit(0);
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
- }
39
- const lastSkill = (() => { try { return fs.readFileSync(lastskillPath, 'utf8').trim(); } catch (_) { return ''; } })();
40
- const isFileEdit = ['Write', 'Edit', 'NotebookEdit'].includes(toolName);
41
- const WRITE_BLOCKED_PHASES = new Set(['gm-complete', 'update-docs']);
42
- if (isFileEdit && WRITE_BLOCKED_PHASES.has(lastSkill)) {
43
- process.stdout.write(JSON.stringify({ decision: 'block', reason: 'File edits are not permitted in ' + lastSkill + ' phase. Regress to gm-execute if changes are needed, or invoke gm-emit to re-emit.' }));
44
- process.exit(0);
45
- }
@@ -1,19 +0,0 @@
1
- #!/usr/bin/env node
2
- const fs = require('fs');
3
- const path = require('path');
4
- const gmDir = path.join(process.cwd(), '.gm');
5
- try {
6
- if (!fs.existsSync(gmDir)) fs.mkdirSync(gmDir, { recursive: true });
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
- }
15
- } catch (_) {}
16
- const response = {
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.'
18
- };
19
- process.stdout.write(JSON.stringify(response));
@@ -1,23 +0,0 @@
1
- #!/usr/bin/env node
2
- const fs = require('fs');
3
- const path = require('path');
4
- const os = require('os');
5
- const { spawn } = require('child_process');
6
- try {
7
- const bootstrapPath = path.join(__dirname, '..', 'bin', 'bootstrap.js');
8
- if (fs.existsSync(bootstrapPath)) {
9
- const child = spawn(process.execPath, [bootstrapPath], { stdio: ['ignore', 'ignore', 'inherit'], detached: true, windowsHide: true });
10
- child.unref();
11
- }
12
- } catch (_) {}
13
- try {
14
- const plugkitJs = path.join(__dirname, '..', 'bin', 'plugkit.js');
15
- const gmToolsWrapper = path.join(os.homedir(), '.claude', 'gm-tools', 'plugkit');
16
- if (fs.existsSync(gmToolsWrapper)) {
17
- const current = fs.readFileSync(gmToolsWrapper, 'utf8');
18
- if (!current.includes('plugkit.js')) {
19
- fs.writeFileSync(gmToolsWrapper, '#!/bin/sh\nexec node "' + plugkitJs + '" "$@"\n', { mode: 0o755 });
20
- }
21
- }
22
- } catch (_) {}
23
- process.exit(0);