@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.
Files changed (87) hide show
  1. package/CHANGELOG.md +63 -0
  2. package/README.md +3 -3
  3. package/dist/bin/graphorin.js +51 -13
  4. package/dist/bin/graphorin.js.map +1 -1
  5. package/dist/commands/audit.d.ts.map +1 -1
  6. package/dist/commands/audit.js +2 -1
  7. package/dist/commands/audit.js.map +1 -1
  8. package/dist/commands/consolidator.d.ts +56 -1
  9. package/dist/commands/consolidator.d.ts.map +1 -1
  10. package/dist/commands/consolidator.js +88 -2
  11. package/dist/commands/consolidator.js.map +1 -1
  12. package/dist/commands/doctor.d.ts.map +1 -1
  13. package/dist/commands/index.d.ts +4 -4
  14. package/dist/commands/index.js +4 -4
  15. package/dist/commands/init.d.ts +11 -4
  16. package/dist/commands/init.d.ts.map +1 -1
  17. package/dist/commands/init.js +15 -11
  18. package/dist/commands/init.js.map +1 -1
  19. package/dist/commands/memory.d.ts +26 -1
  20. package/dist/commands/memory.d.ts.map +1 -1
  21. package/dist/commands/memory.js +56 -3
  22. package/dist/commands/memory.js.map +1 -1
  23. package/dist/commands/pricing.d.ts +6 -0
  24. package/dist/commands/pricing.d.ts.map +1 -1
  25. package/dist/commands/pricing.js +5 -2
  26. package/dist/commands/pricing.js.map +1 -1
  27. package/dist/commands/secrets.d.ts.map +1 -1
  28. package/dist/commands/secrets.js +2 -2
  29. package/dist/commands/secrets.js.map +1 -1
  30. package/dist/commands/skills.d.ts.map +1 -1
  31. package/dist/commands/skills.js +1 -1
  32. package/dist/commands/skills.js.map +1 -1
  33. package/dist/commands/storage.d.ts +41 -1
  34. package/dist/commands/storage.d.ts.map +1 -1
  35. package/dist/commands/storage.js +75 -1
  36. package/dist/commands/storage.js.map +1 -1
  37. package/dist/commands/token.d.ts.map +1 -1
  38. package/dist/commands/token.js +2 -2
  39. package/dist/commands/token.js.map +1 -1
  40. package/dist/commands/tools-lint.js +1 -1
  41. package/dist/commands/tools-lint.js.map +1 -1
  42. package/dist/commands/traces.d.ts +14 -2
  43. package/dist/commands/traces.d.ts.map +1 -1
  44. package/dist/commands/traces.js +39 -22
  45. package/dist/commands/traces.js.map +1 -1
  46. package/dist/commands/triggers.d.ts.map +1 -1
  47. package/dist/commands/triggers.js +5 -2
  48. package/dist/commands/triggers.js.map +1 -1
  49. package/dist/index.d.ts +4 -4
  50. package/dist/index.js +4 -5
  51. package/dist/index.js.map +1 -1
  52. package/dist/internal/output.js +6 -0
  53. package/dist/internal/output.js.map +1 -1
  54. package/dist/internal/store-context.js +13 -2
  55. package/dist/internal/store-context.js.map +1 -1
  56. package/dist/package.js +1 -1
  57. package/dist/package.js.map +1 -1
  58. package/package.json +18 -14
  59. package/src/bin/graphorin.ts +1387 -0
  60. package/src/commands/audit.ts +256 -0
  61. package/src/commands/auth.ts +238 -0
  62. package/src/commands/consolidator.ts +382 -0
  63. package/src/commands/doctor.ts +253 -0
  64. package/src/commands/guard.ts +144 -0
  65. package/src/commands/index.ts +223 -0
  66. package/src/commands/init.ts +194 -0
  67. package/src/commands/memory.ts +1052 -0
  68. package/src/commands/migrate-config.ts +77 -0
  69. package/src/commands/migrate-export.ts +117 -0
  70. package/src/commands/migrate.ts +83 -0
  71. package/src/commands/pricing.ts +244 -0
  72. package/src/commands/secrets.ts +309 -0
  73. package/src/commands/skills.ts +272 -0
  74. package/src/commands/start.ts +180 -0
  75. package/src/commands/storage.ts +659 -0
  76. package/src/commands/telemetry.ts +91 -0
  77. package/src/commands/token.ts +361 -0
  78. package/src/commands/tools-lint.ts +430 -0
  79. package/src/commands/traces.ts +188 -0
  80. package/src/commands/triggers.ts +237 -0
  81. package/src/index.ts +30 -0
  82. package/src/internal/exit.ts +62 -0
  83. package/src/internal/load-config.ts +107 -0
  84. package/src/internal/offline.ts +81 -0
  85. package/src/internal/output.ts +146 -0
  86. package/src/internal/prompts.ts +58 -0
  87. package/src/internal/store-context.ts +165 -0
@@ -0,0 +1,144 @@
1
+ /**
2
+ * `graphorin guard` - inspect the memory-modification guard tier
3
+ * policy.
4
+ *
5
+ * Surface (per Phase 15 § Guard):
6
+ *
7
+ * - `graphorin guard status` - print the four tiers + their guard
8
+ * variants (per DEC-153).
9
+ * - `graphorin guard explain <toolName>` - derive the tier the
10
+ * classifier would assign to a tool with the supplied trust class
11
+ * and tags. The CLI accepts the metadata via `--tags` /
12
+ * `--trust-level` / `--allowed-secrets` so the explain operation
13
+ * matches the runtime classifier without requiring the operator to
14
+ * boot the agent.
15
+ *
16
+ * @packageDocumentation
17
+ */
18
+
19
+ import {
20
+ type ClassifiableTool,
21
+ classifyTool,
22
+ guardVariantForTier,
23
+ type MemoryGuardTier,
24
+ } from '@graphorin/security';
25
+
26
+ import {
27
+ brand,
28
+ type CommonOutputOptions,
29
+ defaultPrintSink,
30
+ emitReport,
31
+ statusMarker,
32
+ } from '../internal/output.js';
33
+
34
+ /** @stable */
35
+ export interface GuardCommonOptions extends CommonOutputOptions {}
36
+
37
+ const TIERS: ReadonlyArray<MemoryGuardTier> = Object.freeze([
38
+ 'pure',
39
+ 'side-effecting-no-memory',
40
+ 'memory-aware',
41
+ 'unknown',
42
+ 'untrusted',
43
+ ] as const);
44
+
45
+ /** @stable */
46
+ export interface GuardStatusEntry {
47
+ readonly tier: MemoryGuardTier;
48
+ readonly variant: ReturnType<typeof guardVariantForTier>;
49
+ readonly description: string;
50
+ }
51
+
52
+ /** @stable */
53
+ export function runGuardStatus(options: GuardCommonOptions = {}): ReadonlyArray<GuardStatusEntry> {
54
+ const rows: GuardStatusEntry[] = TIERS.map((tier) =>
55
+ Object.freeze({
56
+ tier,
57
+ variant: guardVariantForTier(tier),
58
+ description: descriptionFor(tier),
59
+ }),
60
+ );
61
+ emitReport(options, rows, () => {
62
+ const print = options.print ?? defaultPrintSink;
63
+ print(brand('memory-modification guard tiers (DEC-153):'));
64
+ for (const row of rows) {
65
+ print(` ${statusMarker('info')} ${row.tier} -> ${row.variant} (${row.description})`);
66
+ }
67
+ });
68
+ return rows;
69
+ }
70
+
71
+ /** @stable */
72
+ export interface GuardExplainOptions extends GuardCommonOptions {
73
+ readonly toolName: string;
74
+ readonly tags?: ReadonlyArray<string>;
75
+ readonly secretsAllowed?: ReadonlyArray<string>;
76
+ readonly trustLevel?: 'built-in' | 'user-defined' | 'trusted' | 'untrusted';
77
+ readonly explicitTier?: MemoryGuardTier;
78
+ }
79
+
80
+ /** @stable */
81
+ export interface GuardExplainResult {
82
+ readonly toolName: string;
83
+ readonly tier: MemoryGuardTier;
84
+ readonly variant: ReturnType<typeof guardVariantForTier>;
85
+ readonly reason: string;
86
+ }
87
+
88
+ /** @stable */
89
+ export function runGuardExplain(options: GuardExplainOptions): GuardExplainResult {
90
+ const tool: ClassifiableTool = {
91
+ name: options.toolName,
92
+ ...(options.tags !== undefined ? { tags: options.tags } : {}),
93
+ ...(options.secretsAllowed !== undefined ? { secretsAllowed: options.secretsAllowed } : {}),
94
+ ...(options.trustLevel !== undefined ? { trustLevel: options.trustLevel } : {}),
95
+ ...(options.explicitTier !== undefined ? { memoryGuardTier: options.explicitTier } : {}),
96
+ };
97
+ const tier = classifyTool(tool);
98
+ const variant = guardVariantForTier(tier);
99
+ const reason = explainReason(tool, tier);
100
+ const result: GuardExplainResult = Object.freeze({
101
+ toolName: options.toolName,
102
+ tier,
103
+ variant,
104
+ reason,
105
+ });
106
+ emitReport(options, result, () => {
107
+ const print = options.print ?? defaultPrintSink;
108
+ print(
109
+ brand(
110
+ `${statusMarker('info')} ${result.toolName} -> tier=${result.tier} (variant=${result.variant})`,
111
+ ),
112
+ );
113
+ print(` reason: ${result.reason}`);
114
+ });
115
+ return result;
116
+ }
117
+
118
+ function descriptionFor(tier: MemoryGuardTier): string {
119
+ switch (tier) {
120
+ case 'pure':
121
+ return 'no side effects, no guard required';
122
+ case 'side-effecting-no-memory':
123
+ return 'side effects but no long-term memory writes';
124
+ case 'memory-aware':
125
+ return 'API-boundary guard around memory operations';
126
+ case 'unknown':
127
+ return 'audit-only guard (default for unclassified tools)';
128
+ case 'untrusted':
129
+ return 'strict full guard with xxhash integrity check';
130
+ }
131
+ }
132
+
133
+ function explainReason(tool: ClassifiableTool, tier: MemoryGuardTier): string {
134
+ if (tool.memoryGuardTier !== undefined) {
135
+ return `operator-set memoryGuardTier='${tool.memoryGuardTier}' (precedence wins)`;
136
+ }
137
+ if (tool.trustLevel === 'untrusted') {
138
+ return `trustLevel='untrusted' forces tier='untrusted'`;
139
+ }
140
+ if (tier === 'memory-aware') {
141
+ return `tags / secretsAllowed / name match the default memory-tag patterns`;
142
+ }
143
+ return `default classification (no memory hints found in tags / secretsAllowed)`;
144
+ }
@@ -0,0 +1,223 @@
1
+ /**
2
+ * Public command entry points. The CLI binary thin-wraps these
3
+ * helpers; tests + downstream automations consume them directly so
4
+ * they never spawn a child process to exercise the contract.
5
+ *
6
+ * Phase 14a shipped: `init` / `migrate` / `start`.
7
+ * Phase 15 added: `doctor`, `token`, `secrets`, `audit`, `storage`,
8
+ * `memory`, `consolidator`, `triggers`, `auth`, `pricing`, `skills`,
9
+ * `traces`, `migrate-export`, `migrate-config`, `guard`, `telemetry`,
10
+ * `tools lint`.
11
+ *
12
+ * @packageDocumentation
13
+ */
14
+
15
+ export {
16
+ type AuditCommonOptions,
17
+ type AuditExportOptions,
18
+ type AuditExportResult,
19
+ type AuditPruneOptions,
20
+ type AuditVerifyResult,
21
+ runAuditExport,
22
+ runAuditPrune,
23
+ runAuditVerify,
24
+ } from './audit.js';
25
+ export {
26
+ type AuthCommonOptions,
27
+ type AuthListOptions,
28
+ type AuthLoginOptions,
29
+ type AuthRefreshOptions,
30
+ type AuthRevokeOptions,
31
+ runAuthList,
32
+ runAuthLogin,
33
+ runAuthRefresh,
34
+ runAuthRevoke,
35
+ runAuthStatus,
36
+ } from './auth.js';
37
+ export {
38
+ CONSOLIDATOR_INVALID_TIER_EXIT,
39
+ type ConsolidatorCommonOptions,
40
+ type ConsolidatorDlqClearOptions,
41
+ type ConsolidatorDlqClearResult,
42
+ type ConsolidatorDlqEntry,
43
+ type ConsolidatorDlqListOptions,
44
+ type ConsolidatorSetTierOptions,
45
+ type ConsolidatorStatusResult,
46
+ type ConsolidatorStopOptions,
47
+ runConsolidatorDlqClear,
48
+ runConsolidatorDlqList,
49
+ runConsolidatorSetTier,
50
+ runConsolidatorStatus,
51
+ runConsolidatorStop,
52
+ } from './consolidator.js';
53
+ export {
54
+ type DoctorCommandOptions,
55
+ type DoctorReport,
56
+ expectedFileModes,
57
+ runDoctor,
58
+ } from './doctor.js';
59
+ export {
60
+ type GuardCommonOptions,
61
+ type GuardExplainOptions,
62
+ type GuardExplainResult,
63
+ type GuardStatusEntry,
64
+ runGuardExplain,
65
+ runGuardStatus,
66
+ } from './guard.js';
67
+ export { type InitCommandOptions, type InitCommandResult, runInit } from './init.js';
68
+ export {
69
+ type MemoryActivityConflict,
70
+ type MemoryActivityEvent,
71
+ type MemoryActivityOptions,
72
+ type MemoryActivityResult,
73
+ type MemoryCitingInsight,
74
+ type MemoryCommonOptions,
75
+ type MemoryConflictEntry,
76
+ type MemoryHistoryEntry,
77
+ type MemoryInspectEntity,
78
+ type MemoryInspectFact,
79
+ type MemoryInspectOptions,
80
+ type MemoryInspectResult,
81
+ type MemoryMigrateOptions,
82
+ type MemoryPruneHistoryOptions,
83
+ type MemoryPruneHistoryResult,
84
+ type MemoryReviewItem,
85
+ type MemoryReviewOptions,
86
+ type MemoryReviewResult,
87
+ type MemoryStatusEmbedder,
88
+ type MemoryStatusResult,
89
+ type MemoryWhyOptions,
90
+ type MemoryWhyRecall,
91
+ type MemoryWhyResult,
92
+ runMemoryActivity,
93
+ runMemoryInspect,
94
+ runMemoryMigrate,
95
+ runMemoryPruneHistory,
96
+ runMemoryReview,
97
+ runMemoryStatus,
98
+ runMemoryWhy,
99
+ } from './memory.js';
100
+ export { type MigrateCommandOptions, type MigrateCommandResult, runMigrate } from './migrate.js';
101
+ export {
102
+ type MigrateConfigOptions,
103
+ type MigrateConfigResult,
104
+ runMigrateConfig,
105
+ } from './migrate-config.js';
106
+ export {
107
+ type MigrateExportOptions,
108
+ type MigrateExportResult,
109
+ runMigrateExport,
110
+ } from './migrate-export.js';
111
+ export {
112
+ type PricingCommonOptions,
113
+ type PricingDiffOptions,
114
+ type PricingLookupOptions,
115
+ type PricingMissingOptions,
116
+ type PricingRefreshOptions,
117
+ type PricingStatusResult,
118
+ runPricingDiff,
119
+ runPricingLookup,
120
+ runPricingMissing,
121
+ runPricingRefresh,
122
+ runPricingStatus,
123
+ } from './pricing.js';
124
+ export {
125
+ runSecretsDelete,
126
+ runSecretsGet,
127
+ runSecretsList,
128
+ runSecretsRef,
129
+ runSecretsRotate,
130
+ runSecretsSet,
131
+ type SecretsCommonOptions,
132
+ type SecretsDeleteOptions,
133
+ type SecretsGetOptions,
134
+ type SecretsGetResult,
135
+ type SecretsListOptions,
136
+ type SecretsRefOptions,
137
+ type SecretsRefResult,
138
+ type SecretsRotateOptions,
139
+ type SecretsSetOptions,
140
+ } from './secrets.js';
141
+ export {
142
+ runSkillsAudit,
143
+ runSkillsInspect,
144
+ runSkillsInstall,
145
+ runSkillsMigrateFrontmatter,
146
+ type SkillsAuditOptions,
147
+ type SkillsCommonOptions,
148
+ type SkillsInspectOptions,
149
+ type SkillsInstallOptions,
150
+ type SkillsMigrateFrontmatterOptions,
151
+ type SkillsMigrateFrontmatterResult,
152
+ type SkillTrustLevelInput,
153
+ } from './skills.js';
154
+ export { runStart, type SecretsSourceFlag, type StartCommandOptions } from './start.js';
155
+ export {
156
+ runStorageBackup,
157
+ runStorageCleanupBackups,
158
+ runStorageCompact,
159
+ runStorageEncrypt,
160
+ runStorageRekey,
161
+ runStorageStatus,
162
+ type StorageBackupOptions,
163
+ type StorageBackupResult,
164
+ type StorageCleanupBackupsOptions,
165
+ type StorageCleanupBackupsResult,
166
+ type StorageCommonOptions,
167
+ type StorageCompactOptions,
168
+ type StorageCompactResult,
169
+ type StorageEncryptOptions,
170
+ type StorageRekeyOptions,
171
+ type StorageStatusResult,
172
+ } from './storage.js';
173
+ export {
174
+ runTelemetryDisable,
175
+ runTelemetryEnable,
176
+ runTelemetryInspect,
177
+ runTelemetryStatus,
178
+ type TelemetryStatusResult,
179
+ } from './telemetry.js';
180
+ export {
181
+ parseDuration,
182
+ runTokenCreate,
183
+ runTokenList,
184
+ runTokenRekey,
185
+ runTokenRevoke,
186
+ runTokenRotate,
187
+ runTokenVerify,
188
+ type TokenCommonOptions,
189
+ type TokenCreateOptions,
190
+ type TokenCreateResult,
191
+ type TokenListOptions,
192
+ type TokenRekeyOptions,
193
+ type TokenRevokeOptions,
194
+ type TokenRotateOptions,
195
+ type TokenVerifyOptions,
196
+ type TokenVerifyResult,
197
+ } from './token.js';
198
+ export {
199
+ runToolsLint,
200
+ type ToolsLintOptions,
201
+ type ToolsLintReport,
202
+ } from './tools-lint.js';
203
+ export {
204
+ runTracesPrune,
205
+ runTracesStatus,
206
+ type TracesCommonOptions,
207
+ type TracesPruneOptions,
208
+ type TracesPruneResult,
209
+ type TracesStatusResult,
210
+ } from './traces.js';
211
+ export {
212
+ runTriggersDisable,
213
+ runTriggersFire,
214
+ runTriggersList,
215
+ runTriggersPrune,
216
+ runTriggersStatus,
217
+ type TriggersCommonOptions,
218
+ type TriggersDisableOptions,
219
+ type TriggersFireOptions,
220
+ type TriggersPruneOptions,
221
+ type TriggersPruneResult,
222
+ type TriggersStatusOptions,
223
+ } from './triggers.js';
@@ -0,0 +1,194 @@
1
+ /**
2
+ * `graphorin init` - interactive bootstrap.
3
+ *
4
+ * Writes a fresh `graphorin.config.ts` to the current working
5
+ * directory (or `--out`), prompts the operator for the cloud-upload
6
+ * sensitivity tier + storage encryption opt-in, prints the server
7
+ * pepper hex ONCE, and walks the operator through the working
8
+ * credential path: persist the pepper (stdin, never argv), migrate,
9
+ * then mint a real token with `graphorin token create`.
10
+ *
11
+ * W-003: init deliberately does NOT emit a token itself. Token
12
+ * verification requires an HMAC lookup in the auth-token store, which
13
+ * requires migrations + the pepper - init's contract is "write the
14
+ * config file, touch nothing else" (pinned by tests), so any token it
15
+ * printed was guaranteed to 401. Honestly pointing at `token create`
16
+ * follows the IP-4 precedent (no phantom credentials).
17
+ *
18
+ * `--non-interactive` accepts every choice through flags or env vars
19
+ * so the command works equally well in CI / image-build pipelines.
20
+ *
21
+ * @packageDocumentation
22
+ */
23
+
24
+ import { mkdir, stat, writeFile } from 'node:fs/promises';
25
+ import { dirname, isAbsolute, resolve } from 'node:path';
26
+ import process from 'node:process';
27
+
28
+ import { generatePepper } from '@graphorin/security';
29
+
30
+ import { confirm, select } from '../internal/prompts.js';
31
+
32
+ /**
33
+ * @stable
34
+ */
35
+ export interface InitCommandOptions {
36
+ readonly out?: string;
37
+ readonly nonInteractive?: boolean;
38
+ readonly cloudConsent?: 'public-only' | 'public-and-internal' | 'all-with-warnings';
39
+ readonly encrypted?: boolean;
40
+ readonly cwd?: string;
41
+ /** Test seam: skip writing files (only print the report). */
42
+ readonly dryRun?: boolean;
43
+ /** Test seam: redirect stdout/err. */
44
+ readonly print?: (line: string) => void;
45
+ }
46
+
47
+ /**
48
+ * @stable
49
+ */
50
+ export interface InitCommandResult {
51
+ readonly configPath: string;
52
+ readonly serverPepperHex: string;
53
+ readonly cloudConsent: 'public-only' | 'public-and-internal' | 'all-with-warnings';
54
+ readonly storageEncrypted: boolean;
55
+ }
56
+
57
+ /**
58
+ * @stable
59
+ */
60
+ export async function runInit(options: InitCommandOptions = {}): Promise<InitCommandResult> {
61
+ const cwd = options.cwd ?? process.cwd();
62
+ const target = resolveOutPath(cwd, options.out);
63
+ const print = options.print ?? ((line: string) => process.stderr.write(`${line}\n`));
64
+
65
+ const cloudConsent = await resolveCloudConsent(options);
66
+ const storageEncrypted = await resolveEncryption(options);
67
+
68
+ const pepper = generatePepper();
69
+ const pepperHex = await pepper.useBuffer((buf) => buf.toString('hex'));
70
+
71
+ if (options.dryRun !== true) {
72
+ if (await fileExists(target)) {
73
+ throw new Error(
74
+ `[graphorin/cli] refusing to overwrite existing '${target}'. Move it aside or pass --out <path>.`,
75
+ );
76
+ }
77
+ await mkdir(dirname(target), { recursive: true });
78
+ await writeFile(target, renderConfig({ cloudConsent, storageEncrypted }), { mode: 0o600 });
79
+ }
80
+
81
+ print(`[graphorin/cli] wrote ${target}`);
82
+ print(`[graphorin/cli] server pepper hex (store in your keyring as 'graphorin_server_pepper'):`);
83
+ print(` ${pepperHex}`);
84
+ print('');
85
+ print('Next steps:');
86
+ // W-041: never put the pepper on argv - shell history and the process
87
+ // list would hold the key material behind every token HMAC (the
88
+ // secrets CLI itself refuses plaintext on the command line).
89
+ print(
90
+ ` 1. Persist the pepper WITHOUT argv: printf '%s' '<hex-from-above>' | graphorin secrets set graphorin_server_pepper --from-stdin`,
91
+ );
92
+ print(` 2. Run \`graphorin migrate --config ${target}\` to apply storage migrations.`);
93
+ print(
94
+ ' 3. Mint your admin token: graphorin token create --label bootstrap --scopes <scopes> (the raw token is shown ONCE).',
95
+ );
96
+ print(` 4. Run \`graphorin start --config ${target}\` to launch the server.`);
97
+
98
+ return Object.freeze({
99
+ configPath: target,
100
+ serverPepperHex: pepperHex,
101
+ cloudConsent,
102
+ storageEncrypted,
103
+ });
104
+ }
105
+
106
+ function resolveOutPath(cwd: string, out: string | undefined): string {
107
+ if (out === undefined || out.length === 0) return resolve(cwd, 'graphorin.config.ts');
108
+ return isAbsolute(out) ? out : resolve(cwd, out);
109
+ }
110
+
111
+ async function fileExists(path: string): Promise<boolean> {
112
+ try {
113
+ await stat(path);
114
+ return true;
115
+ } catch {
116
+ return false;
117
+ }
118
+ }
119
+
120
+ async function resolveCloudConsent(
121
+ options: InitCommandOptions,
122
+ ): Promise<'public-only' | 'public-and-internal' | 'all-with-warnings'> {
123
+ if (options.cloudConsent !== undefined) return options.cloudConsent;
124
+ const envValue = process.env.GRAPHORIN_CLOUD_CONSENT;
125
+ if (
126
+ envValue === 'public-only' ||
127
+ envValue === 'public-and-internal' ||
128
+ envValue === 'all-with-warnings'
129
+ ) {
130
+ return envValue;
131
+ }
132
+ if (options.nonInteractive === true) return 'public-and-internal';
133
+ const choice = await select(
134
+ 'Cloud-upload consent for context sent to providers:',
135
+ ['public-only', 'public-and-internal', 'all-with-warnings'],
136
+ 'public-and-internal',
137
+ );
138
+ return choice as 'public-only' | 'public-and-internal' | 'all-with-warnings';
139
+ }
140
+
141
+ async function resolveEncryption(options: InitCommandOptions): Promise<boolean> {
142
+ if (options.encrypted !== undefined) return options.encrypted;
143
+ if (process.env.GRAPHORIN_STORAGE_ENCRYPTED === '1') return true;
144
+ if (process.env.GRAPHORIN_STORAGE_ENCRYPTED === '0') return false;
145
+ if (options.nonInteractive === true) return false;
146
+ return await confirm('Enable storage encryption (defense-in-depth on top of FDE)?', false);
147
+ }
148
+
149
+ function renderConfig(input: {
150
+ readonly cloudConsent: 'public-only' | 'public-and-internal' | 'all-with-warnings';
151
+ readonly storageEncrypted: boolean;
152
+ }): string {
153
+ return `import { defineConfig } from '@graphorin/server';
154
+
155
+ export default defineConfig({
156
+ server: {
157
+ host: '127.0.0.1',
158
+ port: 8080,
159
+ },
160
+ auth: {
161
+ kind: 'token',
162
+ pepperRef: 'keyring:graphorin_server_pepper',
163
+ },
164
+ storage: {
165
+ path: './.graphorin/data.db',
166
+ mode: 'server',
167
+ encryption: ${
168
+ input.storageEncrypted
169
+ ? `{
170
+ enabled: true,
171
+ passphraseRef: 'keyring:graphorin_db_passphrase',
172
+ }`
173
+ : `{ enabled: false }`
174
+ },
175
+ },
176
+ audit: {
177
+ enabled: ${input.storageEncrypted ? 'true' : 'false'},
178
+ },
179
+ secrets: {
180
+ source: 'auto',
181
+ strict: false,
182
+ },
183
+ observability: {
184
+ logger: 'json',
185
+ },
186
+ // IP-5: no top-level 'defaults' block - the strict server-config
187
+ // parser rejects unknown keys, so the old render made a fresh
188
+ // 'graphorin init' fail on the very next migrate/start. The tier you
189
+ // chose at init is recorded below; enforce it via the memory
190
+ // package (createMemory contextEngine privacy options):
191
+ // cloudUploadConsent: ${JSON.stringify(input.cloudConsent)}
192
+ });
193
+ `;
194
+ }