@justfortytwo/installer 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.
Files changed (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +70 -0
  3. package/dist/commands/doctor.d.ts +36 -0
  4. package/dist/commands/doctor.d.ts.map +1 -0
  5. package/dist/commands/doctor.js +126 -0
  6. package/dist/commands/doctor.js.map +1 -0
  7. package/dist/commands/enrich.d.ts +2 -0
  8. package/dist/commands/enrich.d.ts.map +1 -0
  9. package/dist/commands/enrich.js +26 -0
  10. package/dist/commands/enrich.js.map +1 -0
  11. package/dist/commands/forget.d.ts +2 -0
  12. package/dist/commands/forget.d.ts.map +1 -0
  13. package/dist/commands/forget.js +19 -0
  14. package/dist/commands/forget.js.map +1 -0
  15. package/dist/commands/init.d.ts +48 -0
  16. package/dist/commands/init.d.ts.map +1 -0
  17. package/dist/commands/init.js +284 -0
  18. package/dist/commands/init.js.map +1 -0
  19. package/dist/commands/pair.d.ts +2 -0
  20. package/dist/commands/pair.d.ts.map +1 -0
  21. package/dist/commands/pair.js +26 -0
  22. package/dist/commands/pair.js.map +1 -0
  23. package/dist/commands/rollback.d.ts +2 -0
  24. package/dist/commands/rollback.d.ts.map +1 -0
  25. package/dist/commands/rollback.js +32 -0
  26. package/dist/commands/rollback.js.map +1 -0
  27. package/dist/commands/unbind.d.ts +16 -0
  28. package/dist/commands/unbind.d.ts.map +1 -0
  29. package/dist/commands/unbind.js +67 -0
  30. package/dist/commands/unbind.js.map +1 -0
  31. package/dist/commands/update.d.ts +2 -0
  32. package/dist/commands/update.d.ts.map +1 -0
  33. package/dist/commands/update.js +60 -0
  34. package/dist/commands/update.js.map +1 -0
  35. package/dist/engine.d.ts +37 -0
  36. package/dist/engine.d.ts.map +1 -0
  37. package/dist/engine.js +170 -0
  38. package/dist/engine.js.map +1 -0
  39. package/dist/index.d.ts +9 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +106 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/render.d.ts +78 -0
  44. package/dist/render.d.ts.map +1 -0
  45. package/dist/render.js +113 -0
  46. package/dist/render.js.map +1 -0
  47. package/dist/state.d.ts +58 -0
  48. package/dist/state.d.ts.map +1 -0
  49. package/dist/state.js +93 -0
  50. package/dist/state.js.map +1 -0
  51. package/package.json +79 -0
@@ -0,0 +1,284 @@
1
+ // init — first-run install + scaffold. The `create-fortytwo` happy path.
2
+ //
3
+ // End state after a successful init:
4
+ // - .fortytwo/identity.json written from captured answers (gitignored)
5
+ // - .env written with secrets + runtime config (gitignored)
6
+ // - CLAUDE.md + context/* rendered from @justfortytwo/persona templates
7
+ // - .mcp.json wired to the memory MCP server
8
+ // - Ollama EMBED_MODEL pulled (warn-only); the memory DB migrated
9
+ // - .fortytwo/state.json records the resolved sibling version set (rollback baseline)
10
+ // - next-step guidance: set ALLOWED_CHAT_IDS / attach the channel
11
+ //
12
+ // Authorization model (v0): the channel allowlist is the static ALLOWED_CHAT_IDS
13
+ // (written to .env); the bridge authorizes off it. The dynamic /login pairing
14
+ // handshake is a future enhancement — see pair.ts — and is intentionally NOT the
15
+ // init path yet.
16
+ import { writeFileSync, readFileSync, existsSync, mkdirSync } from 'node:fs';
17
+ import { join, resolve, dirname } from 'node:path';
18
+ import { spawnSync } from 'node:child_process';
19
+ import { createInterface } from 'node:readline/promises';
20
+ import { writeIdentity, recordVersionSet } from '../state.js';
21
+ import { renderPersona, loadPersonaManifest } from '../render.js';
22
+ import { loadMemory, readInstalledVersion, readSelfCompatRanges } from '../engine.js';
23
+ // The embedder model the engine standardizes on (privacy: local-only embeddings).
24
+ export const EMBED_MODEL = 'qwen3-embedding:0.6b';
25
+ export const DEFAULT_OLLAMA_BASE_URL = 'http://localhost:11434';
26
+ export const DEFAULT_DB_PATH = 'db/fortytwo.db';
27
+ function envKey(key) {
28
+ return `FORTYTWO_${key.toUpperCase()}`;
29
+ }
30
+ function isEmpty(v) {
31
+ if (v == null)
32
+ return true;
33
+ if (typeof v === 'string')
34
+ return v.trim() === '';
35
+ if (Array.isArray(v))
36
+ return v.length === 0;
37
+ return false;
38
+ }
39
+ function coerceList(v) {
40
+ if (Array.isArray(v))
41
+ return v.map(String);
42
+ if (typeof v === 'string')
43
+ return v.split(/\r?\n|,/).map((s) => s.trim()).filter(Boolean);
44
+ return [];
45
+ }
46
+ /**
47
+ * Resolve every manifest field from (in precedence order) the answers file, the
48
+ * environment (FORTYTWO_<KEY>), CLI flags, then the manifest default. List
49
+ * fields are coerced to arrays; null/absent values become '' or [] so the
50
+ * renderer (which fails loud on null) never sees a hole. Required fields left
51
+ * empty are reported back, not silently defaulted.
52
+ */
53
+ export function resolveAnswers(fields, sources) {
54
+ const env = sources.env ?? {};
55
+ const flags = sources.flags ?? {};
56
+ const file = sources.answersFile ?? {};
57
+ const answers = {};
58
+ const missingRequired = [];
59
+ for (const f of fields) {
60
+ const raw = file[f.key] ?? env[envKey(f.key)] ?? flags[f.key] ?? f.default ?? null;
61
+ const value = f.type === 'list' ? coerceList(raw) : raw == null ? '' : String(raw);
62
+ answers[f.key] = value;
63
+ if (f.required && isEmpty(value))
64
+ missingRequired.push(f.key);
65
+ }
66
+ return { answers, missingRequired };
67
+ }
68
+ /**
69
+ * Merge `vars` into existing `.env` content: update matching keys in place,
70
+ * append new ones, preserve comments and unrelated lines. Secrets NEVER go to
71
+ * identity.json — only here.
72
+ */
73
+ export function mergeEnvContent(existing, vars) {
74
+ const out = [];
75
+ const written = new Set();
76
+ for (const line of existing ? existing.split('\n') : []) {
77
+ const key = line.match(/^([A-Z0-9_]+)=/)?.[1];
78
+ if (key && Object.prototype.hasOwnProperty.call(vars, key)) {
79
+ out.push(`${key}=${vars[key]}`);
80
+ written.add(key);
81
+ }
82
+ else {
83
+ out.push(line);
84
+ }
85
+ }
86
+ while (out.length && out[out.length - 1] === '')
87
+ out.pop();
88
+ for (const [k, v] of Object.entries(vars))
89
+ if (!written.has(k))
90
+ out.push(`${k}=${v}`);
91
+ return out.join('\n') + '\n';
92
+ }
93
+ /** Add (or replace) the `fortytwo-memory` MCP server entry, preserving others. */
94
+ export function buildMcpConfig(existing, opts) {
95
+ const cfg = existing ?? { mcpServers: {} };
96
+ cfg.mcpServers = cfg.mcpServers ?? {};
97
+ cfg.mcpServers['fortytwo-memory'] = {
98
+ command: 'npx',
99
+ args: ['-y', '@justfortytwo/memory'],
100
+ env: { DB_PATH: opts.dbPath, EMBED_MODEL, OLLAMA_BASE_URL: DEFAULT_OLLAMA_BASE_URL },
101
+ };
102
+ return cfg;
103
+ }
104
+ /** Pin each declared sibling to its installed version; skip the absent. */
105
+ export function buildVersionPins(compatRanges, readVersion) {
106
+ const pins = [];
107
+ for (const [name, range] of Object.entries(compatRanges)) {
108
+ const resolved = readVersion(name);
109
+ if (resolved)
110
+ pins.push({ name, range, resolved });
111
+ }
112
+ return pins;
113
+ }
114
+ // --- filesystem wrappers (thin; the merge logic above is what's unit-tested) ---
115
+ function writeEnv(secrets, root) {
116
+ const path = join(root, '.env');
117
+ const existing = existsSync(path) ? readFileSync(path, 'utf8') : '';
118
+ writeFileSync(path, mergeEnvContent(existing, secrets), 'utf8');
119
+ }
120
+ function writeMcpJson(root, dbPath) {
121
+ const path = join(root, '.mcp.json');
122
+ const existing = existsSync(path)
123
+ ? JSON.parse(readFileSync(path, 'utf8'))
124
+ : null;
125
+ writeFileSync(path, JSON.stringify(buildMcpConfig(existing, { dbPath }), null, 2) + '\n', 'utf8');
126
+ }
127
+ function recordInstalledSet(root) {
128
+ const pins = buildVersionPins(readSelfCompatRanges(), readInstalledVersion);
129
+ recordVersionSet(pins, root);
130
+ return pins;
131
+ }
132
+ /**
133
+ * Provision local infra: pull the embedder model (warn-only, like wakeup.sh —
134
+ * the engine degrades to a fake embedder rather than hard-failing) and run the
135
+ * memory DB migrations via the memory package (the engine owns the schema; the
136
+ * CLI must not duplicate it).
137
+ */
138
+ async function provision(opts) {
139
+ const notes = [];
140
+ // 1. embedder model (best-effort)
141
+ const pulled = spawnSync('ollama', ['pull', opts.embedModel], { stdio: 'ignore' });
142
+ if (pulled.status !== 0) {
143
+ notes.push(`! could not pull ${opts.embedModel} via ollama (semantic recall will degrade until it is present)`);
144
+ }
145
+ // 2. db migrations via the memory engine
146
+ const mem = await loadMemory();
147
+ if (mem && typeof mem.openDb === 'function' && typeof mem.runMigrations === 'function') {
148
+ mkdirSync(dirname(resolve(opts.dbPath)), { recursive: true });
149
+ const handle = mem.openDb(opts.dbPath);
150
+ try {
151
+ await mem.runMigrations(handle.k);
152
+ notes.push('✓ memory DB migrated');
153
+ }
154
+ finally {
155
+ try {
156
+ await handle.k?.destroy?.();
157
+ }
158
+ catch { /* best-effort */ }
159
+ try {
160
+ handle.close?.();
161
+ }
162
+ catch { /* best-effort */ }
163
+ }
164
+ }
165
+ else {
166
+ notes.push('! @justfortytwo/memory not installed — skipped DB migration (run `fortytwo init` again after installing the engine)');
167
+ }
168
+ return notes;
169
+ }
170
+ /** Parse argv into structured init flags. `--key value` maps to a field/secret. */
171
+ function parseInitArgs(argv) {
172
+ const flags = {};
173
+ const secrets = {};
174
+ let yes = false;
175
+ let answersFile;
176
+ let ollamaBaseUrl = process.env.OLLAMA_BASE_URL ?? DEFAULT_OLLAMA_BASE_URL;
177
+ let dbPath = process.env.DB_PATH ?? DEFAULT_DB_PATH;
178
+ const SECRET_FLAGS = {
179
+ 'telegram-bot-token': 'TELEGRAM_BOT_TOKEN',
180
+ 'allowed-chat-ids': 'ALLOWED_CHAT_IDS',
181
+ };
182
+ for (let i = 0; i < argv.length; i++) {
183
+ const a = argv[i];
184
+ if (a === undefined)
185
+ continue;
186
+ if (a === '--yes' || a === '-y') {
187
+ yes = true;
188
+ continue;
189
+ }
190
+ if (!a.startsWith('--'))
191
+ continue;
192
+ const name = a.slice(2);
193
+ const val = argv[++i] ?? '';
194
+ if (name === 'answers')
195
+ answersFile = val;
196
+ else if (name === 'ollama-base-url')
197
+ ollamaBaseUrl = val;
198
+ else if (name === 'db-path')
199
+ dbPath = val;
200
+ else if (SECRET_FLAGS[name])
201
+ secrets[SECRET_FLAGS[name]] = val;
202
+ else
203
+ flags[name.replace(/-/g, '_')] = val; // --agent-name -> agent_name
204
+ }
205
+ if (process.env.TELEGRAM_BOT_TOKEN)
206
+ secrets.TELEGRAM_BOT_TOKEN ??= process.env.TELEGRAM_BOT_TOKEN;
207
+ if (process.env.ALLOWED_CHAT_IDS)
208
+ secrets.ALLOWED_CHAT_IDS ??= process.env.ALLOWED_CHAT_IDS;
209
+ return { yes, answersFile, flags, secrets, ollamaBaseUrl, dbPath };
210
+ }
211
+ /** Prompt (readline) for the required fields still missing. TTY only. */
212
+ async function promptMissing(fields, missing, answers) {
213
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
214
+ try {
215
+ for (const key of missing) {
216
+ const field = fields.find((f) => f.key === key);
217
+ const ans = (await rl.question(`${field.prompt}\n> `)).trim();
218
+ answers[key] = field.type === 'list' ? coerceList(ans) : ans;
219
+ }
220
+ }
221
+ finally {
222
+ rl.close();
223
+ }
224
+ }
225
+ export async function runInit(argv) {
226
+ const root = process.cwd();
227
+ const opts = parseInitArgs(argv);
228
+ const manifest = loadPersonaManifest();
229
+ const answersFile = opts.answersFile && existsSync(opts.answersFile)
230
+ ? JSON.parse(readFileSync(opts.answersFile, 'utf8'))
231
+ : undefined;
232
+ const resolved = resolveAnswers(manifest.fields, { answersFile, env: process.env, flags: opts.flags });
233
+ let { answers } = resolved;
234
+ const { missingRequired } = resolved;
235
+ if (missingRequired.length > 0) {
236
+ const interactive = process.stdin.isTTY && !opts.yes;
237
+ if (!interactive) {
238
+ process.stderr.write(`init: missing required answers: ${missingRequired.join(', ')}\n` +
239
+ `Provide them via --answers <file.json>, FORTYTWO_<KEY> env, or run interactively.\n`);
240
+ return 2;
241
+ }
242
+ await promptMissing(manifest.fields, missingRequired, answers);
243
+ const recheck = resolveAnswers(manifest.fields, { answersFile: answers, env: {}, flags: {} });
244
+ answers = recheck.answers;
245
+ if (recheck.missingRequired.length > 0) {
246
+ process.stderr.write(`init: still missing required answers: ${recheck.missingRequired.join(', ')}\n`);
247
+ return 2;
248
+ }
249
+ }
250
+ const identity = {
251
+ identityVersion: 1,
252
+ answers,
253
+ createdAt: new Date().toISOString(),
254
+ updatedAt: new Date().toISOString(),
255
+ };
256
+ writeIdentity(identity, root);
257
+ // Seed runtime config alongside any provided secrets.
258
+ writeEnv({
259
+ OLLAMA_BASE_URL: opts.ollamaBaseUrl,
260
+ EMBED_MODEL,
261
+ DB_PATH: opts.dbPath,
262
+ ...opts.secrets,
263
+ }, root);
264
+ const render = renderPersona(identity, { root });
265
+ writeMcpJson(root, opts.dbPath);
266
+ const provisionNotes = await provision({ ollamaBaseUrl: opts.ollamaBaseUrl, embedModel: EMBED_MODEL, dbPath: opts.dbPath });
267
+ const pins = recordInstalledSet(root);
268
+ // Report.
269
+ const out = process.stdout;
270
+ out.write(`✓ wrote .fortytwo/identity.json (${Object.keys(answers).length} answers)\n`);
271
+ out.write(`✓ wrote .env + .mcp.json (memory MCP wired)\n`);
272
+ out.write(`✓ rendered persona: ${render.written.length} written, ${render.skipped.length} preserved\n`);
273
+ for (const n of provisionNotes)
274
+ out.write(` ${n}\n`);
275
+ out.write(`✓ recorded ${pins.length} installed engine package(s)\n`);
276
+ if (!opts.secrets.ALLOWED_CHAT_IDS) {
277
+ out.write(`\nNext: set ALLOWED_CHAT_IDS in .env to your Telegram chat id, then start the channel bridge.\n`);
278
+ }
279
+ else {
280
+ out.write(`\nNext: start the channel bridge; messages from ${opts.secrets.ALLOWED_CHAT_IDS} are authorized.\n`);
281
+ }
282
+ return 0;
283
+ }
284
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,EAAE;AACF,qCAAqC;AACrC,0EAA0E;AAC1E,kFAAkF;AAClF,6EAA6E;AAC7E,8DAA8D;AAC9D,oEAAoE;AACpE,4FAA4F;AAC5F,oEAAoE;AACpE,EAAE;AACF,iFAAiF;AACjF,8EAA8E;AAC9E,iFAAiF;AACjF,iBAAiB;AAEjB,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEzD,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEtF,kFAAkF;AAClF,MAAM,CAAC,MAAM,WAAW,GAAG,sBAAsB,CAAC;AAClD,MAAM,CAAC,MAAM,uBAAuB,GAAG,wBAAwB,CAAC;AAChE,MAAM,CAAC,MAAM,eAAe,GAAG,gBAAgB,CAAC;AAmBhD,SAAS,MAAM,CAAC,GAAW;IACzB,OAAO,YAAY,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC;AACzC,CAAC;AACD,SAAS,OAAO,CAAC,CAAU;IACzB,IAAI,CAAC,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IAC3B,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;IAClD,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QAAE,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC;IAC5C,OAAO,KAAK,CAAC;AACf,CAAC;AACD,SAAS,UAAU,CAAC,CAAU;IAC5B,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QAAE,OAAO,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC3C,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC1F,OAAO,EAAE,CAAC;AACZ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAC5B,MAAuB,EACvB,OAAsB;IAEtB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,EAAE,CAAC;IAC9B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC;IAClC,MAAM,IAAI,GAAG,OAAO,CAAC,WAAW,IAAI,EAAE,CAAC;IACvC,MAAM,OAAO,GAAY,EAAE,CAAC;IAC5B,MAAM,eAAe,GAAa,EAAE,CAAC;IACrC,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,OAAO,IAAI,IAAI,CAAC;QACnF,MAAM,KAAK,GAAsB,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACtG,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACvB,IAAI,CAAC,CAAC,QAAQ,IAAI,OAAO,CAAC,KAAK,CAAC;YAAE,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAChE,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,CAAC;AACtC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,QAAgB,EAAE,IAA4B;IAC5E,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;QACxD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC9C,IAAI,GAAG,IAAI,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC;YAC3D,GAAG,CAAC,IAAI,CAAC,GAAG,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAChC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACnB,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjB,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE;QAAE,GAAG,CAAC,GAAG,EAAE,CAAC;IAC3D,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACtF,OAAO,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAC/B,CAAC;AAOD,kFAAkF;AAClF,MAAM,UAAU,cAAc,CAAC,QAA0B,EAAE,IAAwB;IACjF,MAAM,GAAG,GAAc,QAAQ,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;IACtD,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC,UAAU,IAAI,EAAE,CAAC;IACtC,GAAG,CAAC,UAAU,CAAC,iBAAiB,CAAC,GAAG;QAClC,OAAO,EAAE,KAAK;QACd,IAAI,EAAE,CAAC,IAAI,EAAE,sBAAsB,CAAC;QACpC,GAAG,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,eAAe,EAAE,uBAAuB,EAAE;KACrF,CAAC;IACF,OAAO,GAAG,CAAC;AACb,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,gBAAgB,CAC9B,YAAoC,EACpC,WAA4C;IAE5C,MAAM,IAAI,GAAiB,EAAE,CAAC;IAC9B,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;QACzD,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,QAAQ;YAAE,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;IACrD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,kFAAkF;AAElF,SAAS,QAAQ,CAAC,OAA+B,EAAE,IAAY;IAC7D,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAChC,MAAM,QAAQ,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACpE,aAAa,CAAC,IAAI,EAAE,eAAe,CAAC,QAAQ,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,CAAC;AAClE,CAAC;AAED,SAAS,YAAY,CAAC,IAAY,EAAE,MAAc;IAChD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IACrC,MAAM,QAAQ,GAAqB,UAAU,CAAC,IAAI,CAAC;QACjD,CAAC,CAAE,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAe;QACvD,CAAC,CAAC,IAAI,CAAC;IACT,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC;AACpG,CAAC;AAED,SAAS,kBAAkB,CAAC,IAAY;IACtC,MAAM,IAAI,GAAG,gBAAgB,CAAC,oBAAoB,EAAE,EAAE,oBAAoB,CAAC,CAAC;IAC5E,gBAAgB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC7B,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,SAAS,CAAC,IAAmE;IAC1F,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,kCAAkC;IAClC,MAAM,MAAM,GAAG,SAAS,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,UAAU,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;IACnF,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,KAAK,CAAC,IAAI,CAAC,oBAAoB,IAAI,CAAC,UAAU,gEAAgE,CAAC,CAAC;IAClH,CAAC;IACD,yCAAyC;IACzC,MAAM,GAAG,GAAG,MAAM,UAAU,EAAE,CAAC;IAC/B,IAAI,GAAG,IAAI,OAAO,GAAG,CAAC,MAAM,KAAK,UAAU,IAAI,OAAQ,GAAmC,CAAC,aAAa,KAAK,UAAU,EAAE,CAAC;QACxH,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9D,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAuC,CAAC;QAC7E,IAAI,CAAC;YACH,MAAO,GAAmE,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YACnG,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;QACrC,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC;gBAAC,MAAO,MAAM,CAAC,CAAuC,EAAE,OAAO,EAAE,EAAE,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC;YACvG,IAAI,CAAC;gBAAC,MAAM,CAAC,KAAK,EAAE,EAAE,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,IAAI,CAAC,qHAAqH,CAAC,CAAC;IACpI,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAWD,mFAAmF;AACnF,SAAS,aAAa,CAAC,IAAc;IACnC,MAAM,KAAK,GAA2B,EAAE,CAAC;IACzC,MAAM,OAAO,GAA2B,EAAE,CAAC;IAC3C,IAAI,GAAG,GAAG,KAAK,CAAC;IAChB,IAAI,WAA+B,CAAC;IACpC,IAAI,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,uBAAuB,CAAC;IAC3E,IAAI,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,eAAe,CAAC;IACpD,MAAM,YAAY,GAA2B;QAC3C,oBAAoB,EAAE,oBAAoB;QAC1C,kBAAkB,EAAE,kBAAkB;KACvC,CAAC;IACF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,IAAI,CAAC,KAAK,SAAS;YAAE,SAAS;QAC9B,IAAI,CAAC,KAAK,OAAO,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;YAAC,GAAG,GAAG,IAAI,CAAC;YAAC,SAAS;QAAC,CAAC;QAC1D,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,SAAS;QAClC,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACxB,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,IAAI,KAAK,SAAS;YAAE,WAAW,GAAG,GAAG,CAAC;aACrC,IAAI,IAAI,KAAK,iBAAiB;YAAE,aAAa,GAAG,GAAG,CAAC;aACpD,IAAI,IAAI,KAAK,SAAS;YAAE,MAAM,GAAG,GAAG,CAAC;aACrC,IAAI,YAAY,CAAC,IAAI,CAAC;YAAE,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,GAAG,GAAG,CAAC;;YAC1D,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,6BAA6B;IAC1E,CAAC;IACD,IAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB;QAAE,OAAO,CAAC,kBAAkB,KAAK,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;IAClG,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB;QAAE,OAAO,CAAC,gBAAgB,KAAK,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IAC5F,OAAO,EAAE,GAAG,EAAE,WAAW,EAAE,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,CAAC;AACrE,CAAC;AAED,yEAAyE;AACzE,KAAK,UAAU,aAAa,CAAC,MAAuB,EAAE,OAAiB,EAAE,OAAgB;IACvF,MAAM,EAAE,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC7E,IAAI,CAAC;QACH,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;YAC1B,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,CAAE,CAAC;YACjD,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,GAAG,KAAK,CAAC,MAAM,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YAC9D,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;QAC/D,CAAC;IACH,CAAC;YAAS,CAAC;QACT,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,IAAc;IAC1C,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAC3B,MAAM,IAAI,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IAEjC,MAAM,QAAQ,GAAG,mBAAmB,EAAE,CAAC;IACvC,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC;QAClE,CAAC,CAAE,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,CAA6B;QACjF,CAAC,CAAC,SAAS,CAAC;IAEd,MAAM,QAAQ,GAAG,cAAc,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,WAAW,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;IACvG,IAAI,EAAE,OAAO,EAAE,GAAG,QAAQ,CAAC;IAC3B,MAAM,EAAE,eAAe,EAAE,GAAG,QAAQ,CAAC;IAErC,IAAI,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/B,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;QACrD,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,mCAAmC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;gBACjE,qFAAqF,CACtF,CAAC;YACF,OAAO,CAAC,CAAC;QACX,CAAC;QACD,MAAM,aAAa,CAAC,QAAQ,CAAC,MAAM,EAAE,eAAe,EAAE,OAAO,CAAC,CAAC;QAC/D,MAAM,OAAO,GAAG,cAAc,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;QAC9F,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;QAC1B,IAAI,OAAO,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,yCAAyC,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACtG,OAAO,CAAC,CAAC;QACX,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAa;QACzB,eAAe,EAAE,CAAC;QAClB,OAAO;QACP,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC;IACF,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAE9B,sDAAsD;IACtD,QAAQ,CACN;QACE,eAAe,EAAE,IAAI,CAAC,aAAa;QACnC,WAAW;QACX,OAAO,EAAE,IAAI,CAAC,MAAM;QACpB,GAAG,IAAI,CAAC,OAAO;KAChB,EACD,IAAI,CACL,CAAC;IAEF,MAAM,MAAM,GAAG,aAAa,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IACjD,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAChC,MAAM,cAAc,GAAG,MAAM,SAAS,CAAC,EAAE,aAAa,EAAE,IAAI,CAAC,aAAa,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IAC5H,MAAM,IAAI,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;IAEtC,UAAU;IACV,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC;IAC3B,GAAG,CAAC,KAAK,CAAC,oCAAoC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,aAAa,CAAC,CAAC;IACxF,GAAG,CAAC,KAAK,CAAC,+CAA+C,CAAC,CAAC;IAC3D,GAAG,CAAC,KAAK,CAAC,uBAAuB,MAAM,CAAC,OAAO,CAAC,MAAM,aAAa,MAAM,CAAC,OAAO,CAAC,MAAM,cAAc,CAAC,CAAC;IACxG,KAAK,MAAM,CAAC,IAAI,cAAc;QAAE,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACtD,GAAG,CAAC,KAAK,CAAC,cAAc,IAAI,CAAC,MAAM,gCAAgC,CAAC,CAAC;IACrE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC;QACnC,GAAG,CAAC,KAAK,CAAC,iGAAiG,CAAC,CAAC;IAC/G,CAAC;SAAM,CAAC;QACN,GAAG,CAAC,KAAK,CAAC,mDAAmD,IAAI,CAAC,OAAO,CAAC,gBAAgB,oBAAoB,CAAC,CAAC;IAClH,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function runPair(_argv: string[]): Promise<number>;
2
+ //# sourceMappingURL=pair.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pair.d.ts","sourceRoot":"","sources":["../../src/commands/pair.ts"],"names":[],"mappings":"AAkBA,wBAAsB,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAe9D"}
@@ -0,0 +1,26 @@
1
+ // pair — issue a one-time `/login` pairing code for a channel.
2
+ //
3
+ // Unlike init (which also provisions), pair is the standalone "bind another
4
+ // device/chat" verb. It mints a short-lived code; the owner sends `/login <code>`
5
+ // from the target chat, and the channel adapter confirms the binding (adding the
6
+ // chat to the allowlist and recording it in identity.json's `channels`).
7
+ //
8
+ // This is the lifecycle counterpart to `unbind`.
9
+ export async function runPair(_argv) {
10
+ // BLOCKED: dynamic /login pairing requires that an issued challenge be
11
+ // redeemable by the SEPARATELY-RUNNING bridge. TelegramAdapter currently keeps
12
+ // pending challenges in an in-memory Map, so a code minted by this CLI process
13
+ // is invisible to the bridge process — cross-process pairing can't work until
14
+ // @justfortytwo/telegram persists challenges in its store. The path that works
15
+ // today is the static allowlist: set ALLOWED_CHAT_IDS in .env (fortytwo init
16
+ // writes it), which the bridge authorizes against directly.
17
+ void resolveChannel;
18
+ process.stderr.write('pair: dynamic /login pairing is not available yet (it needs cross-process ' +
19
+ 'challenge persistence in @justfortytwo/telegram). For now, authorize a chat ' +
20
+ 'by adding its id to ALLOWED_CHAT_IDS in .env.\n');
21
+ return 2;
22
+ }
23
+ function resolveChannel(_flags, _identity) {
24
+ return 'telegram';
25
+ }
26
+ //# sourceMappingURL=pair.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pair.js","sourceRoot":"","sources":["../../src/commands/pair.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,EAAE;AACF,4EAA4E;AAC5E,kFAAkF;AAClF,iFAAiF;AACjF,yEAAyE;AACzE,EAAE;AACF,iDAAiD;AAWjD,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,KAAe;IAC3C,uEAAuE;IACvE,+EAA+E;IAC/E,+EAA+E;IAC/E,8EAA8E;IAC9E,+EAA+E;IAC/E,6EAA6E;IAC7E,4DAA4D;IAC5D,KAAK,cAAc,CAAC;IACpB,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,4EAA4E;QAC5E,8EAA8E;QAC9E,iDAAiD,CAClD,CAAC;IACF,OAAO,CAAC,CAAC;AACX,CAAC;AAED,SAAS,cAAc,CAAC,MAAiB,EAAE,SAA0B;IACnE,OAAO,UAAU,CAAC;AACpB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function runRollback(_argv: string[]): Promise<number>;
2
+ //# sourceMappingURL=rollback.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rollback.d.ts","sourceRoot":"","sources":["../../src/commands/rollback.ts"],"names":[],"mappings":"AAWA,wBAAsB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAsBlE"}
@@ -0,0 +1,32 @@
1
+ // rollback — restore the prior version set after a bad update.
2
+ //
3
+ // The counterpart to `update`'s manual-rollback safety model. update records the
4
+ // pre-upgrade set into state.json's `previous`; rollback re-installs exactly that
5
+ // set and rotates the ledger back. This is the ONLY safety net under the
6
+ // "latest-compatible, no bill-of-materials" policy: there's no canonical "known
7
+ // good" list except what we captured at the last successful install.
8
+ import { readState, recordVersionSet } from '../state.js';
9
+ import { runDoctorChecks } from './doctor.js';
10
+ export async function runRollback(_argv) {
11
+ // TODO(impl):
12
+ // Real local validation of the rollback ledger.
13
+ const state = readState();
14
+ if (!state) {
15
+ process.stderr.write('rollback: nothing to roll back — run `fortytwo init` first.\n');
16
+ return 2;
17
+ }
18
+ if (!state.previous) {
19
+ process.stderr.write('rollback: no prior version set recorded (only one install so far, or already rolled back).\n');
20
+ return 2;
21
+ }
22
+ // BLOCKED: the actual re-install of the previous set needs the npm registry
23
+ // (same blocker as `update`). The ledger is valid and the target is known —
24
+ // we just can't fetch the versions until the engine packages are published.
25
+ void recordVersionSet;
26
+ void runDoctorChecks;
27
+ process.stderr.write('rollback: not available yet — restoring the previous set re-installs from npm, ' +
28
+ 'and the @justfortytwo/* engine packages are not published. Would restore:\n' +
29
+ state.previous.map((p) => ` ${p.name}@${p.resolved}`).join('\n') + '\n');
30
+ return 2;
31
+ }
32
+ //# sourceMappingURL=rollback.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rollback.js","sourceRoot":"","sources":["../../src/commands/rollback.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,EAAE;AACF,iFAAiF;AACjF,kFAAkF;AAClF,yEAAyE;AACzE,gFAAgF;AAChF,qEAAqE;AAErE,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,KAAe;IAC/C,cAAc;IACd,gDAAgD;IAChD,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;IAC1B,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,+DAA+D,CAAC,CAAC;QACtF,OAAO,CAAC,CAAC;IACX,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;QACpB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,8FAA8F,CAAC,CAAC;QACrH,OAAO,CAAC,CAAC;IACX,CAAC;IACD,4EAA4E;IAC5E,4EAA4E;IAC5E,4EAA4E;IAC5E,KAAK,gBAAgB,CAAC;IAAC,KAAK,eAAe,CAAC;IAC5C,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,iFAAiF;QACjF,6EAA6E;QAC7E,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CACzE,CAAC;IACF,OAAO,CAAC,CAAC;AACX,CAAC"}
@@ -0,0 +1,16 @@
1
+ import { type ChannelBinding } from '../state.js';
2
+ /**
3
+ * Pure prune: drop bindings matching the selector. With `all`, drop every
4
+ * binding for the (optional) channel; otherwise drop bindings whose
5
+ * allowedChatIds include `chatId`. Bindings for other channels are untouched.
6
+ */
7
+ export declare function pruneChannels(channels: ChannelBinding[], sel: {
8
+ channel?: string;
9
+ chatId?: string;
10
+ all?: boolean;
11
+ }): {
12
+ kept: ChannelBinding[];
13
+ removed: ChannelBinding[];
14
+ };
15
+ export declare function runUnbind(argv: string[]): Promise<number>;
16
+ //# sourceMappingURL=unbind.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unbind.d.ts","sourceRoot":"","sources":["../../src/commands/unbind.ts"],"names":[],"mappings":"AAOA,OAAO,EAA+B,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAQ/E;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,cAAc,EAAE,EAC1B,GAAG,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,OAAO,CAAA;CAAE,GACxD;IAAE,IAAI,EAAE,cAAc,EAAE,CAAC;IAAC,OAAO,EAAE,cAAc,EAAE,CAAA;CAAE,CASvD;AAcD,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAwB/D"}
@@ -0,0 +1,67 @@
1
+ // unbind — revoke a channel binding (the inverse of `pair`).
2
+ //
3
+ // Removes the binding from identity.json's `channels`. The actual authorization
4
+ // today is the static ALLOWED_CHAT_IDS in .env, so unbind also reminds the owner
5
+ // to drop the id there. (Server-side challenge revocation is N/A until dynamic
6
+ // pairing lands in the channel adapter — see pair.ts.)
7
+ import { readIdentity, writeIdentity } from '../state.js';
8
+ /**
9
+ * Pure prune: drop bindings matching the selector. With `all`, drop every
10
+ * binding for the (optional) channel; otherwise drop bindings whose
11
+ * allowedChatIds include `chatId`. Bindings for other channels are untouched.
12
+ */
13
+ export function pruneChannels(channels, sel) {
14
+ const removed = [];
15
+ const kept = channels.filter((c) => {
16
+ if (sel.channel && c.channel !== sel.channel)
17
+ return true;
18
+ const match = sel.all === true || (sel.chatId != null && (c.allowedChatIds ?? []).includes(sel.chatId));
19
+ if (match) {
20
+ removed.push(c);
21
+ return false;
22
+ }
23
+ return true;
24
+ });
25
+ return { kept, removed };
26
+ }
27
+ function parseUnbindArgs(argv) {
28
+ const flags = {};
29
+ for (let i = 0; i < argv.length; i++) {
30
+ const a = argv[i];
31
+ if (a === undefined)
32
+ continue;
33
+ if (a === '--all')
34
+ flags.all = true;
35
+ else if (a === '--channel')
36
+ flags.channel = argv[++i];
37
+ else if (a === '--chat-id')
38
+ flags.chatId = argv[++i];
39
+ }
40
+ return flags;
41
+ }
42
+ export async function runUnbind(argv) {
43
+ const root = process.cwd();
44
+ const flags = parseUnbindArgs(argv);
45
+ const identity = readIdentity(root);
46
+ if (!identity) {
47
+ process.stderr.write('unbind: no .fortytwo/identity.json — run `fortytwo init` first.\n');
48
+ return 2;
49
+ }
50
+ if (!flags.all && !flags.chatId) {
51
+ process.stderr.write('unbind: specify --chat-id <id> or --all (optionally --channel <name>).\n');
52
+ return 2;
53
+ }
54
+ const { kept, removed } = pruneChannels(identity.channels ?? [], flags);
55
+ if (removed.length === 0) {
56
+ process.stdout.write('unbind: no matching binding found; nothing changed.\n');
57
+ return 0;
58
+ }
59
+ writeIdentity({ ...identity, channels: kept }, root);
60
+ const ids = removed.flatMap((c) => c.allowedChatIds ?? []);
61
+ process.stdout.write(`✓ removed ${removed.length} binding(s) from identity.json\n`);
62
+ if (ids.length) {
63
+ process.stdout.write(` Also remove ${ids.join(', ')} from ALLOWED_CHAT_IDS in .env to fully revoke access.\n`);
64
+ }
65
+ return 0;
66
+ }
67
+ //# sourceMappingURL=unbind.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unbind.js","sourceRoot":"","sources":["../../src/commands/unbind.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function runUpdate(_argv: string[]): Promise<number>;
2
+ //# sourceMappingURL=update.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"AA6CA,wBAAsB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAqBhE"}
@@ -0,0 +1,60 @@
1
+ // update — upgrade the engine within the declared semver ranges.
2
+ //
3
+ // Distribution policy: "semver ranges, latest-compatible". There is NO curated
4
+ // bill-of-materials. update therefore:
5
+ // 1. RECORD the current resolved version set as the rollback baseline
6
+ // (state.json: current -> previous) BEFORE changing anything.
7
+ // 2. RESOLVE latest-in-range for every @justfortytwo/* sibling (the ranges in
8
+ // this package's peerDeps / fortytwo.compat).
9
+ // 3. INSTALL that set.
10
+ // 4. POST-VERIFY with doctor (the health check).
11
+ // 5. On success: record the new set as `current`. On failure: leave the failed
12
+ // set in place but LOUDLY point the user at `fortytwo rollback`. Rollback is
13
+ // MANUAL by design — we never auto-revert, so the user can inspect first.
14
+ //
15
+ // Re-render the persona's MANAGED scaffold afterward (render.ts is idempotent and
16
+ // does not clobber captured fields), in case a new persona template version ships.
17
+ import { recordVersionSet, readState } from '../state.js';
18
+ import { renderPersona } from '../render.js';
19
+ import { runDoctorChecks } from './doctor.js';
20
+ /**
21
+ * Resolve latest-in-range for each sibling from the declared ranges.
22
+ * TODO(wire): read this package's peerDeps + fortytwo.compat for ranges, then
23
+ * query the registry (npm view <pkg> versions) and pick the highest satisfying
24
+ * version per range. Returns the VersionPin[] for state.json.
25
+ */
26
+ async function resolveLatestInRange() {
27
+ throw new Error('TODO(wire): resolveLatestInRange — npm registry resolve against declared ranges');
28
+ }
29
+ /**
30
+ * Install the resolved set.
31
+ * TODO(wire): shell out to the user's package manager (npm/pnpm/yarn detected
32
+ * from the lockfile) to install the resolved versions, or update peerDep pins.
33
+ */
34
+ async function installSet(_set) {
35
+ throw new Error('TODO(wire): installSet — install resolved sibling versions');
36
+ }
37
+ export async function runUpdate(_argv) {
38
+ // Real local check: there must be an install baseline (init has run).
39
+ const prior = readState();
40
+ if (!prior) {
41
+ process.stderr.write('update: no install found — run `fortytwo init` first.\n');
42
+ return 2;
43
+ }
44
+ // BLOCKED: resolving latest-in-range and installing require the npm registry,
45
+ // and the @justfortytwo/* engine packages are not published yet. The orchestration
46
+ // (record baseline -> resolveLatestInRange -> installSet -> doctor -> render ->
47
+ // point at rollback on failure) is ready to wire the moment they publish.
48
+ void recordVersionSet;
49
+ void resolveLatestInRange;
50
+ void installSet;
51
+ void runDoctorChecks;
52
+ void renderPersona;
53
+ void null;
54
+ void null;
55
+ process.stderr.write('update: not available yet — it resolves + installs from npm, and the ' +
56
+ '@justfortytwo/* engine packages are not published. Current set:\n' +
57
+ prior.current.map((p) => ` ${p.name}@${p.resolved} (${p.range})`).join('\n') + '\n');
58
+ return 2;
59
+ }
60
+ //# sourceMappingURL=update.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update.js","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,EAAE;AACF,+EAA+E;AAC/E,uCAAuC;AACvC,wEAAwE;AACxE,mEAAmE;AACnE,gFAAgF;AAChF,mDAAmD;AACnD,yBAAyB;AACzB,mDAAmD;AACnD,iFAAiF;AACjF,kFAAkF;AAClF,+EAA+E;AAC/E,EAAE;AACF,kFAAkF;AAClF,mFAAmF;AAEnF,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAqB,MAAM,cAAc,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAO9C;;;;;GAKG;AACH,KAAK,UAAU,oBAAoB;IACjC,MAAM,IAAI,KAAK,CAAC,iFAAiF,CAAC,CAAC;AACrG,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,UAAU,CAAC,IAAwC;IAChE,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAC;AAChF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,KAAe;IAC7C,sEAAsE;IACtE,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;IAC1B,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,yDAAyD,CAAC,CAAC;QAChF,OAAO,CAAC,CAAC;IACX,CAAC;IACD,8EAA8E;IAC9E,mFAAmF;IACnF,gFAAgF;IAChF,0EAA0E;IAC1E,KAAK,gBAAgB,CAAC;IAAC,KAAK,oBAAoB,CAAC;IAAC,KAAK,UAAU,CAAC;IAClE,KAAK,eAAe,CAAC;IAAC,KAAK,aAAa,CAAC;IACzC,KAAM,IAAgC,CAAC;IACvC,KAAM,IAA+B,CAAC;IACtC,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,uEAAuE;QACvE,mEAAmE;QACnE,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CACrF,CAAC;IACF,OAAO,CAAC,CAAC;AACX,CAAC"}
@@ -0,0 +1,37 @@
1
+ /** Dynamically import an engine sibling; null if it is not installed. */
2
+ export declare function loadSibling<T = Record<string, unknown>>(spec: string): Promise<T | null>;
3
+ export declare const loadGate: () => Promise<{
4
+ POLICY_SCHEMA_VERSION?: number;
5
+ } | null>;
6
+ export declare const loadMemory: () => Promise<{
7
+ MEMORY_TOOL_CONTRACT_VERSION?: number;
8
+ openDb?: (path: string) => {
9
+ k: {
10
+ schema: {
11
+ hasTable(name: string): Promise<boolean>;
12
+ };
13
+ };
14
+ };
15
+ runMigrations?: (k: unknown) => Promise<void>;
16
+ } | null>;
17
+ export declare const loadTelegram: () => Promise<Record<string, unknown> | null>;
18
+ /** Installed version of a sibling (its package.json `version`), or null. */
19
+ export declare function readInstalledVersion(spec: string): string | null;
20
+ /** The CLI's declared compat ranges (package.json `fortytwo.compat`). */
21
+ export declare function readSelfCompatRanges(): Record<string, string>;
22
+ /**
23
+ * Minimal semver-range satisfaction for the forms this CLI's compat contract
24
+ * uses: exact (`1.2.3`) and caret (`^1.2.3`, with npm's 0.x rule where the
25
+ * left-most non-zero element is the lock point). Avoids a runtime dependency.
26
+ */
27
+ export declare function satisfiesRange(version: string, range: string): boolean;
28
+ /** GET {baseUrl}/api/tags; return installed model names, or null if unreachable. */
29
+ export declare function fetchOllamaModels(baseUrl: string): Promise<string[] | null>;
30
+ export type MigrationState = 'ok' | 'missing' | 'pending' | 'unavailable';
31
+ /**
32
+ * Migration health for the memory DB: 'missing' (no DB file → run init),
33
+ * 'ok' (the migrated `memories` table exists), 'pending' (DB present but not
34
+ * migrated), or 'unavailable' (memory package not installed / DB unreadable).
35
+ */
36
+ export declare function readMigrationState(dbPath: string): Promise<MigrationState>;
37
+ //# sourceMappingURL=engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAcA,yEAAyE;AACzE,wBAAsB,WAAW,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAM9F;AAED,eAAO,MAAM,QAAQ;4BAA+C,MAAM;SAAyB,CAAC;AACpG,eAAO,MAAM,UAAU;mCAEY,MAAM;aAG5B,CAAC,IAAI,EAAE,MAAM,KAAK;QAAE,CAAC,EAAE;YAAE,MAAM,EAAE;gBAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;aAAE,CAAA;SAAE,CAAA;KAAE;oBAC1E,CAAC,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC;SACrB,CAAC;AAC7B,eAAO,MAAM,YAAY,+CAA8C,CAAC;AAExE,4EAA4E;AAC5E,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAyChE;AAoBD,yEAAyE;AACzE,wBAAgB,oBAAoB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAI7D;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAetE;AAED,oFAAoF;AACpF,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CASjF;AAED,MAAM,MAAM,cAAc,GAAG,IAAI,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,CAAC;AAE1E;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAehF"}