@kleber.mottajr/juninho 1.1.0 → 1.2.0
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 +112 -13
- package/dist/cli.js +40 -23
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +5 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +7 -1
- package/dist/config.js.map +1 -1
- package/dist/installer.d.ts +2 -0
- package/dist/installer.d.ts.map +1 -1
- package/dist/installer.js +178 -54
- package/dist/installer.js.map +1 -1
- package/dist/lint-detection.d.ts +26 -0
- package/dist/lint-detection.d.ts.map +1 -0
- package/dist/lint-detection.js +200 -0
- package/dist/lint-detection.js.map +1 -0
- package/dist/models.js +4 -4
- package/dist/models.js.map +1 -1
- package/dist/project-types.d.ts +47 -0
- package/dist/project-types.d.ts.map +1 -0
- package/dist/project-types.js +251 -0
- package/dist/project-types.js.map +1 -0
- package/dist/templates/agents.d.ts +2 -1
- package/dist/templates/agents.d.ts.map +1 -1
- package/dist/templates/agents.js +7 -5
- package/dist/templates/agents.js.map +1 -1
- package/dist/templates/commands.d.ts.map +1 -1
- package/dist/templates/commands.js +225 -150
- package/dist/templates/commands.js.map +1 -1
- package/dist/templates/docs.d.ts +2 -1
- package/dist/templates/docs.d.ts.map +1 -1
- package/dist/templates/docs.js +61 -14
- package/dist/templates/docs.js.map +1 -1
- package/dist/templates/plugins.d.ts +2 -1
- package/dist/templates/plugins.d.ts.map +1 -1
- package/dist/templates/plugins.js +167 -102
- package/dist/templates/plugins.js.map +1 -1
- package/dist/templates/skills.d.ts +2 -1
- package/dist/templates/skills.d.ts.map +1 -1
- package/dist/templates/skills.js +708 -195
- package/dist/templates/skills.js.map +1 -1
- package/dist/templates/support-scripts.d.ts +2 -1
- package/dist/templates/support-scripts.d.ts.map +1 -1
- package/dist/templates/support-scripts.js +468 -21
- package/dist/templates/support-scripts.js.map +1 -1
- package/dist/templates/tools.d.ts +2 -1
- package/dist/templates/tools.d.ts.map +1 -1
- package/dist/templates/tools.js +315 -74
- package/dist/templates/tools.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# juninho
|
|
2
2
|
|
|
3
|
-
Bootstrap the **Agentic Coding Framework**
|
|
3
|
+
Bootstrap the **Agentic Coding Framework** into any [OpenCode](https://opencode.ai) project in a single command. Multi-stack support for Node.js, Python, Go, Java/Kotlin, and generic projects.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -14,29 +14,115 @@ npm install -g @kleber.mottajr/juninho
|
|
|
14
14
|
# Navigate to your project
|
|
15
15
|
cd my-opencode-project
|
|
16
16
|
|
|
17
|
-
# Run setup —
|
|
17
|
+
# Run setup — auto-detects project type
|
|
18
18
|
juninho setup
|
|
19
19
|
|
|
20
|
+
# Or specify type explicitly
|
|
21
|
+
juninho setup --type python
|
|
22
|
+
|
|
20
23
|
# Output:
|
|
21
24
|
# [juninho] Installing Agentic Coding Framework...
|
|
25
|
+
# [juninho] ✓ Project type: Python
|
|
22
26
|
# [juninho] ✓ Framework installed successfully!
|
|
23
27
|
# [juninho] Open OpenCode — /j.plan, /j.spec and /j.implement are ready.
|
|
24
28
|
```
|
|
25
29
|
|
|
26
|
-
|
|
30
|
+
### Supported project types
|
|
27
31
|
|
|
28
|
-
|
|
32
|
+
| Type | Detection | Skills |
|
|
33
|
+
|------|-----------|--------|
|
|
34
|
+
| `node-nextjs` | `package.json` with `next` dep | 9 (all skills) |
|
|
35
|
+
| `node-generic` | `package.json` without `next` | 5 |
|
|
36
|
+
| `python` | `pyproject.toml`, `requirements.txt`, `setup.py` | 5 |
|
|
37
|
+
| `go` | `go.mod` | 5 |
|
|
38
|
+
| `java` | `pom.xml`, `build.gradle`, `build.gradle.kts` | 5 |
|
|
39
|
+
| `generic` | Fallback | 4 |
|
|
29
40
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
-
|
|
37
|
-
|
|
41
|
+
Java projects with Kotlin (`build.gradle.kts` with kotlin plugin or `.kt` files) automatically get Kotlin-specific lint (ktlint/detekt), test patterns, and skills.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## How It Works
|
|
46
|
+
|
|
47
|
+
The framework orchestrates a multi-agent AI workflow for spec-driven development. The developer never codes directly — instead, specialized agents handle planning, implementation, validation, and closeout through slash commands.
|
|
48
|
+
|
|
49
|
+
### Specification & Planning
|
|
50
|
+
|
|
51
|
+
`/j.spec` conducts a 5-phase interview (Discovery → Requirements → Contract → Data → Review) with background codebase and external research. `/j.plan` runs 3 phases: Metis (intent analysis), Prometheus (interview + decomposition), and Momus (executability review). Both require explicit developer approval.
|
|
52
|
+
|
|
53
|
+

|
|
54
|
+
|
|
55
|
+
### Implementation, Verification & Closeout
|
|
56
|
+
|
|
57
|
+
`/j.implement` executes wave-by-wave with git worktrees for parallelism. Each task follows the READ → ACT → COMMIT → VALIDATE loop. `@j.validator` gates every task against the spec. Pre-commit hooks run lint + related tests. `/j.check` runs repo-wide verification. `/j.unify` reconciles delivery, merges worktrees, updates docs, and creates a PR.
|
|
58
|
+
|
|
59
|
+

|
|
60
|
+
|
|
61
|
+
### Context Injection & Plugin Architecture
|
|
62
|
+
|
|
63
|
+
12 plugins intercept every tool call across 5 tiers to inject context and enforce quality. External knowledge flows through Context7 (library docs) and Context-Mode (semantic search) MCP servers.
|
|
38
64
|
|
|
39
|
-
|
|
65
|
+

|
|
66
|
+
|
|
67
|
+
| Tier | Mechanism | What it provides |
|
|
68
|
+
|------|-----------|-----------------|
|
|
69
|
+
| **1** | `j.directory-agents-injector` | Hierarchical AGENTS.md (root → parent → current dir) |
|
|
70
|
+
| **2** | `j.carl-inject` (CARL) | Content-aware principles + domain docs via keyword matching (≤8KB) |
|
|
71
|
+
| **3** | `j.skill-inject` | File pattern → SKILL.md injection (e.g., `*.test.ts` → test-writing skill) |
|
|
72
|
+
| **4** | Plan `<skills>` declarations | Per-task required skills from plan.md |
|
|
73
|
+
| **5** | State files + `j.memory` | Cross-session persistent context |
|
|
74
|
+
|
|
75
|
+
### Agent Roles
|
|
76
|
+
|
|
77
|
+
| Agent | Model | Role |
|
|
78
|
+
|-------|-------|------|
|
|
79
|
+
| `@j.spec-writer` | Strong | 5-phase interview → spec.md |
|
|
80
|
+
| `@j.planner` | Strong | 3-phase planning → plan.md |
|
|
81
|
+
| `@j.implementer` | Medium | Wave execution, READ→ACT→COMMIT→VALIDATE |
|
|
82
|
+
| `@j.validator` | Medium | Spec-first validation, BLOCK/FIX/NOTE/APPROVED |
|
|
83
|
+
| `@j.plan-reviewer` | Medium | Executability gate for plans |
|
|
84
|
+
| `@j.reviewer` | Medium | Post-PR advisory review (read-only) |
|
|
85
|
+
| `@j.unify` | Medium | Closeout: merge, docs, PR |
|
|
86
|
+
| `@j.explore` | Weak | Read-only codebase research |
|
|
87
|
+
| `@j.librarian` | Weak | External docs via Context7 + Context-Mode MCP |
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## What it creates
|
|
92
|
+
|
|
93
|
+
`juninho setup` automatically generates:
|
|
94
|
+
|
|
95
|
+
- **9 agents** in `.opencode/agents/`
|
|
96
|
+
- **4–9 skills** in `.opencode/skills/` (filtered by project type)
|
|
97
|
+
- **12 plugins** in `.opencode/plugins/` (auto-discovered by OpenCode)
|
|
98
|
+
- **4 tools** in `.opencode/tools/` (find-pattern, next-version, lsp, ast-grep)
|
|
99
|
+
- **15 slash commands** in `.opencode/commands/`
|
|
100
|
+
- **State files** for persistent context and execution tracking
|
|
101
|
+
- **Docs scaffold** with AGENTS.md, domain index, principles docs, and manifest
|
|
102
|
+
- **Support scripts** in `.opencode/scripts/` for pre-commit, related tests, structure lint, and full checks
|
|
103
|
+
- **skill-map.json** for dynamic skill-to-pattern mapping
|
|
104
|
+
|
|
105
|
+
Then patches `opencode.json` with agent definitions, Context7 MCP, and Context-Mode MCP.
|
|
106
|
+
|
|
107
|
+
### Slash Commands
|
|
108
|
+
|
|
109
|
+
| Command | Description |
|
|
110
|
+
|---------|-------------|
|
|
111
|
+
| `/j.spec` | Feature specification via 5-phase interview |
|
|
112
|
+
| `/j.plan` | Strategic planning with 3-phase process |
|
|
113
|
+
| `/j.implement` | Execute plan wave-by-wave with validation |
|
|
114
|
+
| `/j.check` | Repo-wide verification (typecheck + lint + tests) |
|
|
115
|
+
| `/j.unify` | Closeout: merge worktrees, update docs, create PR |
|
|
116
|
+
| `/j.pr-review` | Advisory post-PR code review |
|
|
117
|
+
| `/j.start-work` | Begin work session with context loading |
|
|
118
|
+
| `/j.handoff` | End-of-session handoff document |
|
|
119
|
+
| `/j.status` | Show execution state and task progress |
|
|
120
|
+
| `/j.ulw-loop` | Ultra work loop (parallel implementation) |
|
|
121
|
+
| `/j.init-deep` | Deep codebase initialization (AGENTS.md hierarchy) |
|
|
122
|
+
| `/j.sync-docs` | Refresh domain/principles documentation |
|
|
123
|
+
| `/j.finish-setup` | Scan codebase, generate dynamic skills + docs |
|
|
124
|
+
| `/j.lint` | Run structure lint on staged files |
|
|
125
|
+
| `/j.test` | Run tests related to staged files |
|
|
40
126
|
|
|
41
127
|
## Idempotency
|
|
42
128
|
|
|
@@ -48,6 +134,19 @@ Running `juninho setup` twice is safe — it detects `.opencode/.juninho-install
|
|
|
48
134
|
juninho setup --force
|
|
49
135
|
```
|
|
50
136
|
|
|
137
|
+
## CLI Options
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
juninho setup [dir] [options]
|
|
141
|
+
|
|
142
|
+
Options:
|
|
143
|
+
--force Force reinstall even if already configured
|
|
144
|
+
--type <value> Project type: node-nextjs, node-generic, python, go, java, generic
|
|
145
|
+
--no-tty Non-interactive mode (skip prompts)
|
|
146
|
+
--version Show version number
|
|
147
|
+
--help Show help
|
|
148
|
+
```
|
|
149
|
+
|
|
51
150
|
## License
|
|
52
151
|
|
|
53
152
|
MIT
|
package/dist/cli.js
CHANGED
|
@@ -6,39 +6,47 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
const installer_js_1 = require("./installer.js");
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const project_types_js_1 = require("./project-types.js");
|
|
9
10
|
const { version: VERSION } = require("../package.json");
|
|
10
11
|
const args = process.argv.slice(2);
|
|
11
12
|
const command = args[0] ?? "";
|
|
12
13
|
const forceFlag = args.includes("--force");
|
|
13
|
-
|
|
14
|
+
// Parse --type flag
|
|
15
|
+
const typeIdx = args.indexOf("--type");
|
|
16
|
+
const typeValue = typeIdx !== -1 ? args[typeIdx + 1] : undefined;
|
|
17
|
+
const targetDir = args.find((a, i) => !a.startsWith("--") && a !== command && i !== typeIdx + 1) ?? process.cwd();
|
|
14
18
|
function showHelp() {
|
|
15
19
|
console.log(`
|
|
16
20
|
juninho v${VERSION} — Agentic Coding Framework bootstrapper for OpenCode
|
|
17
|
-
|
|
18
|
-
Usage:
|
|
19
|
-
juninho <command> [project-dir] [options]
|
|
20
|
-
|
|
21
|
-
Commands:
|
|
22
|
-
setup [dir] [--force] Install the framework into a project
|
|
23
|
-
|
|
21
|
+
|
|
22
|
+
Usage:
|
|
23
|
+
juninho <command> [project-dir] [options]
|
|
24
|
+
|
|
25
|
+
Commands:
|
|
26
|
+
setup [dir] [--force] Install the framework into a project
|
|
27
|
+
|
|
24
28
|
Options:
|
|
25
29
|
--force Reinstall even if already configured
|
|
30
|
+
--type <type> Set project type (skips auto-detection)
|
|
31
|
+
Values: ${project_types_js_1.VALID_PROJECT_TYPES.join(", ")}
|
|
26
32
|
--version, -v Show juninho version
|
|
27
33
|
--help, -h Show this help message
|
|
28
|
-
|
|
29
|
-
Model Tiers:
|
|
30
|
-
Strong → Planning & spec writing (default: claude-opus-4.6)
|
|
31
|
-
Medium → Implementation & review (default: claude-sonnet-4.6)
|
|
32
|
-
Weak → Research & exploration (default: claude-haiku-4.5)
|
|
33
|
-
|
|
34
|
-
During setup, juninho detects available models via 'opencode models'
|
|
35
|
-
and lets you choose the best model for each tier.
|
|
36
|
-
To reconfigure models, run 'juninho setup --force'.
|
|
37
|
-
|
|
38
|
-
Examples:
|
|
39
|
-
juninho setup
|
|
40
|
-
juninho setup ./my-project
|
|
41
|
-
juninho setup --
|
|
34
|
+
|
|
35
|
+
Model Tiers:
|
|
36
|
+
Strong → Planning & spec writing (default: claude-opus-4.6)
|
|
37
|
+
Medium → Implementation & review (default: claude-sonnet-4.6)
|
|
38
|
+
Weak → Research & exploration (default: claude-haiku-4.5)
|
|
39
|
+
|
|
40
|
+
During setup, juninho detects available models via 'opencode models'
|
|
41
|
+
and lets you choose the best model for each tier.
|
|
42
|
+
To reconfigure models, run 'juninho setup --force'.
|
|
43
|
+
|
|
44
|
+
Examples:
|
|
45
|
+
juninho setup Auto-detect stack and models
|
|
46
|
+
juninho setup ./my-project Install into a specific directory
|
|
47
|
+
juninho setup --type python Force Python project type
|
|
48
|
+
juninho setup --type java ./spring-app Java/Kotlin project (Kotlin auto-detected)
|
|
49
|
+
juninho setup --force Reinstall & reconfigure models
|
|
42
50
|
`);
|
|
43
51
|
}
|
|
44
52
|
function showVersion() {
|
|
@@ -51,7 +59,16 @@ else if (command === "--version" || command === "-v") {
|
|
|
51
59
|
showVersion();
|
|
52
60
|
}
|
|
53
61
|
else if (command === "setup") {
|
|
54
|
-
|
|
62
|
+
// Validate --type if provided
|
|
63
|
+
if (typeValue !== undefined && !project_types_js_1.VALID_PROJECT_TYPES.includes(typeValue)) {
|
|
64
|
+
console.error(`[juninho] Invalid project type: ${typeValue}`);
|
|
65
|
+
console.error(`[juninho] Valid types: ${project_types_js_1.VALID_PROJECT_TYPES.join(", ")}`);
|
|
66
|
+
process.exit(1);
|
|
67
|
+
}
|
|
68
|
+
(0, installer_js_1.runSetup)(path_1.default.resolve(targetDir), {
|
|
69
|
+
force: forceFlag,
|
|
70
|
+
type: typeValue,
|
|
71
|
+
})
|
|
55
72
|
.then(() => process.exit(0))
|
|
56
73
|
.catch((e) => {
|
|
57
74
|
console.error("[juninho] Error:", e.message);
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;;;;;AACA,iDAAyC;AACzC,gDAAuB;
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;;;;;AACA,iDAAyC;AACzC,gDAAuB;AACvB,yDAA0E;AAE1E,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,iBAAiB,CAAwB,CAAA;AAE9E,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;AAClC,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;AAC7B,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAA;AAE1C,oBAAoB;AACpB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;AACtC,MAAM,SAAS,GAAG,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;AAEhE,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CACzB,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,OAAO,IAAI,CAAC,KAAK,OAAO,GAAG,CAAC,CACpE,IAAI,OAAO,CAAC,GAAG,EAAE,CAAA;AAElB,SAAS,QAAQ;IACf,OAAO,CAAC,GAAG,CAAC;WACH,OAAO;;;;;;;;;;;oCAWkB,sCAAmB,CAAC,IAAI,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;CAmBjE,CAAC,CAAA;AACF,CAAC;AAED,SAAS,WAAW;IAClB,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;AACtB,CAAC;AAED,IAAI,OAAO,KAAK,EAAE,IAAI,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;IAC/D,QAAQ,EAAE,CAAA;AACZ,CAAC;KAAM,IAAI,OAAO,KAAK,WAAW,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;IACvD,WAAW,EAAE,CAAA;AACf,CAAC;KAAM,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;IAC/B,8BAA8B;IAC9B,IAAI,SAAS,KAAK,SAAS,IAAI,CAAC,sCAAmB,CAAC,QAAQ,CAAC,SAAwB,CAAC,EAAE,CAAC;QACvF,OAAO,CAAC,KAAK,CAAC,mCAAmC,SAAS,EAAE,CAAC,CAAA;QAC7D,OAAO,CAAC,KAAK,CAAC,0BAA0B,sCAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACzE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;IAED,IAAA,uBAAQ,EAAC,cAAI,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE;QAChC,KAAK,EAAE,SAAS;QAChB,IAAI,EAAE,SAAoC;KAC3C,CAAC;SACC,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;SAC3B,KAAK,CAAC,CAAC,CAAQ,EAAE,EAAE;QAClB,OAAO,CAAC,KAAK,CAAC,kBAAkB,EAAE,CAAC,CAAC,OAAO,CAAC,CAAA;QAC5C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC,CAAC,CAAA;AACN,CAAC;KAAM,CAAC;IACN,OAAO,CAAC,KAAK,CAAC,8BAA8B,OAAO,EAAE,CAAC,CAAA;IACtD,OAAO,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAA;IAChD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACjB,CAAC"}
|
package/dist/config.d.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* Contains the user's chosen models for each tier (strong/medium/weak).
|
|
6
6
|
*/
|
|
7
7
|
import { type ModelTier } from "./models.js";
|
|
8
|
+
import type { ProjectType } from "./project-types.js";
|
|
8
9
|
export interface JuninhoConfig {
|
|
9
10
|
/** Model ID for strong-tier agents (planner, spec-writer) */
|
|
10
11
|
strong: string;
|
|
@@ -12,6 +13,10 @@ export interface JuninhoConfig {
|
|
|
12
13
|
medium: string;
|
|
13
14
|
/** Model ID for weak-tier agents (explore, librarian) */
|
|
14
15
|
weak: string;
|
|
16
|
+
/** Detected or user-selected project type */
|
|
17
|
+
projectType?: ProjectType;
|
|
18
|
+
/** Whether the java project uses Kotlin */
|
|
19
|
+
isKotlin?: boolean;
|
|
15
20
|
}
|
|
16
21
|
/**
|
|
17
22
|
* Load saved configuration from .opencode/juninho-config.json.
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,KAAK,SAAS,EAAoB,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,KAAK,SAAS,EAAoB,MAAM,aAAa,CAAA;AAE9D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAErD,MAAM,WAAW,aAAa;IAC5B,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAA;IACd,+EAA+E;IAC/E,MAAM,EAAE,MAAM,CAAA;IACd,yDAAyD;IACzD,IAAI,EAAE,MAAM,CAAA;IACZ,6CAA6C;IAC7C,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAQD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAmBnE;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,IAAI,CAM1E;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,aAAa,CA6B/D;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAM/E"}
|
package/dist/config.js
CHANGED
|
@@ -32,7 +32,13 @@ function loadConfig(projectDir) {
|
|
|
32
32
|
try {
|
|
33
33
|
const data = JSON.parse((0, fs_1.readFileSync)(p, "utf-8"));
|
|
34
34
|
if (data.strong && data.medium && data.weak) {
|
|
35
|
-
return {
|
|
35
|
+
return {
|
|
36
|
+
strong: data.strong,
|
|
37
|
+
medium: data.medium,
|
|
38
|
+
weak: data.weak,
|
|
39
|
+
projectType: data.projectType,
|
|
40
|
+
isKotlin: data.isKotlin,
|
|
41
|
+
};
|
|
36
42
|
}
|
|
37
43
|
return null;
|
|
38
44
|
}
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;;;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/installer.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { type ProjectType } from "./project-types.js";
|
|
1
2
|
export interface SetupOptions {
|
|
2
3
|
force?: boolean;
|
|
4
|
+
type?: ProjectType;
|
|
3
5
|
}
|
|
4
6
|
export declare function runSetup(projectDir: string, options?: SetupOptions): Promise<void>;
|
|
5
7
|
//# sourceMappingURL=installer.d.ts.map
|
package/dist/installer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../src/installer.ts"],"names":[],"mappings":"AAqBA,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../src/installer.ts"],"names":[],"mappings":"AAqBA,OAAO,EACL,KAAK,WAAW,EAMjB,MAAM,oBAAoB,CAAA;AAO3B,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,IAAI,CAAC,EAAE,WAAW,CAAA;CACnB;AAmTD,wBAAsB,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAoH5F"}
|
package/dist/installer.js
CHANGED
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.runSetup = runSetup;
|
|
7
7
|
const fs_1 = require("fs");
|
|
8
8
|
const readline_1 = require("readline");
|
|
9
|
+
const child_process_1 = require("child_process");
|
|
9
10
|
const path_1 = __importDefault(require("path"));
|
|
10
11
|
const agents_js_1 = require("./templates/agents.js");
|
|
11
12
|
const skills_js_1 = require("./templates/skills.js");
|
|
@@ -18,6 +19,8 @@ const docs_js_1 = require("./templates/docs.js");
|
|
|
18
19
|
const config_js_1 = require("./config.js");
|
|
19
20
|
const discovery_js_1 = require("./discovery.js");
|
|
20
21
|
const models_js_1 = require("./models.js");
|
|
22
|
+
const project_types_js_1 = require("./project-types.js");
|
|
23
|
+
const lint_detection_js_1 = require("./lint-detection.js");
|
|
21
24
|
/* ─── Readline helper ─── */
|
|
22
25
|
function ask(rl, question) {
|
|
23
26
|
return new Promise((resolve) => {
|
|
@@ -141,33 +144,126 @@ async function manualEntry(rl, existing) {
|
|
|
141
144
|
};
|
|
142
145
|
}
|
|
143
146
|
/* ─── Resolve models (auto or interactive) ─── */
|
|
144
|
-
/**
|
|
145
|
-
* Resolve models for setup:
|
|
146
|
-
* 1. Saved config exists → use it
|
|
147
|
-
* 2. Auto-discovery succeeds and finds exactly one per tier → use auto
|
|
148
|
-
* 3. Otherwise → interactive selection
|
|
149
|
-
*/
|
|
150
147
|
async function resolveModelsForSetup(projectDir, rl) {
|
|
151
|
-
// 1. Check saved config
|
|
152
148
|
const saved = (0, config_js_1.loadConfig)(projectDir);
|
|
153
149
|
if (saved)
|
|
154
150
|
return saved;
|
|
155
|
-
// 2. Try auto-discovery (non-interactive happy path)
|
|
156
151
|
const available = (0, discovery_js_1.discoverAvailableModels)();
|
|
157
152
|
if (available.length > 0) {
|
|
158
153
|
const best = (0, models_js_1.selectBestModels)(available);
|
|
159
154
|
if (best.strong && best.medium && best.weak) {
|
|
160
|
-
// All tiers have a clear best — use them automatically
|
|
161
155
|
return { strong: best.strong, medium: best.medium, weak: best.weak };
|
|
162
156
|
}
|
|
163
157
|
}
|
|
164
|
-
// 3. Non-interactive fallback (CI, piped stdin, no TTY)
|
|
165
158
|
if (!process.stdin.isTTY) {
|
|
166
159
|
return { strong: models_js_1.DEFAULT_MODELS.strong, medium: models_js_1.DEFAULT_MODELS.medium, weak: models_js_1.DEFAULT_MODELS.weak };
|
|
167
160
|
}
|
|
168
|
-
// 4. Interactive selection (discovery failed or ambiguous)
|
|
169
161
|
return interactiveModelSelection(rl, null);
|
|
170
162
|
}
|
|
163
|
+
/* ─── Resolve project type ─── */
|
|
164
|
+
const TYPE_LABELS = {
|
|
165
|
+
"node-nextjs": "Node.js + Next.js",
|
|
166
|
+
"node-generic": "Node.js (generic)",
|
|
167
|
+
"python": "Python",
|
|
168
|
+
"go": "Go",
|
|
169
|
+
"java": "Java / Kotlin (JVM)",
|
|
170
|
+
"generic": "Generic",
|
|
171
|
+
};
|
|
172
|
+
async function resolveProjectType(projectDir, rl, options, savedConfig) {
|
|
173
|
+
// 1. CLI flag takes precedence
|
|
174
|
+
if (options.type) {
|
|
175
|
+
const isKotlin = options.type === "java" && (0, project_types_js_1.detectKotlin)(projectDir);
|
|
176
|
+
if (isKotlin) {
|
|
177
|
+
console.log("[juninho] Kotlin detected in Java project");
|
|
178
|
+
}
|
|
179
|
+
return { projectType: options.type, isKotlin };
|
|
180
|
+
}
|
|
181
|
+
// 2. Saved config (unless --force)
|
|
182
|
+
if (savedConfig?.projectType && !options.force) {
|
|
183
|
+
return {
|
|
184
|
+
projectType: savedConfig.projectType,
|
|
185
|
+
isKotlin: savedConfig.isKotlin ?? false,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
// 3. Auto-detect
|
|
189
|
+
const detected = (0, project_types_js_1.detectProjectType)(projectDir);
|
|
190
|
+
if (detected) {
|
|
191
|
+
const isKotlin = detected === "java" && (0, project_types_js_1.detectKotlin)(projectDir);
|
|
192
|
+
const label = isKotlin ? "Java/Kotlin (JVM)" : TYPE_LABELS[detected];
|
|
193
|
+
if (process.stdin.isTTY) {
|
|
194
|
+
const response = await ask(rl, `[juninho] Tipo de projeto detectado: ${label}. Confirma? (S/n): `);
|
|
195
|
+
if (response.toLowerCase() === "n") {
|
|
196
|
+
return interactiveTypeSelection(rl, projectDir);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return { projectType: detected, isKotlin };
|
|
200
|
+
}
|
|
201
|
+
// 4. No detection — interactive or fallback
|
|
202
|
+
if (process.stdin.isTTY) {
|
|
203
|
+
console.log("[juninho] Tipo de projeto não detectado automaticamente.");
|
|
204
|
+
return interactiveTypeSelection(rl, projectDir);
|
|
205
|
+
}
|
|
206
|
+
return { projectType: "generic", isKotlin: false };
|
|
207
|
+
}
|
|
208
|
+
async function interactiveTypeSelection(rl, projectDir) {
|
|
209
|
+
console.log("");
|
|
210
|
+
console.log("[juninho] Selecione o tipo de projeto:");
|
|
211
|
+
project_types_js_1.VALID_PROJECT_TYPES.forEach((t, i) => {
|
|
212
|
+
console.log(` ${i + 1}) ${TYPE_LABELS[t]}`);
|
|
213
|
+
});
|
|
214
|
+
const response = await ask(rl, ` Escolha (1-${project_types_js_1.VALID_PROJECT_TYPES.length}): `);
|
|
215
|
+
const idx = parseInt(response, 10);
|
|
216
|
+
const projectType = (idx >= 1 && idx <= project_types_js_1.VALID_PROJECT_TYPES.length)
|
|
217
|
+
? project_types_js_1.VALID_PROJECT_TYPES[idx - 1]
|
|
218
|
+
: "generic";
|
|
219
|
+
const isKotlin = projectType === "java" && (0, project_types_js_1.detectKotlin)(projectDir);
|
|
220
|
+
if (isKotlin) {
|
|
221
|
+
console.log("[juninho] Kotlin detected in Java project");
|
|
222
|
+
}
|
|
223
|
+
return { projectType, isKotlin };
|
|
224
|
+
}
|
|
225
|
+
/* ─── Lint detection and suggestion ─── */
|
|
226
|
+
async function handleLintDetection(projectDir, projectType, isKotlin, rl) {
|
|
227
|
+
const result = (0, lint_detection_js_1.detectLintTool)(projectDir, projectType, isKotlin);
|
|
228
|
+
if (result.detected) {
|
|
229
|
+
console.log(`[juninho] ✓ Linter detectado: ${result.detected}${result.configFile ? ` (${result.configFile})` : ""}`);
|
|
230
|
+
return result.detected;
|
|
231
|
+
}
|
|
232
|
+
// No linter detected — suggest if interactive
|
|
233
|
+
if (!process.stdin.isTTY)
|
|
234
|
+
return undefined;
|
|
235
|
+
const suggestions = (0, lint_detection_js_1.suggestLintTools)(projectType, isKotlin);
|
|
236
|
+
if (suggestions.length === 0)
|
|
237
|
+
return undefined;
|
|
238
|
+
const typeLabel = isKotlin ? "Kotlin" : TYPE_LABELS[projectType];
|
|
239
|
+
console.log("");
|
|
240
|
+
console.log(`[juninho] Nenhum linter detectado. Sugestões para projetos ${typeLabel}:`);
|
|
241
|
+
suggestions.forEach((s, i) => {
|
|
242
|
+
console.log(` ${i + 1}) ${s.name} — ${s.command}`);
|
|
243
|
+
});
|
|
244
|
+
console.log(` ${suggestions.length + 1}) Skip`);
|
|
245
|
+
const response = await ask(rl, ` Escolha (1-${suggestions.length + 1}) ou Enter para skip: `);
|
|
246
|
+
const idx = parseInt(response, 10);
|
|
247
|
+
if (idx >= 1 && idx <= suggestions.length) {
|
|
248
|
+
const chosen = suggestions[idx - 1];
|
|
249
|
+
if (chosen.install) {
|
|
250
|
+
console.log(`[juninho] Instalando ${chosen.name}...`);
|
|
251
|
+
try {
|
|
252
|
+
(0, child_process_1.execSync)(chosen.install, {
|
|
253
|
+
cwd: projectDir,
|
|
254
|
+
stdio: "inherit",
|
|
255
|
+
timeout: 120_000,
|
|
256
|
+
});
|
|
257
|
+
console.log(`[juninho] ✓ ${chosen.name} instalado`);
|
|
258
|
+
}
|
|
259
|
+
catch {
|
|
260
|
+
console.log(`[juninho] ⚠ Falha ao instalar ${chosen.name}. Continue manualmente.`);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return chosen.name;
|
|
264
|
+
}
|
|
265
|
+
return undefined;
|
|
266
|
+
}
|
|
171
267
|
/* ─── Main setup ─── */
|
|
172
268
|
async function runSetup(projectDir, options = {}) {
|
|
173
269
|
const marker = path_1.default.join(projectDir, ".opencode", ".juninho-installed");
|
|
@@ -186,40 +282,53 @@ async function runSetup(projectDir, options = {}) {
|
|
|
186
282
|
console.log(`[juninho] Strong: ${models.strong}`);
|
|
187
283
|
console.log(`[juninho] Medium: ${models.medium}`);
|
|
188
284
|
console.log(`[juninho] Weak: ${models.weak}`);
|
|
285
|
+
// Step 0.5: Resolve project type
|
|
286
|
+
const savedConfig = (0, config_js_1.loadConfig)(projectDir);
|
|
287
|
+
const { projectType, isKotlin } = await resolveProjectType(projectDir, rl, options, savedConfig);
|
|
288
|
+
const typeLabel = isKotlin ? "Java/Kotlin" : TYPE_LABELS[projectType];
|
|
289
|
+
console.log(`[juninho] ✓ Project type: ${typeLabel}`);
|
|
290
|
+
// Step 0.7: Detect/suggest lint tool
|
|
291
|
+
const lintTool = await handleLintDetection(projectDir, projectType, isKotlin, rl);
|
|
189
292
|
// Step 1: Create directory structure
|
|
190
|
-
|
|
293
|
+
const config = (0, project_types_js_1.getEffectiveConfig)(projectType, isKotlin);
|
|
294
|
+
createDirectories(projectDir, config.skills);
|
|
191
295
|
console.log("[juninho] ✓ Directories created");
|
|
192
|
-
// Step 2: Save
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
296
|
+
// Step 2: Save config (models + project type)
|
|
297
|
+
const fullConfig = {
|
|
298
|
+
...models,
|
|
299
|
+
projectType,
|
|
300
|
+
isKotlin: isKotlin || undefined,
|
|
301
|
+
};
|
|
302
|
+
(0, config_js_1.saveConfig)(projectDir, fullConfig);
|
|
303
|
+
console.log("[juninho] ✓ Config saved");
|
|
304
|
+
// Step 3: Write agents
|
|
305
|
+
(0, agents_js_1.writeAgents)(projectDir, models, projectType, isKotlin);
|
|
197
306
|
console.log("[juninho] ✓ Agents created (9)");
|
|
198
|
-
// Step 4: Write skills
|
|
199
|
-
(0, skills_js_1.writeSkills)(projectDir);
|
|
200
|
-
console.log(
|
|
307
|
+
// Step 4: Write skills (filtered by project type)
|
|
308
|
+
(0, skills_js_1.writeSkills)(projectDir, projectType, isKotlin);
|
|
309
|
+
console.log(`[juninho] ✓ Skills created (${config.skills.length})`);
|
|
201
310
|
// Step 5: Write plugins
|
|
202
|
-
(0, plugins_js_1.writePlugins)(projectDir);
|
|
311
|
+
(0, plugins_js_1.writePlugins)(projectDir, projectType, isKotlin);
|
|
203
312
|
console.log("[juninho] ✓ Plugins created (12)");
|
|
204
313
|
// Step 6: Write tools
|
|
205
|
-
(0, tools_js_1.writeTools)(projectDir);
|
|
314
|
+
(0, tools_js_1.writeTools)(projectDir, projectType, isKotlin);
|
|
206
315
|
console.log("[juninho] ✓ Tools created (4)");
|
|
207
316
|
// Step 7: Write support scripts
|
|
208
|
-
(0, support_scripts_js_1.writeSupportScripts)(projectDir);
|
|
317
|
+
(0, support_scripts_js_1.writeSupportScripts)(projectDir, projectType, isKotlin, lintTool);
|
|
209
318
|
console.log("[juninho] ✓ Support scripts created (4)");
|
|
210
319
|
// Step 8: Write commands
|
|
211
320
|
(0, commands_js_1.writeCommands)(projectDir);
|
|
212
|
-
console.log("[juninho] ✓ Commands created (
|
|
321
|
+
console.log("[juninho] ✓ Commands created (15)");
|
|
213
322
|
// Step 9: Write state files
|
|
214
323
|
(0, state_js_1.writeState)(projectDir);
|
|
215
324
|
console.log("[juninho] ✓ State files created");
|
|
216
|
-
// Step 10: Write docs
|
|
217
|
-
(0, docs_js_1.writeDocs)(projectDir);
|
|
325
|
+
// Step 10: Write docs (parameterized by project type)
|
|
326
|
+
(0, docs_js_1.writeDocs)(projectDir, projectType, isKotlin);
|
|
218
327
|
console.log("[juninho] ✓ Docs scaffold created");
|
|
219
|
-
// Step 11: Patch opencode.json
|
|
328
|
+
// Step 11: Patch opencode.json
|
|
220
329
|
(0, docs_js_1.patchOpencodeJson)(projectDir, models);
|
|
221
330
|
console.log("[juninho] ✓ opencode.json patched");
|
|
222
|
-
// Step 12: Install pre-commit hook
|
|
331
|
+
// Step 12: Install pre-commit hook
|
|
223
332
|
writePreCommitHook(projectDir);
|
|
224
333
|
// Step 13: Write marker
|
|
225
334
|
(0, fs_1.writeFileSync)(marker, new Date().toISOString());
|
|
@@ -227,6 +336,30 @@ async function runSetup(projectDir, options = {}) {
|
|
|
227
336
|
console.log("[juninho] ✓ Framework installed successfully!");
|
|
228
337
|
console.log("[juninho] Open OpenCode — /j.plan, /j.spec and /j.implement are ready.");
|
|
229
338
|
console.log("[juninho] Agents: @j.planner, @j.spec-writer, @j.implementer, @j.validator, @j.reviewer, @j.unify, @j.explore, @j.librarian");
|
|
339
|
+
// Step 14: Offer /j.finish-setup
|
|
340
|
+
if (process.stdin.isTTY) {
|
|
341
|
+
console.log("");
|
|
342
|
+
const finishResponse = await ask(rl, "[juninho] Deseja executar /j.finish-setup agora para gerar skills e docs do projeto? (S/n): ");
|
|
343
|
+
if (finishResponse.toLowerCase() !== "n") {
|
|
344
|
+
console.log("[juninho] Executando /j.finish-setup via opencode...");
|
|
345
|
+
try {
|
|
346
|
+
(0, child_process_1.execSync)('opencode -p "/j.finish-setup"', {
|
|
347
|
+
cwd: projectDir,
|
|
348
|
+
stdio: "inherit",
|
|
349
|
+
timeout: 600_000, // 10 minutes
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
catch {
|
|
353
|
+
console.log("[juninho] ⚠ Falha ao executar /j.finish-setup. Execute manualmente no OpenCode.");
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
else {
|
|
357
|
+
console.log("[juninho] Rode /j.finish-setup no OpenCode quando quiser gerar skills e documentação.");
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
else {
|
|
361
|
+
console.log("[juninho] Rode /j.finish-setup no OpenCode quando quiser gerar skills e documentação do projeto.");
|
|
362
|
+
}
|
|
230
363
|
}
|
|
231
364
|
finally {
|
|
232
365
|
rl.close();
|
|
@@ -235,32 +368,30 @@ async function runSetup(projectDir, options = {}) {
|
|
|
235
368
|
function writePreCommitHook(projectDir) {
|
|
236
369
|
const gitHooksDir = path_1.default.join(projectDir, ".git", "hooks");
|
|
237
370
|
if (!(0, fs_1.existsSync)(gitHooksDir)) {
|
|
238
|
-
// Not a git repo or hooks dir doesn't exist — skip silently
|
|
239
371
|
return;
|
|
240
372
|
}
|
|
241
373
|
const hookPath = path_1.default.join(gitHooksDir, "pre-commit");
|
|
242
374
|
if ((0, fs_1.existsSync)(hookPath)) {
|
|
243
375
|
const existing = (0, fs_1.readFileSync)(hookPath, "utf-8");
|
|
244
376
|
if (!existing.includes("installed by juninho")) {
|
|
245
|
-
// Preserve existing hook — do not overwrite
|
|
246
377
|
console.log("[juninho] ⚠ pre-commit hook already exists — skipping (not installed by juninho)");
|
|
247
378
|
return;
|
|
248
379
|
}
|
|
249
380
|
}
|
|
250
|
-
const hookContent = `#!/bin/sh
|
|
251
|
-
# Deterministic outer validation loop — installed by juninho
|
|
252
|
-
# Runs structure lint + related tests before every commit.
|
|
253
|
-
# Do not bypass with --no-verify.
|
|
254
|
-
set -e
|
|
255
|
-
|
|
256
|
-
ROOT_DIR="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
|
|
257
|
-
|
|
258
|
-
if [ ! -x "$ROOT_DIR/.opencode/scripts/pre-commit.sh" ]; then
|
|
259
|
-
echo "[pre-commit] FAIL: .opencode/scripts/pre-commit.sh not found or not executable"
|
|
260
|
-
exit 1
|
|
261
|
-
fi
|
|
262
|
-
|
|
263
|
-
exec "$ROOT_DIR/.opencode/scripts/pre-commit.sh"
|
|
381
|
+
const hookContent = `#!/bin/sh
|
|
382
|
+
# Deterministic outer validation loop — installed by juninho
|
|
383
|
+
# Runs structure lint + related tests before every commit.
|
|
384
|
+
# Do not bypass with --no-verify.
|
|
385
|
+
set -e
|
|
386
|
+
|
|
387
|
+
ROOT_DIR="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
|
|
388
|
+
|
|
389
|
+
if [ ! -x "$ROOT_DIR/.opencode/scripts/pre-commit.sh" ]; then
|
|
390
|
+
echo "[pre-commit] FAIL: .opencode/scripts/pre-commit.sh not found or not executable"
|
|
391
|
+
exit 1
|
|
392
|
+
fi
|
|
393
|
+
|
|
394
|
+
exec "$ROOT_DIR/.opencode/scripts/pre-commit.sh"
|
|
264
395
|
`;
|
|
265
396
|
(0, fs_1.writeFileSync)(hookPath, hookContent);
|
|
266
397
|
try {
|
|
@@ -271,20 +402,13 @@ exec "$ROOT_DIR/.opencode/scripts/pre-commit.sh"
|
|
|
271
402
|
console.log("[juninho] ✓ pre-commit hook written (chmod not supported on this platform — make it executable manually)");
|
|
272
403
|
}
|
|
273
404
|
}
|
|
274
|
-
function createDirectories(projectDir) {
|
|
405
|
+
function createDirectories(projectDir, skills) {
|
|
275
406
|
const dirs = [
|
|
276
407
|
".opencode",
|
|
277
408
|
".opencode/agents",
|
|
278
409
|
".opencode/skills",
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
".opencode/skills/j.api-route-creation",
|
|
282
|
-
".opencode/skills/j.server-action-creation",
|
|
283
|
-
".opencode/skills/j.schema-migration",
|
|
284
|
-
".opencode/skills/j.agents-md-writing",
|
|
285
|
-
".opencode/skills/j.domain-doc-writing",
|
|
286
|
-
".opencode/skills/j.principle-doc-writing",
|
|
287
|
-
".opencode/skills/j.shell-script-writing",
|
|
410
|
+
// Only create skill directories for the relevant project type
|
|
411
|
+
...skills.map((s) => `.opencode/skills/${s}`),
|
|
288
412
|
".opencode/plugins",
|
|
289
413
|
".opencode/tools",
|
|
290
414
|
".opencode/scripts",
|