@ch4p/cli 0.1.2 → 0.1.4

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.
Files changed (49) hide show
  1. package/dist/agent-6WIHK7NM.js +767 -0
  2. package/dist/agent-ANIZYPPF.js +767 -0
  3. package/dist/agent-HSAJ5EBN.js +761 -0
  4. package/dist/audit-HLOQBMBT.js +12 -0
  5. package/dist/audit-UIGPH3FK.js +12 -0
  6. package/dist/canvas-3VTC4XPV.js +313 -0
  7. package/dist/canvas-4FMNW6FZ.js +313 -0
  8. package/dist/canvas-LNQGR57A.js +313 -0
  9. package/dist/canvas-XQHVCY27.js +313 -0
  10. package/dist/chunk-3XAW4XHG.js +185 -0
  11. package/dist/chunk-4IRZQCRN.js +1832 -0
  12. package/dist/chunk-AORLXQHZ.js +304 -0
  13. package/dist/chunk-BMEBRUYL.js +6995 -0
  14. package/dist/chunk-IN2I6XRM.js +185 -0
  15. package/dist/chunk-TB4IZ7F7.js +301 -0
  16. package/dist/chunk-U7S375OS.js +1841 -0
  17. package/dist/chunk-XRUNSIVU.js +1776 -0
  18. package/dist/dist-37TB6EWP.js +25 -0
  19. package/dist/dist-CIJPZC2B.js +25 -0
  20. package/dist/doctor-5M3ZB435.js +274 -0
  21. package/dist/doctor-IQ3MWQSN.js +274 -0
  22. package/dist/gateway-72PE334E.js +2094 -0
  23. package/dist/gateway-DV5OL45G.js +2164 -0
  24. package/dist/gateway-LUCG72YX.js +2129 -0
  25. package/dist/gateway-O3QNSZKF.js +2123 -0
  26. package/dist/gateway-OJW7RY3H.js +2094 -0
  27. package/dist/gateway-PBLJEK5I.js +2165 -0
  28. package/dist/gateway-PHPRQTZP.js +2165 -0
  29. package/dist/gateway-YKKJ4DZE.js +2115 -0
  30. package/dist/gateway-Z65DCM2Q.js +2097 -0
  31. package/dist/gateway-ZSXTAYPF.js +2157 -0
  32. package/dist/identity-RHQFPSDS.js +215 -0
  33. package/dist/identity-VGDDAKBY.js +215 -0
  34. package/dist/index.js +12 -12
  35. package/dist/install-6LV7B2SV.js +378 -0
  36. package/dist/install-NAUPXVCI.js +378 -0
  37. package/dist/message-TGAPVVI4.js +189 -0
  38. package/dist/message-YQGIARNE.js +189 -0
  39. package/dist/onboard-CN56V5P6.js +849 -0
  40. package/dist/onboard-LJFC6HXD.js +849 -0
  41. package/dist/onboard-TH2AOMUO.js +849 -0
  42. package/dist/pairing-6LQDDRGX.js +147 -0
  43. package/dist/pairing-ARWQYATE.js +147 -0
  44. package/dist/pairing-PXCJMCT2.js +147 -0
  45. package/dist/skills-4EELFYO2.js +138 -0
  46. package/dist/skills-KXRTDSF2.js +138 -0
  47. package/dist/status-2ZJPK3VL.js +94 -0
  48. package/dist/status-W2OXOSH4.js +94 -0
  49. package/package.json +24 -24
@@ -0,0 +1,304 @@
1
+ // src/config.ts
2
+ import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
3
+ import { resolve, join } from "path";
4
+ import { homedir } from "os";
5
+ var CH4P_DIR_NAME = ".ch4p";
6
+ var CONFIG_FILE_NAME = "config.json";
7
+ var LOGS_DIR_NAME = "logs";
8
+ function getCh4pDir() {
9
+ return resolve(homedir(), CH4P_DIR_NAME);
10
+ }
11
+ function getConfigPath() {
12
+ return join(getCh4pDir(), CONFIG_FILE_NAME);
13
+ }
14
+ function getLogsDir() {
15
+ return join(getCh4pDir(), LOGS_DIR_NAME);
16
+ }
17
+ function getDefaultConfig() {
18
+ return {
19
+ agent: {
20
+ model: "claude-sonnet-4-6",
21
+ provider: "anthropic",
22
+ thinkingLevel: "medium"
23
+ },
24
+ providers: {
25
+ anthropic: {
26
+ apiKey: "${ANTHROPIC_API_KEY}"
27
+ },
28
+ openai: {
29
+ apiKey: "${OPENAI_API_KEY}"
30
+ }
31
+ },
32
+ channels: {},
33
+ memory: {
34
+ backend: "sqlite",
35
+ autoSave: true,
36
+ vectorWeight: 0.7,
37
+ keywordWeight: 0.3
38
+ },
39
+ gateway: {
40
+ port: 18789,
41
+ requirePairing: true,
42
+ allowPublicBind: false
43
+ },
44
+ security: {
45
+ workspaceOnly: true,
46
+ blockedPaths: []
47
+ },
48
+ autonomy: {
49
+ level: "supervised",
50
+ allowedCommands: [
51
+ "git",
52
+ "npm",
53
+ "pnpm",
54
+ "node",
55
+ "npx",
56
+ "cargo",
57
+ "ls",
58
+ "cat",
59
+ "grep",
60
+ "find",
61
+ "wc",
62
+ "sort",
63
+ "head",
64
+ "tail",
65
+ "mkdir",
66
+ "cp",
67
+ "mv",
68
+ "echo",
69
+ "touch"
70
+ ]
71
+ },
72
+ engines: {
73
+ default: "native",
74
+ available: {
75
+ native: {
76
+ provider: "anthropic",
77
+ model: "claude-sonnet-4-6"
78
+ },
79
+ "claude-cli": {
80
+ command: "claude",
81
+ timeout: 6e5
82
+ },
83
+ "codex-cli": {
84
+ command: "codex",
85
+ timeout: 6e5
86
+ }
87
+ }
88
+ },
89
+ tunnel: {
90
+ provider: "none"
91
+ },
92
+ secrets: {
93
+ encrypt: true
94
+ },
95
+ observability: {
96
+ observers: ["console"],
97
+ logLevel: "info"
98
+ },
99
+ skills: {
100
+ enabled: true,
101
+ paths: ["~/.ch4p/skills", ".ch4p/skills", ".agents/skills"],
102
+ autoLoad: true,
103
+ contextBudget: 16e3
104
+ },
105
+ verification: {
106
+ enabled: true,
107
+ semantic: true
108
+ },
109
+ mesh: {
110
+ enabled: false,
111
+ maxConcurrency: 3,
112
+ defaultTimeout: 12e4
113
+ }
114
+ };
115
+ }
116
+ function loadEnvFile() {
117
+ const envPath = join(getCh4pDir(), ".env");
118
+ let raw;
119
+ try {
120
+ raw = readFileSync(envPath, "utf8");
121
+ } catch {
122
+ return 0;
123
+ }
124
+ let loaded = 0;
125
+ for (const line of raw.split("\n")) {
126
+ const trimmed = line.trim();
127
+ if (!trimmed || trimmed.startsWith("#")) continue;
128
+ const stripped = trimmed.startsWith("export ") ? trimmed.slice(7).trim() : trimmed;
129
+ const eqIdx = stripped.indexOf("=");
130
+ if (eqIdx === -1) continue;
131
+ const key = stripped.slice(0, eqIdx).trim();
132
+ let value = stripped.slice(eqIdx + 1).trim();
133
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
134
+ value = value.slice(1, -1);
135
+ }
136
+ if (key && process.env[key] === void 0) {
137
+ process.env[key] = value;
138
+ loaded++;
139
+ }
140
+ }
141
+ return loaded;
142
+ }
143
+ function resolveEnvVars(obj, missing) {
144
+ if (typeof obj === "string") {
145
+ return obj.replace(/\$\{([^}]+)\}/g, (_match, varName) => {
146
+ const value = process.env[varName];
147
+ if (value === void 0) {
148
+ missing?.add(varName);
149
+ }
150
+ return value ?? "";
151
+ });
152
+ }
153
+ if (Array.isArray(obj)) {
154
+ return obj.map((item) => resolveEnvVars(item, missing));
155
+ }
156
+ if (obj !== null && typeof obj === "object") {
157
+ const result = {};
158
+ for (const [key, value] of Object.entries(obj)) {
159
+ result[key] = resolveEnvVars(value, missing);
160
+ }
161
+ return result;
162
+ }
163
+ return obj;
164
+ }
165
+ function deepMerge(target, source, seen = /* @__PURE__ */ new WeakSet()) {
166
+ if (seen.has(source)) return target;
167
+ seen.add(source);
168
+ const result = { ...target };
169
+ for (const key of Object.keys(source)) {
170
+ const sourceVal = source[key];
171
+ const targetVal = result[key];
172
+ if (sourceVal !== null && typeof sourceVal === "object" && !Array.isArray(sourceVal) && targetVal !== null && typeof targetVal === "object" && !Array.isArray(targetVal)) {
173
+ result[key] = deepMerge(
174
+ targetVal,
175
+ sourceVal,
176
+ seen
177
+ );
178
+ } else {
179
+ result[key] = sourceVal;
180
+ }
181
+ }
182
+ return result;
183
+ }
184
+ function validateConfig(config) {
185
+ const errors = [];
186
+ if (!config.agent?.model) {
187
+ errors.push({ field: "agent.model", message: "Model is required" });
188
+ }
189
+ if (!config.agent?.provider) {
190
+ errors.push({ field: "agent.provider", message: "Provider is required" });
191
+ }
192
+ if (config.agent?.maxToolResults != null && (typeof config.agent.maxToolResults !== "number" || config.agent.maxToolResults < 1)) {
193
+ errors.push({ field: "agent.maxToolResults", message: "Must be a positive number" });
194
+ }
195
+ if (config.agent?.maxToolOutputLen != null && (typeof config.agent.maxToolOutputLen !== "number" || config.agent.maxToolOutputLen < 1024)) {
196
+ errors.push({ field: "agent.maxToolOutputLen", message: "Must be at least 1024 bytes" });
197
+ }
198
+ if (config.agent?.maxStateRecords != null && (typeof config.agent.maxStateRecords !== "number" || config.agent.maxStateRecords < 1)) {
199
+ errors.push({ field: "agent.maxStateRecords", message: "Must be a positive number" });
200
+ }
201
+ if (config.agent?.maxSessionErrors != null && (typeof config.agent.maxSessionErrors !== "number" || config.agent.maxSessionErrors < 1)) {
202
+ errors.push({ field: "agent.maxSessionErrors", message: "Must be a positive number" });
203
+ }
204
+ if (config.agent?.runTimeout != null && (typeof config.agent.runTimeout !== "number" || config.agent.runTimeout < 3e4)) {
205
+ errors.push({ field: "agent.runTimeout", message: "Must be at least 30000 (30 seconds)" });
206
+ }
207
+ if (typeof config.gateway?.port !== "number" || config.gateway.port < 1 || config.gateway.port > 65535) {
208
+ errors.push({ field: "gateway.port", message: "Port must be a number between 1 and 65535" });
209
+ }
210
+ if (config.autonomy?.level && !["readonly", "supervised", "full"].includes(config.autonomy.level)) {
211
+ errors.push({ field: "autonomy.level", message: "Must be one of: readonly, supervised, full" });
212
+ }
213
+ if (config.observability?.logLevel && !["debug", "info", "warn", "error"].includes(config.observability.logLevel)) {
214
+ errors.push({ field: "observability.logLevel", message: "Must be one of: debug, info, warn, error" });
215
+ }
216
+ if (config.memory?.backend && !["sqlite", "markdown", "noop"].includes(config.memory.backend)) {
217
+ errors.push({ field: "memory.backend", message: "Must be one of: sqlite, markdown, noop" });
218
+ }
219
+ if (config.tunnel?.provider && !["none", "cloudflare", "tailscale", "ngrok"].includes(config.tunnel.provider)) {
220
+ errors.push({ field: "tunnel.provider", message: "Must be one of: none, cloudflare, tailscale, ngrok" });
221
+ }
222
+ if (config.engines?.default && config.engines.available && !Object.keys(config.engines.available).includes(config.engines.default)) {
223
+ errors.push({
224
+ field: "engines.default",
225
+ message: `Engine "${config.engines.default}" is not defined in engines.available`
226
+ });
227
+ }
228
+ if (config.skills?.contextBudget != null && (typeof config.skills.contextBudget !== "number" || config.skills.contextBudget < 0)) {
229
+ errors.push({ field: "skills.contextBudget", message: "Must be a non-negative number" });
230
+ }
231
+ if (config.mesh?.maxConcurrency != null && (typeof config.mesh.maxConcurrency !== "number" || config.mesh.maxConcurrency < 1)) {
232
+ errors.push({ field: "mesh.maxConcurrency", message: "Must be a positive number" });
233
+ }
234
+ if (config.mesh?.defaultTimeout != null && (typeof config.mesh.defaultTimeout !== "number" || config.mesh.defaultTimeout < 1e3)) {
235
+ errors.push({ field: "mesh.defaultTimeout", message: "Must be at least 1000ms" });
236
+ }
237
+ return errors;
238
+ }
239
+ function ensureConfigDir() {
240
+ const ch4pDir = getCh4pDir();
241
+ const logsDir = getLogsDir();
242
+ if (!existsSync(ch4pDir)) {
243
+ mkdirSync(ch4pDir, { recursive: true, mode: 448 });
244
+ }
245
+ if (!existsSync(logsDir)) {
246
+ mkdirSync(logsDir, { recursive: true, mode: 448 });
247
+ }
248
+ }
249
+ function loadConfig() {
250
+ loadEnvFile();
251
+ const defaults = getDefaultConfig();
252
+ let merged = defaults;
253
+ const configPath = getConfigPath();
254
+ if (existsSync(configPath)) {
255
+ try {
256
+ const raw = readFileSync(configPath, "utf8");
257
+ const userConfig = JSON.parse(raw);
258
+ merged = deepMerge(defaults, userConfig);
259
+ } catch (err) {
260
+ const message = err instanceof Error ? err.message : String(err);
261
+ throw new ConfigLoadError(`Failed to parse ${configPath}: ${message}`);
262
+ }
263
+ }
264
+ const missingVars = /* @__PURE__ */ new Set();
265
+ const resolved = resolveEnvVars(merged, missingVars);
266
+ for (const varName of missingVars) {
267
+ console.warn(` \u26A0 Config references \${${varName}} but it is not set in environment.`);
268
+ }
269
+ const errors = validateConfig(resolved);
270
+ if (errors.length > 0) {
271
+ const details = errors.map((e) => ` - ${e.field}: ${e.message}`).join("\n");
272
+ throw new ConfigLoadError(`Configuration validation failed:
273
+ ${details}`);
274
+ }
275
+ return resolved;
276
+ }
277
+ function saveConfig(config) {
278
+ ensureConfigDir();
279
+ const configPath = getConfigPath();
280
+ writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n", {
281
+ encoding: "utf8",
282
+ mode: 384
283
+ });
284
+ }
285
+ function configExists() {
286
+ return existsSync(getConfigPath());
287
+ }
288
+ var ConfigLoadError = class extends Error {
289
+ constructor(message) {
290
+ super(message);
291
+ this.name = "ConfigLoadError";
292
+ }
293
+ };
294
+
295
+ export {
296
+ getCh4pDir,
297
+ getConfigPath,
298
+ getLogsDir,
299
+ getDefaultConfig,
300
+ ensureConfigDir,
301
+ loadConfig,
302
+ saveConfig,
303
+ configExists
304
+ };