@touchskyer/opc 0.2.0 → 0.2.2

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
@@ -35,6 +35,8 @@ git clone https://github.com/iamtouchskyer/opc.git
35
35
  ln -s $(pwd)/opc ~/.claude/skills/opc
36
36
  ```
37
37
 
38
+ > **Note:** Symlink tracks the repo — `git pull` updates the skill immediately. Use `cp -r` instead if you want a stable snapshot.
39
+
38
40
  ### Use it
39
41
 
40
42
  ```bash
@@ -130,7 +132,13 @@ You: /opc review this PR
130
132
  6. Report → Curated findings with severity, file:line references, and fix suggestions
131
133
  ```
132
134
 
133
- ## Works better with memex
135
+ ## Requirements
136
+
137
+ - [Claude Code](https://claude.ai/code) (CLI, desktop app, or IDE extension)
138
+ - Node.js ≥ 18 (for npm install only — not needed if you install manually)
139
+ - That's it. No runtime dependencies, no build step, no MCP server. Just markdown files.
140
+
141
+ ## Works better with memex (optional)
134
142
 
135
143
  OPC works standalone — but pair it with [memex](https://github.com/iamtouchskyer/memex) and it learns across sessions. Memex remembers which roles were useful, which findings were false positives, and your project-specific context. OPC doesn't need to know how memex works — memex drives itself.
136
144
 
@@ -138,11 +146,6 @@ OPC works standalone — but pair it with [memex](https://github.com/iamtouchsky
138
146
  npm install -g @touchskyer/memex
139
147
  ```
140
148
 
141
- ## Requirements
142
-
143
- - [Claude Code](https://claude.ai/code) (CLI, desktop app, or IDE extension)
144
- - That's it. No dependencies, no build step, no MCP server. Just markdown files.
145
-
146
149
  ## License
147
150
 
148
151
  MIT
package/bin/opc.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { existsSync, mkdirSync, cpSync, rmSync, readFileSync } from "fs";
3
+ import { existsSync, mkdirSync, cpSync, rmSync, readdirSync, readFileSync, lstatSync, readlinkSync, realpathSync } from "fs";
4
4
  import { join, dirname } from "path";
5
5
  import { homedir } from "os";
6
6
  import { fileURLToPath } from "url";
@@ -9,15 +9,27 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
9
9
  const SKILL_NAME = "opc";
10
10
  const skillsDir = join(homedir(), ".claude", "skills", SKILL_NAME);
11
11
  const srcDir = join(__dirname, "..");
12
- const entries = ["skill.md", "roles"];
12
+
13
+ // Only these files/dirs are managed by OPC — custom roles are left alone
14
+ const MANAGED_ENTRIES = ["skill.md", "roles"];
13
15
 
14
16
  const pkg = JSON.parse(readFileSync(join(srcDir, "package.json"), "utf8"));
15
17
  const command = process.argv[2];
16
18
 
17
19
  switch (command) {
18
20
  case "install": {
21
+ // If skillsDir is a symlink pointing to srcDir, it's already installed via symlink
22
+ if (existsSync(skillsDir) && lstatSync(skillsDir).isSymbolicLink()) {
23
+ const target = realpathSync(skillsDir);
24
+ const src = realpathSync(srcDir);
25
+ if (target === src) {
26
+ console.log(`✓ OPC v${pkg.version} already linked at ${skillsDir}`);
27
+ console.log(` Use /opc in Claude Code to get started.`);
28
+ break;
29
+ }
30
+ }
19
31
  mkdirSync(skillsDir, { recursive: true });
20
- for (const entry of entries) {
32
+ for (const entry of MANAGED_ENTRIES) {
21
33
  const src = join(srcDir, entry);
22
34
  if (!existsSync(src)) continue;
23
35
  cpSync(src, join(skillsDir, entry), { recursive: true, force: true });
@@ -28,12 +40,40 @@ switch (command) {
28
40
  }
29
41
 
30
42
  case "uninstall": {
31
- if (existsSync(skillsDir)) {
32
- rmSync(skillsDir, { recursive: true });
33
- console.log(`✓ OPC removed from ${skillsDir}`);
34
- } else {
43
+ if (!existsSync(skillsDir)) {
35
44
  console.log(`Nothing to remove — ${skillsDir} does not exist.`);
45
+ break;
46
+ }
47
+
48
+ // Only remove OPC-managed files, preserve custom roles
49
+ const rolesDir = join(skillsDir, "roles");
50
+ const managedRoles = readdirSync(join(srcDir, "roles"));
51
+
52
+ // Remove managed role files
53
+ if (existsSync(rolesDir)) {
54
+ for (const role of managedRoles) {
55
+ const rolePath = join(rolesDir, role);
56
+ if (existsSync(rolePath)) rmSync(rolePath);
57
+ }
58
+ // Remove roles dir only if empty
59
+ try {
60
+ const remaining = readdirSync(rolesDir);
61
+ if (remaining.length === 0) rmSync(rolesDir);
62
+ else console.log(` Kept ${remaining.length} custom role(s) in ${rolesDir}`);
63
+ } catch {}
36
64
  }
65
+
66
+ // Remove skill.md
67
+ const skillFile = join(skillsDir, "skill.md");
68
+ if (existsSync(skillFile)) rmSync(skillFile);
69
+
70
+ // Remove dir only if empty
71
+ try {
72
+ const remaining = readdirSync(skillsDir);
73
+ if (remaining.length === 0) rmSync(skillsDir);
74
+ } catch {}
75
+
76
+ console.log(`✓ OPC removed from ${skillsDir}`);
37
77
  break;
38
78
  }
39
79
 
@@ -49,7 +89,7 @@ switch (command) {
49
89
  console.log();
50
90
  console.log("Usage:");
51
91
  console.log(" opc install Install skill files to ~/.claude/skills/opc/");
52
- console.log(" opc uninstall Remove skill files");
92
+ console.log(" opc uninstall Remove skill files (preserves custom roles)");
53
93
  console.log(" opc version Show version");
54
94
  console.log();
55
95
  console.log("Once installed, use /opc in Claude Code.");
package/package.json CHANGED
@@ -1,16 +1,21 @@
1
1
  {
2
2
  "name": "@touchskyer/opc",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "OPC — One Person Company. A full team in a single Claude Code skill.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "opc": "bin/opc.mjs"
8
8
  },
9
+ "engines": {
10
+ "node": ">=18"
11
+ },
9
12
  "files": [
10
13
  "bin",
11
14
  "scripts",
12
15
  "skill.md",
13
- "roles"
16
+ "roles",
17
+ "README.md",
18
+ "LICENSE"
14
19
  ],
15
20
  "scripts": {
16
21
  "postinstall": "node scripts/postinstall.mjs"
@@ -1,31 +1,17 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { existsSync, mkdirSync, cpSync, readFileSync } from "fs";
4
- import { join } from "path";
5
- import { homedir } from "os";
3
+ // Delegate to bin/opc.mjs install
4
+ import { execFileSync } from "child_process";
5
+ import { join, dirname } from "path";
6
+ import { fileURLToPath } from "url";
6
7
 
7
- const SKILL_NAME = "opc";
8
- const skillsDir = join(homedir(), ".claude", "skills", SKILL_NAME);
9
- const srcDir = join(import.meta.dirname, "..");
10
-
11
- // Files to copy
12
- const entries = ["skill.md", "roles"];
8
+ const __dirname = dirname(fileURLToPath(import.meta.url));
13
9
 
14
10
  try {
15
- mkdirSync(skillsDir, { recursive: true });
16
-
17
- for (const entry of entries) {
18
- const src = join(srcDir, entry);
19
- if (!existsSync(src)) continue;
20
- cpSync(src, join(skillsDir, entry), { recursive: true, force: true });
21
- }
22
-
23
- const pkg = JSON.parse(readFileSync(join(srcDir, "package.json"), "utf8"));
24
- console.log(`✓ OPC v${pkg.version} installed to ${skillsDir}`);
25
- console.log(` Use /opc in Claude Code to get started.`);
11
+ execFileSync(process.execPath, [join(__dirname, "..", "bin", "opc.mjs"), "install"], {
12
+ stdio: "inherit",
13
+ });
26
14
  } catch (err) {
27
- // Don't fail the install if copy fails (e.g., permissions)
28
- console.warn(`⚠ Could not install OPC skill files to ${skillsDir}`);
29
- console.warn(` Run 'opc install' manually to retry.`);
15
+ console.warn(`⚠ Postinstall failed. Run 'opc install' manually.`);
30
16
  console.warn(` Error: ${err.message}`);
31
17
  }
package/skill.md CHANGED
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: opc
3
- version: 0.2.0
3
+ version: 0.2.2
4
4
  description: "OPC — One Person Company. A full team in a single skill: 11 specialist agents for review, analysis, execution, and brainstorming. /opc review, /opc -i, or /opc <role>."
5
5
  ---
6
6
 
@@ -143,6 +143,8 @@ For Modes B/C/D, light context gathering (read key files) is sufficient — no f
143
143
 
144
144
  ## Step 5: Dispatch Agents
145
145
 
146
+ **Agent prompt = mode template + role file only.** Do NOT inject full skill.md into agents. Each agent gets: its mode-specific instruction block, the role's expertise + anti-patterns, project context, and task scope. The coordinator reads skill.md; agents do not.
147
+
146
148
  Launch agents in parallel. Each agent prompt is assembled from:
147
149
 
148
150
  ```
@@ -311,12 +313,11 @@ For findings that pass mechanical checks:
311
313
  2. **Challenge severity** — "Is this really 🔴? What's the concrete exploit path?"
312
314
  3. **Deduplicate** — multiple agents reporting same issue → keep best-articulated one
313
315
 
314
- ### Effort Check (Mode A/B)
316
+ ### Effort Check
315
317
 
316
- - Count files agent referenced vs files in assigned scope
317
- - If scope 5 files: coverage must be 100%. If scope > 5 files: coverage 50%.
318
- - If output is suspiciously thin for scope complexity RE-DISPATCH with explicit file list
319
- - Mode C: verify all files in scope were addressed. Mode D: check that key constraints were considered.
318
+ - **Mode A/B:** Count files agent referenced vs files in assigned scope. If scope ≤ 5 files: coverage must be 100%. If scope > 5 files: coverage ≥ 50%. If suspiciously thin → RE-DISPATCH with explicit file list.
319
+ - **Mode C:** Verify all files in scope were addressed in the modification list.
320
+ - **Mode D:** Check that key constraints from the prompt were considered. No file-coverage metric.
320
321
 
321
322
  ### Coordinator Actions
322
323
 
@@ -389,7 +390,6 @@ Recommendation: {coordinator's pick with rationale}
389
390
  ## Notes
390
391
 
391
392
  - Agents run via the Agent tool with `subagent_type: "general-purpose"`.
392
- - **Agent prompt = mode template + role file only.** Do NOT inject full skill.md into agents. Each agent gets: its mode-specific instruction block, the role's expertise + anti-patterns, project context, and task scope. The coordinator reads skill.md; agents do not.
393
393
  - Agents are READ-ONLY by default. No code changes except in Mode C.
394
394
  - Scope each agent to specific files — don't let them scan everything.
395
395
  - If scope exceeds 20 files, split across multiple agents of the same role.