@coralai/nps-cli 0.1.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 +21 -0
- package/README.md +459 -0
- package/dist/audit-log.d.ts +26 -0
- package/dist/audit-log.d.ts.map +1 -0
- package/dist/audit-log.js +120 -0
- package/dist/audit-log.js.map +1 -0
- package/dist/bindings/bindings-loader.d.ts +19 -0
- package/dist/bindings/bindings-loader.d.ts.map +1 -0
- package/dist/bindings/bindings-loader.js +84 -0
- package/dist/bindings/bindings-loader.js.map +1 -0
- package/dist/cli/agent-cmd.d.ts +2 -0
- package/dist/cli/agent-cmd.d.ts.map +1 -0
- package/dist/cli/agent-cmd.js +125 -0
- package/dist/cli/agent-cmd.js.map +1 -0
- package/dist/cli/bind-cmd.d.ts +2 -0
- package/dist/cli/bind-cmd.d.ts.map +1 -0
- package/dist/cli/bind-cmd.js +127 -0
- package/dist/cli/bind-cmd.js.map +1 -0
- package/dist/cli/daemon-cmd.d.ts +4 -0
- package/dist/cli/daemon-cmd.d.ts.map +1 -0
- package/dist/cli/daemon-cmd.js +137 -0
- package/dist/cli/daemon-cmd.js.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +62 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/config/loader.d.ts +5 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +54 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/paths.d.ts +14 -0
- package/dist/config/paths.d.ts.map +1 -0
- package/dist/config/paths.js +27 -0
- package/dist/config/paths.js.map +1 -0
- package/dist/config/schema.d.ts +48 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +52 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/daemon/control-client.d.ts +2 -0
- package/dist/daemon/control-client.d.ts.map +1 -0
- package/dist/daemon/control-client.js +51 -0
- package/dist/daemon/control-client.js.map +1 -0
- package/dist/daemon/control-socket.d.ts +19 -0
- package/dist/daemon/control-socket.d.ts.map +1 -0
- package/dist/daemon/control-socket.js +192 -0
- package/dist/daemon/control-socket.js.map +1 -0
- package/dist/daemon/daemon.d.ts +20 -0
- package/dist/daemon/daemon.d.ts.map +1 -0
- package/dist/daemon/daemon.js +166 -0
- package/dist/daemon/daemon.js.map +1 -0
- package/dist/dispatch/dispatch-pipeline.d.ts +39 -0
- package/dist/dispatch/dispatch-pipeline.d.ts.map +1 -0
- package/dist/dispatch/dispatch-pipeline.js +219 -0
- package/dist/dispatch/dispatch-pipeline.js.map +1 -0
- package/dist/dispatch/slash-commands.d.ts +35 -0
- package/dist/dispatch/slash-commands.d.ts.map +1 -0
- package/dist/dispatch/slash-commands.js +67 -0
- package/dist/dispatch/slash-commands.js.map +1 -0
- package/dist/errors.d.ts +22 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +17 -0
- package/dist/errors.js.map +1 -0
- package/dist/gateway/matrix-gateway.d.ts +24 -0
- package/dist/gateway/matrix-gateway.d.ts.map +1 -0
- package/dist/gateway/matrix-gateway.js +166 -0
- package/dist/gateway/matrix-gateway.js.map +1 -0
- package/dist/logger.d.ts +13 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +19 -0
- package/dist/logger.js.map +1 -0
- package/dist/main.d.ts +3 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +7 -0
- package/dist/main.js.map +1 -0
- package/dist/profile/profile-registry.d.ts +24 -0
- package/dist/profile/profile-registry.d.ts.map +1 -0
- package/dist/profile/profile-registry.js +114 -0
- package/dist/profile/profile-registry.js.map +1 -0
- package/dist/runtime-check.d.ts +18 -0
- package/dist/runtime-check.d.ts.map +1 -0
- package/dist/runtime-check.js +62 -0
- package/dist/runtime-check.js.map +1 -0
- package/dist/session/compat-hash.d.ts +21 -0
- package/dist/session/compat-hash.d.ts.map +1 -0
- package/dist/session/compat-hash.js +115 -0
- package/dist/session/compat-hash.js.map +1 -0
- package/dist/session/session-store.d.ts +29 -0
- package/dist/session/session-store.d.ts.map +1 -0
- package/dist/session/session-store.js +123 -0
- package/dist/session/session-store.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +2 -0
- package/dist/version.js.map +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config loading helpers — read + parse + zod-validate.
|
|
3
|
+
*/
|
|
4
|
+
import { readFileSync } from 'node:fs';
|
|
5
|
+
import { parse as parseYaml } from 'yaml';
|
|
6
|
+
import { NpsError } from '../errors.js';
|
|
7
|
+
import { GlobalConfigSchema, ProfileConfigSchema, BindingsFileSchema, expandConfigEnv, } from './schema.js';
|
|
8
|
+
export function loadGlobalConfig(path) {
|
|
9
|
+
let raw;
|
|
10
|
+
try {
|
|
11
|
+
raw = parseYaml(readFileSync(path, 'utf8'));
|
|
12
|
+
}
|
|
13
|
+
catch (e) {
|
|
14
|
+
throw new NpsError('NPS_YAML_INVALID', `failed to parse global config at ${path}: ${e instanceof Error ? e.message : e}`);
|
|
15
|
+
}
|
|
16
|
+
const expanded = expandConfigEnv(raw);
|
|
17
|
+
const parsed = GlobalConfigSchema.safeParse(expanded);
|
|
18
|
+
if (!parsed.success) {
|
|
19
|
+
throw new NpsError('NPS_YAML_INVALID', `global config at ${path} invalid: ${parsed.error.message}`);
|
|
20
|
+
}
|
|
21
|
+
return parsed.data;
|
|
22
|
+
}
|
|
23
|
+
export function loadProfileConfig(path) {
|
|
24
|
+
let raw;
|
|
25
|
+
try {
|
|
26
|
+
raw = parseYaml(readFileSync(path, 'utf8'));
|
|
27
|
+
}
|
|
28
|
+
catch (e) {
|
|
29
|
+
throw new NpsError('NPS_YAML_INVALID', `failed to parse profile yaml at ${path}: ${e instanceof Error ? e.message : e}`);
|
|
30
|
+
}
|
|
31
|
+
const expanded = expandConfigEnv(raw);
|
|
32
|
+
const parsed = ProfileConfigSchema.safeParse(expanded);
|
|
33
|
+
if (!parsed.success) {
|
|
34
|
+
throw new NpsError('NPS_YAML_INVALID', `profile yaml at ${path} invalid: ${parsed.error.message}`);
|
|
35
|
+
}
|
|
36
|
+
return parsed.data;
|
|
37
|
+
}
|
|
38
|
+
export function loadBindings(path) {
|
|
39
|
+
let raw;
|
|
40
|
+
try {
|
|
41
|
+
raw = parseYaml(readFileSync(path, 'utf8'));
|
|
42
|
+
}
|
|
43
|
+
catch (e) {
|
|
44
|
+
throw new NpsError('NPS_YAML_INVALID', `failed to parse bindings at ${path}: ${e instanceof Error ? e.message : e}`);
|
|
45
|
+
}
|
|
46
|
+
if (raw === null || raw === undefined)
|
|
47
|
+
raw = {};
|
|
48
|
+
const parsed = BindingsFileSchema.safeParse(raw);
|
|
49
|
+
if (!parsed.success) {
|
|
50
|
+
throw new NpsError('NPS_YAML_INVALID', `bindings at ${path} invalid: ${parsed.error.message}`);
|
|
51
|
+
}
|
|
52
|
+
return parsed.data;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare const NPS_HOME: string;
|
|
2
|
+
export declare const PATHS: {
|
|
3
|
+
readonly home: string;
|
|
4
|
+
readonly configFile: string;
|
|
5
|
+
readonly bindingsFile: string;
|
|
6
|
+
readonly agentsDir: string;
|
|
7
|
+
readonly stateDir: string;
|
|
8
|
+
readonly auditFile: string;
|
|
9
|
+
readonly daemonSocket: string;
|
|
10
|
+
readonly daemonPid: string;
|
|
11
|
+
readonly bindingsLock: string;
|
|
12
|
+
};
|
|
13
|
+
export declare function expandTilde(p: string): string;
|
|
14
|
+
//# sourceMappingURL=paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/config/paths.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,QAAQ,QAEM,CAAC;AAE5B,eAAO,MAAM,KAAK;;;;;;;;;;CAUR,CAAC;AAEX,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAI7C"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NPS path helpers — resolves tilde, default directories.
|
|
3
|
+
*/
|
|
4
|
+
import { homedir } from 'node:os';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
export const NPS_HOME = process.env['NPS_HOME']?.length
|
|
7
|
+
? expandTilde(process.env['NPS_HOME'])
|
|
8
|
+
: join(homedir(), '.nps');
|
|
9
|
+
export const PATHS = {
|
|
10
|
+
home: NPS_HOME,
|
|
11
|
+
configFile: join(NPS_HOME, 'config.yaml'),
|
|
12
|
+
bindingsFile: join(NPS_HOME, 'bindings.yaml'),
|
|
13
|
+
agentsDir: join(NPS_HOME, 'agents'),
|
|
14
|
+
stateDir: join(NPS_HOME, 'state'),
|
|
15
|
+
auditFile: join(NPS_HOME, 'audit.jsonl'),
|
|
16
|
+
daemonSocket: join(NPS_HOME, 'daemon.sock'),
|
|
17
|
+
daemonPid: join(NPS_HOME, 'daemon.pid'),
|
|
18
|
+
bindingsLock: join(NPS_HOME, '.bindings.lock'),
|
|
19
|
+
};
|
|
20
|
+
export function expandTilde(p) {
|
|
21
|
+
if (p === '~')
|
|
22
|
+
return homedir();
|
|
23
|
+
if (p.startsWith('~/'))
|
|
24
|
+
return join(homedir(), p.slice(2));
|
|
25
|
+
return p;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/config/paths.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,CAAC,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,MAAM;IACrD,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACtC,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,MAAM,CAAC,CAAC;AAE5B,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE,IAAI,CAAC,QAAQ,EAAE,aAAa,CAAC;IACzC,YAAY,EAAE,IAAI,CAAC,QAAQ,EAAE,eAAe,CAAC;IAC7C,SAAS,EAAE,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC;IACnC,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC;IACjC,SAAS,EAAE,IAAI,CAAC,QAAQ,EAAE,aAAa,CAAC;IACxC,YAAY,EAAE,IAAI,CAAC,QAAQ,EAAE,aAAa,CAAC;IAC3C,SAAS,EAAE,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC;IACvC,YAAY,EAAE,IAAI,CAAC,QAAQ,EAAE,gBAAgB,CAAC;CACtC,CAAC;AAEX,MAAM,UAAU,WAAW,CAAC,CAAS;IACnC,IAAI,CAAC,KAAK,GAAG;QAAE,OAAO,OAAO,EAAE,CAAC;IAChC,IAAI,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3D,OAAO,CAAC,CAAC;AACX,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config schemas — zod-validated yaml shapes for ~/.nps/config.yaml,
|
|
3
|
+
* ~/.nps/agents/<name>/nps.yaml, and ~/.nps/bindings.yaml.
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
export declare const GlobalConfigSchema: z.ZodObject<{
|
|
7
|
+
daemon: z.ZodObject<{
|
|
8
|
+
controlSocket: z.ZodDefault<z.ZodString>;
|
|
9
|
+
pidFile: z.ZodDefault<z.ZodString>;
|
|
10
|
+
logLevel: z.ZodDefault<z.ZodEnum<{
|
|
11
|
+
info: "info";
|
|
12
|
+
fatal: "fatal";
|
|
13
|
+
error: "error";
|
|
14
|
+
warn: "warn";
|
|
15
|
+
debug: "debug";
|
|
16
|
+
trace: "trace";
|
|
17
|
+
}>>;
|
|
18
|
+
adminUserIds: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
19
|
+
}, z.core.$strip>;
|
|
20
|
+
im: z.ZodDefault<z.ZodObject<{
|
|
21
|
+
matrix: z.ZodOptional<z.ZodObject<{
|
|
22
|
+
homeserver: z.ZodString;
|
|
23
|
+
user: z.ZodString;
|
|
24
|
+
accessToken: z.ZodString;
|
|
25
|
+
}, z.core.$strip>>;
|
|
26
|
+
}, z.core.$strip>>;
|
|
27
|
+
}, z.core.$strip>;
|
|
28
|
+
export type GlobalConfig = z.infer<typeof GlobalConfigSchema>;
|
|
29
|
+
export declare const ProfileConfigSchema: z.ZodObject<{
|
|
30
|
+
workspace: z.ZodString;
|
|
31
|
+
env: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
32
|
+
permissionMode: z.ZodDefault<z.ZodEnum<{
|
|
33
|
+
readonly: "readonly";
|
|
34
|
+
auto: "auto";
|
|
35
|
+
manual: "manual";
|
|
36
|
+
}>>;
|
|
37
|
+
recording: z.ZodOptional<z.ZodString>;
|
|
38
|
+
}, z.core.$strip>;
|
|
39
|
+
export type ProfileConfig = z.infer<typeof ProfileConfigSchema>;
|
|
40
|
+
export declare const BindingsFileSchema: z.ZodObject<{
|
|
41
|
+
matrix: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
42
|
+
}, z.core.$strip>;
|
|
43
|
+
export type BindingsFile = z.infer<typeof BindingsFileSchema>;
|
|
44
|
+
/** Expand `${VAR}` patterns from environment in a string. */
|
|
45
|
+
export declare function expandEnvVars(s: string): string;
|
|
46
|
+
/** Recursively expand env-var refs inside an object (only string leaves). */
|
|
47
|
+
export declare function expandConfigEnv<T>(cfg: T): T;
|
|
48
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/config/schema.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;iBAc7B,CAAC;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAG9D,eAAO,MAAM,mBAAmB;;;;;;;;;iBAK9B,CAAC;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAGhE,eAAO,MAAM,kBAAkB;;iBAE7B,CAAC;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D,6DAA6D;AAC7D,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED,6EAA6E;AAC7E,wBAAgB,eAAe,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAW5C"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config schemas — zod-validated yaml shapes for ~/.nps/config.yaml,
|
|
3
|
+
* ~/.nps/agents/<name>/nps.yaml, and ~/.nps/bindings.yaml.
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
// ─── Global config (~/.nps/config.yaml) ──────────────────────────
|
|
7
|
+
export const GlobalConfigSchema = z.object({
|
|
8
|
+
daemon: z.object({
|
|
9
|
+
controlSocket: z.string().default('~/.nps/daemon.sock'),
|
|
10
|
+
pidFile: z.string().default('~/.nps/daemon.pid'),
|
|
11
|
+
logLevel: z.enum(['fatal', 'error', 'warn', 'info', 'debug', 'trace']).default('info'),
|
|
12
|
+
adminUserIds: z.array(z.string()).default([]),
|
|
13
|
+
}),
|
|
14
|
+
im: z.object({
|
|
15
|
+
matrix: z.object({
|
|
16
|
+
homeserver: z.string().url(),
|
|
17
|
+
user: z.string(),
|
|
18
|
+
accessToken: z.string(),
|
|
19
|
+
}).optional(),
|
|
20
|
+
}).default({}),
|
|
21
|
+
});
|
|
22
|
+
// ─── Per-agent profile (~/.nps/agents/<name>/nps.yaml) ───────────
|
|
23
|
+
export const ProfileConfigSchema = z.object({
|
|
24
|
+
workspace: z.string(), // SINGULAR per D3=A
|
|
25
|
+
env: z.record(z.string(), z.string()).default({}),
|
|
26
|
+
permissionMode: z.enum(['auto', 'readonly', 'manual']).default('auto'),
|
|
27
|
+
recording: z.string().optional(),
|
|
28
|
+
});
|
|
29
|
+
// ─── Channel bindings (~/.nps/bindings.yaml) ─────────────────────
|
|
30
|
+
export const BindingsFileSchema = z.object({
|
|
31
|
+
matrix: z.record(z.string(), z.string()).default({}),
|
|
32
|
+
});
|
|
33
|
+
/** Expand `${VAR}` patterns from environment in a string. */
|
|
34
|
+
export function expandEnvVars(s) {
|
|
35
|
+
return s.replace(/\$\{([A-Z_][A-Z0-9_]*)\}/g, (_, name) => process.env[name] ?? '');
|
|
36
|
+
}
|
|
37
|
+
/** Recursively expand env-var refs inside an object (only string leaves). */
|
|
38
|
+
export function expandConfigEnv(cfg) {
|
|
39
|
+
if (typeof cfg === 'string')
|
|
40
|
+
return expandEnvVars(cfg);
|
|
41
|
+
if (Array.isArray(cfg))
|
|
42
|
+
return cfg.map(v => expandConfigEnv(v));
|
|
43
|
+
if (cfg && typeof cfg === 'object') {
|
|
44
|
+
const out = {};
|
|
45
|
+
for (const [k, v] of Object.entries(cfg)) {
|
|
46
|
+
out[k] = expandConfigEnv(v);
|
|
47
|
+
}
|
|
48
|
+
return out;
|
|
49
|
+
}
|
|
50
|
+
return cfg;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/config/schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"control-client.d.ts","sourceRoot":"","sources":["../../src/daemon/control-client.ts"],"names":[],"mappings":"AAUA,wBAAsB,OAAO,CAAC,CAAC,GAAG,OAAO,EACvC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,OAAO,EAChB,SAAS,SAAQ,GAChB,OAAO,CAAC,CAAC,CAAC,CAyCZ"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight client for the daemon's JSON-RPC control socket.
|
|
3
|
+
* Used by the `nps` CLI to talk to a running daemon.
|
|
4
|
+
*/
|
|
5
|
+
import { createConnection } from 'node:net';
|
|
6
|
+
import { existsSync } from 'node:fs';
|
|
7
|
+
import { NpsError } from '../errors.js';
|
|
8
|
+
let nextId = 1;
|
|
9
|
+
export async function rpcCall(socketPath, method, params, timeoutMs = 5_000) {
|
|
10
|
+
if (!existsSync(socketPath)) {
|
|
11
|
+
throw new NpsError('SOCKET_BUSY', `nps daemon not running (socket not found at ${socketPath}). Start with: nps daemon start`);
|
|
12
|
+
}
|
|
13
|
+
return await new Promise((resolve, reject) => {
|
|
14
|
+
const sock = createConnection(socketPath);
|
|
15
|
+
let buffer = '';
|
|
16
|
+
const timer = setTimeout(() => {
|
|
17
|
+
sock.destroy();
|
|
18
|
+
reject(new Error(`RPC timeout after ${timeoutMs}ms for method ${method}`));
|
|
19
|
+
}, timeoutMs);
|
|
20
|
+
const id = nextId++;
|
|
21
|
+
sock.on('connect', () => {
|
|
22
|
+
const payload = { jsonrpc: '2.0', method, params, id };
|
|
23
|
+
sock.write(JSON.stringify(payload) + '\n');
|
|
24
|
+
});
|
|
25
|
+
sock.on('data', chunk => {
|
|
26
|
+
buffer += chunk.toString('utf8');
|
|
27
|
+
const nl = buffer.indexOf('\n');
|
|
28
|
+
if (nl !== -1) {
|
|
29
|
+
clearTimeout(timer);
|
|
30
|
+
const line = buffer.slice(0, nl).trim();
|
|
31
|
+
try {
|
|
32
|
+
const resp = JSON.parse(line);
|
|
33
|
+
sock.end();
|
|
34
|
+
if (resp.error)
|
|
35
|
+
reject(new Error(resp.error.message));
|
|
36
|
+
else
|
|
37
|
+
resolve(resp.result);
|
|
38
|
+
}
|
|
39
|
+
catch (e) {
|
|
40
|
+
sock.destroy();
|
|
41
|
+
reject(e);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
sock.on('error', err => {
|
|
46
|
+
clearTimeout(timer);
|
|
47
|
+
reject(err);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=control-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"control-client.js","sourceRoot":"","sources":["../../src/daemon/control-client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAExC,IAAI,MAAM,GAAG,CAAC,CAAC;AAEf,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,UAAkB,EAClB,MAAc,EACd,MAAgB,EAChB,SAAS,GAAG,KAAK;IAEjB,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,QAAQ,CAChB,aAAa,EACb,+CAA+C,UAAU,iCAAiC,CAC3F,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,IAAI,OAAO,CAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC9C,MAAM,IAAI,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAC;QAC1C,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,IAAI,CAAC,OAAO,EAAE,CAAC;YACf,MAAM,CAAC,IAAI,KAAK,CAAC,qBAAqB,SAAS,iBAAiB,MAAM,EAAE,CAAC,CAAC,CAAC;QAC7E,CAAC,EAAE,SAAS,CAAC,CAAC;QACd,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC;QACpB,IAAI,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;YACtB,MAAM,OAAO,GAAG,EAAE,OAAO,EAAE,KAAc,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;YAChE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE;YACtB,MAAM,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YACjC,MAAM,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAChC,IAAI,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC;gBACd,YAAY,CAAC,KAAK,CAAC,CAAC;gBACpB,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;gBACxC,IAAI,CAAC;oBACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAgD,CAAC;oBAC7E,IAAI,CAAC,GAAG,EAAE,CAAC;oBACX,IAAI,IAAI,CAAC,KAAK;wBAAE,MAAM,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;;wBACjD,OAAO,CAAC,IAAI,CAAC,MAAW,CAAC,CAAC;gBACjC,CAAC;gBAAC,OAAO,CAAC,EAAE,CAAC;oBACX,IAAI,CAAC,OAAO,EAAE,CAAC;oBACf,MAAM,CAAC,CAAC,CAAC,CAAC;gBACZ,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE;YACrB,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,MAAM,CAAC,GAAG,CAAC,CAAC;QACd,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Logger } from 'pino';
|
|
2
|
+
export type RpcHandler = (params: unknown) => Promise<unknown>;
|
|
3
|
+
export declare class ControlSocket {
|
|
4
|
+
private readonly socketPath;
|
|
5
|
+
private readonly pidFile;
|
|
6
|
+
private logger;
|
|
7
|
+
private server;
|
|
8
|
+
private handlers;
|
|
9
|
+
constructor(socketPath: string, pidFile: string, logger?: Logger);
|
|
10
|
+
register(method: string, handler: RpcHandler): void;
|
|
11
|
+
/** Start the socket server. Checks for stale daemon first. */
|
|
12
|
+
start(): Promise<void>;
|
|
13
|
+
stop(): Promise<void>;
|
|
14
|
+
private checkStale;
|
|
15
|
+
private handleConnection;
|
|
16
|
+
private handleRequest;
|
|
17
|
+
private writeResponse;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=control-socket.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"control-socket.d.ts","sourceRoot":"","sources":["../../src/daemon/control-socket.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAInC,MAAM,MAAM,UAAU,GAAG,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAqB/D,qBAAa,aAAa;IAMtB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAN1B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,QAAQ,CAAiC;gBAG9B,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EAChC,MAAM,CAAC,EAAE,MAAM;IAKjB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,IAAI;IAInD,8DAA8D;IACxD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAyBtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAa3B,OAAO,CAAC,UAAU;IAoClB,OAAO,CAAC,gBAAgB;YAmBV,aAAa;IA0B3B,OAAO,CAAC,aAAa;CAGtB"}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* M1 — control socket (Unix domain socket + JSON-RPC 2.0).
|
|
3
|
+
*
|
|
4
|
+
* RPC methods (server-side):
|
|
5
|
+
* - health → { status, pid, uptime, profiles, bindings, version }
|
|
6
|
+
* - stop → graceful shutdown trigger
|
|
7
|
+
* - bindings.list → current bindings snapshot
|
|
8
|
+
* - profile.list → registered profile names
|
|
9
|
+
* - version → daemon + claude + shim versions
|
|
10
|
+
*
|
|
11
|
+
* Stale-socket detection: at start, if pidFile exists and that PID is alive,
|
|
12
|
+
* refuse to bind. If PID is dead, remove stale socket + pid + start.
|
|
13
|
+
*/
|
|
14
|
+
import { createServer } from 'node:net';
|
|
15
|
+
import { existsSync, readFileSync, writeFileSync, unlinkSync, chmodSync } from 'node:fs';
|
|
16
|
+
import { getLogger } from '../logger.js';
|
|
17
|
+
import { NpsError } from '../errors.js';
|
|
18
|
+
export class ControlSocket {
|
|
19
|
+
socketPath;
|
|
20
|
+
pidFile;
|
|
21
|
+
logger;
|
|
22
|
+
server;
|
|
23
|
+
handlers = new Map();
|
|
24
|
+
constructor(socketPath, pidFile, logger) {
|
|
25
|
+
this.socketPath = socketPath;
|
|
26
|
+
this.pidFile = pidFile;
|
|
27
|
+
this.logger = logger ?? getLogger('control-socket');
|
|
28
|
+
}
|
|
29
|
+
register(method, handler) {
|
|
30
|
+
this.handlers.set(method, handler);
|
|
31
|
+
}
|
|
32
|
+
/** Start the socket server. Checks for stale daemon first. */
|
|
33
|
+
async start() {
|
|
34
|
+
this.checkStale();
|
|
35
|
+
await new Promise((resolve, reject) => {
|
|
36
|
+
this.server = createServer(socket => this.handleConnection(socket));
|
|
37
|
+
this.server.on('error', err => {
|
|
38
|
+
this.logger.error({ err: err.message }, 'control socket error');
|
|
39
|
+
reject(err);
|
|
40
|
+
});
|
|
41
|
+
this.server.listen(this.socketPath, () => {
|
|
42
|
+
try {
|
|
43
|
+
chmodSync(this.socketPath, 0o600);
|
|
44
|
+
}
|
|
45
|
+
catch (e) {
|
|
46
|
+
this.logger.warn({ err: e instanceof Error ? e.message : e }, 'chmod socket failed');
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
writeFileSync(this.pidFile, String(process.pid), { mode: 0o600 });
|
|
50
|
+
}
|
|
51
|
+
catch (e) {
|
|
52
|
+
this.logger.warn({ err: e instanceof Error ? e.message : e }, 'pidfile write failed');
|
|
53
|
+
}
|
|
54
|
+
this.logger.info({ socket: this.socketPath, pid: process.pid }, 'control socket listening');
|
|
55
|
+
resolve();
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
async stop() {
|
|
60
|
+
if (this.server) {
|
|
61
|
+
await new Promise(resolve => this.server.close(() => resolve()));
|
|
62
|
+
this.server = undefined;
|
|
63
|
+
}
|
|
64
|
+
if (existsSync(this.socketPath)) {
|
|
65
|
+
try {
|
|
66
|
+
unlinkSync(this.socketPath);
|
|
67
|
+
}
|
|
68
|
+
catch { /* ignore */ }
|
|
69
|
+
}
|
|
70
|
+
if (existsSync(this.pidFile)) {
|
|
71
|
+
try {
|
|
72
|
+
unlinkSync(this.pidFile);
|
|
73
|
+
}
|
|
74
|
+
catch { /* ignore */ }
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
checkStale() {
|
|
78
|
+
if (!existsSync(this.pidFile)) {
|
|
79
|
+
// No pid file — cleanup any orphan socket and continue
|
|
80
|
+
if (existsSync(this.socketPath)) {
|
|
81
|
+
this.logger.warn({ socket: this.socketPath }, 'orphan socket without pid file — removing');
|
|
82
|
+
try {
|
|
83
|
+
unlinkSync(this.socketPath);
|
|
84
|
+
}
|
|
85
|
+
catch { /* ignore */ }
|
|
86
|
+
}
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
let pid;
|
|
90
|
+
try {
|
|
91
|
+
pid = parseInt(readFileSync(this.pidFile, 'utf8').trim(), 10);
|
|
92
|
+
}
|
|
93
|
+
catch (e) {
|
|
94
|
+
this.logger.warn({ err: e instanceof Error ? e.message : e }, 'pidfile unreadable — treating as stale');
|
|
95
|
+
try {
|
|
96
|
+
unlinkSync(this.pidFile);
|
|
97
|
+
}
|
|
98
|
+
catch { /* ignore */ }
|
|
99
|
+
if (existsSync(this.socketPath))
|
|
100
|
+
try {
|
|
101
|
+
unlinkSync(this.socketPath);
|
|
102
|
+
}
|
|
103
|
+
catch { /* ignore */ }
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (!Number.isFinite(pid) || pid <= 0) {
|
|
107
|
+
this.logger.warn({ pid }, 'pidfile contained non-numeric — treating as stale');
|
|
108
|
+
try {
|
|
109
|
+
unlinkSync(this.pidFile);
|
|
110
|
+
}
|
|
111
|
+
catch { /* ignore */ }
|
|
112
|
+
if (existsSync(this.socketPath))
|
|
113
|
+
try {
|
|
114
|
+
unlinkSync(this.socketPath);
|
|
115
|
+
}
|
|
116
|
+
catch { /* ignore */ }
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if (isAlive(pid)) {
|
|
120
|
+
throw new NpsError('DAEMON_ALREADY_RUNNING', `nps daemon already running (pid ${pid}). Stop it first with: nps daemon stop`, { context: { pid, pidFile: this.pidFile } });
|
|
121
|
+
}
|
|
122
|
+
this.logger.info({ stalePid: pid }, 'stale daemon detected — cleaning up');
|
|
123
|
+
try {
|
|
124
|
+
unlinkSync(this.pidFile);
|
|
125
|
+
}
|
|
126
|
+
catch { /* ignore */ }
|
|
127
|
+
if (existsSync(this.socketPath))
|
|
128
|
+
try {
|
|
129
|
+
unlinkSync(this.socketPath);
|
|
130
|
+
}
|
|
131
|
+
catch { /* ignore */ }
|
|
132
|
+
}
|
|
133
|
+
handleConnection(socket) {
|
|
134
|
+
let buffer = '';
|
|
135
|
+
socket.on('data', chunk => {
|
|
136
|
+
buffer += chunk.toString('utf8');
|
|
137
|
+
// newline-delimited JSON per line
|
|
138
|
+
let nl;
|
|
139
|
+
while ((nl = buffer.indexOf('\n')) !== -1) {
|
|
140
|
+
const line = buffer.slice(0, nl).trim();
|
|
141
|
+
buffer = buffer.slice(nl + 1);
|
|
142
|
+
if (line.length > 0) {
|
|
143
|
+
void this.handleRequest(socket, line);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
socket.on('error', err => {
|
|
148
|
+
this.logger.debug({ err: err.message }, 'client socket error');
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
async handleRequest(socket, line) {
|
|
152
|
+
let req;
|
|
153
|
+
try {
|
|
154
|
+
req = JSON.parse(line);
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
this.writeResponse(socket, { jsonrpc: '2.0', error: { code: -32700, message: 'Parse error' }, id: null });
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
if (req.jsonrpc !== '2.0' || typeof req.method !== 'string') {
|
|
161
|
+
this.writeResponse(socket, { jsonrpc: '2.0', error: { code: -32600, message: 'Invalid Request' }, id: req.id ?? null });
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
const handler = this.handlers.get(req.method);
|
|
165
|
+
if (!handler) {
|
|
166
|
+
this.writeResponse(socket, { jsonrpc: '2.0', error: { code: -32601, message: `Method not found: ${req.method}` }, id: req.id });
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
try {
|
|
170
|
+
const result = await handler(req.params);
|
|
171
|
+
this.writeResponse(socket, { jsonrpc: '2.0', result, id: req.id });
|
|
172
|
+
}
|
|
173
|
+
catch (e) {
|
|
174
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
175
|
+
this.writeResponse(socket, { jsonrpc: '2.0', error: { code: -32603, message: msg }, id: req.id });
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
writeResponse(socket, payload) {
|
|
179
|
+
socket.write(JSON.stringify(payload) + '\n');
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
function isAlive(pid) {
|
|
183
|
+
try {
|
|
184
|
+
// Signal 0 doesn't kill; just checks if the process exists + is accessible.
|
|
185
|
+
process.kill(pid, 0);
|
|
186
|
+
return true;
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=control-socket.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"control-socket.js","sourceRoot":"","sources":["../../src/daemon/control-socket.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Logger } from 'pino';
|
|
2
|
+
import { AuditLog } from '../audit-log.js';
|
|
3
|
+
import { ProfileRegistry } from '../profile/profile-registry.js';
|
|
4
|
+
import { BindingsLoader } from '../bindings/bindings-loader.js';
|
|
5
|
+
import { SessionStore } from '../session/session-store.js';
|
|
6
|
+
import { ControlSocket } from './control-socket.js';
|
|
7
|
+
import { MatrixGateway } from '../gateway/matrix-gateway.js';
|
|
8
|
+
export interface DaemonState {
|
|
9
|
+
logger: Logger;
|
|
10
|
+
audit: AuditLog;
|
|
11
|
+
registry: ProfileRegistry;
|
|
12
|
+
bindings: BindingsLoader;
|
|
13
|
+
sessions: SessionStore;
|
|
14
|
+
controlSocket: ControlSocket;
|
|
15
|
+
matrix?: MatrixGateway;
|
|
16
|
+
startedAt: number;
|
|
17
|
+
}
|
|
18
|
+
export declare function startDaemon(): Promise<DaemonState>;
|
|
19
|
+
export declare function stopDaemon(): Promise<void>;
|
|
20
|
+
//# sourceMappingURL=daemon.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../../src/daemon/daemon.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAKnC,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAQ7D,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,QAAQ,CAAC;IAChB,QAAQ,EAAE,eAAe,CAAC;IAC1B,QAAQ,EAAE,cAAc,CAAC;IACzB,QAAQ,EAAE,YAAY,CAAC;IACvB,aAAa,EAAE,aAAa,CAAC;IAC7B,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CACnB;AAmBD,wBAAsB,WAAW,IAAI,OAAO,CAAC,WAAW,CAAC,CA2GxD;AAED,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAUhD"}
|