@naraya/cli 0.1.0 → 0.4.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/LICENSE +20 -0
- package/README.md +394 -93
- package/bin/naraya-native.mjs +4 -0
- package/bin/naraya.mjs +1 -142
- package/bin/undici-timeout.mjs +1 -0
- package/dist/assets.pack.gz +0 -0
- package/dist/mcp/config-loader.js +32 -0
- package/dist/mcp/lifecycle.js +90 -0
- package/dist/mcp/tool-mapper.js +31 -0
- package/dist/mcp/transport.js +30 -0
- package/dist/pentest/catalog/catalog-loader.js +45 -0
- package/dist/pentest/catalog/index.js +1 -0
- package/dist/pentest/cli.js +117 -0
- package/dist/pentest/command-builder/command-builder.js +90 -0
- package/dist/pentest/command-builder/index.js +1 -0
- package/dist/pentest/index.js +10 -0
- package/dist/pentest/installer/index.js +1 -0
- package/dist/pentest/installer/tool-installer.js +90 -0
- package/dist/pentest/manager.js +125 -0
- package/dist/pentest/mode/index.js +1 -0
- package/dist/pentest/mode/mode-selector.js +127 -0
- package/dist/pentest/selector/index.js +1 -0
- package/dist/pentest/selector/tool-selector.js +66 -0
- package/dist/pentest/skill-bridge/index.js +1 -0
- package/dist/pentest/skill-bridge/skill-bridge.js +66 -0
- package/dist/pentest/skills/generator/index.js +1 -0
- package/dist/pentest/skills/generator/skill-generator.js +310 -0
- package/dist/pentest/skills/index.js +3 -0
- package/dist/pentest/skills/loader/index.js +1 -0
- package/dist/pentest/skills/loader/skill-loader.js +167 -0
- package/dist/pentest/skills/register/index.js +1 -0
- package/dist/pentest/skills/register/skill-register.js +162 -0
- package/dist/pentest/skills/types.js +1 -0
- package/dist/pentest/types.js +90 -0
- package/package.json +42 -14
- package/src/assets-pack.mjs +1 -0
- package/src/banner.mjs +5 -0
- package/src/clipboard.mjs +1 -0
- package/src/config.mjs +1 -40
- package/src/goodbye.mjs +7 -0
- package/src/login.mjs +7 -49
- package/src/mcp/config-loader.ts +50 -0
- package/src/mcp/lifecycle.ts +113 -0
- package/src/mcp/tool-mapper.ts +42 -0
- package/src/mcp/transport.ts +38 -0
- package/src/mcp-cli.mjs +5 -0
- package/src/pentest/catalog/catalog-loader.ts +55 -0
- package/src/pentest/catalog/index.ts +1 -0
- package/src/pentest/cli.ts +130 -0
- package/src/pentest/command-builder/command-builder.ts +109 -0
- package/src/pentest/command-builder/index.ts +1 -0
- package/src/pentest/index.ts +11 -0
- package/src/pentest/installer/index.ts +1 -0
- package/src/pentest/installer/tool-installer.ts +107 -0
- package/src/pentest/manager.ts +167 -0
- package/src/pentest/mode/index.ts +1 -0
- package/src/pentest/mode/mode-selector.ts +159 -0
- package/src/pentest/selector/index.ts +1 -0
- package/src/pentest/selector/tool-selector.ts +87 -0
- package/src/pentest/skill-bridge/index.ts +1 -0
- package/src/pentest/skill-bridge/skill-bridge.ts +86 -0
- package/src/pentest/skills/generator/index.ts +1 -0
- package/src/pentest/skills/generator/skill-generator.ts +373 -0
- package/src/pentest/skills/index.ts +4 -0
- package/src/pentest/skills/loader/index.ts +1 -0
- package/src/pentest/skills/loader/skill-loader.ts +206 -0
- package/src/pentest/skills/register/index.ts +1 -0
- package/src/pentest/skills/register/skill-register.ts +196 -0
- package/src/pentest/skills/types.ts +66 -0
- package/src/pentest/types.ts +341 -0
- package/src/seed.mjs +1 -36
- package/src/splash.mjs +4 -0
- package/src/status.mjs +2 -71
- package/assets/APPEND-SYSTEM.md +0 -9
- package/assets/extensions/naraya-brand.ts +0 -251
- package/assets/extensions/naraya-gate.ts +0 -23
- package/assets/naraya-logo.txt +0 -5
- package/assets/skills/narabuild/SKILL.md +0 -156
- package/assets/skills/naradroid/SKILL.md +0 -118
- package/assets/skills/naraexplore/SKILL.md +0 -71
- package/assets/skills/narafe/SKILL.md +0 -94
- package/assets/skills/naraplan/SKILL.md +0 -47
- package/assets/skills/narasearch/SKILL.md +0 -141
package/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Naraya CLI — Proprietary License
|
|
2
|
+
Copyright (c) 2026 PT. Naraya Teknologi Indonesia. All rights reserved.
|
|
3
|
+
|
|
4
|
+
This software and its accompanying assets (including but not limited to system
|
|
5
|
+
prompts, agent definitions, skills, and configuration) are the confidential and
|
|
6
|
+
proprietary property of PT. Naraya Teknologi Indonesia ("Naraya").
|
|
7
|
+
|
|
8
|
+
NO LICENSE IS GRANTED to copy, modify, distribute, sublicense, reverse engineer,
|
|
9
|
+
decompile, disassemble, or create derivative works from any part of this
|
|
10
|
+
software or its assets, in whole or in part, except as expressly authorized in
|
|
11
|
+
writing by Naraya.
|
|
12
|
+
|
|
13
|
+
Use of this software requires a valid Naraya account and API key and is governed
|
|
14
|
+
by the Naraya Terms of Service. Access may be revoked at any time.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
18
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL NARAYA BE LIABLE
|
|
19
|
+
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,93 +1,394 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
1
|
+
# Naraya CLI
|
|
2
|
+
|
|
3
|
+
> One sign-in, every model. A coding agent that delegates specialist work to focused subagents and brings evidence to every claim.
|
|
4
|
+
|
|
5
|
+
[](https://nodejs.org) [](LICENSE) [](package.json)
|
|
6
|
+
|
|
7
|
+
Naraya CLI is a thin wrapper around [pi](https://github.com/earendil-works/pi-mono) that:
|
|
8
|
+
|
|
9
|
+
- Routes all model traffic through [router.naraya.ai](https://router.naraya.ai) with one API key.
|
|
10
|
+
- Ships **11 focused subagents** (`nara-build`, `nara-architect`, `nara-release`, `nara-review`, `nara-debug`, `nara-plan`, `nara-explore`, `nara-search`, `nara-fe`, `nara-droid`, `nara-vision`) as folder-based packages with their own skills, scripts, and references.
|
|
11
|
+
- Injects a `APPEND-SYSTEM.md` so the model reaches for the bundled agents and skills on every turn.
|
|
12
|
+
- Provides a `delegate` tool that fans work out to subagents in parallel, sequential chains, or single focus — each in an isolated context window.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Table of contents
|
|
17
|
+
|
|
18
|
+
- [Install](#install)
|
|
19
|
+
- [Quickstart](#quickstart)
|
|
20
|
+
- [Usage](#usage)
|
|
21
|
+
- [Subagents](#subagents)
|
|
22
|
+
- [Skills](#skills)
|
|
23
|
+
- [Agent structure](#agent-structure)
|
|
24
|
+
- [Extending](#extending)
|
|
25
|
+
- [Development](#development)
|
|
26
|
+
- [Architecture](#architecture)
|
|
27
|
+
- [License](#license)
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Install
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# Requires Node.js >= 22.19
|
|
35
|
+
npm install -g @naraya/cli
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Or use directly from a checkout:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
git clone https://gitlab.naraya.ai/adearman/naracli
|
|
42
|
+
cd naracli
|
|
43
|
+
npm install
|
|
44
|
+
npm link # expose `naraya` on PATH
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Quickstart
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# 1. Sign in (one-time)
|
|
53
|
+
naraya login
|
|
54
|
+
|
|
55
|
+
# 2. Verify auth
|
|
56
|
+
naraya status
|
|
57
|
+
|
|
58
|
+
# 3. Launch the agent in the current project
|
|
59
|
+
naraya
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Inside the agent, press `/` for the command palette, `/agents` to list subagents, `/skills` to list skills.
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
# Quick subcommands without launching the TUI
|
|
66
|
+
naraya login # OAuth-style sign-in to router.naraya.ai
|
|
67
|
+
naraya logout # wipe local credentials
|
|
68
|
+
naraya status # show auth + quota + current model
|
|
69
|
+
naraya status --usd # same, with USD cost equivalent
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Usage
|
|
75
|
+
|
|
76
|
+
### Interactive mode
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
naraya # launch in cwd
|
|
80
|
+
naraya --model naraya/glm-5 # override default model for this session
|
|
81
|
+
naraya --continue # resume the last session
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Slash commands inside the TUI:
|
|
85
|
+
|
|
86
|
+
| Command | Effect |
|
|
87
|
+
|---|---|
|
|
88
|
+
| `/agents` | list subagents |
|
|
89
|
+
| `/agent-model <name>` | change a subagent's model |
|
|
90
|
+
| `/skill:<name> [args]` | load a skill |
|
|
91
|
+
| `/skills` | list available skills |
|
|
92
|
+
| `/help` | full command palette |
|
|
93
|
+
|
|
94
|
+
### Headless / scripted
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
naraya -p "audit the auth module for OWASP top 10" # single prompt, prints result, exits
|
|
98
|
+
naraya -p --json <task> # machine-readable output
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Delegation patterns (built into the model)
|
|
102
|
+
|
|
103
|
+
The agent delegates to specialists via the `delegate` tool. You do not invoke it directly — you phrase the request and the model decides.
|
|
104
|
+
|
|
105
|
+
Patterns the model uses:
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
// One focused specialist
|
|
109
|
+
delegate { agent: "nara-droid", task: "..." }
|
|
110
|
+
|
|
111
|
+
// Independent units in parallel (max 8 at once, 4 concurrent)
|
|
112
|
+
delegate { tasks: [
|
|
113
|
+
{ agent: "nara-search", task: "research X" },
|
|
114
|
+
{ agent: "nara-explore", task: "find usages of Y" },
|
|
115
|
+
{ agent: "nara-plan", task: "draft plan for Z" }
|
|
116
|
+
]}
|
|
117
|
+
|
|
118
|
+
// Sequential, {previous} injects the prior step's output
|
|
119
|
+
delegate { chain: [
|
|
120
|
+
{ agent: "nara-explore", task: "map the auth flow" },
|
|
121
|
+
{ agent: "nara-plan", task: "draft a plan based on {previous}" },
|
|
122
|
+
{ agent: "nara-review", task: "review the plan in {previous}" }
|
|
123
|
+
]}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Subagents
|
|
129
|
+
|
|
130
|
+
Naraya ships **11 subagents**. Each is a self-contained folder under `assets/agents/`.
|
|
131
|
+
|
|
132
|
+
### Coordination
|
|
133
|
+
|
|
134
|
+
| Agent | Purpose | When to use |
|
|
135
|
+
|---|---|---|
|
|
136
|
+
| `nara-build` | Implements features, bugfixes, refactors, releases | Top-level orchestrator. Default for "implement X", "fix Y", "refactor Z" |
|
|
137
|
+
| `nara-architect` | System design, ADRs, component decomposition | Greenfield design, scaling decisions, API contract design, trade-off analysis. Read-only — never edits code |
|
|
138
|
+
| `nara-release` | Version sync, verification, deploy safety | Before any production push, mobile store release, or schema migration |
|
|
139
|
+
| `nara-review` | Multi-aspect code review (security, perf, a11y, API, tests) | Pre-merge review, audit, self-review before push. Does not fix |
|
|
140
|
+
| `nara-debug` | 4-phase root-cause debugging | "X is broken", flaky tests, intermittent failures. Stops after 3 failed fix attempts |
|
|
141
|
+
|
|
142
|
+
### Investigation (read-only)
|
|
143
|
+
|
|
144
|
+
| Agent | Purpose | When to use |
|
|
145
|
+
|---|---|---|
|
|
146
|
+
| `nara-plan` | Implementation plans, never edits code | Pair with `nara-build` for hand-off |
|
|
147
|
+
| `nara-explore` | Fast codebase navigation (haiku) | "Where is X defined?", "who calls Y?", quick map |
|
|
148
|
+
| `nara-search` | Evidence-first research with citations | Library comparison, version migration, external doc lookup |
|
|
149
|
+
|
|
150
|
+
### Specialist (writes code in their domain)
|
|
151
|
+
|
|
152
|
+
| Agent | Purpose | When to use |
|
|
153
|
+
|---|---|---|
|
|
154
|
+
| `nara-fe` | Frontend UI/UX (React, Vue, Svelte, Angular, CSS, Tailwind, a11y) | UI changes, component design, responsive, accessibility |
|
|
155
|
+
| `nara-droid` | Native Android (Kotlin, Gradle, Compose, Room, Hilt, adb, APK/AAB) | Android-specific tasks, build failures, release |
|
|
156
|
+
| `nara-vision` | Image analysis using mistral-medium-3-5 vision model | Screenshots, diagrams, UI layouts, code snippets, visual content |
|
|
157
|
+
|
|
158
|
+
### Picking the right agent
|
|
159
|
+
|
|
160
|
+
The model picks based on the **unit of work**, not the surface form. Quick heuristic:
|
|
161
|
+
|
|
162
|
+
- The user said "implement", "fix", "build", "add", "refactor" → `nara-build`
|
|
163
|
+
- The user said "plan", "design", "architect", "decompose" → `nara-architect` (design) or `nara-plan` (task breakdown)
|
|
164
|
+
- The user said "review", "audit", "check this" → `nara-review`
|
|
165
|
+
- The user said "release", "deploy", "ship" → `nara-release`
|
|
166
|
+
- The user said "debug", "broken", "crash", "flaky" → `nara-debug`
|
|
167
|
+
- The user said "find", "where", "who calls" → `nara-explore`
|
|
168
|
+
- The user said "research", "compare", "what is the best", "how does X work in library Y" → `nara-search`
|
|
169
|
+
- The user said something Android-specific → `nara-droid`
|
|
170
|
+
- The user said something UI/frontend-specific → `nara-fe`
|
|
171
|
+
- The user shared an image, screenshot, or needs visual analysis → `nara-vision`
|
|
172
|
+
|
|
173
|
+
If multiple of these apply, the model fans out to parallel subagents.
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Skills
|
|
178
|
+
|
|
179
|
+
Naraya bundles a **global skill pool** at `skills/` (~100 skills) that any agent can load on demand via `/skill:<name>` or by reading `skills/<name>/SKILL.md` directly.
|
|
180
|
+
|
|
181
|
+
Highlights:
|
|
182
|
+
|
|
183
|
+
| Skill | What it covers |
|
|
184
|
+
|---|---|
|
|
185
|
+
| `systematic-debugging` | 4-phase root-cause debugging |
|
|
186
|
+
| `test-driven-development` | RED-GREEN-REFACTOR discipline |
|
|
187
|
+
| `writing-plans` | Implementation plans with bite-sized tasks |
|
|
188
|
+
| `web-app-release-workflow` | Ship Dockerized web apps |
|
|
189
|
+
| `security`, `auth-identity`, `compliance-governance` | Security review and compliance |
|
|
190
|
+
| `architecture`, `api-design-patterns`, `distributed-systems` | System design |
|
|
191
|
+
| `mlops/*` | ML/LLM training, serving, fine-tuning, evaluation |
|
|
192
|
+
| `creative/{humanizer, p5js, claude-design}` | Content / UI generation |
|
|
193
|
+
| `android-kotlin`, `compose-patterns`, `gradle-troubleshoot` | Android development |
|
|
194
|
+
| `react-patterns`, `css-patterns` | Frontend |
|
|
195
|
+
|
|
196
|
+
**Skills vs subagents:** a skill is a workflow / lens the agent applies inline. A subagent is a separate context that runs in parallel. Use skills for "do X the right way", subagents for "do X in isolation".
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## Agent structure
|
|
201
|
+
|
|
202
|
+
Each agent is a folder under `assets/agents/`. Folder name MUST equal the frontmatter `name:` field.
|
|
203
|
+
|
|
204
|
+
```
|
|
205
|
+
assets/agents/
|
|
206
|
+
├── nara-build/ # Generalist implementer (top-level)
|
|
207
|
+
│ ├── AGENTS.md # Frontmatter (name/description/tools/model) + system prompt
|
|
208
|
+
│ ├── skills/ # Agent-specific skills, NOT published to global pool
|
|
209
|
+
│ │ └── engineering-patterns/SKILL.md
|
|
210
|
+
│ ├── scripts/ # Helper shell scripts (chmod +x)
|
|
211
|
+
│ │ ├── impact-scan.sh
|
|
212
|
+
│ │ └── scan.sh
|
|
213
|
+
│ ├── references/ # On-demand docs the agent may read into context
|
|
214
|
+
│ │ └── adr-template.md
|
|
215
|
+
│ ├── assets/ # Static resources (templates, data)
|
|
216
|
+
│ └── README.md # per-agent docs
|
|
217
|
+
├── nara-plan/ # Read-only planner
|
|
218
|
+
├── nara-explore/ # Fast read-only code navigation (haiku)
|
|
219
|
+
├── nara-search/ # Evidence-first research
|
|
220
|
+
├── nara-droid/ # Native Android specialist
|
|
221
|
+
├── nara-fe/ # Frontend UI/UX specialist
|
|
222
|
+
├── nara-vision/ # Image analysis (mistral-medium-3-5 vision)
|
|
223
|
+
├── nara-architect/ # System design & ADRs (read-only)
|
|
224
|
+
├── nara-release/ # Release safety
|
|
225
|
+
├── nara-review/ # Multi-aspect code review
|
|
226
|
+
└── nara-debug/ # 4-phase root-cause debugging
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Conventions
|
|
230
|
+
|
|
231
|
+
- **Folder name = frontmatter `name:`.** The orchestrator warns but does not fail if they diverge.
|
|
232
|
+
- **`AGENTS.md` is the only file the loader reads.** Everything else is opt-in for the agent to `read` into context.
|
|
233
|
+
- **Per-agent `skills/` are NOT published to the global skill pool.** They are scoped to that agent.
|
|
234
|
+
- **Scripts are executable** (`chmod +x`). They can be invoked from the agent's `bash` tool.
|
|
235
|
+
- **References are docs the agent may read.** Large checklists, protocol walkthroughs, template snippets.
|
|
236
|
+
|
|
237
|
+
### Adding a new agent
|
|
238
|
+
|
|
239
|
+
1. Create `assets/agents/<your-role>/AGENTS.md` with frontmatter (`name`, `description`, `tools`, `model`) + body.
|
|
240
|
+
2. Add the four subdirs: `skills/`, `scripts/`, `references/`, `assets/`.
|
|
241
|
+
3. (Optional) Add a `README.md` documenting the agent.
|
|
242
|
+
4. Run `npm test` to confirm the seed manifest picks it up.
|
|
243
|
+
5. (Optional) Add the agent to the roster in `assets/APPEND-SYSTEM.md` so the model knows to delegate to it.
|
|
244
|
+
|
|
245
|
+
### Editing an existing agent
|
|
246
|
+
|
|
247
|
+
Edit `assets/agents/<role>/AGENTS.md`. The orchestrator hot-reads this on each `delegate` call, so changes take effect on the next invocation. No restart needed.
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## Extending
|
|
252
|
+
|
|
253
|
+
### Adding a skill to a specific agent
|
|
254
|
+
|
|
255
|
+
Drop a directory under `assets/agents/<role>/skills/<skill-name>/` with a `SKILL.md` inside:
|
|
256
|
+
|
|
257
|
+
```
|
|
258
|
+
assets/agents/nara-fe/
|
|
259
|
+
└── skills/
|
|
260
|
+
└── vue-patterns/
|
|
261
|
+
└── SKILL.md
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### Adding a skill to the global pool
|
|
265
|
+
|
|
266
|
+
Drop it under `skills/<skill-name>/SKILL.md` at the repo root. The global pool is auto-discovered by pi.
|
|
267
|
+
|
|
268
|
+
### Overriding model per-agent
|
|
269
|
+
|
|
270
|
+
Edit the frontmatter `model:` field in `AGENTS.md`. Or set a per-agent override at runtime with `/agent-model <agent> <model>`.
|
|
271
|
+
|
|
272
|
+
### Customizing the system prompt
|
|
273
|
+
|
|
274
|
+
Edit `assets/APPEND-SYSTEM.md`. This file is appended to the model's system prompt on every launch.
|
|
275
|
+
|
|
276
|
+
---
|
|
277
|
+
|
|
278
|
+
## Development
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
git clone https://gitlab.naraya.ai/adearman/naracli
|
|
282
|
+
cd naracli
|
|
283
|
+
npm install
|
|
284
|
+
npm test # run node:test suite (8 tests)
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### Project layout
|
|
288
|
+
|
|
289
|
+
```
|
|
290
|
+
naraya-cli/
|
|
291
|
+
├── bin/
|
|
292
|
+
│ └── naraya.mjs # CLI entry: subcommand dispatch + pi launch
|
|
293
|
+
├── src/
|
|
294
|
+
│ ├── banner.mjs # login/launch banner
|
|
295
|
+
│ ├── clipboard.mjs # copy auth URL to clipboard
|
|
296
|
+
│ ├── config.mjs # models.json read/write
|
|
297
|
+
│ ├── goodbye.mjs # farewell on quit
|
|
298
|
+
│ ├── login.mjs # naraya login (OAuth-style)
|
|
299
|
+
│ ├── seed.mjs # asset sync to ~/.naraya/agent
|
|
300
|
+
│ ├── splash.mjs # startup animation
|
|
301
|
+
│ └── status.mjs # naraya status (quota, cost)
|
|
302
|
+
├── assets/
|
|
303
|
+
│ ├── APPEND-SYSTEM.md # injected into system prompt
|
|
304
|
+
│ ├── agents/ # 10 subagent folders (see above)
|
|
305
|
+
│ ├── extensions/ # .ts extensions loaded by pi
|
|
306
|
+
│ ├── skills/ # empty (skills live at repo root for global pool)
|
|
307
|
+
│ └── themes/naraya.json # default theme
|
|
308
|
+
├── skills/ # global skill pool (~100 skills)
|
|
309
|
+
├── test/
|
|
310
|
+
│ ├── config.test.mjs
|
|
311
|
+
│ ├── seed.test.mjs # covers agent folder + nested resources
|
|
312
|
+
│ └── status.test.mjs
|
|
313
|
+
├── package.json
|
|
314
|
+
└── README.md
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### Testing
|
|
318
|
+
|
|
319
|
+
```bash
|
|
320
|
+
npm test # all 8 tests
|
|
321
|
+
node --test test/seed.test.mjs # just seed (asset sync)
|
|
322
|
+
node --test test/status.test.mjs # just status rendering
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
The seed test covers both the legacy flat layout and the new folder-based agent layout (AGENTS.md + nested skills/scripts).
|
|
326
|
+
|
|
327
|
+
---
|
|
328
|
+
|
|
329
|
+
## Architecture
|
|
330
|
+
|
|
331
|
+
### Request flow
|
|
332
|
+
|
|
333
|
+
```
|
|
334
|
+
User input
|
|
335
|
+
│
|
|
336
|
+
▼
|
|
337
|
+
┌─────────────────────────┐
|
|
338
|
+
│ bin/naraya.mjs │ CLI entry, subcommand dispatch
|
|
339
|
+
│ - login/logout/status │
|
|
340
|
+
│ - else: launch pi │
|
|
341
|
+
└──────────┬──────────────┘
|
|
342
|
+
│
|
|
343
|
+
▼
|
|
344
|
+
┌─────────────────────────┐
|
|
345
|
+
│ src/seed.mjs │ Sync assets/ to ~/.naraya/agent
|
|
346
|
+
│ - assets/agents/* │ (only managed files; user files preserved)
|
|
347
|
+
│ - assets/extensions/* │
|
|
348
|
+
│ - assets/APPEND-SYSTEM │
|
|
349
|
+
└──────────┬──────────────┘
|
|
350
|
+
│
|
|
351
|
+
▼
|
|
352
|
+
┌─────────────────────────┐
|
|
353
|
+
│ pi-coding-agent │ pi runtime
|
|
354
|
+
│ - system prompt: │ ← APPEND-SYSTEM.md appended
|
|
355
|
+
│ - skill discovery │ ← global pool + per-agent
|
|
356
|
+
│ - extension loading │ ← naraya-orchestrator, naraya-debug, etc.
|
|
357
|
+
│ - delegate tool │ ← fans out to subagents
|
|
358
|
+
└──────────┬──────────────┘
|
|
359
|
+
│
|
|
360
|
+
▼
|
|
361
|
+
┌─────────────────────────┐
|
|
362
|
+
│ Subagent (isolated ctx) │ one per `delegate` call
|
|
363
|
+
│ - reads AGENTS.md │
|
|
364
|
+
│ - reads per-agent │
|
|
365
|
+
│ skills/scripts/refs │
|
|
366
|
+
│ - reads global skills │
|
|
367
|
+
│ - returns result │
|
|
368
|
+
└─────────────────────────┘
|
|
369
|
+
│
|
|
370
|
+
▼
|
|
371
|
+
Output to user
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
### Why folder-based agents?
|
|
375
|
+
|
|
376
|
+
- **Colocation.** Each agent is one self-contained directory: definition + skills + scripts + references + assets. Move it, version it, delete it as one unit.
|
|
377
|
+
- **No global namespace pollution.** Per-agent `skills/` are scoped; only `AGENTS.md` is published.
|
|
378
|
+
- **Easier to share.** A folder is a package. An `.md` file in a flat dir is a file in a list.
|
|
379
|
+
- **Scales.** Adding an agent = adding a folder. Adding an agent to the old flat layout = adding a file that could collide.
|
|
380
|
+
- **Backward compatible.** The orchestrator loader supports both folder layout (`<role>/AGENTS.md`) and legacy flat (`<role>.md`).
|
|
381
|
+
|
|
382
|
+
### Why split coordination / specialist / investigation?
|
|
383
|
+
|
|
384
|
+
- **Coordination agents** (`nara-build`, `nara-architect`, `nara-release`, `nara-review`, `nara-debug`) need broad context. They route, sequence, verify.
|
|
385
|
+
- **Specialist agents** (`nara-fe`, `nara-droid`) need deep domain knowledge. Their system prompt is shaped by their domain.
|
|
386
|
+
- **Investigation agents** (`nara-plan`, `nara-explore`, `nara-search`) are read-only. They never modify state. They produce artifacts (plans, maps, evidence) that the orchestrator consumes.
|
|
387
|
+
|
|
388
|
+
Mixing these roles in one agent produces shallow specialists and shallow coordinators.
|
|
389
|
+
|
|
390
|
+
---
|
|
391
|
+
|
|
392
|
+
## License
|
|
393
|
+
|
|
394
|
+
MIT. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import D from"node:os";import p from"node:path";import f from"node:fs";import"node:crypto";import{AuthStorage as te,ModelRegistry as ne,SessionManager as se,createAgentSession as ae,initTheme as q,getMarkdownTheme as re,getSelectListTheme as oe}from"@earendil-works/pi-coding-agent";import{fileURLToPath as ie}from"node:url";import{TUI as ce,Container as b,Editor as Be,Text as x,Markdown as _e,ProcessTerminal as le,KeybindingsManager as de,TUI_KEYBINDINGS as me,setKeybindings as $e}from"@earendil-works/pi-tui";import{readClipboardImage as ue}from"../src/clipboard.mjs";import"../src/splash.mjs";const F=p.join(D.homedir(),".naraya","native-debug.log"),$=e=>{try{f.appendFileSync(F,`${new Date().toISOString()} ${e}
|
|
3
|
+
`)}catch{}};try{f.rmSync(F,{force:!0})}catch{}process.on("uncaughtException",e=>{$(`UNCAUGHT ${e?.stack??e}`)}),process.on("unhandledRejection",e=>{$(`UNHANDLED ${e?.stack??e}`)});const c="\x1B[38;2;45;123;255m",pe="\x1B[48;2;45;123;255m",he="\x1B[38;2;10;29;77m",ge="\x1B[48;2;10;29;77m",T="\x1B[38;2;255;140;40m",Ne="\x1B[38;2;111;191;115m",B="\x1B[2m",k="\x1B[1m",s="\x1B[0m",fe=/\x1b\[[0-9;]*m/g,m=e=>e.replace(fe,"").length,Ue=(()=>{try{const e=p.dirname(p.dirname(ie(import.meta.url)));return JSON.parse(f.readFileSync(p.join(e,"package.json"),"utf8")).version??"dev"}catch{return"dev"}})(),w=["_____________BB___","___BBB_______BBB__","_BBBBBB______BBBBB","_BBBBBBBB____BBBBB","B_BBBBBBBB___BBBBB","BB_BBBBBBBB__BBBNN","BBB_BBBBBBB__BBNNN","BBBB__BBB____BNNNN","BBBBBB_____BBBNNNN","BBBBBB___BBBBBNNNN","BBBBB___BBBBBBNNNN","BBBBB___BBBBBBNNNN","BBBBB____BBBBBNNNN","BBBBB______BBBNNN_","BBBBB_______BBNN__","_BBBB________B____","__BBB_____________","____B_____________"],M=e=>e==="B"?c:e==="N"?he:"",ye=e=>e==="B"?pe:e==="N"?ge:"";function Ye(){const e=[];for(let t=0;t<w.length;t+=2){let n="";for(let r=0;r<w[t].length;r++){const a=w[t][r],o=w[t+1]?.[r]??"_";a==="_"&&o==="_"?n+=" ":a!=="_"&&o==="_"?n+=`${M(a)}\u2580${s}`:a==="_"&&o!=="_"?n+=`${M(o)}\u2584${s}`:a===o?n+=`${M(a)}\u2588${s}`:n+=`${M(a)}${ye(o)}\u2580${s}`}e.push(n)}return e}const j=(e,t)=>e+" ".repeat(Math.max(0,t-m(e)));function Ke(e,t){const n=Math.max(...e.map(m),0),r=Math.max(...t.map(m),0),a=Math.max(e.length,t.length),o=Math.floor((a-e.length)/2),_=Math.floor((a-t.length)/2);return Array.from({length:a},(N,l)=>`${j(e[l-o]??"",n)} ${j(t[l-_]??"",r)}`)}const E=p.join(D.homedir(),".naraya","agent"),G=p.join(E,"models.json");let U;try{U=JSON.parse(f.readFileSync(G,"utf8"))}catch{console.error("Run `naraya login` first."),process.exit(1)}const y=U.providers?.naraya??{},be=(y.models??[]).map(e=>e.id),h=process.env.NARAYA_MODEL??be[0],xe=(y.models??[]).find(e=>e.id===h)?.name??h;h||(console.error("No naraya models \u2014 run `naraya login`."),process.exit(1));const Y=te.create(p.join(E,"auth.json")),K=ne.create(Y,G),P=K.find("naraya",h);P||(console.error(`Model naraya/${h} not found.`),process.exit(1));const{session:I}=await ae({cwd:process.cwd(),agentDir:E,model:P,thinkingLevel:"off",authStorage:Y,modelRegistry:K,tools:["read","grep","find","ls","edit","write","bash"],sessionManager:se.create(process.cwd())});try{$e(new de(me))}catch{}try{q("naraya",!0)}catch{try{q("dark",!0)}catch{}}const we=re(),Me={borderColor:e=>`${c}${e}${s}`,selectList:oe()};let V=!1,J=!1,z=0,H=0,u=null;async function Se(){try{const e=await fetch(`${y.baseUrl}/me`,{headers:{authorization:`Bearer ${y.apiKey}`},signal:AbortSignal.timeout(3e3)});if(!e.ok)return;const t=await e.json(),n=Number(t.quota?.limit??0),r=Number(t.quota?.remaining??0),a=o=>o>=1e6?`${(o/1e6).toFixed(1).replace(/\.0$/,"")}M`:Number(o).toLocaleString("id-ID");u={email:t.account?.email??"",plan:t.account?.plan??"",saldo:`Rp ${Number(t.credit?.available??0).toLocaleString("id-ID",{maximumFractionDigits:0})}`,usd:t.credit?.usd_equivalent?`$${t.credit.usd_equivalent}`:"",kuota:n>0?`${a(r)} / ${a(n)}`:"fair-use",models:Array.isArray(t.models)?t.models.length:0}}catch{}}const Ae={render(e){const t=Math.min(48,Math.max(40,e-2)),n=t-4,r=(d,L)=>{const ee=Math.max(1,n-m(d)-m(L));return`${d}${" ".repeat(ee)}${L}`},a=y?`${B} v${process.env.NARAYA_VERSION??"dev"}${s}${c}`:"",o=` ${k}NARAYA${s}${a}${c} `,_=`${c}\u256D\u2500${o}${"\u2500".repeat(Math.max(0,t-m(o)-3))}\u256E${s}`,N=`${c}\u2570${"\u2500".repeat(Math.max(0,t-2))}\u256F${s}`,l=d=>`${c}\u2502${s} ${d}${" ".repeat(Math.max(0,n-m(d)))} ${c}\u2502${s}`;return u?[_,l(r(`${k}${u.email}${s}`,`${B}${u.plan}${s}`)),l(r(`${c}Saldo${s} ${u.saldo}`,`${B}${u.usd}${s}`)),l(r(`${c}Kuota${s} ${u.kuota}`,`${B}${u.models} model${s}`)),N,""]:[_,l(`${B}memuat akun\u2026${s}`),N,""]}},Ce={render(e){const t=process.cwd(),n=`${c}\u25C6 ${xe}${s}`,r=Math.max(1,e-m(t)-m(n)),a=`${B}${t}${s}${" ".repeat(r)}${n}`,o=d=>d<1e3?`${d}`:`${(d/1e3).toFixed(1).replace(/\.0$/,"")}k`,_=`${B}\u2191${o(z)} \u2193${o(H)} tokens${s}`,N=`${V?T:B}\u26A1 auto-approve ${V?"ON":"OFF"} \xB7 Ctrl+Alt+A${s}`,l=`${J?T:B}\u2702\uFE0F truncate ${J?"ON":"OFF"} \xB7 Ctrl+Alt+O${s}`;return["\u2500".repeat(e),a,_,N,l]}},i=new ce(new le,!1),W=()=>{try{i.stop()}catch{}try{I.dispose?.()}catch{}process.exit(0)};process.on("SIGINT",W);const X=new b,g=new b,Q=new b,Z=new b;X.addChild(Ae),Z.addChild(Ce);let R=null,O="",S=!1;const A=new Map;let C=0;async function Te(e){$(`submit text=${JSON.stringify((e??"").slice(0,40))} busy=${S}`);let t=(e??"").trim();if(!t&&A.size===0||S){$("submit skipped (empty/busy)");return}const n=[];t=t.replace(/\[🖼 Image #(\d+)\]/g,(a,o)=>{const _=A.get(Number(o));if(_)try{n.push({type:"image",data:f.readFileSync(_.path).toString("base64"),mimeType:_.mimeType})}catch{}return""}).replace(/\s{2,}/g," ").trim(),A.clear(),C=0;const r=n.length?`${B}\u{1F4CE} ${n.length} gambar${s} `:"";g.addChild(new x(`${r}${k}\u203A${s} ${t||"(gambar)"}`,1,0)),O="",R=new _e("",1,0,we),g.addChild(R),i.requestRender(),S=!0;try{await I.prompt(t||"Describe this image.",n.length?{images:n}:void 0)}catch(a){$(`prompt error ${a?.stack??a}`),g.addChild(new x(`${T}[error]${s} ${a?.message??a}`,1,0))}finally{S=!1,i.requestRender()}}class ke extends Be{handleInput(t){if($(`handleInput ${JSON.stringify(t.slice(0,10))} len=${t.length}`),t===""){W();return}if(t==="\r"||t===`
|
|
4
|
+
`){const n=this.getText();this.setText(""),Te(n);return}if(t==="\x1Bv"||t==="\x1BV"){const n=ue();if(n){C+=1,A.set(C,n);const r=this.getText(),a=r&&!r.endsWith(" ")?" ":"";this.setText(`${r}${a}[\u{1F5BC} Image #${C}] `),i.requestRender()}return}super.handleInput(t)}}const v=new ke(i,Me,{placeholder:"Pesan ke Naraya \u2014 Enter kirim \xB7 Alt+V tempel gambar \xB7 Ctrl+C keluar"});Q.addChild(v),I.subscribe(e=>{if($(`event ${e.type}${e.assistantMessageEvent?.type?"/"+e.assistantMessageEvent.type:""}`),e.type==="message_update"&&e.assistantMessageEvent?.type==="text_delta")O+=e.assistantMessageEvent.delta,R?.setText(O),i.requestRender();else if(e.type==="tool_execution_start")g.addChild(new x(`${B}\u2699 ${e.toolName??"tool"}\u2026${s}`,1,0)),i.requestRender();else if(e.type==="turn_end"){const t=e.message?.usage;t&&(z+=t.input??0,H+=t.output??0),i.requestRender()}}),i.addChild(X),i.addChild(g),i.addChild(Q),i.addChild(Z),i.setFocus(v),i.start(),$(`started; focus=${i.focusedComponent===v?"editor":"other"} isTTY=${process.stdin.isTTY}`),g.addChild(new x(`${Ne}\u2713${s} Naraya native \u2014 naraya/${h}. Ketik pesan, Enter kirim.`,1,0)),Se().then(()=>i.requestRender());
|