agim-cli 1.2.1 → 1.2.2

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.
@@ -91,6 +91,27 @@ export function ensureBootstrapTokenIfNeeded() {
91
91
  console.log();
92
92
  return token;
93
93
  }
94
+ /**
95
+ * v1.2.2 — generate an admin INVITE token unconditionally (even when an
96
+ * admin already exists). Reuses the same bootstrap-token file + the same
97
+ * `/setup admin <token>` IM flow. Overwrites any existing unconsumed
98
+ * token so only the latest invite is valid at any time.
99
+ *
100
+ * Intended for an existing admin to onboard additional admins without
101
+ * SSH'ing into the server to look up the autogen bootstrap token.
102
+ * Triggered by `agim admin invite` CLI / the entry-menu option.
103
+ */
104
+ export function generateAdminInviteToken() {
105
+ const token = generateToken();
106
+ mkdirSync(dirname(BOOTSTRAP_TOKEN_FILE), { recursive: true });
107
+ writeFileSync(BOOTSTRAP_TOKEN_FILE, token + '\n');
108
+ chmodSync(BOOTSTRAP_TOKEN_FILE, 0o600);
109
+ log.info({
110
+ event: 'admin-bootstrap.invite_generated',
111
+ file: BOOTSTRAP_TOKEN_FILE,
112
+ }, 'admin invite token generated (existing admin invoked invite flow)');
113
+ return { token, file: BOOTSTRAP_TOKEN_FILE };
114
+ }
94
115
  /**
95
116
  * Verify a candidate token + promote the caller to admin on success.
96
117
  * Returns the outcome so the slash-command handler can craft the right
@@ -1 +1 @@
1
- {"version":3,"file":"admin-bootstrap.js","sourceRoot":"","sources":["../../src/core/admin-bootstrap.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"admin-bootstrap.js","sourceRoot":"","sources":["../../src/core/admin-bootstrap.ts"],"names":[],"mappings":"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"}
@@ -259,6 +259,7 @@
259
259
  memoryPersonaPlaceholder: '(No persona for this user yet — will be auto-generated at next consolidation, or write one manually.)',
260
260
  memoryPersonaSave: 'Save persona',
261
261
  memoryPersonaDelete: 'Delete persona',
262
+ memoryPersonaConsolidate: '🔁 Rebuild persona now',
262
263
  memoryFactsCard: 'Facts',
263
264
  memoryFactsSearch: 'Search (FTS5)',
264
265
  memoryFactsCatAll: 'All types',
@@ -532,6 +533,7 @@
532
533
  memoryPersonaPlaceholder: '(此用户暂无记忆画像 — 等下次 consolidation 自动生成,或手动写入)',
533
534
  memoryPersonaSave: '保存记忆画像',
534
535
  memoryPersonaDelete: '删除记忆画像',
536
+ memoryPersonaConsolidate: '🔁 立刻重建画像',
535
537
  memoryFactsCard: 'Facts',
536
538
  memoryFactsSearch: '搜索(FTS5)',
537
539
  memoryFactsCatAll: '所有类型',
@@ -1244,9 +1246,10 @@
1244
1246
  <span class="muted" id="mem-persona-meta" style="font-size:12px"></span>
1245
1247
  </div>
1246
1248
  <textarea id="mem-persona-text" rows="6" style="width:100%;font-family:ui-monospace,monospace;font-size:13px;box-sizing:border-box" data-i18n-attr="placeholder:memoryPersonaPlaceholder" placeholder="(此用户暂无记忆画像 — 等下次 consolidation 自动生成,或手动写入)"></textarea>
1247
- <div class="actions" style="margin-top:8px;display:flex;gap:8px">
1249
+ <div class="actions" style="margin-top:8px;display:flex;gap:8px;flex-wrap:wrap">
1248
1250
  <button type="button" id="btn-mem-persona-save" class="btn btn-primary" data-i18n="memoryPersonaSave">保存记忆画像</button>
1249
1251
  <button type="button" id="btn-mem-persona-delete" class="btn" data-i18n="memoryPersonaDelete">删除记忆画像</button>
1252
+ <button type="button" id="btn-mem-persona-consolidate" class="btn" title="立刻跑一次 consolidation 重建画像,不等 24h 周期" data-i18n="memoryPersonaConsolidate">🔁 立刻重建画像</button>
1250
1253
  </div>
1251
1254
  <p class="muted" id="mem-persona-status" style="margin-top:6px;font-size:12px"></p>
1252
1255
  </div>
@@ -3329,6 +3332,57 @@
3329
3332
  if (status) status.textContent = '删除失败: ' + (err.message || err);
3330
3333
  }
3331
3334
  });
3335
+ document.getElementById('btn-mem-persona-consolidate')?.addEventListener('click', async () => {
3336
+ const status = document.getElementById('mem-persona-status');
3337
+ const btn = document.getElementById('btn-mem-persona-consolidate');
3338
+ if (btn) btn.disabled = true;
3339
+ if (status) status.textContent = '⏳ 已提交后台任务(每用户 1 次 LLM 调用,10–60 秒)…';
3340
+ let pollTimer = null;
3341
+ const stopPoll = () => { if (pollTimer) { clearInterval(pollTimer); pollTimer = null; } };
3342
+ try {
3343
+ // Async kickoff: server returns 202 + jobId immediately, then the
3344
+ // LLM call runs in the background. Polling avoids cloudflare /
3345
+ // nginx / browser fetch timeouts on long-held POSTs.
3346
+ const r = await api('/api/memory/consolidate', { method: 'POST' });
3347
+ const targetJobId = r.jobId;
3348
+ if (!targetJobId) throw new Error('server did not return jobId');
3349
+ const startedAt = Date.now();
3350
+ pollTimer = setInterval(async () => {
3351
+ try {
3352
+ const s = await api('/api/memory/consolidate/status');
3353
+ const job = (s.jobs || []).find(j => j.id === targetJobId);
3354
+ if (!job) return;
3355
+ const elapsed = ((Date.now() - startedAt) / 1000).toFixed(0);
3356
+ if (job.phase === 'running') {
3357
+ if (status) status.textContent = `⏳ 重建中 (${elapsed}s)…`;
3358
+ return;
3359
+ }
3360
+ stopPoll();
3361
+ if (btn) btn.disabled = false;
3362
+ if (job.phase === 'done') {
3363
+ const u = (job.result && job.result.updated) || 0;
3364
+ const n = (job.result && job.result.users) || 0;
3365
+ if (status) status.textContent = `✓ 完成 (${elapsed}s) · 处理 ${n} 个用户、更新 ${u} 个画像`;
3366
+ await loadMemoryUserDetail();
3367
+ } else {
3368
+ const e = (job.result && job.result.error) || 'unknown error';
3369
+ if (status) status.textContent = '失败: ' + e;
3370
+ }
3371
+ } catch (pollErr) {
3372
+ // Poll failures are non-fatal; UI keeps trying. Stop after 5 min.
3373
+ if (Date.now() - startedAt > 300_000) {
3374
+ stopPoll();
3375
+ if (btn) btn.disabled = false;
3376
+ if (status) status.textContent = '轮询超时(>5min),请刷新查看实际结果';
3377
+ }
3378
+ }
3379
+ }, 2000);
3380
+ } catch (err) {
3381
+ if (status) status.textContent = '失败: ' + (err.message || err);
3382
+ if (btn) btn.disabled = false;
3383
+ stopPoll();
3384
+ }
3385
+ });
3332
3386
  document.getElementById('btn-mem-facts-clear-lowconf')?.addEventListener('click', async () => {
3333
3387
  if (!memCurrentUser) return;
3334
3388
  if (!confirm('删除 confidence ≤ 40% 的所有事实?')) return;
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/web/server.ts"],"names":[],"mappings":"AA+JA,wBAAgB,iBAAiB,IAAI,CAAC,EAAE,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,KAAK,IAAI,CAOrE;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE;IAC5C,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,YAAY,EAAE,MAAM,CAAA;CACrB,GAAG,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAgxB/C"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/web/server.ts"],"names":[],"mappings":"AA+JA,wBAAgB,iBAAiB,IAAI,CAAC,EAAE,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,KAAK,IAAI,CAOrE;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE;IAC5C,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,YAAY,EAAE,MAAM,CAAA;CACrB,GAAG,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAwxB/C"}
@@ -615,6 +615,14 @@ export async function startWebServer(options) {
615
615
  if (url.pathname === '/api/memory/vector/clear' && req.method === 'POST') {
616
616
  return handleVectorClear(req, res, url);
617
617
  }
618
+ // v1.2.2 — manual trigger for the daily consolidation. Useful when the
619
+ // user just wants a persona summary now without waiting 24h.
620
+ if (url.pathname === '/api/memory/consolidate' && req.method === 'POST') {
621
+ return handleMemoryConsolidate(req, res);
622
+ }
623
+ if (url.pathname === '/api/memory/consolidate/status' && req.method === 'GET') {
624
+ return handleMemoryConsolidateStatus(req, res);
625
+ }
618
626
  // PR-B: HITL approvals — global pending list + per-reqId resolve.
619
627
  if (url.pathname === '/api/approvals' && req.method === 'GET') {
620
628
  return handleListApprovals(req, res);
@@ -2370,6 +2378,52 @@ async function handleVectorBackfill(req, res, url) {
2370
2378
  sendJson(res, 500, { error: err instanceof Error ? err.message : String(err) });
2371
2379
  }
2372
2380
  }
2381
+ const consolidateJobs = new Map();
2382
+ function pickRecentConsolidate() {
2383
+ return Array.from(consolidateJobs.values())
2384
+ .sort((a, b) => b.startedAt - a.startedAt)
2385
+ .slice(0, 5);
2386
+ }
2387
+ async function handleMemoryConsolidate(_req, res) {
2388
+ try {
2389
+ // Dedupe: if a consolidate is already running, return that jobId.
2390
+ for (const j of consolidateJobs.values()) {
2391
+ if (j.phase === 'running') {
2392
+ sendJson(res, 202, { ok: true, jobId: j.id, alreadyRunning: true });
2393
+ return;
2394
+ }
2395
+ }
2396
+ const id = `consolidate-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
2397
+ const job = { id, startedAt: Date.now(), finishedAt: null, phase: 'running', result: {} };
2398
+ consolidateJobs.set(id, job);
2399
+ if (consolidateJobs.size > 50) {
2400
+ const oldest = Array.from(consolidateJobs.values()).sort((a, b) => a.startedAt - b.startedAt)[0];
2401
+ if (oldest)
2402
+ consolidateJobs.delete(oldest.id);
2403
+ }
2404
+ void (async () => {
2405
+ try {
2406
+ const { runConsolidationOnce } = await import('../core/memory-consolidate.js');
2407
+ const r = await runConsolidationOnce();
2408
+ job.finishedAt = Date.now();
2409
+ job.phase = 'done';
2410
+ job.result = r;
2411
+ }
2412
+ catch (err) {
2413
+ job.finishedAt = Date.now();
2414
+ job.phase = 'failed';
2415
+ job.result = { error: err instanceof Error ? err.message : String(err) };
2416
+ }
2417
+ })();
2418
+ sendJson(res, 202, { ok: true, jobId: id, hint: 'poll /api/memory/consolidate/status for progress' });
2419
+ }
2420
+ catch (err) {
2421
+ sendJson(res, 500, { error: err instanceof Error ? err.message : String(err) });
2422
+ }
2423
+ }
2424
+ async function handleMemoryConsolidateStatus(_req, res) {
2425
+ sendJson(res, 200, { jobs: pickRecentConsolidate() });
2426
+ }
2373
2427
  async function handleVectorClear(_req, res, url) {
2374
2428
  try {
2375
2429
  const { clearEmbeddings } = await import('../core/memory.js');