@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
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pentest Types - Full integration from pentest-core
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// ── Flag Types ──
|
|
6
|
+
|
|
7
|
+
export type FlagType = "boolean" | "string" | "number" | "path" | "choice" | "repeat"
|
|
8
|
+
|
|
9
|
+
export interface FlagDefinition {
|
|
10
|
+
readonly name: string
|
|
11
|
+
readonly type: FlagType
|
|
12
|
+
readonly description: string
|
|
13
|
+
readonly default?: unknown
|
|
14
|
+
readonly required?: boolean
|
|
15
|
+
readonly choices?: readonly string[]
|
|
16
|
+
readonly depends_on?: string
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface PositionalArgument {
|
|
20
|
+
readonly name: string
|
|
21
|
+
readonly type: string
|
|
22
|
+
readonly description: string
|
|
23
|
+
readonly required: boolean
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// ── Command Structure ──
|
|
27
|
+
|
|
28
|
+
export interface CommandDefinition {
|
|
29
|
+
readonly base: string
|
|
30
|
+
readonly flags: readonly FlagDefinition[]
|
|
31
|
+
readonly positional: readonly PositionalArgument[]
|
|
32
|
+
readonly pipes?: readonly string[]
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// ── Installation ──
|
|
36
|
+
|
|
37
|
+
export interface PlatformInstallation {
|
|
38
|
+
readonly command: string
|
|
39
|
+
readonly manager: string
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface InstallationConfig {
|
|
43
|
+
readonly linux?: PlatformInstallation
|
|
44
|
+
readonly darwin?: PlatformInstallation
|
|
45
|
+
readonly win32?: PlatformInstallation
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// ── Check Installed ──
|
|
49
|
+
|
|
50
|
+
export interface CheckInstalledConfig {
|
|
51
|
+
readonly command: string
|
|
52
|
+
readonly exit_code?: number
|
|
53
|
+
readonly parse_version?: string
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ── Categories & Phases ──
|
|
57
|
+
|
|
58
|
+
export type ToolCategory = "recon" | "enumeration" | "exploitation" | "reporting" | "utility"
|
|
59
|
+
|
|
60
|
+
export type PentestPhase = "recon" | "enumeration" | "exploitation" | "reporting"
|
|
61
|
+
|
|
62
|
+
export type OutputFormat = "text" | "json" | "xml" | "csv" | "html" | "markdown" | "sarif" | "grepable" | "binary" | "log" | "graph" | "ndjson"
|
|
63
|
+
|
|
64
|
+
// ── Tool Entry ──
|
|
65
|
+
|
|
66
|
+
export interface ToolEntry {
|
|
67
|
+
readonly tools_name: string
|
|
68
|
+
readonly description: string
|
|
69
|
+
readonly category: ToolCategory
|
|
70
|
+
readonly command: CommandDefinition
|
|
71
|
+
readonly installation: InstallationConfig
|
|
72
|
+
readonly check_installed: CheckInstalledConfig
|
|
73
|
+
readonly skills_loader: string
|
|
74
|
+
readonly phase: readonly PentestPhase[]
|
|
75
|
+
readonly tags: readonly string[]
|
|
76
|
+
readonly requires_root: boolean
|
|
77
|
+
readonly output_format: readonly OutputFormat[]
|
|
78
|
+
readonly homepage?: string
|
|
79
|
+
readonly alternatives?: readonly string[]
|
|
80
|
+
readonly min_version?: string
|
|
81
|
+
readonly max_version?: string
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// ── Catalog Root ──
|
|
85
|
+
|
|
86
|
+
export interface ToolsCatalog {
|
|
87
|
+
readonly $schema: string
|
|
88
|
+
readonly version: string
|
|
89
|
+
readonly categories: readonly ToolCategory[]
|
|
90
|
+
readonly tools: readonly ToolEntry[]
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ── Runtime Types ──
|
|
94
|
+
|
|
95
|
+
export interface ToolAvailability {
|
|
96
|
+
readonly tools_name: string
|
|
97
|
+
readonly installed: boolean
|
|
98
|
+
readonly version?: string
|
|
99
|
+
readonly error?: string
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface CommandBuildResult {
|
|
103
|
+
readonly command: string
|
|
104
|
+
readonly args: readonly string[]
|
|
105
|
+
readonly fullCommand: string
|
|
106
|
+
readonly requires_root: boolean
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export interface SkillBridgeResult {
|
|
110
|
+
readonly skill_name: string
|
|
111
|
+
readonly skill_path?: string
|
|
112
|
+
readonly loaded: boolean
|
|
113
|
+
readonly error?: string
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// ── Selector Options ──
|
|
117
|
+
|
|
118
|
+
export interface ToolSelectorOptions {
|
|
119
|
+
readonly category?: ToolCategory
|
|
120
|
+
readonly phase?: PentestPhase
|
|
121
|
+
readonly tags?: readonly string[]
|
|
122
|
+
readonly requires_root?: boolean
|
|
123
|
+
readonly installed_only?: boolean
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// ── Command Builder Options ──
|
|
127
|
+
|
|
128
|
+
export interface CommandBuildOptions {
|
|
129
|
+
readonly flags?: Record<string, unknown>
|
|
130
|
+
readonly positional?: readonly string[]
|
|
131
|
+
readonly pipe_to?: readonly string[]
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// ── Pentest Mode Types ──
|
|
135
|
+
|
|
136
|
+
export type PentestMode = "auto" | "ctf" | "bug-bounty" | "red-team" | "blue-team" | "offensive" | "grey-hat"
|
|
137
|
+
|
|
138
|
+
export type ScopeEnforcement = "strict" | "moderate" | "none"
|
|
139
|
+
|
|
140
|
+
export type ReportFormat = "standard" | "hackerone" | "bugcrowd" | "executive" | "technical" | "ir" | "flag"
|
|
141
|
+
|
|
142
|
+
export interface ModeConfig {
|
|
143
|
+
readonly mode: PentestMode
|
|
144
|
+
readonly description: string
|
|
145
|
+
readonly scope_enforcement: ScopeEnforcement
|
|
146
|
+
readonly tool_priority: readonly ToolCategory[]
|
|
147
|
+
readonly skill_chain: readonly string[]
|
|
148
|
+
readonly parallelism: number
|
|
149
|
+
readonly stealth: boolean
|
|
150
|
+
readonly report_format: ReportFormat
|
|
151
|
+
readonly loop_config: ModeLoopConfig
|
|
152
|
+
readonly safety_constraints: SafetyConfig
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export interface ModeLoopConfig {
|
|
156
|
+
readonly max_iterations: number
|
|
157
|
+
readonly iteration_timeout_ms: number
|
|
158
|
+
readonly strategy: "reset" | "continue" | "adaptive"
|
|
159
|
+
readonly auto_continue: boolean
|
|
160
|
+
readonly speed: "fast" | "moderate" | "slow"
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export interface SafetyConfig {
|
|
164
|
+
readonly scope_strict: boolean
|
|
165
|
+
readonly no_dos: boolean
|
|
166
|
+
readonly no_exfiltration: boolean
|
|
167
|
+
readonly stealth_mode: boolean
|
|
168
|
+
readonly auto_stop_on_scope_violation: boolean
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// ── Mode Presets ──
|
|
172
|
+
|
|
173
|
+
export const MODE_PRESETS: Record<PentestMode, ModeConfig> = {
|
|
174
|
+
"auto": {
|
|
175
|
+
mode: "auto",
|
|
176
|
+
description: "Auto-detect mode based on target type. Smart tool priority and adaptive strategy.",
|
|
177
|
+
scope_enforcement: "moderate",
|
|
178
|
+
tool_priority: ["recon", "enumeration", "exploitation", "reporting", "utility"],
|
|
179
|
+
skill_chain: ["pentest-recon", "pentest-enum", "pentest-exploit", "pentest-report"],
|
|
180
|
+
parallelism: 4,
|
|
181
|
+
stealth: false,
|
|
182
|
+
report_format: "standard",
|
|
183
|
+
loop_config: { max_iterations: 100, iteration_timeout_ms: 300000, strategy: "adaptive", auto_continue: true, speed: "moderate" },
|
|
184
|
+
safety_constraints: { scope_strict: true, no_dos: true, no_exfiltration: true, stealth_mode: false, auto_stop_on_scope_violation: true }
|
|
185
|
+
},
|
|
186
|
+
"ctf": {
|
|
187
|
+
mode: "ctf",
|
|
188
|
+
description: "CTF challenge mode. Speed-first, parallel everything, flag-focused reporting.",
|
|
189
|
+
scope_enforcement: "none",
|
|
190
|
+
tool_priority: ["exploitation", "enumeration", "recon", "utility"],
|
|
191
|
+
skill_chain: ["ctf-recon", "ctf-exploit", "ctf-crypto", "ctf-forensics"],
|
|
192
|
+
parallelism: 8,
|
|
193
|
+
stealth: false,
|
|
194
|
+
report_format: "flag",
|
|
195
|
+
loop_config: { max_iterations: 200, iteration_timeout_ms: 120000, strategy: "adaptive", auto_continue: true, speed: "fast" },
|
|
196
|
+
safety_constraints: { scope_strict: false, no_dos: false, no_exfiltration: false, stealth_mode: false, auto_stop_on_scope_violation: false }
|
|
197
|
+
},
|
|
198
|
+
"bug-bounty": {
|
|
199
|
+
mode: "bug-bounty",
|
|
200
|
+
description: "Bug bounty mode. Scope-strict, web-focused, HackerOne/Bugcrowd report format.",
|
|
201
|
+
scope_enforcement: "strict",
|
|
202
|
+
tool_priority: ["recon", "enumeration", "exploitation", "reporting"],
|
|
203
|
+
skill_chain: ["pentest-recon", "pentest-enum", "pentest-exploit", "pentest-report"],
|
|
204
|
+
parallelism: 6,
|
|
205
|
+
stealth: false,
|
|
206
|
+
report_format: "hackerone",
|
|
207
|
+
loop_config: { max_iterations: 150, iteration_timeout_ms: 300000, strategy: "continue", auto_continue: true, speed: "moderate" },
|
|
208
|
+
safety_constraints: { scope_strict: true, no_dos: true, no_exfiltration: true, stealth_mode: false, auto_stop_on_scope_violation: true }
|
|
209
|
+
},
|
|
210
|
+
"red-team": {
|
|
211
|
+
mode: "red-team",
|
|
212
|
+
description: "Red team mode. Stealth-first, persistence, lateral movement, executive reporting.",
|
|
213
|
+
scope_enforcement: "strict",
|
|
214
|
+
tool_priority: ["recon", "exploitation", "enumeration", "reporting"],
|
|
215
|
+
skill_chain: ["red-recon", "red-exploit", "red-lateral", "red-persistence"],
|
|
216
|
+
parallelism: 2,
|
|
217
|
+
stealth: true,
|
|
218
|
+
report_format: "executive",
|
|
219
|
+
loop_config: { max_iterations: 50, iteration_timeout_ms: 600000, strategy: "continue", auto_continue: true, speed: "slow" },
|
|
220
|
+
safety_constraints: { scope_strict: true, no_dos: true, no_exfiltration: true, stealth_mode: true, auto_stop_on_scope_violation: true }
|
|
221
|
+
},
|
|
222
|
+
"blue-team": {
|
|
223
|
+
mode: "blue-team",
|
|
224
|
+
description: "Blue team mode. Detection-first, log analysis, incident response, IR reporting.",
|
|
225
|
+
scope_enforcement: "strict",
|
|
226
|
+
tool_priority: ["enumeration", "recon", "reporting", "utility"],
|
|
227
|
+
skill_chain: ["blue-detect", "blue-ir", "blue-forensics", "blue-report"],
|
|
228
|
+
parallelism: 4,
|
|
229
|
+
stealth: false,
|
|
230
|
+
report_format: "ir",
|
|
231
|
+
loop_config: { max_iterations: 100, iteration_timeout_ms: 300000, strategy: "continue", auto_continue: true, speed: "moderate" },
|
|
232
|
+
safety_constraints: { scope_strict: true, no_dos: true, no_exfiltration: true, stealth_mode: false, auto_stop_on_scope_violation: true }
|
|
233
|
+
},
|
|
234
|
+
"offensive": {
|
|
235
|
+
mode: "offensive",
|
|
236
|
+
description: "Offensive mode. Aggressive exploitation, privilege escalation, technical reporting.",
|
|
237
|
+
scope_enforcement: "strict",
|
|
238
|
+
tool_priority: ["exploitation", "enumeration", "recon", "reporting"],
|
|
239
|
+
skill_chain: ["pentest-recon", "pentest-enum", "pentest-exploit", "pentest-privesc"],
|
|
240
|
+
parallelism: 6,
|
|
241
|
+
stealth: false,
|
|
242
|
+
report_format: "technical",
|
|
243
|
+
loop_config: { max_iterations: 100, iteration_timeout_ms: 300000, strategy: "continue", auto_continue: true, speed: "moderate" },
|
|
244
|
+
safety_constraints: { scope_strict: true, no_dos: true, no_exfiltration: true, stealth_mode: false, auto_stop_on_scope_violation: true }
|
|
245
|
+
},
|
|
246
|
+
"grey-hat": {
|
|
247
|
+
mode: "grey-hat",
|
|
248
|
+
description: "Grey hat mode. Balanced offensive/defensive, moderate stealth, hybrid reporting.",
|
|
249
|
+
scope_enforcement: "moderate",
|
|
250
|
+
tool_priority: ["recon", "enumeration", "exploitation", "reporting", "utility"],
|
|
251
|
+
skill_chain: ["pentest-recon", "pentest-enum", "pentest-exploit", "pentest-report"],
|
|
252
|
+
parallelism: 4,
|
|
253
|
+
stealth: true,
|
|
254
|
+
report_format: "technical",
|
|
255
|
+
loop_config: { max_iterations: 100, iteration_timeout_ms: 300000, strategy: "adaptive", auto_continue: true, speed: "moderate" },
|
|
256
|
+
safety_constraints: { scope_strict: true, no_dos: true, no_exfiltration: true, stealth_mode: true, auto_stop_on_scope_violation: true }
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// ── Mode Selector Options ──
|
|
261
|
+
|
|
262
|
+
export interface ModeSelectorOptions {
|
|
263
|
+
readonly target?: string
|
|
264
|
+
readonly scope_file?: string
|
|
265
|
+
readonly preferred_mode?: PentestMode
|
|
266
|
+
readonly auto_detect?: boolean
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export interface ModeSelectionResult {
|
|
270
|
+
readonly selected_mode: PentestMode
|
|
271
|
+
readonly config: ModeConfig
|
|
272
|
+
readonly auto_detected: boolean
|
|
273
|
+
readonly detection_reason?: string
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// ── Pentest Skill Types ──
|
|
277
|
+
|
|
278
|
+
export interface PentestSkill {
|
|
279
|
+
readonly name: string
|
|
280
|
+
readonly description: string
|
|
281
|
+
readonly version: string
|
|
282
|
+
readonly phase: readonly PentestPhase[]
|
|
283
|
+
readonly category: readonly ToolCategory[]
|
|
284
|
+
readonly tools: readonly string[]
|
|
285
|
+
readonly author?: string
|
|
286
|
+
readonly homepage?: string
|
|
287
|
+
readonly tags: readonly string[]
|
|
288
|
+
readonly template: string
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
export interface PentestSkillManifest {
|
|
292
|
+
readonly name: string
|
|
293
|
+
readonly description: string
|
|
294
|
+
readonly version: string
|
|
295
|
+
readonly phase: readonly PentestPhase[]
|
|
296
|
+
readonly category: readonly ToolCategory[]
|
|
297
|
+
readonly tools: readonly string[]
|
|
298
|
+
readonly tags: readonly string[]
|
|
299
|
+
readonly skill_path: string
|
|
300
|
+
readonly loaded: boolean
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
export interface SkillRegisterEntry {
|
|
304
|
+
readonly name: string
|
|
305
|
+
readonly skill: PentestSkill
|
|
306
|
+
readonly registered_at: string
|
|
307
|
+
readonly enabled: boolean
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export interface SkillRegisterConfig {
|
|
311
|
+
readonly skills_dir: string
|
|
312
|
+
readonly auto_discover: boolean
|
|
313
|
+
readonly search_paths: readonly string[]
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
export interface GeneratedSkill {
|
|
317
|
+
readonly name: string
|
|
318
|
+
readonly content: string
|
|
319
|
+
readonly path: string
|
|
320
|
+
readonly tools_referenced: readonly string[]
|
|
321
|
+
readonly phase: readonly PentestPhase[]
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
export interface SkillGenerationOptions {
|
|
325
|
+
readonly name: string
|
|
326
|
+
readonly description: string
|
|
327
|
+
readonly phase: readonly PentestPhase[]
|
|
328
|
+
readonly category: readonly ToolCategory[]
|
|
329
|
+
readonly tools: readonly string[]
|
|
330
|
+
readonly author?: string
|
|
331
|
+
readonly tags?: readonly string[]
|
|
332
|
+
readonly output_dir?: string
|
|
333
|
+
readonly template?: "basic" | "recon" | "exploitation" | "reporting" | "custom"
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
export interface SkillLoadResult {
|
|
337
|
+
readonly name: string
|
|
338
|
+
readonly loaded: boolean
|
|
339
|
+
readonly skill?: PentestSkill
|
|
340
|
+
readonly error?: string
|
|
341
|
+
}
|
package/src/seed.mjs
CHANGED
|
@@ -1,36 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
|
|
4
|
-
const MANIFEST = ".naraya-managed.json";
|
|
5
|
-
|
|
6
|
-
/** Recursively list files under dir, relative paths, forward slashes. */
|
|
7
|
-
function listFiles(dir, base = dir) {
|
|
8
|
-
if (!fs.existsSync(dir)) return [];
|
|
9
|
-
return fs.readdirSync(dir, { withFileTypes: true }).flatMap((e) => {
|
|
10
|
-
const p = path.join(dir, e.name);
|
|
11
|
-
return e.isDirectory() ? listFiles(p, base) : [path.relative(base, p).replaceAll("\\", "/")];
|
|
12
|
-
});
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Sync assets into the agent config dir. Only files listed in the previous
|
|
17
|
-
* manifest are ever overwritten or deleted; user files are untouched.
|
|
18
|
-
*/
|
|
19
|
-
export function seed(assetsDir, agentDir) {
|
|
20
|
-
fs.mkdirSync(agentDir, { recursive: true });
|
|
21
|
-
const manifestPath = path.join(agentDir, MANIFEST);
|
|
22
|
-
const previous = fs.existsSync(manifestPath)
|
|
23
|
-
? JSON.parse(fs.readFileSync(manifestPath, "utf8")).files
|
|
24
|
-
: [];
|
|
25
|
-
|
|
26
|
-
const current = listFiles(assetsDir);
|
|
27
|
-
for (const rel of current) {
|
|
28
|
-
const dst = path.join(agentDir, rel);
|
|
29
|
-
fs.mkdirSync(path.dirname(dst), { recursive: true });
|
|
30
|
-
fs.copyFileSync(path.join(assetsDir, rel), dst);
|
|
31
|
-
}
|
|
32
|
-
for (const rel of previous) {
|
|
33
|
-
if (!current.includes(rel)) fs.rmSync(path.join(agentDir, rel), { force: true });
|
|
34
|
-
}
|
|
35
|
-
fs.writeFileSync(manifestPath, JSON.stringify({ files: current }, null, 2));
|
|
36
|
-
}
|
|
1
|
+
import e from"node:fs";import t from"node:path";const u=".naraya-managed.json";function a(n,r=n){return e.existsSync(n)?e.readdirSync(n,{withFileTypes:!0}).flatMap(i=>{const c=t.join(n,i.name);return i.isDirectory()?a(c,r):[t.relative(r,c).replaceAll("\\","/")]}):[]}function y(n,r){e.mkdirSync(r,{recursive:!0});const i=t.join(r,u),c=e.existsSync(i)?JSON.parse(e.readFileSync(i,"utf8")).files:[],l=n.map(o=>o.rel);for(const o of n){const f=t.join(r,o.rel);e.mkdirSync(t.dirname(f),{recursive:!0}),e.writeFileSync(f,o.buf)}for(const o of c){if(l.includes(o))continue;const f=t.join(r,o);e.rmSync(f,{force:!0});let s=t.dirname(f);for(;s!==r&&s.startsWith(r);){try{if(e.readdirSync(s).length>0)break;e.rmdirSync(s)}catch{break}s=t.dirname(s)}}e.writeFileSync(i,JSON.stringify({files:l},null,2))}function S(n,r){const i=a(n).map(c=>({rel:c,buf:e.readFileSync(t.join(n,c))}));y(i,r)}export{S as seed,y as seedEntries};
|
package/src/splash.mjs
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import b from"node:fs";import x from"node:os";import f from"node:path";const m="\x1B[38;2;45;123;255m",d="\x1B[48;2;45;123;255m",k="\x1B[38;2;10;29;77m",y="\x1B[48;2;10;29;77m",w="\x1B[38;2;111;191;115m",T="\x1B[38;2;224;163;62m",E="\x1B[1m",c="\x1B[2m",s="\x1B[0m",L="\x1B[?25l",S="\x1B[?25h",p="\x1B[2J\x1B[3J\x1B[H",$=B=>new Promise(_=>setTimeout(_,B)),A=B=>B.replace(/\x1b\[[0-9;?]*[a-zA-Z]/g,"").length,l=["_____________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_____________"],N=B=>B==="B"?m:B==="N"?k:"",I=B=>B==="B"?d:B==="N"?y:"";function O(){const B=[];for(let _=0;_<l.length;_+=2){let t="";for(let n=0;n<l[_].length;n++){const o=l[_][n],e=l[_+1]?.[n]??"_";o==="_"&&e==="_"?t+=" ":o!=="_"&&e==="_"?t+=`${N(o)}\u2580${s}`:o==="_"&&e!=="_"?t+=`${N(e)}\u2584${s}`:o===e?t+=`${N(o)}\u2588${s}`:t+=`${N(o)}${I(e)}\u2580${s}`}B.push(t)}return B}function D(){return process.env.PI_CODING_AGENT_DIR??f.join(x.homedir(),".naraya","agent")}function G(){try{const _=JSON.parse(b.readFileSync(f.join(D(),"models.json"),"utf8")).providers?.naraya;if(_?.baseUrl&&_?.apiKey)return _}catch{}return null}function g(B,_,t){const n=`
|
|
2
|
+
`.repeat(Math.max(0,Math.floor((_-t.length)/2))),o=t.map(e=>" ".repeat(Math.max(0,Math.floor((B-A(e))/2)))+e).join(`
|
|
3
|
+
`);return`${p}${n}${o}
|
|
4
|
+
`}async function P(){const B=G();if(!process.stdout.isTTY)return{ok:!!B,reason:B?"ok":"login"};const _=process.stdout.columns||80,t=process.stdout.rows||24,n=B?fetch(`${B.baseUrl}/me`,{headers:{authorization:`Bearer ${B.apiKey}`},signal:AbortSignal.timeout(3e3)}).then(r=>r.ok?"ok":"expired").catch(()=>"offline"):Promise.resolve("login"),o=O(),e=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"];process.stdout.write(L);try{for(let u=0;u<24;u++){const h=`${m}${e[u%e.length]}${s} ${E}Starting Naraya CLI${s}${c}\u2026${s}`;process.stdout.write(g(_,t,[...o,"",h])),await $(105)}const r=await n;let i,a;return r==="login"?(i=`${c}\u2192 Belum login \u2014 mengarahkan ke login\u2026${s}`,a=!1):r==="expired"?(i=`${c}\u2192 Sesi habis \u2014 login ulang\u2026${s}`,a=!1):r==="offline"?(i=`${c}\u2192 Masuk terminal (gateway tak terjangkau)\u2026${s}`,a=!0):(i=`${w}\u2713 Auth sukses${s}${c} \u2014 masuk terminal\u2026${s}`,a=!0),process.stdout.write(g(_,t,[...o,"",i])),await $(a?700:1200),{ok:a,reason:r}}finally{process.stdout.write(p+S)}}export{P as splash};
|
package/src/status.mjs
CHANGED
|
@@ -1,71 +1,2 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
import { BASE_URL as DEFAULT_BASE_URL } from "./config.mjs";
|
|
4
|
-
|
|
5
|
-
/** Read the saved key from models.json (written by `naraya login`). Null if absent. */
|
|
6
|
-
function readKey(agentDir) {
|
|
7
|
-
const p = path.join(agentDir, "models.json");
|
|
8
|
-
if (!fs.existsSync(p)) return null;
|
|
9
|
-
try {
|
|
10
|
-
return JSON.parse(fs.readFileSync(p, "utf8")).providers?.naraya?.apiKey ?? null;
|
|
11
|
-
} catch {
|
|
12
|
-
return null;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/** Format the credit. Credits are Rupiah (1 credit = Rp1); `--usd` shows the
|
|
17
|
-
* server-provided USD equivalent instead. */
|
|
18
|
-
function formatCredit(credit, usd) {
|
|
19
|
-
if (usd && credit?.usd_equivalent != null) {
|
|
20
|
-
return `$${Number(credit.usd_equivalent).toFixed(2)} available (USD est.)`;
|
|
21
|
-
}
|
|
22
|
-
const amount = Number(credit?.available ?? 0);
|
|
23
|
-
return `Rp ${amount.toLocaleString("id-ID", { maximumFractionDigits: 0 })} available`;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Format the /v1/me response into a printable block. Pure (no I/O).
|
|
28
|
-
* quota.remaining/limit are DAILY TOKENS (unit:"tokens"), never request counts —
|
|
29
|
-
* usage.requests_* are the counts, kept separate.
|
|
30
|
-
*/
|
|
31
|
-
export function renderStatus(s, { usd = false } = {}) {
|
|
32
|
-
const quota =
|
|
33
|
-
s.quota?.limit > 0
|
|
34
|
-
? `${s.quota.remaining.toLocaleString("en-US")} / ${s.quota.limit.toLocaleString("en-US")} ${s.quota.unit ?? "tokens"} today (reset ${String(s.quota.reset_at).slice(0, 10)})`
|
|
35
|
-
: "no daily cap (fair-use)";
|
|
36
|
-
const models = Array.isArray(s.models) ? s.models : [];
|
|
37
|
-
const modelList = models.slice(0, 6).join(", ") + (models.length > 6 ? ` … (${models.length})` : ` (${models.length})`);
|
|
38
|
-
const ok = s.usage ? `${s.usage.requests_today} req, ${(s.usage.success_rate * 100).toFixed(1)}% ok` : "";
|
|
39
|
-
return [
|
|
40
|
-
`Signed in: ${s.account?.email ?? "?"} [${s.account?.plan ?? "?"}]`,
|
|
41
|
-
`Credit: ${formatCredit(s.credit, usd)}`,
|
|
42
|
-
`Quota: ${quota}`,
|
|
43
|
-
`Today: ${ok}`,
|
|
44
|
-
`Models: ${modelList}`,
|
|
45
|
-
].join("\n");
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/** Fetch /v1/me with the saved key and print the status block. */
|
|
49
|
-
export async function status(agentDir, { BASE_URL = DEFAULT_BASE_URL } = {}, { usd = false } = {}) {
|
|
50
|
-
const key = readKey(agentDir);
|
|
51
|
-
if (!key) {
|
|
52
|
-
console.error("Run `naraya login` first.");
|
|
53
|
-
process.exit(1);
|
|
54
|
-
}
|
|
55
|
-
let res;
|
|
56
|
-
try {
|
|
57
|
-
res = await fetch(`${BASE_URL}/me`, { headers: { authorization: `Bearer ${key}` } });
|
|
58
|
-
} catch (err) {
|
|
59
|
-
console.error(`status failed: ${err.message}`);
|
|
60
|
-
process.exit(1);
|
|
61
|
-
}
|
|
62
|
-
if (res.status === 401) {
|
|
63
|
-
console.error("Key rejected. Run `naraya login` again.");
|
|
64
|
-
process.exit(1);
|
|
65
|
-
}
|
|
66
|
-
if (!res.ok) {
|
|
67
|
-
console.error(`status failed: HTTP ${res.status}`);
|
|
68
|
-
process.exit(1);
|
|
69
|
-
}
|
|
70
|
-
console.log(renderStatus(await res.json(), { usd }));
|
|
71
|
-
}
|
|
1
|
+
import i from"node:fs";import s from"node:path";import{BASE_URL as l}from"./config.mjs";function u(e){const t=s.join(e,"models.json");if(!i.existsSync(t))return null;try{return JSON.parse(i.readFileSync(t,"utf8")).providers?.naraya?.apiKey??null}catch{return null}}function c(e,t){return t&&e?.usd_equivalent!=null?`$${Number(e.usd_equivalent).toFixed(2)} available (USD est.)`:`Rp ${Number(e?.available??0).toLocaleString("id-ID",{maximumFractionDigits:0})} available`}function d(e,{usd:t=!1}={}){const r=e.quota?.limit>0?`${e.quota.remaining.toLocaleString("en-US")} / ${e.quota.limit.toLocaleString("en-US")} ${e.quota.unit??"tokens"} today (reset ${String(e.quota.reset_at).slice(0,10)})`:"no daily cap (fair-use)",a=Array.isArray(e.models)?e.models:[],o=a.slice(0,6).join(", ")+(a.length>6?` \u2026 (${a.length})`:` (${a.length})`),n=e.usage?`${e.usage.requests_today} req, ${(e.usage.success_rate*100).toFixed(1)}% ok`:"";return[`Signed in: ${e.account?.email??"?"} [${e.account?.plan??"?"}]`,`Credit: ${c(e.credit,t)}`,`Quota: ${r}`,`Today: ${n}`,`Models: ${o}`].join(`
|
|
2
|
+
`)}async function g(e,{BASE_URL:t=l}={},{usd:r=!1}={}){const a=u(e);a||(console.error("Run `naraya login` first."),process.exit(1));let o;try{o=await fetch(`${t}/me`,{headers:{authorization:`Bearer ${a}`}})}catch(n){console.error(`status failed: ${n.message}`),process.exit(1)}o.status===401&&(console.error("Key rejected. Run `naraya login` again."),process.exit(1)),o.ok||(console.error(`status failed: HTTP ${o.status}`),process.exit(1)),console.log(d(await o.json(),{usd:r}))}export{d as renderStatus,g as status};
|
package/assets/APPEND-SYSTEM.md
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
You are Naraya, an AI coding agent powered by router.naraya.ai.
|
|
2
|
-
|
|
3
|
-
Specialist skills are available on demand — load the matching one before starting a task:
|
|
4
|
-
- NaraBuild (`/skill:narabuild`) — implement features, bugfixes, refactors, releases (changes code).
|
|
5
|
-
- NaraPlan (`/skill:naraplan`) — investigate and write an implementation plan; never edits code.
|
|
6
|
-
- NaraSearch (`/skill:narasearch`) — evidence-first research over docs, libraries, codebases.
|
|
7
|
-
- NaraExplore (`/skill:naraexplore`) — fast read-only codebase navigation.
|
|
8
|
-
- NaraFE (`/skill:narafe`) — UI/UX, React/Vue/Svelte, CSS/Tailwind, accessibility.
|
|
9
|
-
- NaraDroid (`/skill:naradroid`) — native Android: Kotlin/Gradle/Compose, adb, APK/AAB.
|