@graphorin/cli 0.6.1 → 0.7.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/CHANGELOG.md +63 -0
- package/README.md +3 -3
- package/dist/bin/graphorin.js +51 -13
- package/dist/bin/graphorin.js.map +1 -1
- package/dist/commands/audit.d.ts.map +1 -1
- package/dist/commands/audit.js +2 -1
- package/dist/commands/audit.js.map +1 -1
- package/dist/commands/consolidator.d.ts +56 -1
- package/dist/commands/consolidator.d.ts.map +1 -1
- package/dist/commands/consolidator.js +88 -2
- package/dist/commands/consolidator.js.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/index.d.ts +4 -4
- package/dist/commands/index.js +4 -4
- package/dist/commands/init.d.ts +11 -4
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +15 -11
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/memory.d.ts +26 -1
- package/dist/commands/memory.d.ts.map +1 -1
- package/dist/commands/memory.js +56 -3
- package/dist/commands/memory.js.map +1 -1
- package/dist/commands/pricing.d.ts +6 -0
- package/dist/commands/pricing.d.ts.map +1 -1
- package/dist/commands/pricing.js +5 -2
- package/dist/commands/pricing.js.map +1 -1
- package/dist/commands/secrets.d.ts.map +1 -1
- package/dist/commands/secrets.js +2 -2
- package/dist/commands/secrets.js.map +1 -1
- package/dist/commands/skills.d.ts.map +1 -1
- package/dist/commands/skills.js +1 -1
- package/dist/commands/skills.js.map +1 -1
- package/dist/commands/storage.d.ts +41 -1
- package/dist/commands/storage.d.ts.map +1 -1
- package/dist/commands/storage.js +75 -1
- package/dist/commands/storage.js.map +1 -1
- package/dist/commands/token.d.ts.map +1 -1
- package/dist/commands/token.js +2 -2
- package/dist/commands/token.js.map +1 -1
- package/dist/commands/tools-lint.js +1 -1
- package/dist/commands/tools-lint.js.map +1 -1
- package/dist/commands/traces.d.ts +14 -2
- package/dist/commands/traces.d.ts.map +1 -1
- package/dist/commands/traces.js +39 -22
- package/dist/commands/traces.js.map +1 -1
- package/dist/commands/triggers.d.ts.map +1 -1
- package/dist/commands/triggers.js +5 -2
- package/dist/commands/triggers.js.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +4 -5
- package/dist/index.js.map +1 -1
- package/dist/internal/output.js +6 -0
- package/dist/internal/output.js.map +1 -1
- package/dist/internal/store-context.js +13 -2
- package/dist/internal/store-context.js.map +1 -1
- package/dist/package.js +1 -1
- package/dist/package.js.map +1 -1
- package/package.json +18 -14
- package/src/bin/graphorin.ts +1387 -0
- package/src/commands/audit.ts +256 -0
- package/src/commands/auth.ts +238 -0
- package/src/commands/consolidator.ts +382 -0
- package/src/commands/doctor.ts +253 -0
- package/src/commands/guard.ts +144 -0
- package/src/commands/index.ts +223 -0
- package/src/commands/init.ts +194 -0
- package/src/commands/memory.ts +1052 -0
- package/src/commands/migrate-config.ts +77 -0
- package/src/commands/migrate-export.ts +117 -0
- package/src/commands/migrate.ts +83 -0
- package/src/commands/pricing.ts +244 -0
- package/src/commands/secrets.ts +309 -0
- package/src/commands/skills.ts +272 -0
- package/src/commands/start.ts +180 -0
- package/src/commands/storage.ts +659 -0
- package/src/commands/telemetry.ts +91 -0
- package/src/commands/token.ts +361 -0
- package/src/commands/tools-lint.ts +430 -0
- package/src/commands/traces.ts +188 -0
- package/src/commands/triggers.ts +237 -0
- package/src/index.ts +30 -0
- package/src/internal/exit.ts +62 -0
- package/src/internal/load-config.ts +107 -0
- package/src/internal/offline.ts +81 -0
- package/src/internal/output.ts +146 -0
- package/src/internal/prompts.ts +58 -0
- package/src/internal/store-context.ts +165 -0
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `graphorin start [--config <path>]`. Boots the standalone server.
|
|
3
|
+
*
|
|
4
|
+
* Exits 1 on every recoverable failure (missing pepper, unresolvable
|
|
5
|
+
* SecretRef, missing encryption peer, migration error). The CLI never
|
|
6
|
+
* prints raw secret values; failure messages reference the offending
|
|
7
|
+
* config path + the suggested `graphorin doctor` follow-up (Phase 15).
|
|
8
|
+
*
|
|
9
|
+
* @packageDocumentation
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import process from 'node:process';
|
|
13
|
+
|
|
14
|
+
import { applyProcessHardening, RefuseToRunAsRootError } from '@graphorin/security';
|
|
15
|
+
import { ConfigInvalidError, createServer, GraphorinServerError } from '@graphorin/server';
|
|
16
|
+
|
|
17
|
+
import { loadConfig } from '../internal/load-config.js';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Selector for which `SecretsStore` flavour the server activates at
|
|
21
|
+
* startup. Mirrors `--secrets-source` from DEC-136.
|
|
22
|
+
*
|
|
23
|
+
* @stable
|
|
24
|
+
*/
|
|
25
|
+
export type SecretsSourceFlag = 'auto' | 'keyring' | 'encrypted-file' | 'env';
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @stable
|
|
29
|
+
*/
|
|
30
|
+
export interface StartCommandOptions {
|
|
31
|
+
readonly config?: string;
|
|
32
|
+
readonly host?: string;
|
|
33
|
+
readonly port?: number;
|
|
34
|
+
readonly logResolved?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Override the `secrets.source` field of the loaded config. Mirrors
|
|
37
|
+
* the `--secrets-source <kind>` flag from DEC-136.
|
|
38
|
+
*/
|
|
39
|
+
readonly secretsSource?: SecretsSourceFlag;
|
|
40
|
+
/**
|
|
41
|
+
* Refuse to fall back when the requested primary store is
|
|
42
|
+
* unavailable. Mirrors `--strict-secrets` from DEC-136.
|
|
43
|
+
*/
|
|
44
|
+
readonly strictSecrets?: boolean;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Programmatic entry - used both by the CLI binary and by tests so
|
|
49
|
+
* the spawn cost of running the binary is paid only when an operator
|
|
50
|
+
* actually invokes `graphorin start` from a shell.
|
|
51
|
+
*
|
|
52
|
+
* @stable
|
|
53
|
+
*/
|
|
54
|
+
export async function runStart(
|
|
55
|
+
options: StartCommandOptions = {},
|
|
56
|
+
): Promise<{ readonly host: string; readonly port: number }> {
|
|
57
|
+
applyHardeningEarly();
|
|
58
|
+
const loaded = await loadConfig(options.config);
|
|
59
|
+
if (options.logResolved !== false) {
|
|
60
|
+
process.stderr.write(`[graphorin/cli] resolved config: ${loaded.path}\n`);
|
|
61
|
+
}
|
|
62
|
+
const overrides = applyCliOverrides(loaded.config, options);
|
|
63
|
+
|
|
64
|
+
let server: Awaited<ReturnType<typeof createServer>> | undefined;
|
|
65
|
+
try {
|
|
66
|
+
server = await createServer({ config: overrides });
|
|
67
|
+
} catch (err) {
|
|
68
|
+
fatal(err);
|
|
69
|
+
}
|
|
70
|
+
if (server === undefined) process.exit(1);
|
|
71
|
+
|
|
72
|
+
const listening = await safeStart(server);
|
|
73
|
+
process.stderr.write(
|
|
74
|
+
`[graphorin/cli] @graphorin/server v${server.version} listening on http://${listening.host}:${listening.port}${server.config.server.basePath}\n`,
|
|
75
|
+
);
|
|
76
|
+
installSignalHandlers(server);
|
|
77
|
+
return listening;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Merge CLI flag overrides into the loaded `graphorin.config` payload.
|
|
82
|
+
* Exported for unit tests so callers can assert the precedence rules
|
|
83
|
+
* without spinning up a real server.
|
|
84
|
+
*
|
|
85
|
+
* @internal
|
|
86
|
+
*/
|
|
87
|
+
export function applyCliOverrides(
|
|
88
|
+
input: { readonly server?: unknown; readonly secrets?: unknown } | undefined,
|
|
89
|
+
options: StartCommandOptions,
|
|
90
|
+
): Record<string, unknown> {
|
|
91
|
+
const next = { ...(input ?? {}) } as Record<string, unknown>;
|
|
92
|
+
const serverInput = (next.server as Record<string, unknown> | undefined) ?? {};
|
|
93
|
+
if (options.host !== undefined || options.port !== undefined) {
|
|
94
|
+
next.server = {
|
|
95
|
+
...serverInput,
|
|
96
|
+
...(options.host !== undefined ? { host: options.host } : {}),
|
|
97
|
+
...(options.port !== undefined ? { port: options.port } : {}),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
const secretsInput = (next.secrets as Record<string, unknown> | undefined) ?? {};
|
|
101
|
+
if (options.secretsSource !== undefined || options.strictSecrets !== undefined) {
|
|
102
|
+
next.secrets = {
|
|
103
|
+
...secretsInput,
|
|
104
|
+
...(options.secretsSource !== undefined ? { source: options.secretsSource } : {}),
|
|
105
|
+
...(options.strictSecrets !== undefined ? { strict: options.strictSecrets } : {}),
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
return next;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async function safeStart(server: Awaited<ReturnType<typeof createServer>>) {
|
|
112
|
+
try {
|
|
113
|
+
return await server.start();
|
|
114
|
+
} catch (err) {
|
|
115
|
+
fatal(err);
|
|
116
|
+
}
|
|
117
|
+
process.exit(1);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function fatal(err: unknown): never {
|
|
121
|
+
if (err instanceof ConfigInvalidError) {
|
|
122
|
+
process.stderr.write('[graphorin/cli] graphorin.config invalid:\n');
|
|
123
|
+
for (const issue of err.issues) {
|
|
124
|
+
process.stderr.write(` - ${issue.path.join('.') || '<root>'}: ${issue.message}\n`);
|
|
125
|
+
}
|
|
126
|
+
} else if (err instanceof GraphorinServerError) {
|
|
127
|
+
process.stderr.write(`[graphorin/cli] ${err.kind}: ${err.message}\n`);
|
|
128
|
+
if (err.hint !== undefined) {
|
|
129
|
+
process.stderr.write(` hint: ${err.hint}\n`);
|
|
130
|
+
}
|
|
131
|
+
} else if (err instanceof Error) {
|
|
132
|
+
process.stderr.write(`[graphorin/cli] ${err.message}\n`);
|
|
133
|
+
} else {
|
|
134
|
+
process.stderr.write(`[graphorin/cli] unknown error: ${String(err)}\n`);
|
|
135
|
+
}
|
|
136
|
+
process.exit(1);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Apply the standard hardening hooks before the server bootstraps.
|
|
141
|
+
* Failures (e.g. running as root on Linux/macOS) abort the start with
|
|
142
|
+
* a documented exit code.
|
|
143
|
+
*
|
|
144
|
+
* @internal
|
|
145
|
+
*/
|
|
146
|
+
export function applyHardeningEarly(): void {
|
|
147
|
+
try {
|
|
148
|
+
applyProcessHardening({});
|
|
149
|
+
} catch (err) {
|
|
150
|
+
if (err instanceof RefuseToRunAsRootError) {
|
|
151
|
+
process.stderr.write(`[graphorin/cli] ${err.message}\n`);
|
|
152
|
+
process.stderr.write(
|
|
153
|
+
'[graphorin/cli] hint: drop privileges (systemd User=, k8s runAsNonRoot, docker --user) and retry.\n',
|
|
154
|
+
);
|
|
155
|
+
process.exit(1);
|
|
156
|
+
}
|
|
157
|
+
throw err;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function installSignalHandlers(server: Awaited<ReturnType<typeof createServer>>): void {
|
|
162
|
+
let shuttingDown = false;
|
|
163
|
+
const onSignal = (signal: NodeJS.Signals) => {
|
|
164
|
+
if (shuttingDown) return;
|
|
165
|
+
shuttingDown = true;
|
|
166
|
+
process.stderr.write(`[graphorin/cli] received ${signal}; draining...\n`);
|
|
167
|
+
server
|
|
168
|
+
.stop()
|
|
169
|
+
.then(() => {
|
|
170
|
+
process.stderr.write('[graphorin/cli] graceful shutdown complete\n');
|
|
171
|
+
process.exit(0);
|
|
172
|
+
})
|
|
173
|
+
.catch((err) => {
|
|
174
|
+
process.stderr.write(`[graphorin/cli] shutdown error: ${(err as Error).message}\n`);
|
|
175
|
+
process.exit(1);
|
|
176
|
+
});
|
|
177
|
+
};
|
|
178
|
+
process.once('SIGTERM', onSignal);
|
|
179
|
+
process.once('SIGINT', onSignal);
|
|
180
|
+
}
|