@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 +9 -6
- package/bin/opc.mjs +48 -8
- package/package.json +7 -2
- package/scripts/postinstall.mjs +9 -23
- package/skill.md +7 -7
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
|
-
##
|
|
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
|
-
|
|
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
|
|
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.
|
|
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"
|
package/scripts/postinstall.mjs
CHANGED
|
@@ -1,31 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
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
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
|
316
|
+
### Effort Check
|
|
315
317
|
|
|
316
|
-
- Count files agent referenced vs files in assigned scope
|
|
317
|
-
-
|
|
318
|
-
-
|
|
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.
|