@aliyunrds/ctxdb 1.0.11-beta.0 → 1.0.12-beta.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.
@@ -2724,26 +2724,26 @@ var require_directives = __commonJS({
2724
2724
  this.tags = Object.assign({}, _Directives.defaultTags);
2725
2725
  this.atNextDocument = false;
2726
2726
  }
2727
- const parts = line.trim().split(/[ \t]+/);
2728
- const name = parts.shift();
2727
+ const parts2 = line.trim().split(/[ \t]+/);
2728
+ const name = parts2.shift();
2729
2729
  switch (name) {
2730
2730
  case "%TAG": {
2731
- if (parts.length !== 2) {
2731
+ if (parts2.length !== 2) {
2732
2732
  onError(0, "%TAG directive should contain exactly two parts");
2733
- if (parts.length < 2)
2733
+ if (parts2.length < 2)
2734
2734
  return false;
2735
2735
  }
2736
- const [handle, prefix] = parts;
2736
+ const [handle, prefix] = parts2;
2737
2737
  this.tags[handle] = prefix;
2738
2738
  return true;
2739
2739
  }
2740
2740
  case "%YAML": {
2741
2741
  this.yaml.explicit = true;
2742
- if (parts.length !== 1) {
2742
+ if (parts2.length !== 1) {
2743
2743
  onError(0, "%YAML directive should contain exactly one part");
2744
2744
  return false;
2745
2745
  }
2746
- const [version] = parts;
2746
+ const [version] = parts2;
2747
2747
  if (version === "1.1" || version === "1.2") {
2748
2748
  this.yaml.version = version;
2749
2749
  return true;
@@ -5516,9 +5516,9 @@ var require_timestamp = __commonJS({
5516
5516
  var stringifyNumber = require_stringifyNumber();
5517
5517
  function parseSexagesimal(str, asBigInt) {
5518
5518
  const sign = str[0];
5519
- const parts = sign === "-" || sign === "+" ? str.substring(1) : str;
5519
+ const parts2 = sign === "-" || sign === "+" ? str.substring(1) : str;
5520
5520
  const num = (n) => asBigInt ? BigInt(n) : Number(n);
5521
- const res = parts.replace(/_/g, "").split(":").reduce((res2, p) => res2 * num(60) + num(p), num(0));
5521
+ const res = parts2.replace(/_/g, "").split(":").reduce((res2, p) => res2 * num(60) + num(p), num(0));
5522
5522
  return sign === "-" ? num(-1) * res : res;
5523
5523
  }
5524
5524
  function stringifySexagesimal(node) {
@@ -5534,18 +5534,18 @@ var require_timestamp = __commonJS({
5534
5534
  value *= num(-1);
5535
5535
  }
5536
5536
  const _60 = num(60);
5537
- const parts = [value % _60];
5537
+ const parts2 = [value % _60];
5538
5538
  if (value < 60) {
5539
- parts.unshift(0);
5539
+ parts2.unshift(0);
5540
5540
  } else {
5541
- value = (value - parts[0]) / _60;
5542
- parts.unshift(value % _60);
5541
+ value = (value - parts2[0]) / _60;
5542
+ parts2.unshift(value % _60);
5543
5543
  if (value >= 60) {
5544
- value = (value - parts[0]) / _60;
5545
- parts.unshift(value);
5544
+ value = (value - parts2[0]) / _60;
5545
+ parts2.unshift(value);
5546
5546
  }
5547
5547
  }
5548
- return sign + parts.map((n) => String(n).padStart(2, "0")).join(":").replace(/000000\d*$/, "");
5548
+ return sign + parts2.map((n) => String(n).padStart(2, "0")).join(":").replace(/000000\d*$/, "");
5549
5549
  }
5550
5550
  var intTime = {
5551
5551
  identify: (value) => typeof value === "bigint" || Number.isInteger(value),
@@ -13867,12 +13867,6 @@ function selectTurnMessages(allParsed, opts = {}) {
13867
13867
  }
13868
13868
  }
13869
13869
  const candidates = [];
13870
- const summaryRange = turnStart >= 0 ? turnStart : allParsed.length;
13871
- for (let ai = 0; ai < summaryRange; ai++) {
13872
- if (allParsed[ai].isSummary) {
13873
- candidates.push(allParsed[ai]);
13874
- }
13875
- }
13876
13870
  const seenIndices = new Set(candidates.map((m) => m.index));
13877
13871
  if (turnStart >= 0) {
13878
13872
  const total = allParsed.length - turnStart;
@@ -14099,10 +14093,21 @@ function selectAndFormatRecalledMemories(memories, userId, config2 = {}) {
14099
14093
 
14100
14094
  // ../shared/src/debug-policy.ts
14101
14095
  init_define_CTXDB_DISTRIBUTION_MANIFEST();
14102
- var OFFICIAL_PRODUCTION_BASE_URLS = [
14103
- "https://api.cn-hangzhou.agentcontext.aliyuncs.com",
14104
- "https://context-database.aliyuncs.com"
14105
- ];
14096
+
14097
+ // ../shared/src/sites.ts
14098
+ init_define_CTXDB_DISTRIBUTION_MANIFEST();
14099
+ var PUBLIC_SITES = {
14100
+ cn: {
14101
+ baseUrl: "https://api.cn-hangzhou.agentcontext.aliyuncs.com",
14102
+ aliases: ["https://context-database.aliyuncs.com"],
14103
+ authorizationUrl: "https://rdsnext.console.aliyun.com/contextDbCliAuthorization/cn-hangzhou"
14104
+ },
14105
+ intl: {
14106
+ baseUrl: "https://context-database.ap-southeast-1.aliyuncs.com",
14107
+ aliases: [],
14108
+ authorizationUrl: "https://rds.console.alibabacloud.com/contextDbCliAuthorization/ap-southeast-1"
14109
+ }
14110
+ };
14106
14111
  function normalizeBaseUrl(value) {
14107
14112
  try {
14108
14113
  const parsed = new URL(value.trim());
@@ -14114,12 +14119,18 @@ function normalizeBaseUrl(value) {
14114
14119
  return null;
14115
14120
  }
14116
14121
  }
14117
- var NORMALIZED_PRODUCTION_URLS = new Set(
14118
- OFFICIAL_PRODUCTION_BASE_URLS.map((url) => normalizeBaseUrl(url))
14119
- );
14120
- function isOfficialProductionUrl(value) {
14122
+ function publicSiteForUrl(value) {
14121
14123
  const normalized = normalizeBaseUrl(value);
14122
- return normalized !== null && NORMALIZED_PRODUCTION_URLS.has(normalized);
14124
+ return Object.keys(PUBLIC_SITES).find((site) => {
14125
+ const preset = PUBLIC_SITES[site];
14126
+ return [preset.baseUrl, ...preset.aliases].some((url) => url === normalized);
14127
+ });
14128
+ }
14129
+
14130
+ // ../shared/src/debug-policy.ts
14131
+ var OFFICIAL_PRODUCTION_BASE_URLS = Object.values(PUBLIC_SITES).flatMap((site) => [site.baseUrl, ...site.aliases]);
14132
+ function isOfficialProductionUrl(value) {
14133
+ return publicSiteForUrl(value) !== void 0;
14123
14134
  }
14124
14135
  function resolveDebugPolicy(configuredDebug, effectiveBaseUrl) {
14125
14136
  const debugForced = !isOfficialProductionUrl(effectiveBaseUrl);
@@ -15335,6 +15346,7 @@ function createRequestAuthorizationProvider(credential, baseUrl) {
15335
15346
 
15336
15347
  // ../shared/src/data-endpoint.ts
15337
15348
  init_define_CTXDB_DISTRIBUTION_MANIFEST();
15349
+ var DEFAULT_DATA_BASE_URL = PUBLIC_SITES.cn.baseUrl;
15338
15350
 
15339
15351
  // ../shared/src/login-cleanup.ts
15340
15352
  init_define_CTXDB_DISTRIBUTION_MANIFEST();
@@ -15349,6 +15361,339 @@ init_define_CTXDB_DISTRIBUTION_MANIFEST();
15349
15361
  init_define_CTXDB_DISTRIBUTION_MANIFEST();
15350
15362
  import { dirname as dirname7, join as join6 } from "path";
15351
15363
 
15364
+ // ../shared/src/memory-cleanup.ts
15365
+ init_define_CTXDB_DISTRIBUTION_MANIFEST();
15366
+ var SHELL_TOOLS = /* @__PURE__ */ new Set([
15367
+ "bash",
15368
+ "exec",
15369
+ "shell",
15370
+ "sh",
15371
+ "terminal",
15372
+ "exec_command",
15373
+ "run_in_terminal",
15374
+ "functions.exec_command",
15375
+ "functions.shell_command",
15376
+ "shell_command"
15377
+ ]);
15378
+ var CONTEXTDB_PROVIDERS = /* @__PURE__ */ new Set(["ctxdb", "contextdb", "openclaw_memory_rds_ctxdb"]);
15379
+ var DELETE_TOOLS = /* @__PURE__ */ new Set(["memory_delete", "memory_batch_delete"]);
15380
+ var CLI_NAMES = /* @__PURE__ */ new Set(["ctxdb", "ctxdb-qoder", "ctxdb_qoder", "rds-ctxdb", "rds_ctxdb", "qoder-ctxdb", "qoder_ctxdb"]);
15381
+ var BOOLEAN_FLAGS = /* @__PURE__ */ new Set(["help", "json", "verbose", "all", "yes"]);
15382
+ function shellTokens(command) {
15383
+ const tokens = [];
15384
+ let value = "", active = false, quote = "";
15385
+ const flush = () => {
15386
+ if (active) tokens.push({ value });
15387
+ value = "";
15388
+ active = false;
15389
+ };
15390
+ for (let i = 0; i < command.length; i++) {
15391
+ const c = command[i];
15392
+ if (quote) {
15393
+ if (c === quote) {
15394
+ quote = "";
15395
+ continue;
15396
+ }
15397
+ if (quote === '"' && c === "\\" && /["\\$`\n]/.test(command[i + 1] ?? "")) {
15398
+ const next = command[++i];
15399
+ if (next !== "\n") value += next;
15400
+ continue;
15401
+ }
15402
+ if (quote === '"' && (c === "`" || c === "$" && command[i + 1] === "(")) return null;
15403
+ value += c;
15404
+ continue;
15405
+ }
15406
+ if (c === "'" || c === '"') {
15407
+ active = true;
15408
+ quote = c;
15409
+ continue;
15410
+ }
15411
+ if (c === "\\") {
15412
+ const next = command[i + 1];
15413
+ if (next === void 0) return null;
15414
+ if (/[\s'"\\;&|<>$`]/.test(next)) {
15415
+ i++;
15416
+ if (next !== "\n") {
15417
+ value += next;
15418
+ active = true;
15419
+ }
15420
+ } else {
15421
+ value += c;
15422
+ active = true;
15423
+ }
15424
+ continue;
15425
+ }
15426
+ if (c === "#" && !active) {
15427
+ while (i < command.length && command[i] !== "\n") i++;
15428
+ flush();
15429
+ tokens.push({ value: ";", operator: true });
15430
+ continue;
15431
+ }
15432
+ if (c === "`" || c === "$" && command[i + 1] === "(") return null;
15433
+ if (c === "<" && command[i + 1] === "<") return null;
15434
+ if (/[;&|\n()<>]/.test(c)) {
15435
+ flush();
15436
+ let op = c;
15437
+ if (command[i + 1] === c && /[&|>]/.test(c)) op += command[++i];
15438
+ tokens.push({ value: op, operator: true });
15439
+ continue;
15440
+ }
15441
+ if (/\s/.test(c)) {
15442
+ flush();
15443
+ continue;
15444
+ }
15445
+ active = true;
15446
+ value += c;
15447
+ }
15448
+ if (quote) return null;
15449
+ flush();
15450
+ return tokens;
15451
+ }
15452
+ function basename(path) {
15453
+ return path.split(/[\\/]/).at(-1).replace(/\.(?:cmd|exe)$/i, "");
15454
+ }
15455
+ function cliOperation(argv) {
15456
+ if (argv.some((a) => a === "--help" || a.startsWith("--help=") || a === "-h")) return;
15457
+ const positional = [];
15458
+ let literal = false;
15459
+ for (let i = 1; i < argv.length; i++) {
15460
+ const arg = argv[i];
15461
+ if (arg === "--") {
15462
+ literal = true;
15463
+ continue;
15464
+ }
15465
+ if (!literal && arg.startsWith("--")) {
15466
+ if (!arg.includes("=") && !BOOLEAN_FLAGS.has(arg.slice(2)) && argv[i + 1] && !argv[i + 1].startsWith("--")) i++;
15467
+ } else positional.push(arg);
15468
+ }
15469
+ if (positional[0] !== "memory") return;
15470
+ if (positional[1] === "delete" || positional[1] === "batch-delete") return positional[1];
15471
+ }
15472
+ function commandOperation(argv, depth) {
15473
+ let i = 0;
15474
+ while (/^[A-Za-z_][\w]*=/.test(argv[i] ?? "")) i++;
15475
+ if (basename(argv[i] ?? "") === "env") {
15476
+ i++;
15477
+ while (i < argv.length) {
15478
+ if (argv[i] === "--") {
15479
+ i++;
15480
+ break;
15481
+ }
15482
+ if (argv[i] === "-u" || argv[i] === "--unset") {
15483
+ i += 2;
15484
+ continue;
15485
+ }
15486
+ if (argv[i] === "-i" || argv[i] === "--ignore-environment" || argv[i].startsWith("--unset=") || /^[A-Za-z_][\w]*=/.test(argv[i])) {
15487
+ i++;
15488
+ continue;
15489
+ }
15490
+ break;
15491
+ }
15492
+ }
15493
+ if (argv[i] === "command") {
15494
+ i++;
15495
+ if (argv[i] === "--") i++;
15496
+ }
15497
+ const name = basename(argv[i] ?? "");
15498
+ if (CLI_NAMES.has(name)) return cliOperation(argv.slice(i));
15499
+ if (depth < 3 && ["bash", "sh", "zsh"].includes(name)) {
15500
+ const flag = argv[i + 1];
15501
+ if (/^-[a-z]*c[a-z]*$/.test(flag ?? "") && argv[i + 2]) return shellOperation(argv[i + 2], depth + 1);
15502
+ }
15503
+ }
15504
+ function shellOperation(command, depth = 0) {
15505
+ const tokens = shellTokens(command);
15506
+ if (!tokens) return;
15507
+ let argv = [];
15508
+ for (let i = 0; i <= tokens.length; i++) {
15509
+ const token = tokens[i];
15510
+ if (token?.operator && ["<", ">", ">>"].includes(token.value)) {
15511
+ if (/^\d+$/.test(argv.at(-1) ?? "")) argv.pop();
15512
+ if (tokens[i + 1]?.value === "&") i++;
15513
+ i++;
15514
+ continue;
15515
+ }
15516
+ if (!token || token.operator) {
15517
+ const operation = commandOperation(argv, depth);
15518
+ if (operation) return operation;
15519
+ argv = [];
15520
+ } else argv.push(token.value);
15521
+ }
15522
+ }
15523
+ function detectMemoryCleanup(calls) {
15524
+ for (const call of calls) {
15525
+ const qualified = /^mcp__(ctxdb|contextdb)__([^_].*)$/.exec(call.name);
15526
+ const provider = call.provider ?? qualified?.[1];
15527
+ const toolName = qualified?.[2] ?? call.name;
15528
+ if (provider && CONTEXTDB_PROVIDERS.has(provider) && DELETE_TOOLS.has(toolName)) {
15529
+ return { detected: true, operation: toolName === "memory_batch_delete" ? "batch-delete" : "delete", source: "tool" };
15530
+ }
15531
+ if (!SHELL_TOOLS.has(call.name.toLowerCase())) continue;
15532
+ const command = call.arguments.command ?? call.arguments.cmd;
15533
+ if (typeof command !== "string") continue;
15534
+ const operation = shellOperation(command);
15535
+ if (operation) return { detected: true, operation, source: "cli" };
15536
+ }
15537
+ return { detected: false };
15538
+ }
15539
+
15540
+ // ../shared/src/capture-events.ts
15541
+ init_define_CTXDB_DISTRIBUTION_MANIFEST();
15542
+ var object4 = (v) => v && typeof v === "object" && !Array.isArray(v) ? v : {};
15543
+ function captureRecord(value) {
15544
+ const row = object4(value);
15545
+ if (row.type === "response_item" || row.type === "event_msg") return object4(row.payload);
15546
+ if (row.type === "message" && row.role) return row;
15547
+ if (row.message) return object4(row.message);
15548
+ return row;
15549
+ }
15550
+ var info = (v) => object4(object4(v).info);
15551
+ var role = (v) => info(v).role ?? captureRecord(v).role ?? object4(v).type;
15552
+ var parts = (v) => object4(v).parts ?? captureRecord(v).content ?? captureRecord(v).text;
15553
+ function hidden(v) {
15554
+ const row = object4(v), body = captureRecord(v);
15555
+ return [row, body, info(v)].some((r) => r.isMeta || r.isSidechain || r.is_synthetic || r.synthetic || r.ignored || r._pre_verify_synthetic || r._verify_on_stop_synthetic);
15556
+ }
15557
+ function captureText(value) {
15558
+ const content = parts(value);
15559
+ if (typeof content === "string") return content;
15560
+ if (!Array.isArray(content)) return "";
15561
+ if (role(value) === "user" && content.some((b) => object4(b).type === "tool_result")) return "";
15562
+ return content.flatMap((b) => {
15563
+ const block2 = object4(b);
15564
+ return !block2.synthetic && !block2.ignored && ["text", "input_text", "output_text"].includes(block2.type) && typeof block2.text === "string" ? [block2.text] : [];
15565
+ }).join("\n");
15566
+ }
15567
+ function human(v) {
15568
+ if (hidden(v) || role(v) !== "user") return false;
15569
+ let text3 = captureText(v).trim();
15570
+ if (text3.includes("<user_query>")) text3 = /<user_query>([\s\S]*?)<\/user_query>/.exec(text3)?.[1] ?? "";
15571
+ if (/^(?:Stop hook feedback:|# AGENTS\.md instructions|<environment_context>|<INSTRUCTIONS>|<permissions instructions>|<collaboration_mode>|<recommended_plugins>|<apps_instructions>|<skills_instructions>|<plugins_instructions>|## Memory\s+You have access to a memory folder|<recalled-memories>|<available-knowledge-bases>|<external_codex_apps_open_page>)/.test(text3)) return false;
15572
+ if (stripNoiseFromContent(text3).trim()) return true;
15573
+ const content = parts(v);
15574
+ return Array.isArray(content) && content.some((b) => ["image", "input_image"].includes(object4(b).type));
15575
+ }
15576
+ function nativeTurn(v) {
15577
+ const row = object4(v), body = captureRecord(v), metadata = info(v);
15578
+ return (row.type === "turn_context" ? row.payload?.turn_id : void 0) ?? row.turn_id ?? row.turnId ?? body.turn_id ?? body.turnId ?? (metadata.role === "user" ? metadata.id : metadata.parentID);
15579
+ }
15580
+ function selectCaptureTurn(records) {
15581
+ let start = -1;
15582
+ for (let i = records.length - 1; i >= 0; i--) if (human(records[i])) {
15583
+ start = i;
15584
+ break;
15585
+ }
15586
+ if (start < 0) return [];
15587
+ let contextIndex = -1;
15588
+ for (let i = records.length - 1; i >= 0; i--) {
15589
+ const row = object4(records[i]);
15590
+ if (row.type === "turn_context" || row.type === "event_msg" && row.payload?.type === "task_started") {
15591
+ contextIndex = i;
15592
+ break;
15593
+ }
15594
+ }
15595
+ if (contextIndex > start) return [];
15596
+ const turn = nativeTurn(records[start]) ?? (contextIndex >= 0 ? nativeTurn(records[contextIndex]) : void 0);
15597
+ while (start > 0 && human(records[start - 1]) && (turn ? nativeTurn(records[start - 1]) === turn : !nativeTurn(records[start - 1]))) start--;
15598
+ const selected = records.slice(start).filter((r) => !hidden(r) && (role(r) !== "user" || human(r) || Array.isArray(parts(r)) && parts(r).some((b) => b?.type === "tool_result")) && (!turn || !nativeTurn(r) || nativeTurn(r) === turn));
15599
+ return contextIndex >= 0 ? [records[contextIndex], ...selected] : selected;
15600
+ }
15601
+ function argumentsObject(v) {
15602
+ if (typeof v !== "string") return object4(v);
15603
+ try {
15604
+ return object4(JSON.parse(v));
15605
+ } catch {
15606
+ return {};
15607
+ }
15608
+ }
15609
+ function captureToolCalls(records, registeredTools = {}) {
15610
+ const calls = [];
15611
+ for (const raw of records) {
15612
+ if (hidden(raw)) continue;
15613
+ const body = captureRecord(raw);
15614
+ const blocks = [];
15615
+ if (body.type === "function_call" || body.type === "custom_tool_call") blocks.push(body);
15616
+ if (role(raw) === "assistant") {
15617
+ if (Array.isArray(parts(raw))) blocks.push(...parts(raw).map(object4).filter((b) => ["tool_use", "toolCall", "tool"].includes(b.type)));
15618
+ if (Array.isArray(body.tool_calls)) blocks.push(...body.tool_calls.map(object4));
15619
+ }
15620
+ for (const block2 of blocks) {
15621
+ const fn = object4(block2.function);
15622
+ const name = fn.name ?? block2.name ?? block2.tool;
15623
+ if (typeof name !== "string") continue;
15624
+ const encodedArguments = fn.arguments ?? block2.arguments;
15625
+ let invalidArguments = false;
15626
+ if (typeof encodedArguments === "string") {
15627
+ try {
15628
+ const parsed = JSON.parse(encodedArguments);
15629
+ invalidArguments = !parsed || typeof parsed !== "object" || Array.isArray(parsed);
15630
+ } catch {
15631
+ invalidArguments = true;
15632
+ }
15633
+ }
15634
+ const args = argumentsObject(encodedArguments ?? block2.input ?? block2.parameters ?? block2.state?.input);
15635
+ const provider = block2.provider ?? block2.server_name ?? registeredTools[name];
15636
+ const id = block2.call_id ?? block2.callID ?? block2.callId ?? block2.id;
15637
+ calls.push({
15638
+ name,
15639
+ arguments: args,
15640
+ ...invalidArguments ? { invalidArguments: true } : {},
15641
+ ...typeof provider === "string" ? { provider } : {},
15642
+ ...typeof id === "string" ? { id } : {}
15643
+ });
15644
+ }
15645
+ }
15646
+ return calls;
15647
+ }
15648
+ function captureCompletionReason(records, signal = {}) {
15649
+ if (!records.length) return "no_user_in_turn";
15650
+ const pending = /* @__PURE__ */ new Set();
15651
+ let lastAssistant, lastAssistantIndex = -1, lastToolIndex = -1;
15652
+ for (let i = 0; i < records.length; i++) {
15653
+ const raw = records[i], body2 = captureRecord(raw), metadata2 = info(raw), row2 = object4(raw);
15654
+ const session = row2.sessionId ?? row2.session_id ?? body2.session_id ?? metadata2.sessionID;
15655
+ if (signal.sessionId && session && session !== signal.sessionId) return "session_mismatch";
15656
+ const turn = nativeTurn(raw);
15657
+ if (signal.turnId && turn && turn !== signal.turnId) return "turn_unverified";
15658
+ if (role(raw) === "assistant") {
15659
+ lastAssistant = raw;
15660
+ lastAssistantIndex = i;
15661
+ }
15662
+ const calls = captureToolCalls([raw]);
15663
+ for (const call of calls) {
15664
+ if (call.invalidArguments) return "capture_input_incomplete";
15665
+ pending.add(call.id ?? `unknown:${i}`);
15666
+ lastToolIndex = i;
15667
+ }
15668
+ const content = Array.isArray(parts(raw)) ? parts(raw) : [];
15669
+ for (const part of content) {
15670
+ if (part?.type === "tool_result" && role(raw) !== "assistant" && typeof part.tool_use_id === "string") {
15671
+ pending.delete(part.tool_use_id);
15672
+ lastToolIndex = i;
15673
+ }
15674
+ if (part?.type === "tool" && ["completed", "error"].includes(part.state?.status)) pending.delete(part.callID ?? part.id);
15675
+ }
15676
+ if (["tool", "toolResult"].includes(String(role(raw))) || ["function_call_output", "function_call_result", "custom_tool_call_output"].includes(body2.type)) {
15677
+ pending.delete(body2.tool_call_id ?? body2.toolCallId ?? body2.call_id ?? body2.callId);
15678
+ lastToolIndex = i;
15679
+ }
15680
+ }
15681
+ if (pending.size) return "awaiting_tools";
15682
+ if (!lastAssistant || !captureText(lastAssistant).trim()) return "awaiting_assistant";
15683
+ const body = captureRecord(lastAssistant), metadata = info(lastAssistant), row = object4(lastAssistant);
15684
+ const phase = body.phase ?? row.phase;
15685
+ const finish = metadata.finish ?? body.stop_reason ?? body.finish_reason ?? row.finish_reason;
15686
+ if (metadata.error || body.error || ["tool_use", "tool_calls", "tool-calls", "length", "max_tokens", "error", "aborted"].includes(finish)) return "awaiting_final";
15687
+ if (phase && phase !== "final" && phase !== "final_answer") return "awaiting_final";
15688
+ const canonical = (s) => stripNoiseFromContent(s).replace(/\r\n/g, "\n").trim();
15689
+ if (signal.lastAssistantMessage && canonical(captureText(lastAssistant)) !== canonical(signal.lastAssistantMessage)) return "awaiting_host_final";
15690
+ const sdkFinal = metadata.time?.completed && metadata.finish === "stop";
15691
+ if (metadata.role === "assistant" && !sdkFinal) return "awaiting_final";
15692
+ if (lastAssistantIndex <= lastToolIndex && !sdkFinal) return "awaiting_final";
15693
+ if (signal.completed || signal.lastAssistantMessage || sdkFinal || ["end_turn", "stop"].includes(finish) || phase === "final" || phase === "final_answer") return;
15694
+ return "awaiting_final";
15695
+ }
15696
+
15352
15697
  // ../ctxdb/src/lib/credentials.ts
15353
15698
  init_define_CTXDB_DISTRIBUTION_MANIFEST();
15354
15699
  function apiKeyCredential(apiKey) {
@@ -15818,7 +16163,7 @@ function parseErrorResponse(text3, fallback) {
15818
16163
  init_define_CTXDB_DISTRIBUTION_MANIFEST();
15819
16164
  import { readFileSync as readFileSync5, existsSync as existsSync6, unlinkSync as unlinkSync4 } from "fs";
15820
16165
  import { homedir as homedir5 } from "os";
15821
- import { basename, dirname as dirname11, join as join10 } from "path";
16166
+ import { basename as basename2, dirname as dirname11, join as join10 } from "path";
15822
16167
 
15823
16168
  // ../ctxdb/src/lib/agents.ts
15824
16169
  init_define_CTXDB_DISTRIBUTION_MANIFEST();
@@ -15886,7 +16231,7 @@ function configDir(env = process.env) {
15886
16231
  return dirname11(defaultConfigPath(env));
15887
16232
  }
15888
16233
  function configFileName(env = process.env) {
15889
- return basename(defaultConfigPath(env));
16234
+ return basename2(defaultConfigPath(env));
15890
16235
  }
15891
16236
  var DEFAULT_BASE_URL = "https://api.cn-hangzhou.agentcontext.aliyuncs.com";
15892
16237
  var DEFAULT_USER_ID = "default";
@@ -17038,8 +17383,8 @@ function isString(obj) {
17038
17383
  return _class(obj) === "[object String]";
17039
17384
  }
17040
17385
  var _hasOwnProperty = Object.prototype.hasOwnProperty;
17041
- function has(object4, key) {
17042
- return _hasOwnProperty.call(object4, key);
17386
+ function has(object5, key) {
17387
+ return _hasOwnProperty.call(object5, key);
17043
17388
  }
17044
17389
  function assign(obj) {
17045
17390
  const sources = Array.prototype.slice.call(arguments, 1);
@@ -17445,11 +17790,11 @@ default_rules.code_block = function(tokens, idx, options2, env, slf) {
17445
17790
  };
17446
17791
  default_rules.fence = function(tokens, idx, options2, env, slf) {
17447
17792
  const token = tokens[idx];
17448
- const info = token.info ? unescapeAll(token.info).trim() : "";
17793
+ const info2 = token.info ? unescapeAll(token.info).trim() : "";
17449
17794
  let langName = "";
17450
17795
  let langAttrs = "";
17451
- if (info) {
17452
- const arr = info.split(/(\s+)/g);
17796
+ if (info2) {
17797
+ const arr = info2.split(/(\s+)/g);
17453
17798
  langName = arr[0];
17454
17799
  langAttrs = arr.slice(2).join("");
17455
17800
  }
@@ -17462,7 +17807,7 @@ default_rules.fence = function(tokens, idx, options2, env, slf) {
17462
17807
  if (highlighted.indexOf("<pre") === 0) {
17463
17808
  return highlighted + "\n";
17464
17809
  }
17465
- if (info) {
17810
+ if (info2) {
17466
17811
  const i = token.attrIndex("class");
17467
17812
  const tmpAttrs = token.attrs ? token.attrs.slice() : [];
17468
17813
  if (i < 0) {
@@ -21189,11 +21534,11 @@ function map(array, callback) {
21189
21534
  return result;
21190
21535
  }
21191
21536
  function mapDomain(domain, callback) {
21192
- const parts = domain.split("@");
21537
+ const parts2 = domain.split("@");
21193
21538
  let result = "";
21194
- if (parts.length > 1) {
21195
- result = parts[0] + "@";
21196
- domain = parts[1];
21539
+ if (parts2.length > 1) {
21540
+ result = parts2[0] + "@";
21541
+ domain = parts2[1];
21197
21542
  }
21198
21543
  domain = domain.replace(regexSeparators, ".");
21199
21544
  const labels = domain.split(".");
@@ -21760,8 +22105,8 @@ import { dirname as dirname12, resolve as resolve2, sep as sep2, join as join12
21760
22105
  import { randomUUID } from "crypto";
21761
22106
  import { AsyncLocalStorage } from "async_hooks";
21762
22107
  var skillRoot = () => configDir();
21763
- function privatePath(root, ...parts) {
21764
- const base2 = resolve2(root), target = resolve2(base2, ...parts);
22108
+ function privatePath(root, ...parts2) {
22109
+ const base2 = resolve2(root), target = resolve2(base2, ...parts2);
21765
22110
  if (target !== base2 && !target.startsWith(base2 + sep2)) throw new Error("invalid_state_path");
21766
22111
  let path = base2;
21767
22112
  for (const part of ["", ...target.slice(base2.length + 1).split(sep2).filter(Boolean)]) {
@@ -22045,24 +22390,24 @@ function normalizeSkillRows(agent, rows, sessionId) {
22045
22390
  if (session && session !== sessionId) return [];
22046
22391
  const message = agent === "workbuddy" && row.type === "message" ? row : row.message ?? row.info ?? row;
22047
22392
  const workbuddyTool = agent === "workbuddy" && ["function_call", "function_call_result"].includes(row.type);
22048
- const role = message.role ?? (workbuddyTool ? "assistant" : row.type);
22049
- if (!["user", "assistant", "tool"].includes(role)) return [];
22393
+ const role2 = message.role ?? (workbuddyTool ? "assistant" : row.type);
22394
+ if (!["user", "assistant", "tool"].includes(role2)) return [];
22050
22395
  const id = row.uuid ?? message.id ?? row.id ?? `${ordinal}`;
22051
- const turn = row.turn_id ?? message.turn_id ?? (agent === "opencode" ? role === "user" ? message.id : message.parentID : void 0);
22396
+ const turn = row.turn_id ?? message.turn_id ?? (agent === "opencode" ? role2 === "user" ? message.id : message.parentID : void 0);
22052
22397
  const result = [];
22053
22398
  const item = (payload) => result.push({ type: "response_item", payload });
22054
22399
  const text3 = (value, part) => {
22055
- if (agent === "workbuddy" && row.type === "message" && role === "user") {
22400
+ if (agent === "workbuddy" && row.type === "message" && role2 === "user") {
22056
22401
  if (value.trimStart().startsWith("Stop hook feedback:")) return;
22057
22402
  value = /<user_query>([\s\S]*)<\/user_query>\s*$/.exec(value)?.[1] ?? value;
22058
22403
  }
22059
22404
  item({
22060
22405
  type: "message",
22061
22406
  id: `${id}:${part}`,
22062
- role,
22063
- ...role === "assistant" ? { phase: "final" } : {},
22407
+ role: role2,
22408
+ ...role2 === "assistant" ? { phase: "final" } : {},
22064
22409
  ...turn ? { internal_chat_message_metadata_passthrough: { turn_id: turn } } : {},
22065
- content: [{ type: role === "user" ? "input_text" : "output_text", text: value }]
22410
+ content: [{ type: role2 === "user" ? "input_text" : "output_text", text: value }]
22066
22411
  });
22067
22412
  };
22068
22413
  const call = (callId, name, args) => {
@@ -22094,21 +22439,21 @@ function normalizeSkillRows(agent, rows, sessionId) {
22094
22439
  }
22095
22440
  return result;
22096
22441
  }
22097
- if (role === "tool") {
22442
+ if (role2 === "tool") {
22098
22443
  output(message.tool_call_id, message.content);
22099
22444
  return result;
22100
22445
  }
22101
22446
  const content = row.parts ?? message.content;
22102
22447
  if (typeof content === "string") text3(content, 0);
22103
22448
  if (Array.isArray(content)) {
22104
- const visible = content.filter((block2) => (block2?.type === "text" || agent === "workbuddy" && block2?.type === (role === "user" ? "input_text" : "output_text")) && !block2.synthetic && !block2.ignored && typeof block2.text === "string").map((block2) => block2.text).join("\n");
22449
+ const visible = content.filter((block2) => (block2?.type === "text" || agent === "workbuddy" && block2?.type === (role2 === "user" ? "input_text" : "output_text")) && !block2.synthetic && !block2.ignored && typeof block2.text === "string").map((block2) => block2.text).join("\n");
22105
22450
  if (visible) text3(visible, 0);
22106
22451
  }
22107
22452
  if (Array.isArray(content)) content.forEach((block2) => {
22108
22453
  if (!block2 || block2.synthetic || block2.ignored) return;
22109
22454
  if (block2.type === "tool_use") call(block2.id, block2.name, block2.input);
22110
22455
  if (block2.type === "tool_result") output(block2.tool_use_id, block2.content, block2.is_error);
22111
- if (block2.type === "tool" && role === "assistant") {
22456
+ if (block2.type === "tool" && role2 === "assistant") {
22112
22457
  call(block2.callID, block2.tool, block2.state?.input);
22113
22458
  if (["completed", "error"].includes(block2.state?.status)) output(block2.callID, block2.state.output ?? block2.state.error, block2.state.status === "error");
22114
22459
  }
@@ -23363,7 +23708,7 @@ async function fetchKbCatalogBlock(client, timeoutMs, agent = "opencode") {
23363
23708
  // src/warmup.ts
23364
23709
  init_define_CTXDB_DISTRIBUTION_MANIFEST();
23365
23710
  import { execSync } from "child_process";
23366
- import { basename as basename2 } from "path";
23711
+ import { basename as basename3 } from "path";
23367
23712
  function collectGitSignals(cwd) {
23368
23713
  const result = { branch: "", recentCommits: [] };
23369
23714
  try {
@@ -23393,11 +23738,11 @@ function collectGitSignals(cwd) {
23393
23738
  return result;
23394
23739
  }
23395
23740
  function buildWarmupQuery(cwd, git) {
23396
- const project = basename2(cwd) || "unknown";
23397
- const parts = [`project: ${project}`];
23398
- if (git.branch) parts.push(`branch: ${git.branch}`);
23399
- if (git.recentCommits.length > 0) parts.push(`recent work: ${git.recentCommits.join("; ")}`);
23400
- return parts.join(", ");
23741
+ const project = basename3(cwd) || "unknown";
23742
+ const parts2 = [`project: ${project}`];
23743
+ if (git.branch) parts2.push(`branch: ${git.branch}`);
23744
+ if (git.recentCommits.length > 0) parts2.push(`recent work: ${git.recentCommits.join("; ")}`);
23745
+ return parts2.join(", ");
23401
23746
  }
23402
23747
 
23403
23748
  // src/capture.ts
@@ -23442,9 +23787,9 @@ function toParsedMessage(m, index) {
23442
23787
  if (!m || typeof m !== "object") return null;
23443
23788
  const obj = m;
23444
23789
  if (obj.info && typeof obj.info === "object" && Array.isArray(obj.parts)) {
23445
- const info = obj.info;
23446
- const role = info.role;
23447
- if (role !== "user" && role !== "assistant") return null;
23790
+ const info2 = obj.info;
23791
+ const role2 = info2.role;
23792
+ if (role2 !== "user" && role2 !== "assistant") return null;
23448
23793
  const textChunks = [];
23449
23794
  for (const rawPart of obj.parts) {
23450
23795
  if (!rawPart || typeof rawPart !== "object") continue;
@@ -23455,8 +23800,8 @@ function toParsedMessage(m, index) {
23455
23800
  }
23456
23801
  const content = textChunks.join("\n").trim();
23457
23802
  if (!content) return null;
23458
- const isSummary = role === "assistant" && info.summary === true;
23459
- return { role, content, index, isSummary };
23803
+ const isSummary = role2 === "assistant" && info2.summary === true;
23804
+ return { role: role2, content, index, isSummary };
23460
23805
  }
23461
23806
  if (obj.type === "user") {
23462
23807
  const content = typeof obj.text === "string" ? obj.text.trim() : "";
@@ -23490,7 +23835,13 @@ async function runCapture(messages, cfg, client, timeoutMs, lastFingerprint, ses
23490
23835
  if (!cfg.autoCapture) return { ...EMPTY2, reason: "auto_capture_disabled" };
23491
23836
  if (!cfg.baseUrl) return { ...EMPTY2, reason: "config_incomplete" };
23492
23837
  if (messages.length === 0) return { ...EMPTY2, reason: "empty_transcript" };
23493
- const parsed = toParsedMessages(messages);
23838
+ const current = selectCaptureTurn(messages);
23839
+ const cleanup = detectMemoryCleanup(captureToolCalls(current));
23840
+ if (cleanup.detected) return { ...EMPTY2, reason: "memory_cleanup_skip" };
23841
+ const completionReason = captureCompletionReason(current, { sessionId });
23842
+ if (!current.length) return { ...EMPTY2, reason: "empty_turn_slice" };
23843
+ if (completionReason && completionReason !== "awaiting_assistant") return { ...EMPTY2, reason: completionReason };
23844
+ const parsed = toParsedMessages(current);
23494
23845
  if (parsed.length === 0) return { ...EMPTY2, reason: "transcript_no_text_parts" };
23495
23846
  const turn = selectTurnMessages(parsed);
23496
23847
  if (turn.length === 0) return { ...EMPTY2, reason: "empty_turn_slice" };
@@ -23498,6 +23849,7 @@ async function runCapture(messages, cfg, client, timeoutMs, lastFingerprint, ses
23498
23849
  if (!turn.some((m) => m.role === "assistant")) {
23499
23850
  return { ...EMPTY2, reason: "no_assistant_in_turn" };
23500
23851
  }
23852
+ if (completionReason) return { ...EMPTY2, reason: completionReason };
23501
23853
  const raw = turn.map((m) => ({ role: m.role, content: m.content }));
23502
23854
  const filtered = filterMessagesForExtraction(raw);
23503
23855
  if (filtered.length === 0) return { ...EMPTY2, reason: "all_filtered" };
@@ -23582,9 +23934,9 @@ function pruneSessions(state) {
23582
23934
  for (let i = 0; i < Math.min(overflow, sorted.length); i++) state.delete(sorted[i][0]);
23583
23935
  }
23584
23936
  }
23585
- function extractTextPrompt(parts) {
23937
+ function extractTextPrompt(parts2) {
23586
23938
  const chunks = [];
23587
- for (const p of parts) {
23939
+ for (const p of parts2) {
23588
23940
  if (p.type !== "text") continue;
23589
23941
  if (p.synthetic === true || p.ignored === true) continue;
23590
23942
  if (typeof p.text === "string" && p.text) chunks.push(p.text);