@yhong91/vibetime 0.1.50 → 0.1.52

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 (2) hide show
  1. package/bin/vibetime.mjs +754 -192
  2. package/package.json +1 -1
package/bin/vibetime.mjs CHANGED
@@ -886,7 +886,7 @@ var init_esm = __esm({
886
886
  import { spawn as spawn2, spawnSync } from "node:child_process";
887
887
  import { mkdir as mkdir5, open, rm, stat as stat13, writeFile as writeFile4 } from "node:fs/promises";
888
888
  import os11 from "node:os";
889
- import path24 from "node:path";
889
+ import path25 from "node:path";
890
890
  import { fileURLToPath } from "node:url";
891
891
 
892
892
  // ../shared/src/index.ts
@@ -924,7 +924,7 @@ var TELEMETRY_EVENT_TYPES = [
924
924
  "agent.operation"
925
925
  ];
926
926
  var FILE_ACTIVITY_OPERATIONS = ["read", "search", "create", "write", "edit", "delete"];
927
- var BACKFILL_SOURCE_IDS = ["codex", "claude-code", "claude-cowork", "copilot", "opencode", "pi", "agy", "codebuddy", "qoder", "qoder-cn", "workbuddy", "zcode", "grok-build", "zed"];
927
+ var BACKFILL_SOURCE_IDS = ["codex", "claude-code", "claude-cowork", "copilot", "opencode", "pi", "agy", "codebuddy", "qoder", "qoder-cn", "workbuddy", "zcode", "grok-build", "zed", "kimi-code"];
928
928
  function createWorkspaceId(input) {
929
929
  const basis = input.repoUrl || input.repoRoot || input.projectName || "unknown";
930
930
  return `workspace_${fnv1a(basis)}`;
@@ -2047,7 +2047,7 @@ function claudeStyleFileMetrics(tool, input) {
2047
2047
  }
2048
2048
 
2049
2049
  // src/lib/constants.ts
2050
- var PACKAGE_VERSION = true ? "0.1.50" : "0.1.1";
2050
+ var PACKAGE_VERSION = true ? "0.1.52" : "0.1.1";
2051
2051
  var DEFAULT_API_URL = "http://121.196.224.82:3001";
2052
2052
  var DEFAULT_BACKFILL_BATCH_SIZE = 50;
2053
2053
  var DEFAULT_BACKFILL_BATCH_BYTES = 800 * 1024;
@@ -6935,9 +6935,476 @@ function createGrokBuildAdapter() {
6935
6935
  };
6936
6936
  }
6937
6937
 
6938
+ // src/adapters/kimi-code.ts
6939
+ import { readFile as readFile9 } from "node:fs/promises";
6940
+ import path14 from "node:path";
6941
+ function kimiCodeHome(home, env) {
6942
+ const override = env?.KIMI_CODE_HOME || env?.KIMI_HOME;
6943
+ if (override && override.trim()) {
6944
+ return path14.resolve(override);
6945
+ }
6946
+ return path14.join(home, ".kimi-code");
6947
+ }
6948
+ function kimiCodeSessionsDir(home, env) {
6949
+ return path14.join(kimiCodeHome(home, env), "sessions");
6950
+ }
6951
+ function baseKimiEvent(event) {
6952
+ return {
6953
+ schemaVersion: AGENT_TIME_SCHEMA_VERSION,
6954
+ source: "kimi-code",
6955
+ agent: "kimi-code",
6956
+ workspaceId: createWorkspaceId({ projectName: event.project, repoRoot: event.cwd }),
6957
+ ...event
6958
+ };
6959
+ }
6960
+ function extractTextParts(input) {
6961
+ if (typeof input === "string") {
6962
+ return input;
6963
+ }
6964
+ if (!Array.isArray(input)) {
6965
+ return "";
6966
+ }
6967
+ return input.filter((item) => isPlainObject(item) && item.type === "text").map((item) => stringField(item, "text") || "").join("");
6968
+ }
6969
+ function kimiUsageFromRecord(usage) {
6970
+ const inputOther = numberField(usage, "inputOther") || 0;
6971
+ const output = numberField(usage, "output") || 0;
6972
+ const cacheRead = numberField(usage, "inputCacheRead") || 0;
6973
+ const cacheWrite = numberField(usage, "inputCacheCreation") || 0;
6974
+ const inputTokens = numberField(usage, "input_tokens") || numberField(usage, "input") || 0;
6975
+ const outputTokens = numberField(usage, "output_tokens") || 0;
6976
+ const nonCached = inputOther || inputTokens;
6977
+ const out = output || outputTokens;
6978
+ const total = nonCached + out + cacheRead + cacheWrite;
6979
+ if (total <= 0) {
6980
+ return void 0;
6981
+ }
6982
+ return {
6983
+ tokensInput: nonCached + cacheRead + cacheWrite || void 0,
6984
+ tokensOutput: out || void 0,
6985
+ tokensCacheReadInput: cacheRead || void 0,
6986
+ tokensCacheCreationInput: cacheWrite || void 0,
6987
+ tokensCachedInput: cacheRead + cacheWrite || void 0,
6988
+ tokensTotal: total,
6989
+ modelCalls: 1
6990
+ };
6991
+ }
6992
+ function normalizeTurnId(raw) {
6993
+ if (typeof raw === "number" && Number.isFinite(raw)) {
6994
+ return `turn_${raw}`;
6995
+ }
6996
+ if (typeof raw === "string" && raw.trim()) {
6997
+ return raw.startsWith("turn_") ? raw : `turn_${raw}`;
6998
+ }
6999
+ return void 0;
7000
+ }
7001
+ function sessionIdFromWirePath(filePath) {
7002
+ const normalized = filePath.replaceAll("\\", "/");
7003
+ const match = normalized.match(/\/(session_[^/]+)\/agents\/[^/]+\/wire\.jsonl$/);
7004
+ return match?.[1];
7005
+ }
7006
+ async function readSessionState(filePath) {
7007
+ const sessionDir = path14.dirname(path14.dirname(path14.dirname(filePath)));
7008
+ const statePath = path14.join(sessionDir, "state.json");
7009
+ try {
7010
+ const text = await readFile9(statePath, "utf8");
7011
+ const raw = JSON.parse(text);
7012
+ if (!isPlainObject(raw)) {
7013
+ return {};
7014
+ }
7015
+ return {
7016
+ sessionId: stringField(raw, "id"),
7017
+ cwd: stringField(raw, "cwd"),
7018
+ title: stringField(raw, "title")
7019
+ };
7020
+ } catch {
7021
+ return {};
7022
+ }
7023
+ }
7024
+ async function parseKimiCodeSessionFile(filePath, options) {
7025
+ if (path14.basename(filePath) !== "wire.jsonl") {
7026
+ return [];
7027
+ }
7028
+ const text = await readFile9(filePath, "utf8");
7029
+ const lines = text.split("\n").filter(Boolean);
7030
+ const stateMeta = await readSessionState(filePath);
7031
+ let sessionId = stateMeta.sessionId || sessionIdFromWirePath(filePath);
7032
+ let cwd = stateMeta.cwd;
7033
+ let project = cwd ? path14.basename(cwd) : void 0;
7034
+ let model;
7035
+ let provider;
7036
+ let reasoningEffort;
7037
+ const pendingToolCalls = /* @__PURE__ */ new Map();
7038
+ const pendingPermissions = /* @__PURE__ */ new Map();
7039
+ let sawUsageRecord = false;
7040
+ const state = new SessionParserState(filePath, options, (event) => baseKimiEvent({ ...event, cwd, project, model, provider }));
7041
+ if (sessionId) {
7042
+ state.sessionId = sessionId;
7043
+ }
7044
+ const push = (event, ln, topType) => {
7045
+ state.push(
7046
+ {
7047
+ ...event,
7048
+ sessionId: event.sessionId || sessionId,
7049
+ workspaceId: event.workspaceId || createWorkspaceId({ projectName: project, repoRoot: cwd })
7050
+ },
7051
+ ln,
7052
+ topType || event.type,
7053
+ event.type
7054
+ );
7055
+ };
7056
+ for (const [index, line] of lines.entries()) {
7057
+ const lineNumber = index + 1;
7058
+ const raw = parseJsonLine(line);
7059
+ if (!raw) {
7060
+ continue;
7061
+ }
7062
+ const entryType = stringField(raw, "type");
7063
+ const ts = timestampFrom(raw.time) || timestampFrom(raw.created_at) || timestampFrom(raw.timestamp);
7064
+ if (!ts || !entryType) {
7065
+ continue;
7066
+ }
7067
+ if (entryType === "metadata") {
7068
+ state.ensureSessionStarted(ts, lineNumber, entryType);
7069
+ continue;
7070
+ }
7071
+ if (entryType === "profile.bind") {
7072
+ state.ensureSessionStarted(ts, lineNumber, entryType);
7073
+ model = stringField(raw, "modelAlias") || stringField(raw, "model") || model;
7074
+ reasoningEffort = stringField(raw, "thinkingEffort") || reasoningEffort;
7075
+ const disclosure = objectField(raw, "environmentDisclosure");
7076
+ const disclosedCwd = stringField(disclosure, "cwd");
7077
+ if (disclosedCwd) {
7078
+ cwd = disclosedCwd;
7079
+ project = path14.basename(disclosedCwd);
7080
+ }
7081
+ continue;
7082
+ }
7083
+ if (entryType === "turn.prompt") {
7084
+ state.ensureSessionStarted(ts, lineNumber, entryType);
7085
+ if (isTurnIdle(state.currentTurnLastEventAt) || state.currentTurnId) {
7086
+ state.closeTurn(ts, lineNumber, entryType);
7087
+ }
7088
+ const nextOrdinal = state.currentTurnId ? Number.parseInt(state.currentTurnId.replace(/^turn_/, ""), 10) : Number.NaN;
7089
+ const turnOrdinal = Number.isFinite(nextOrdinal) ? nextOrdinal + 1 : 0;
7090
+ const turnId = `turn_${turnOrdinal}`;
7091
+ state.startTurn(turnId, ts);
7092
+ push(baseKimiEvent({
7093
+ ts,
7094
+ type: "turn.started",
7095
+ sessionId,
7096
+ turnId,
7097
+ cwd,
7098
+ project,
7099
+ model,
7100
+ provider,
7101
+ confidence: "exact"
7102
+ }), lineNumber, entryType);
7103
+ const promptText = extractTextParts(raw.input);
7104
+ push(baseKimiEvent({
7105
+ ts,
7106
+ type: "prompt.submitted",
7107
+ sessionId,
7108
+ turnId,
7109
+ cwd,
7110
+ project,
7111
+ model,
7112
+ provider,
7113
+ confidence: "exact",
7114
+ metrics: {
7115
+ prompts: 1,
7116
+ promptChars: promptText.length || void 0
7117
+ },
7118
+ refs: stringRefs({
7119
+ promptHash: promptText ? `sha256:${createStableHash(promptText)}` : void 0
7120
+ })
7121
+ }), lineNumber, entryType);
7122
+ continue;
7123
+ }
7124
+ if (entryType === "llm.request") {
7125
+ state.ensureSessionStarted(ts, lineNumber, entryType);
7126
+ model = stringField(raw, "modelAlias") || stringField(raw, "model") || model;
7127
+ provider = stringField(raw, "provider") || provider;
7128
+ reasoningEffort = stringField(raw, "thinkingEffort") || reasoningEffort;
7129
+ const turnStep = stringField(raw, "turnStep");
7130
+ if (turnStep && !state.currentTurnId) {
7131
+ const turnPart = turnStep.split(".")[0];
7132
+ const turnId = normalizeTurnId(turnPart);
7133
+ if (turnId) {
7134
+ state.startTurn(turnId, ts);
7135
+ }
7136
+ }
7137
+ continue;
7138
+ }
7139
+ if (entryType === "usage.record") {
7140
+ state.ensureSessionStarted(ts, lineNumber, entryType);
7141
+ sawUsageRecord = true;
7142
+ model = stringField(raw, "model") || model;
7143
+ const usage = objectField(raw, "usage");
7144
+ const metrics = kimiUsageFromRecord(usage);
7145
+ if (metrics) {
7146
+ if (reasoningEffort) {
7147
+ metrics.reasoningEffort = reasoningEffort;
7148
+ }
7149
+ push(baseKimiEvent({
7150
+ ts,
7151
+ type: "model.usage",
7152
+ sessionId,
7153
+ turnId: state.currentTurnId,
7154
+ cwd,
7155
+ project,
7156
+ model,
7157
+ provider,
7158
+ confidence: "exact",
7159
+ metrics
7160
+ }), lineNumber, entryType);
7161
+ }
7162
+ continue;
7163
+ }
7164
+ if (entryType === "context.append_loop_event") {
7165
+ state.ensureSessionStarted(ts, lineNumber, entryType);
7166
+ const loopEvent = objectField(raw, "event");
7167
+ const loopType = stringField(loopEvent, "type");
7168
+ const turnId = normalizeTurnId(loopEvent.turnId) || state.currentTurnId;
7169
+ if (turnId && turnId !== state.currentTurnId) {
7170
+ if (state.currentTurnId) {
7171
+ state.closeTurn(ts, lineNumber, entryType);
7172
+ }
7173
+ state.startTurn(turnId, ts);
7174
+ }
7175
+ if (loopType === "tool.call") {
7176
+ const toolCallId = stringField(loopEvent, "toolCallId") || stringField(loopEvent, "uuid");
7177
+ const toolName = stringField(loopEvent, "name") || "tool";
7178
+ const toolInput = isPlainObject(loopEvent.args) ? loopEvent.args : {};
7179
+ if (toolCallId) {
7180
+ pendingToolCalls.set(toolCallId, {
7181
+ toolName,
7182
+ startedAt: ts,
7183
+ turnId: turnId || state.currentTurnId,
7184
+ input: toolInput
7185
+ });
7186
+ }
7187
+ push(baseKimiEvent({
7188
+ ts,
7189
+ type: "tool.started",
7190
+ operation: `${toolName} started`,
7191
+ sessionId,
7192
+ turnId: turnId || state.currentTurnId,
7193
+ cwd,
7194
+ project,
7195
+ model,
7196
+ provider,
7197
+ tool: toolName,
7198
+ confidence: "exact",
7199
+ metrics: { toolCalls: 1 },
7200
+ refs: stringRefs({
7201
+ sourceId: toolCallId,
7202
+ commandHash: toolName.toLowerCase() === "bash" && stringField(toolInput, "command") ? createStableHash(stringField(toolInput, "command")) : void 0
7203
+ })
7204
+ }), lineNumber, entryType);
7205
+ const fileActivities = claudeStyleToolFileActivities(
7206
+ toolName,
7207
+ toolInput,
7208
+ ts,
7209
+ cwd
7210
+ );
7211
+ if (fileActivities.length > 0) {
7212
+ push(baseKimiEvent({
7213
+ ts,
7214
+ type: eventTypeFromFileActivities(fileActivities),
7215
+ operation: `${toolName} file activity`,
7216
+ sessionId,
7217
+ turnId: turnId || state.currentTurnId,
7218
+ cwd,
7219
+ project,
7220
+ model,
7221
+ provider,
7222
+ tool: toolName,
7223
+ confidence: "derived",
7224
+ fileActivities,
7225
+ metrics: summarizeFileActivities(fileActivities),
7226
+ refs: stringRefs({ sourceId: toolCallId })
7227
+ }), lineNumber, entryType);
7228
+ }
7229
+ continue;
7230
+ }
7231
+ if (loopType === "tool.result") {
7232
+ const toolCallId = stringField(loopEvent, "toolCallId");
7233
+ const pending = toolCallId ? pendingToolCalls.get(toolCallId) : void 0;
7234
+ if (toolCallId) {
7235
+ pendingToolCalls.delete(toolCallId);
7236
+ }
7237
+ const result = objectField(loopEvent, "result");
7238
+ const isError = Boolean(result.isError);
7239
+ const toolName = pending?.toolName || "tool";
7240
+ const durationMs = pending ? durationMsBetween(pending.startedAt, ts) : void 0;
7241
+ push(baseKimiEvent({
7242
+ ts,
7243
+ type: isError ? "tool.failed" : "tool.completed",
7244
+ operation: isError ? `${toolName} failed` : `${toolName} completed`,
7245
+ sessionId,
7246
+ turnId: pending?.turnId || turnId || state.currentTurnId,
7247
+ cwd,
7248
+ project,
7249
+ model,
7250
+ provider,
7251
+ tool: toolName,
7252
+ success: !isError,
7253
+ confidence: "exact",
7254
+ metrics: {
7255
+ toolDurationMs: durationMs,
7256
+ durationMs
7257
+ },
7258
+ refs: stringRefs({ sourceId: toolCallId })
7259
+ }), lineNumber, entryType);
7260
+ if (toolName.toLowerCase() === "bash") {
7261
+ push(baseKimiEvent({
7262
+ ts,
7263
+ type: isError ? "command.failed" : "command.completed",
7264
+ operation: "command completed",
7265
+ sessionId,
7266
+ turnId: pending?.turnId || turnId || state.currentTurnId,
7267
+ cwd,
7268
+ project,
7269
+ model,
7270
+ provider,
7271
+ tool: "Bash",
7272
+ success: !isError,
7273
+ confidence: "derived",
7274
+ metrics: {
7275
+ commandCalls: 1,
7276
+ commandDurationMs: durationMs,
7277
+ durationMs
7278
+ },
7279
+ refs: stringRefs({
7280
+ sourceId: toolCallId,
7281
+ commandHash: pending?.input.command ? `sha256:${createStableHash(String(pending.input.command))}` : void 0
7282
+ })
7283
+ }), lineNumber, entryType);
7284
+ }
7285
+ continue;
7286
+ }
7287
+ if (loopType === "step.end") {
7288
+ if (!sawUsageRecord) {
7289
+ const streamMs = numberField(loopEvent, "llmStreamDurationMs") || numberField(loopEvent, "llmServerDecodeMs");
7290
+ const usage = objectField(loopEvent, "usage");
7291
+ const metrics = kimiUsageFromRecord(usage);
7292
+ if (metrics) {
7293
+ if (streamMs) {
7294
+ metrics.modelDurationMs = streamMs;
7295
+ }
7296
+ if (reasoningEffort) {
7297
+ metrics.reasoningEffort = reasoningEffort;
7298
+ }
7299
+ push(baseKimiEvent({
7300
+ ts,
7301
+ type: "model.usage",
7302
+ sessionId,
7303
+ turnId: turnId || state.currentTurnId,
7304
+ cwd,
7305
+ project,
7306
+ model,
7307
+ provider,
7308
+ confidence: "exact",
7309
+ metrics
7310
+ }), lineNumber, entryType);
7311
+ }
7312
+ }
7313
+ continue;
7314
+ }
7315
+ continue;
7316
+ }
7317
+ if (entryType === "interaction.request") {
7318
+ state.ensureSessionStarted(ts, lineNumber, entryType);
7319
+ const requestId = stringField(raw, "id") || stringField(raw, "toolCallId");
7320
+ const request2 = objectField(raw, "request");
7321
+ const toolName = stringField(request2, "toolName") || stringField(raw, "toolName");
7322
+ const turnId = normalizeTurnId(request2.turnId) || state.currentTurnId;
7323
+ if (requestId) {
7324
+ pendingPermissions.set(requestId, { toolName, startedAt: ts, turnId });
7325
+ }
7326
+ push(baseKimiEvent({
7327
+ ts,
7328
+ type: "permission.requested",
7329
+ operation: toolName ? `${toolName} permission` : "permission requested",
7330
+ sessionId,
7331
+ turnId,
7332
+ cwd,
7333
+ project,
7334
+ model,
7335
+ provider,
7336
+ tool: toolName,
7337
+ confidence: "exact",
7338
+ refs: stringRefs({ sourceId: requestId })
7339
+ }), lineNumber, entryType);
7340
+ continue;
7341
+ }
7342
+ if (entryType === "interaction.resolved") {
7343
+ state.ensureSessionStarted(ts, lineNumber, entryType);
7344
+ const requestId = stringField(raw, "id");
7345
+ const pending = requestId ? pendingPermissions.get(requestId) : void 0;
7346
+ if (requestId) {
7347
+ pendingPermissions.delete(requestId);
7348
+ }
7349
+ const response = objectField(raw, "response");
7350
+ const decision = stringField(response, "decision") || stringField(raw, "decision");
7351
+ const granted = decision === "approved" || decision === "allow" || decision === "granted";
7352
+ const denied = decision === "denied" || decision === "reject" || decision === "rejected";
7353
+ push(baseKimiEvent({
7354
+ ts,
7355
+ type: granted ? "permission.granted" : denied ? "permission.denied" : "permission.resolved",
7356
+ operation: decision ? `permission ${decision}` : "permission resolved",
7357
+ sessionId,
7358
+ turnId: pending?.turnId || state.currentTurnId,
7359
+ cwd,
7360
+ project,
7361
+ model,
7362
+ provider,
7363
+ tool: pending?.toolName,
7364
+ success: granted ? true : denied ? false : void 0,
7365
+ confidence: "exact",
7366
+ metrics: {
7367
+ durationMs: pending ? durationMsBetween(pending.startedAt, ts) : void 0,
7368
+ approvalWaitMs: pending ? durationMsBetween(pending.startedAt, ts) : void 0
7369
+ },
7370
+ refs: stringRefs({ sourceId: requestId })
7371
+ }), lineNumber, entryType);
7372
+ continue;
7373
+ }
7374
+ }
7375
+ if (isTurnIdle(state.currentTurnLastEventAt)) {
7376
+ state.closeTurn(state.currentTurnLastEventAt, lines.length);
7377
+ }
7378
+ return state.events.filter((event) => matchesBackfillFilters(event, options));
7379
+ }
7380
+ function createKimiCodeAdapter() {
7381
+ return {
7382
+ id: "kimi-code",
7383
+ label: "Kimi Code",
7384
+ agentName: "kimi-code",
7385
+ kind: "agent",
7386
+ detectPath(home, env) {
7387
+ return kimiCodeHome(home, env);
7388
+ },
7389
+ installedPath(home, env) {
7390
+ return path14.join(kimiCodeHome(home, env), "vibetime-marker");
7391
+ },
7392
+ async isInstalled() {
7393
+ return false;
7394
+ },
7395
+ installEntries(_home, _env) {
7396
+ return [];
7397
+ },
7398
+ sourcePaths(home, env) {
7399
+ return [kimiCodeSessionsDir(home, env)];
7400
+ },
7401
+ parseSessionFile: parseKimiCodeSessionFile
7402
+ };
7403
+ }
7404
+
6938
7405
  // src/adapters/opencode.ts
6939
7406
  import os6 from "node:os";
6940
- import path14 from "node:path";
7407
+ import path15 from "node:path";
6941
7408
  async function parseOpenCodeSessionFile(dbPath, options) {
6942
7409
  const { DatabaseSync } = await import("node:sqlite");
6943
7410
  if (!dbPath.endsWith(".db")) {
@@ -6994,7 +7461,7 @@ async function parseOpenCodeSessionFile(dbPath, options) {
6994
7461
  const rawSessionId = session.id;
6995
7462
  const sessionId = rootIdByRawId.get(rawSessionId) || rawSessionId;
6996
7463
  const cwd = session.directory || session.path || void 0;
6997
- const project = cwd ? path14.basename(cwd) : void 0;
7464
+ const project = cwd ? path15.basename(cwd) : void 0;
6998
7465
  const sessionTs = msToIso(session.time_created);
6999
7466
  events.push(baseOpenCodeEvent({
7000
7467
  ts: sessionTs,
@@ -7102,7 +7569,7 @@ async function parseOpenCodeSessionFile(dbPath, options) {
7102
7569
  const provider = currentProvider;
7103
7570
  const pathObj = objectField(info, "path");
7104
7571
  const assistantCwd = stringField(pathObj, "cwd") || cwd;
7105
- const assistantProject = assistantCwd ? path14.basename(assistantCwd) : project;
7572
+ const assistantProject = assistantCwd ? path15.basename(assistantCwd) : project;
7106
7573
  const completedTs = numberField(objectField(info, "time"), "completed");
7107
7574
  const createdTs = timeCreated;
7108
7575
  const tokens = opencodeUsageFromInfo(info);
@@ -7373,18 +7840,18 @@ function opencodeUsageFromInfo(info) {
7373
7840
  function opencodeConfigDir(home, env) {
7374
7841
  const override = env?.OPENCODE_CONFIG_DIR;
7375
7842
  if (override && override.trim()) {
7376
- return path14.resolve(override);
7843
+ return path15.resolve(override);
7377
7844
  }
7378
7845
  const xdgConfig = env?.XDG_CONFIG_HOME;
7379
7846
  if (xdgConfig && xdgConfig.trim()) {
7380
- return path14.join(path14.resolve(xdgConfig), "opencode");
7847
+ return path15.join(path15.resolve(xdgConfig), "opencode");
7381
7848
  }
7382
- return path14.join(home, ".config", "opencode");
7849
+ return path15.join(home, ".config", "opencode");
7383
7850
  }
7384
7851
  function opencodeDataCandidates(home, env) {
7385
7852
  const xdgData = env?.XDG_DATA_HOME;
7386
- const primary = xdgData && xdgData.trim() ? path14.join(path14.resolve(xdgData), "opencode", "opencode.db") : path14.join(home, ".local", "share", "opencode", "opencode.db");
7387
- return [primary, path14.join(home, ".opencode", "opencode.db")];
7853
+ const primary = xdgData && xdgData.trim() ? path15.join(path15.resolve(xdgData), "opencode", "opencode.db") : path15.join(home, ".local", "share", "opencode", "opencode.db");
7854
+ return [primary, path15.join(home, ".opencode", "opencode.db")];
7388
7855
  }
7389
7856
  async function opencodeBackfillFiles(sourceRoot, home = os6.homedir(), env) {
7390
7857
  const { stat: stat14 } = await import("node:fs/promises");
@@ -7474,12 +7941,12 @@ function createOpenCodeAdapter() {
7474
7941
  return opencodeConfigDir(home, env);
7475
7942
  },
7476
7943
  installedPath(home, env) {
7477
- return path14.join(opencodeConfigDir(home, env), PLUGIN_PATH);
7944
+ return path15.join(opencodeConfigDir(home, env), PLUGIN_PATH);
7478
7945
  },
7479
7946
  async isInstalled(home, env) {
7480
7947
  try {
7481
7948
  const { pathExists: pathExists2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
7482
- return await pathExists2(path14.join(opencodeConfigDir(home, env), PLUGIN_PATH)) || await pathExists2(path14.join(".opencode", PLUGIN_PATH));
7949
+ return await pathExists2(path15.join(opencodeConfigDir(home, env), PLUGIN_PATH)) || await pathExists2(path15.join(".opencode", PLUGIN_PATH));
7483
7950
  } catch {
7484
7951
  return false;
7485
7952
  }
@@ -7487,7 +7954,7 @@ function createOpenCodeAdapter() {
7487
7954
  installEntries(home, env) {
7488
7955
  return [{
7489
7956
  kind: "file",
7490
- path: path14.join(opencodeConfigDir(home, env), PLUGIN_PATH),
7957
+ path: path15.join(opencodeConfigDir(home, env), PLUGIN_PATH),
7491
7958
  content: opencodePluginContent()
7492
7959
  }];
7493
7960
  },
@@ -7499,12 +7966,12 @@ function createOpenCodeAdapter() {
7499
7966
  }
7500
7967
 
7501
7968
  // src/adapters/pi.ts
7502
- import { readFile as readFile9 } from "node:fs/promises";
7503
- import path15 from "node:path";
7969
+ import { readFile as readFile10 } from "node:fs/promises";
7970
+ import path16 from "node:path";
7504
7971
  function parsePiSubagentLink(filePath, headerParentSession) {
7505
7972
  if (headerParentSession) {
7506
- const parentFile = path15.isAbsolute(headerParentSession) ? headerParentSession : void 0;
7507
- const parentSessionId2 = parentFile ? path15.basename(parentFile, ".jsonl") : headerParentSession;
7973
+ const parentFile = path16.isAbsolute(headerParentSession) ? headerParentSession : void 0;
7974
+ const parentSessionId2 = parentFile ? path16.basename(parentFile, ".jsonl") : headerParentSession;
7508
7975
  return { parentSessionId: parentSessionId2, parentSessionFile: parentFile, explicit: true };
7509
7976
  }
7510
7977
  const normalized = filePath.replaceAll("\\", "/");
@@ -7517,20 +7984,20 @@ function parsePiSubagentLink(filePath, headerParentSession) {
7517
7984
  return void 0;
7518
7985
  }
7519
7986
  const parentSessionId = parentBasename.endsWith(".jsonl") ? parentBasename.slice(0, -".jsonl".length) : parentBasename;
7520
- const parentDir = path15.dirname(path15.dirname(path15.dirname(filePath)));
7521
- const parentSessionFile = path15.join(path15.dirname(parentDir), `${parentBasename}.jsonl`);
7987
+ const parentDir = path16.dirname(path16.dirname(path16.dirname(filePath)));
7988
+ const parentSessionFile = path16.join(path16.dirname(parentDir), `${parentBasename}.jsonl`);
7522
7989
  return { parentSessionId, parentSessionFile, explicit: false };
7523
7990
  }
7524
7991
  async function resolveParentContext(link, options) {
7525
7992
  if (link.parentSessionFile) {
7526
7993
  try {
7527
- const text = await readFile9(link.parentSessionFile, "utf8");
7994
+ const text = await readFile10(link.parentSessionFile, "utf8");
7528
7995
  const firstLine = text.split("\n").find((line) => line.trim().length > 0);
7529
7996
  const raw = firstLine ? parseJsonLine(firstLine) : void 0;
7530
7997
  if (raw) {
7531
7998
  const id = stringField(raw, "id");
7532
7999
  const cwd = stringField(raw, "cwd");
7533
- const project = cwd ? path15.basename(cwd) : void 0;
8000
+ const project = cwd ? path16.basename(cwd) : void 0;
7534
8001
  if (id || cwd || project) {
7535
8002
  return { sessionId: id, cwd, project };
7536
8003
  }
@@ -7575,7 +8042,7 @@ function rebuildEventIdentity2(event) {
7575
8042
  };
7576
8043
  }
7577
8044
  async function parsePiSessionFile(filePath, options) {
7578
- const text = await readFile9(filePath, "utf8");
8045
+ const text = await readFile10(filePath, "utf8");
7579
8046
  const lines = text.split("\n").filter(Boolean);
7580
8047
  let sessionId;
7581
8048
  let cwd;
@@ -7607,7 +8074,7 @@ async function parsePiSessionFile(filePath, options) {
7607
8074
  sessionId = stringField(raw, "id") || state.sessionId;
7608
8075
  state.sessionId = sessionId || state.sessionId;
7609
8076
  cwd = stringField(raw, "cwd") || cwd;
7610
- project = cwd ? path15.basename(cwd) : project;
8077
+ project = cwd ? path16.basename(cwd) : project;
7611
8078
  headerParentSession = stringField(raw, "parentSession") || headerParentSession;
7612
8079
  continue;
7613
8080
  }
@@ -8040,16 +8507,16 @@ export default function (pi: ExtensionAPI) {
8040
8507
  function piAgentDir(home, env) {
8041
8508
  const override = env?.PI_CODING_AGENT_DIR;
8042
8509
  if (override && override.trim()) {
8043
- return path15.resolve(override);
8510
+ return path16.resolve(override);
8044
8511
  }
8045
- return path15.join(home, ".pi", "agent");
8512
+ return path16.join(home, ".pi", "agent");
8046
8513
  }
8047
8514
  function piSessionDir(home, env) {
8048
8515
  const override = env?.PI_CODING_AGENT_SESSION_DIR;
8049
8516
  if (override && override.trim()) {
8050
- return path15.resolve(override);
8517
+ return path16.resolve(override);
8051
8518
  }
8052
- return path15.join(piAgentDir(home, env), "sessions");
8519
+ return path16.join(piAgentDir(home, env), "sessions");
8053
8520
  }
8054
8521
  function createPiAdapter() {
8055
8522
  return {
@@ -8061,12 +8528,12 @@ function createPiAdapter() {
8061
8528
  return piAgentDir(home, env);
8062
8529
  },
8063
8530
  installedPath(home, env) {
8064
- return path15.join(piAgentDir(home, env), "extensions", "vibetime.ts");
8531
+ return path16.join(piAgentDir(home, env), "extensions", "vibetime.ts");
8065
8532
  },
8066
8533
  async isInstalled(home, env) {
8067
8534
  try {
8068
8535
  const { pathExists: pathExists2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
8069
- return await pathExists2(path15.join(piAgentDir(home, env), "extensions", "vibetime.ts"));
8536
+ return await pathExists2(path16.join(piAgentDir(home, env), "extensions", "vibetime.ts"));
8070
8537
  } catch {
8071
8538
  return false;
8072
8539
  }
@@ -8074,7 +8541,7 @@ function createPiAdapter() {
8074
8541
  installEntries(home, env) {
8075
8542
  return [{
8076
8543
  kind: "file",
8077
- path: path15.join(piAgentDir(home, env), "extensions", "vibetime.ts"),
8544
+ path: path16.join(piAgentDir(home, env), "extensions", "vibetime.ts"),
8078
8545
  content: piExtensionContent()
8079
8546
  }];
8080
8547
  },
@@ -8086,14 +8553,14 @@ function createPiAdapter() {
8086
8553
  }
8087
8554
 
8088
8555
  // src/adapters/qoder-cn.ts
8089
- import { readdir as readdir7, readFile as readFile10, stat as stat8 } from "node:fs/promises";
8556
+ import { readdir as readdir7, readFile as readFile11, stat as stat8 } from "node:fs/promises";
8090
8557
  import os8 from "node:os";
8091
- import path17 from "node:path";
8558
+ import path18 from "node:path";
8092
8559
 
8093
8560
  // src/adapters/qoder-local-db.ts
8094
8561
  import { access } from "node:fs/promises";
8095
8562
  import os7 from "node:os";
8096
- import path16 from "node:path";
8563
+ import path17 from "node:path";
8097
8564
  function takeQoderDbModelCall(calls, requestId, blockStart) {
8098
8565
  if (requestId) {
8099
8566
  const call = calls.byRequestId.get(requestId)?.shift();
@@ -8112,12 +8579,12 @@ function takeQoderDbModelCall(calls, requestId, blockStart) {
8112
8579
  }
8113
8580
  function appDataRoot(appDirName, home = os7.homedir()) {
8114
8581
  if (process.platform === "darwin") {
8115
- return path16.join(home, "Library", "Application Support", appDirName);
8582
+ return path17.join(home, "Library", "Application Support", appDirName);
8116
8583
  }
8117
8584
  if (process.platform === "win32") {
8118
- return path16.join(process.env.APPDATA || path16.join(home, "AppData", "Roaming"), appDirName);
8585
+ return path17.join(process.env.APPDATA || path17.join(home, "AppData", "Roaming"), appDirName);
8119
8586
  }
8120
- return path16.join(home, ".config", appDirName);
8587
+ return path17.join(home, ".config", appDirName);
8121
8588
  }
8122
8589
  function qoderLocalDbCandidates(appDirName) {
8123
8590
  const candidates = [];
@@ -8127,8 +8594,8 @@ function qoderLocalDbCandidates(appDirName) {
8127
8594
  }
8128
8595
  const configRoot = appDataRoot(appDirName);
8129
8596
  candidates.push(
8130
- path16.join(configRoot, "SharedClientCache", "cache", "db", "local.db"),
8131
- path16.join(configRoot, "SharedClientCache", "db", "local.db")
8597
+ path17.join(configRoot, "SharedClientCache", "cache", "db", "local.db"),
8598
+ path17.join(configRoot, "SharedClientCache", "db", "local.db")
8132
8599
  );
8133
8600
  return candidates;
8134
8601
  }
@@ -8137,7 +8604,7 @@ async function loadQoderIdeModelCatalog(appDirName, home) {
8137
8604
  try {
8138
8605
  const { DatabaseSync } = await import("node:sqlite");
8139
8606
  const db = new DatabaseSync(
8140
- path16.join(appDataRoot(appDirName, home), "User", "globalStorage", "state.vscdb"),
8607
+ path17.join(appDataRoot(appDirName, home), "User", "globalStorage", "state.vscdb"),
8141
8608
  { readOnly: true }
8142
8609
  );
8143
8610
  try {
@@ -8279,7 +8746,7 @@ function resolveSessionPreferredModel(db, sessionId, modelMap) {
8279
8746
 
8280
8747
  // src/adapters/qoder-cn.ts
8281
8748
  function parseQoderCnPaths(filePath) {
8282
- const parts = filePath.split(path17.sep);
8749
+ const parts = filePath.split(path18.sep);
8283
8750
  const subagentsIdx = parts.lastIndexOf("subagents");
8284
8751
  let sessionId = "";
8285
8752
  let projectName = "";
@@ -8289,17 +8756,17 @@ function parseQoderCnPaths(filePath) {
8289
8756
  sessionId = parts[subagentsIdx - 1];
8290
8757
  projectName = parts[subagentsIdx - 2];
8291
8758
  const projectsIdx = parts.lastIndexOf("projects");
8292
- configDir2 = parts.slice(0, projectsIdx).join(path17.sep);
8293
- mainTranscriptPath = [...parts.slice(0, subagentsIdx - 1), `${sessionId}.jsonl`].join(path17.sep);
8759
+ configDir2 = parts.slice(0, projectsIdx).join(path18.sep);
8760
+ mainTranscriptPath = [...parts.slice(0, subagentsIdx - 1), `${sessionId}.jsonl`].join(path18.sep);
8294
8761
  } else {
8295
8762
  const filename = parts.at(-1) || "";
8296
- sessionId = path17.basename(filename, ".jsonl");
8763
+ sessionId = path18.basename(filename, ".jsonl");
8297
8764
  projectName = parts.at(-2) || "";
8298
8765
  if (projectName === "transcript") {
8299
8766
  projectName = parts.at(-3) || "";
8300
8767
  }
8301
8768
  const projectsIdx = parts.lastIndexOf("projects");
8302
- configDir2 = parts.slice(0, projectsIdx).join(path17.sep);
8769
+ configDir2 = parts.slice(0, projectsIdx).join(path18.sep);
8303
8770
  }
8304
8771
  return { configDir: configDir2, projectName, sessionId, mainTranscriptPath };
8305
8772
  }
@@ -8322,7 +8789,7 @@ function rebuildEventIdentity3(event) {
8322
8789
  }
8323
8790
  async function parseModelNamesFromDynamicTexts(dynamicTextsPath) {
8324
8791
  try {
8325
- const content = await readFile10(dynamicTextsPath, "utf8");
8792
+ const content = await readFile11(dynamicTextsPath, "utf8");
8326
8793
  const json = JSON.parse(content);
8327
8794
  const texts = json.texts || {};
8328
8795
  const map = {};
@@ -8338,10 +8805,10 @@ async function parseModelNamesFromDynamicTexts(dynamicTextsPath) {
8338
8805
  }
8339
8806
  }
8340
8807
  async function loadQoderCnModelNames(configDir2, home) {
8341
- const map = await parseModelNamesFromDynamicTexts(path17.join(configDir2, ".auth", "dynamic-texts.json"));
8808
+ const map = await parseModelNamesFromDynamicTexts(path18.join(configDir2, ".auth", "dynamic-texts.json"));
8342
8809
  const siblingConfigDir = configDir2.replace(/\.qoder-cn$/, ".qoder");
8343
8810
  if (siblingConfigDir !== configDir2) {
8344
- const siblingMap = await parseModelNamesFromDynamicTexts(path17.join(siblingConfigDir, ".auth", "dynamic-texts.json"));
8811
+ const siblingMap = await parseModelNamesFromDynamicTexts(path18.join(siblingConfigDir, ".auth", "dynamic-texts.json"));
8345
8812
  for (const [key, val] of Object.entries(siblingMap)) {
8346
8813
  if (!(key in map)) {
8347
8814
  map[key] = val;
@@ -8360,7 +8827,7 @@ async function loadQoderCnModelNames(configDir2, home) {
8360
8827
  }
8361
8828
  async function loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMap) {
8362
8829
  const { configDir: configDir2, projectName, sessionId } = parseQoderCnPaths(filePath);
8363
- const segmentsPath = path17.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
8830
+ const segmentsPath = path18.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
8364
8831
  const modelCalls = [];
8365
8832
  try {
8366
8833
  const files = await readdir7(segmentsPath);
@@ -8368,7 +8835,7 @@ async function loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMa
8368
8835
  if (!file.endsWith(".jsonl")) {
8369
8836
  continue;
8370
8837
  }
8371
- const content = await readFile10(path17.join(segmentsPath, file), "utf8");
8838
+ const content = await readFile11(path18.join(segmentsPath, file), "utf8");
8372
8839
  let currentTurnIsSubagent = false;
8373
8840
  for (const line of content.split("\n").filter(Boolean)) {
8374
8841
  const raw = parseJsonLine(line);
@@ -8402,7 +8869,7 @@ async function loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMa
8402
8869
  return modelCalls.filter((call) => call.isSubagent === isSubagentSession);
8403
8870
  }
8404
8871
  async function parseQoderCnSessionFile(filePath, options) {
8405
- const text = await readFile10(filePath, "utf8");
8872
+ const text = await readFile11(filePath, "utf8");
8406
8873
  const lines = text.split("\n").filter(Boolean);
8407
8874
  const parsedPaths = parseQoderCnPaths(filePath);
8408
8875
  const { configDir: configDir2 } = parsedPaths;
@@ -8413,7 +8880,7 @@ async function parseQoderCnSessionFile(filePath, options) {
8413
8880
  let cwd;
8414
8881
  let project = projectContext.project;
8415
8882
  let model;
8416
- const home = path17.resolve(stringOption(options.home) || os8.homedir());
8883
+ const home = path18.resolve(stringOption(options.home) || os8.homedir());
8417
8884
  const modelMap = await loadQoderCnModelNames(configDir2, home);
8418
8885
  const isSubagentSession = filePath.includes("subagents");
8419
8886
  const segmentModelCalls = await loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMap);
@@ -8448,7 +8915,7 @@ async function parseQoderCnSessionFile(filePath, options) {
8448
8915
  sessionId = stringField(raw, "sessionId") || sessionId;
8449
8916
  state.sessionId = sessionId;
8450
8917
  cwd = stringField(raw, "cwd") || cwd;
8451
- project = projectContext.project || (cwd ? path17.basename(cwd) : project || await qoderCnProjectFromFilePath(filePath, options));
8918
+ project = projectContext.project || (cwd ? path18.basename(cwd) : project || await qoderCnProjectFromFilePath(filePath, options));
8452
8919
  if (!ts) {
8453
8920
  continue;
8454
8921
  }
@@ -8533,6 +9000,41 @@ async function parseQoderCnSessionFile(filePath, options) {
8533
9000
  }
8534
9001
  pendingTools.delete(pending.id);
8535
9002
  }
9003
+ const attachedPrompt = extractQoderAttachedPrompt(qoderCnToolResultItems(message)[0]?.content);
9004
+ if (attachedPrompt) {
9005
+ const prompt = qoderCnTextStats(attachedPrompt);
9006
+ state.closeTurn(ts, lineNumber, topType);
9007
+ state.currentTurnId = stringField(raw, "uuid") || stringField(raw, "promptId") || `turn_${createStableHash([sessionId, lineNumber]).slice(0, 24)}`;
9008
+ state.currentTurnStartedAt = ts;
9009
+ state.currentTurnLastEventAt = ts;
9010
+ push(baseQoderCnEvent({
9011
+ ts,
9012
+ type: "turn.started",
9013
+ sessionId,
9014
+ turnId: state.currentTurnId,
9015
+ cwd,
9016
+ project,
9017
+ model,
9018
+ confidence: "derived"
9019
+ }), lineNumber, topType, "attached_prompt");
9020
+ push(baseQoderCnEvent({
9021
+ ts,
9022
+ type: "prompt.submitted",
9023
+ sessionId,
9024
+ turnId: state.currentTurnId,
9025
+ cwd,
9026
+ project,
9027
+ model,
9028
+ confidence: "exact",
9029
+ metrics: {
9030
+ prompts: 1,
9031
+ promptChars: prompt.chars
9032
+ },
9033
+ refs: stringRefs({
9034
+ promptHash: prompt.hash
9035
+ })
9036
+ }), lineNumber, topType, "attached_prompt");
9037
+ }
8536
9038
  continue;
8537
9039
  }
8538
9040
  if (topType === "user") {
@@ -8748,7 +9250,7 @@ async function parseQoderCnSessionFile(filePath, options) {
8748
9250
  }
8749
9251
  dbModelCalls ??= await loadQoderDbModelCalls("QoderCN", parsedPaths.sessionId, modelMap);
8750
9252
  if (dbModelCalls.rootSessionId) {
8751
- const parentPath = path17.join(path17.dirname(filePath), `${dbModelCalls.rootSessionId}.jsonl`);
9253
+ const parentPath = path18.join(path18.dirname(filePath), `${dbModelCalls.rootSessionId}.jsonl`);
8752
9254
  const parentSourcePathHash = `sha256:${createStableHash(parentPath)}`;
8753
9255
  return validEvents.map((event) => rebuildEventIdentity3({
8754
9256
  ...event,
@@ -8874,30 +9376,54 @@ function isNoisePrompt(text) {
8874
9376
  }
8875
9377
  return false;
8876
9378
  }
9379
+ function extractQoderAttachedPrompt(content) {
9380
+ let text;
9381
+ if (typeof content === "string") {
9382
+ text = content;
9383
+ } else if (Array.isArray(content)) {
9384
+ text = content.filter((it) => isPlainObject(it) && it.type === "text").map((it) => stringField(it, "text")).join("\n");
9385
+ } else {
9386
+ return void 0;
9387
+ }
9388
+ if (!text.includes("aicoding-text-field") || !text.includes("text-field-content")) {
9389
+ return void 0;
9390
+ }
9391
+ const fenceStart = text.indexOf("```");
9392
+ if (fenceStart === -1) {
9393
+ return void 0;
9394
+ }
9395
+ const afterFence = text.slice(fenceStart + 3);
9396
+ const fenceEnd = afterFence.indexOf("```");
9397
+ if (fenceEnd === -1) {
9398
+ return void 0;
9399
+ }
9400
+ const inner = afterFence.slice(0, fenceEnd);
9401
+ return inner.split("\n").map((line) => line.replace(/^\s*\d+->/, "")).join("\n").trim() || void 0;
9402
+ }
8877
9403
  async function qoderCnProjectContextFromLines(filePath, lines, options, configDir2) {
8878
9404
  const { projectName: projectDir, sessionId } = parseQoderCnPaths(filePath);
8879
- const isSubagent = filePath.includes(`${path17.sep}subagents${path17.sep}`);
9405
+ const isSubagent = filePath.includes(`${path18.sep}subagents${path18.sep}`);
8880
9406
  const inherited = isSubagent ? await readPersistedSessionContextFromOptions(options, sessionId) : void 0;
8881
9407
  let cwds = [];
8882
9408
  for (const line of lines) {
8883
9409
  const raw = parseJsonLine(line);
8884
9410
  const cwd = raw ? stringField(raw, "cwd") : void 0;
8885
- if (cwd && path17.isAbsolute(cwd)) {
9411
+ if (cwd && path18.isAbsolute(cwd)) {
8886
9412
  cwds.push(cwd);
8887
9413
  }
8888
9414
  }
8889
9415
  if (isSubagent) {
8890
- if (inherited?.cwd && path17.isAbsolute(inherited.cwd)) {
9416
+ if (inherited?.cwd && path18.isAbsolute(inherited.cwd)) {
8891
9417
  cwds = [inherited.cwd];
8892
9418
  } else {
8893
- const parentSessionPath = path17.join(configDir2, "projects", projectDir, `${sessionId}.jsonl`);
9419
+ const parentSessionPath = path18.join(configDir2, "projects", projectDir, `${sessionId}.jsonl`);
8894
9420
  try {
8895
- const parentText = await readFile10(parentSessionPath, "utf8");
9421
+ const parentText = await readFile11(parentSessionPath, "utf8");
8896
9422
  const parentCwds = [];
8897
9423
  for (const line of parentText.split("\n").filter(Boolean)) {
8898
9424
  const raw = parseJsonLine(line);
8899
9425
  const cwd = raw ? stringField(raw, "cwd") : void 0;
8900
- if (cwd && path17.isAbsolute(cwd)) {
9426
+ if (cwd && path18.isAbsolute(cwd)) {
8901
9427
  parentCwds.push(cwd);
8902
9428
  }
8903
9429
  }
@@ -8909,7 +9435,7 @@ async function qoderCnProjectContextFromLines(filePath, lines, options, configDi
8909
9435
  }
8910
9436
  }
8911
9437
  const root = await gitRootFromCwds2(cwds) || qoderCnProjectRootFromCwds(projectDir, cwds);
8912
- const project = inherited?.project || (cwds.length > 0 ? path17.basename(cwds[0]) : root ? path17.basename(root) : await qoderCnProjectFromFilePath(filePath, options));
9438
+ const project = inherited?.project || (cwds.length > 0 ? path18.basename(cwds[0]) : root ? path18.basename(root) : await qoderCnProjectFromFilePath(filePath, options));
8913
9439
  return {
8914
9440
  project,
8915
9441
  workspaceId: createWorkspaceId({ projectName: project, repoRoot: root })
@@ -8918,15 +9444,15 @@ async function qoderCnProjectContextFromLines(filePath, lines, options, configDi
8918
9444
  async function gitRootFromCwds2(cwds) {
8919
9445
  const seen = /* @__PURE__ */ new Set();
8920
9446
  for (const cwd of cwds) {
8921
- let current = path17.resolve(cwd);
9447
+ let current = path18.resolve(cwd);
8922
9448
  while (!seen.has(current)) {
8923
9449
  seen.add(current);
8924
9450
  try {
8925
- await stat8(path17.join(current, ".git"));
9451
+ await stat8(path18.join(current, ".git"));
8926
9452
  return current;
8927
9453
  } catch {
8928
9454
  }
8929
- const parent = path17.dirname(current);
9455
+ const parent = path18.dirname(current);
8930
9456
  if (parent === current) {
8931
9457
  break;
8932
9458
  }
@@ -8937,12 +9463,12 @@ async function gitRootFromCwds2(cwds) {
8937
9463
  }
8938
9464
  function qoderCnProjectRootFromCwds(projectDir, cwds) {
8939
9465
  for (const cwd of cwds) {
8940
- let current = path17.resolve(cwd);
9466
+ let current = path18.resolve(cwd);
8941
9467
  while (true) {
8942
9468
  if (encodeQoderCnProjectPath(current) === projectDir) {
8943
9469
  return current;
8944
9470
  }
8945
- const parent = path17.dirname(current);
9471
+ const parent = path18.dirname(current);
8946
9472
  if (parent === current) {
8947
9473
  break;
8948
9474
  }
@@ -8952,14 +9478,14 @@ function qoderCnProjectRootFromCwds(projectDir, cwds) {
8952
9478
  return void 0;
8953
9479
  }
8954
9480
  function encodeQoderCnProjectPath(value) {
8955
- return path17.resolve(value).split(path17.sep).join("-").replaceAll("_", "-");
9481
+ return path18.resolve(value).split(path18.sep).join("-").replaceAll("_", "-");
8956
9482
  }
8957
9483
  async function qoderCnProjectFromFilePath(filePath, options) {
8958
- const projectDir = path17.basename(path17.dirname(filePath));
8959
- const home = options ? path17.resolve(stringOption(options.home) || os8.homedir()) : os8.homedir();
9484
+ const projectDir = path18.basename(path18.dirname(filePath));
9485
+ const home = options ? path18.resolve(stringOption(options.home) || os8.homedir()) : os8.homedir();
8960
9486
  const resolved = await resolveQoderCnProjectPath(projectDir, home);
8961
9487
  if (resolved) {
8962
- return path17.basename(resolved);
9488
+ return path18.basename(resolved);
8963
9489
  }
8964
9490
  const homePrefix = `${encodeQoderCnProjectPath(home)}-`;
8965
9491
  if (projectDir.startsWith(homePrefix)) {
@@ -8984,7 +9510,7 @@ async function resolveQoderCnProjectPath(projectDir, home) {
8984
9510
  if (!entry.isDirectory()) {
8985
9511
  continue;
8986
9512
  }
8987
- const candidate = path17.join(current, entry.name);
9513
+ const candidate = path18.join(current, entry.name);
8988
9514
  const encoded = encodeQoderCnProjectPath(candidate);
8989
9515
  if (encoded === projectDir) {
8990
9516
  return candidate;
@@ -9029,9 +9555,9 @@ function hookConfig6() {
9029
9555
  function qoderCnConfigDir(home, env) {
9030
9556
  const override = env?.QODER_CN_CONFIG_DIR;
9031
9557
  if (override && override.trim()) {
9032
- return path17.resolve(override);
9558
+ return path18.resolve(override);
9033
9559
  }
9034
- return path17.join(home, ".qoder-cn");
9560
+ return path18.join(home, ".qoder-cn");
9035
9561
  }
9036
9562
  function createQoderCnAdapter() {
9037
9563
  return {
@@ -9043,27 +9569,27 @@ function createQoderCnAdapter() {
9043
9569
  return qoderCnConfigDir(home, env);
9044
9570
  },
9045
9571
  installedPath(home, env) {
9046
- return path17.join(qoderCnConfigDir(home, env), "settings.json");
9572
+ return path18.join(qoderCnConfigDir(home, env), "settings.json");
9047
9573
  },
9048
9574
  async isInstalled(home, env) {
9049
9575
  return isHooksJsonInstalled(
9050
- path17.join(qoderCnConfigDir(home, env), "settings.json"),
9576
+ path18.join(qoderCnConfigDir(home, env), "settings.json"),
9051
9577
  "vibetime hook --agent qoder-cn"
9052
9578
  );
9053
9579
  },
9054
9580
  installEntries(home, env) {
9055
9581
  return [{
9056
9582
  kind: "hooks-json",
9057
- path: path17.join(qoderCnConfigDir(home, env), "settings.json"),
9583
+ path: path18.join(qoderCnConfigDir(home, env), "settings.json"),
9058
9584
  content: hookConfig6()
9059
9585
  }];
9060
9586
  },
9061
9587
  sourcePaths(home, env) {
9062
9588
  const base = qoderCnConfigDir(home, env);
9063
9589
  return [
9064
- path17.join(base, "projects"),
9065
- path17.join(base, ".qoder.json"),
9066
- path17.join(home, ".qoder.json")
9590
+ path18.join(base, "projects"),
9591
+ path18.join(base, ".qoder.json"),
9592
+ path18.join(home, ".qoder.json")
9067
9593
  ];
9068
9594
  },
9069
9595
  parseSessionFile: parseQoderCnSessionFile
@@ -9072,11 +9598,11 @@ function createQoderCnAdapter() {
9072
9598
 
9073
9599
  // src/adapters/qoder.ts
9074
9600
  import { existsSync } from "node:fs";
9075
- import { readdir as readdir8, readFile as readFile11, stat as stat9 } from "node:fs/promises";
9601
+ import { readdir as readdir8, readFile as readFile12, stat as stat9 } from "node:fs/promises";
9076
9602
  import os9 from "node:os";
9077
- import path18 from "node:path";
9603
+ import path19 from "node:path";
9078
9604
  function parseQoderPaths(filePath) {
9079
- const parts = filePath.split(path18.sep);
9605
+ const parts = filePath.split(path19.sep);
9080
9606
  const subagentsIdx = parts.lastIndexOf("subagents");
9081
9607
  let sessionId = "";
9082
9608
  let projectName = "";
@@ -9086,17 +9612,17 @@ function parseQoderPaths(filePath) {
9086
9612
  sessionId = parts[subagentsIdx - 1];
9087
9613
  projectName = parts[subagentsIdx - 2];
9088
9614
  const projectsIdx = parts.lastIndexOf("projects");
9089
- configDir2 = parts.slice(0, projectsIdx).join(path18.sep);
9090
- mainTranscriptPath = [...parts.slice(0, subagentsIdx - 1), `${sessionId}.jsonl`].join(path18.sep);
9615
+ configDir2 = parts.slice(0, projectsIdx).join(path19.sep);
9616
+ mainTranscriptPath = [...parts.slice(0, subagentsIdx - 1), `${sessionId}.jsonl`].join(path19.sep);
9091
9617
  } else {
9092
9618
  const filename = parts.at(-1) || "";
9093
- sessionId = path18.basename(filename, ".jsonl");
9619
+ sessionId = path19.basename(filename, ".jsonl");
9094
9620
  projectName = parts.at(-2) || "";
9095
9621
  if (projectName === "transcript") {
9096
9622
  projectName = parts.at(-3) || "";
9097
9623
  }
9098
9624
  const projectsIdx = parts.lastIndexOf("projects");
9099
- configDir2 = parts.slice(0, projectsIdx).join(path18.sep);
9625
+ configDir2 = parts.slice(0, projectsIdx).join(path19.sep);
9100
9626
  }
9101
9627
  return { configDir: configDir2, projectName, sessionId, mainTranscriptPath };
9102
9628
  }
@@ -9119,7 +9645,7 @@ function rebuildEventIdentity4(event) {
9119
9645
  }
9120
9646
  async function parseModelNamesFromDynamicTexts2(dynamicTextsPath) {
9121
9647
  try {
9122
- const content = await readFile11(dynamicTextsPath, "utf8");
9648
+ const content = await readFile12(dynamicTextsPath, "utf8");
9123
9649
  const json = JSON.parse(content);
9124
9650
  const texts = json.texts || {};
9125
9651
  const map = {};
@@ -9135,10 +9661,10 @@ async function parseModelNamesFromDynamicTexts2(dynamicTextsPath) {
9135
9661
  }
9136
9662
  }
9137
9663
  async function loadQoderModelNames(configDir2, home) {
9138
- const map = await parseModelNamesFromDynamicTexts2(path18.join(configDir2, ".auth", "dynamic-texts.json"));
9664
+ const map = await parseModelNamesFromDynamicTexts2(path19.join(configDir2, ".auth", "dynamic-texts.json"));
9139
9665
  const siblingConfigDir = configDir2.replace(/\.qoder$/, ".qoder-cn");
9140
9666
  if (siblingConfigDir !== configDir2) {
9141
- const siblingMap = await parseModelNamesFromDynamicTexts2(path18.join(siblingConfigDir, ".auth", "dynamic-texts.json"));
9667
+ const siblingMap = await parseModelNamesFromDynamicTexts2(path19.join(siblingConfigDir, ".auth", "dynamic-texts.json"));
9142
9668
  for (const [key, val] of Object.entries(siblingMap)) {
9143
9669
  if (!(key in map)) {
9144
9670
  map[key] = val;
@@ -9146,11 +9672,11 @@ async function loadQoderModelNames(configDir2, home) {
9146
9672
  }
9147
9673
  }
9148
9674
  if (isQwenworkConfigRoot(configDir2)) {
9149
- for (const dir of [path18.join(home, ".qoder"), path18.join(home, ".qoder-cn")]) {
9150
- if (path18.resolve(dir) === path18.resolve(configDir2)) {
9675
+ for (const dir of [path19.join(home, ".qoder"), path19.join(home, ".qoder-cn")]) {
9676
+ if (path19.resolve(dir) === path19.resolve(configDir2)) {
9151
9677
  continue;
9152
9678
  }
9153
- const fallbackMap = await parseModelNamesFromDynamicTexts2(path18.join(dir, ".auth", "dynamic-texts.json"));
9679
+ const fallbackMap = await parseModelNamesFromDynamicTexts2(path19.join(dir, ".auth", "dynamic-texts.json"));
9154
9680
  for (const [key, val] of Object.entries(fallbackMap)) {
9155
9681
  if (!(key in map)) {
9156
9682
  map[key] = val;
@@ -9169,17 +9695,17 @@ async function loadQoderModelNames(configDir2, home) {
9169
9695
  return map;
9170
9696
  }
9171
9697
  function isQwenworkConfigRoot(configDir2) {
9172
- const name = path18.basename(path18.resolve(configDir2));
9698
+ const name = path19.basename(path19.resolve(configDir2));
9173
9699
  if (name === ".qwenworkcn" || name === ".qwenwork") {
9174
9700
  return true;
9175
9701
  }
9176
9702
  const override = process.env.QWENWORK_CONFIG_DIR;
9177
- return Boolean(override && override.trim() && path18.basename(path18.resolve(override)) === name);
9703
+ return Boolean(override && override.trim() && path19.basename(path19.resolve(override)) === name);
9178
9704
  }
9179
9705
  var FAILED_SEGMENT_STOP_REASONS = /* @__PURE__ */ new Set(["cancelled", "canceled", "error", "failed", "refusal"]);
9180
9706
  async function loadQoderSegmentModelCalls(filePath, isSubagentSession, modelMap) {
9181
9707
  const { configDir: configDir2, projectName, sessionId } = parseQoderPaths(filePath);
9182
- const segmentsPath = path18.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
9708
+ const segmentsPath = path19.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
9183
9709
  const modelCalls = [];
9184
9710
  try {
9185
9711
  const files = await readdir8(segmentsPath);
@@ -9187,7 +9713,7 @@ async function loadQoderSegmentModelCalls(filePath, isSubagentSession, modelMap)
9187
9713
  if (!file.endsWith(".jsonl")) {
9188
9714
  continue;
9189
9715
  }
9190
- const content = await readFile11(path18.join(segmentsPath, file), "utf8");
9716
+ const content = await readFile12(path19.join(segmentsPath, file), "utf8");
9191
9717
  let currentTurnIsSubagent = false;
9192
9718
  for (const line of content.split("\n").filter(Boolean)) {
9193
9719
  const raw = parseJsonLine(line);
@@ -9221,7 +9747,7 @@ async function loadQoderSegmentModelCalls(filePath, isSubagentSession, modelMap)
9221
9747
  return modelCalls.filter((call) => call.isSubagent === isSubagentSession);
9222
9748
  }
9223
9749
  async function parseQoderSessionFile(filePath, options) {
9224
- const text = await readFile11(filePath, "utf8");
9750
+ const text = await readFile12(filePath, "utf8");
9225
9751
  const lines = text.split("\n").filter(Boolean);
9226
9752
  const parsedPaths = parseQoderPaths(filePath);
9227
9753
  const { configDir: configDir2 } = parsedPaths;
@@ -9232,7 +9758,7 @@ async function parseQoderSessionFile(filePath, options) {
9232
9758
  let cwd;
9233
9759
  let project = projectContext.project;
9234
9760
  let model;
9235
- const home = path18.resolve(stringOption(options.home) || os9.homedir());
9761
+ const home = path19.resolve(stringOption(options.home) || os9.homedir());
9236
9762
  const modelMap = await loadQoderModelNames(configDir2, home);
9237
9763
  const qwenworkRoot = isQwenworkConfigRoot(configDir2);
9238
9764
  const isSubagentSession = filePath.includes("subagents");
@@ -9268,7 +9794,7 @@ async function parseQoderSessionFile(filePath, options) {
9268
9794
  sessionId = stringField(raw, "sessionId") || sessionId;
9269
9795
  state.sessionId = sessionId;
9270
9796
  cwd = stringField(raw, "cwd") || cwd;
9271
- project = projectContext.project || (cwd ? path18.basename(cwd) : project || await qoderProjectFromFilePath(filePath, options));
9797
+ project = projectContext.project || (cwd ? path19.basename(cwd) : project || await qoderProjectFromFilePath(filePath, options));
9272
9798
  if (!ts) {
9273
9799
  continue;
9274
9800
  }
@@ -9353,6 +9879,41 @@ async function parseQoderSessionFile(filePath, options) {
9353
9879
  }
9354
9880
  pendingTools.delete(pending.id);
9355
9881
  }
9882
+ const attachedPrompt = extractQoderAttachedPrompt(qoderToolResultItems(message)[0]?.content);
9883
+ if (attachedPrompt) {
9884
+ const prompt = qoderTextStats(attachedPrompt);
9885
+ state.closeTurn(ts, lineNumber, topType);
9886
+ state.currentTurnId = stringField(raw, "uuid") || stringField(raw, "promptId") || `turn_${createStableHash([sessionId, lineNumber]).slice(0, 24)}`;
9887
+ state.currentTurnStartedAt = ts;
9888
+ state.currentTurnLastEventAt = ts;
9889
+ push(baseQoderEvent({
9890
+ ts,
9891
+ type: "turn.started",
9892
+ sessionId,
9893
+ turnId: state.currentTurnId,
9894
+ cwd,
9895
+ project,
9896
+ model,
9897
+ confidence: "derived"
9898
+ }), lineNumber, topType, "attached_prompt");
9899
+ push(baseQoderEvent({
9900
+ ts,
9901
+ type: "prompt.submitted",
9902
+ sessionId,
9903
+ turnId: state.currentTurnId,
9904
+ cwd,
9905
+ project,
9906
+ model,
9907
+ confidence: "exact",
9908
+ metrics: {
9909
+ prompts: 1,
9910
+ promptChars: prompt.chars
9911
+ },
9912
+ refs: stringRefs({
9913
+ promptHash: prompt.hash
9914
+ })
9915
+ }), lineNumber, topType, "attached_prompt");
9916
+ }
9356
9917
  continue;
9357
9918
  }
9358
9919
  if (topType === "user") {
@@ -9543,7 +10104,7 @@ async function parseQoderSessionFile(filePath, options) {
9543
10104
  }
9544
10105
  dbModelCalls ??= await loadQoderDbModelCalls("Qoder", parsedPaths.sessionId, modelMap);
9545
10106
  if (dbModelCalls.rootSessionId) {
9546
- const parentPath = path18.join(path18.dirname(filePath), `${dbModelCalls.rootSessionId}.jsonl`);
10107
+ const parentPath = path19.join(path19.dirname(filePath), `${dbModelCalls.rootSessionId}.jsonl`);
9547
10108
  const parentSourcePathHash = `sha256:${createStableHash(parentPath)}`;
9548
10109
  return validEvents.map((event) => rebuildEventIdentity4({
9549
10110
  ...event,
@@ -9659,41 +10220,41 @@ function qoderExtractText(value) {
9659
10220
  }
9660
10221
  async function qoderProjectContextFromLines(filePath, lines, options, configDir2) {
9661
10222
  const { projectName: projectDir, sessionId } = parseQoderPaths(filePath);
9662
- const isSubagent = filePath.includes(`${path18.sep}subagents${path18.sep}`);
10223
+ const isSubagent = filePath.includes(`${path19.sep}subagents${path19.sep}`);
9663
10224
  const inherited = isSubagent ? await readPersistedSessionContextFromOptions(options, sessionId) : void 0;
9664
10225
  let cwds = [];
9665
10226
  const workspaceDirs = [];
9666
10227
  for (const line of lines) {
9667
10228
  const raw = parseJsonLine(line);
9668
10229
  const cwd = raw ? stringField(raw, "cwd") : void 0;
9669
- if (cwd && path18.isAbsolute(cwd)) {
10230
+ if (cwd && path19.isAbsolute(cwd)) {
9670
10231
  cwds.push(cwd);
9671
10232
  }
9672
10233
  if (raw && stringField(raw, "type") === "workspace-directories") {
9673
10234
  for (const dir of arrayField5(raw, "directories")) {
9674
- if (typeof dir === "string" && path18.isAbsolute(dir)) {
10235
+ if (typeof dir === "string" && path19.isAbsolute(dir)) {
9675
10236
  workspaceDirs.push(dir);
9676
10237
  }
9677
10238
  }
9678
10239
  }
9679
10240
  }
9680
10241
  if (isSubagent) {
9681
- if (inherited?.cwd && path18.isAbsolute(inherited.cwd)) {
10242
+ if (inherited?.cwd && path19.isAbsolute(inherited.cwd)) {
9682
10243
  cwds = [inherited.cwd];
9683
10244
  } else {
9684
- const parentSessionPath = path18.join(configDir2, "projects", projectDir, `${sessionId}.jsonl`);
10245
+ const parentSessionPath = path19.join(configDir2, "projects", projectDir, `${sessionId}.jsonl`);
9685
10246
  try {
9686
- const parentText = await readFile11(parentSessionPath, "utf8");
10247
+ const parentText = await readFile12(parentSessionPath, "utf8");
9687
10248
  const parentCwds = [];
9688
10249
  for (const line of parentText.split("\n").filter(Boolean)) {
9689
10250
  const raw = parseJsonLine(line);
9690
10251
  const cwd = raw ? stringField(raw, "cwd") : void 0;
9691
- if (cwd && path18.isAbsolute(cwd)) {
10252
+ if (cwd && path19.isAbsolute(cwd)) {
9692
10253
  parentCwds.push(cwd);
9693
10254
  }
9694
10255
  if (workspaceDirs.length === 0 && raw && stringField(raw, "type") === "workspace-directories") {
9695
10256
  for (const dir of arrayField5(raw, "directories")) {
9696
- if (typeof dir === "string" && path18.isAbsolute(dir)) {
10257
+ if (typeof dir === "string" && path19.isAbsolute(dir)) {
9697
10258
  workspaceDirs.push(dir);
9698
10259
  }
9699
10260
  }
@@ -9713,29 +10274,29 @@ async function qoderProjectContextFromLines(filePath, lines, options, configDir2
9713
10274
  }
9714
10275
  }
9715
10276
  const root = await gitRootFromCwds3(cwds) || qoderProjectRootFromCwds(projectDir, cwds);
9716
- const project = inherited?.project || (cwds.length > 0 ? path18.basename(cwds[0]) : root ? path18.basename(root) : await qoderProjectFromFilePath(filePath, options));
10277
+ const project = inherited?.project || (cwds.length > 0 ? path19.basename(cwds[0]) : root ? path19.basename(root) : await qoderProjectFromFilePath(filePath, options));
9717
10278
  return {
9718
10279
  project,
9719
10280
  workspaceId: createWorkspaceId({ projectName: project, repoRoot: root })
9720
10281
  };
9721
10282
  }
9722
10283
  function pathInsideDir(candidate, dir) {
9723
- const resolvedDir = path18.resolve(dir);
9724
- const resolved = path18.resolve(candidate);
9725
- return resolved === resolvedDir || resolved.startsWith(`${resolvedDir}${path18.sep}`);
10284
+ const resolvedDir = path19.resolve(dir);
10285
+ const resolved = path19.resolve(candidate);
10286
+ return resolved === resolvedDir || resolved.startsWith(`${resolvedDir}${path19.sep}`);
9726
10287
  }
9727
10288
  async function gitRootFromCwds3(cwds) {
9728
10289
  const seen = /* @__PURE__ */ new Set();
9729
10290
  for (const cwd of cwds) {
9730
- let current = path18.resolve(cwd);
10291
+ let current = path19.resolve(cwd);
9731
10292
  while (!seen.has(current)) {
9732
10293
  seen.add(current);
9733
10294
  try {
9734
- await stat9(path18.join(current, ".git"));
10295
+ await stat9(path19.join(current, ".git"));
9735
10296
  return current;
9736
10297
  } catch {
9737
10298
  }
9738
- const parent = path18.dirname(current);
10299
+ const parent = path19.dirname(current);
9739
10300
  if (parent === current) {
9740
10301
  break;
9741
10302
  }
@@ -9746,12 +10307,12 @@ async function gitRootFromCwds3(cwds) {
9746
10307
  }
9747
10308
  function qoderProjectRootFromCwds(projectDir, cwds) {
9748
10309
  for (const cwd of cwds) {
9749
- let current = path18.resolve(cwd);
10310
+ let current = path19.resolve(cwd);
9750
10311
  while (true) {
9751
10312
  if (qoderEncodedVariants(current).includes(projectDir)) {
9752
10313
  return current;
9753
10314
  }
9754
- const parent = path18.dirname(current);
10315
+ const parent = path19.dirname(current);
9755
10316
  if (parent === current) {
9756
10317
  break;
9757
10318
  }
@@ -9761,7 +10322,7 @@ function qoderProjectRootFromCwds(projectDir, cwds) {
9761
10322
  return void 0;
9762
10323
  }
9763
10324
  function rawQoderProjectPath(value) {
9764
- return path18.resolve(value).split(path18.sep).join("-");
10325
+ return path19.resolve(value).split(path19.sep).join("-");
9765
10326
  }
9766
10327
  function qoderEncodedVariants(value) {
9767
10328
  const raw = rawQoderProjectPath(value);
@@ -9782,11 +10343,11 @@ function qoderEncodedProjectSuffix(projectDir, home) {
9782
10343
  return void 0;
9783
10344
  }
9784
10345
  async function qoderProjectFromFilePath(filePath, options) {
9785
- const projectDir = path18.basename(path18.dirname(filePath));
9786
- const home = options ? path18.resolve(stringOption(options.home) || os9.homedir()) : os9.homedir();
10346
+ const projectDir = path19.basename(path19.dirname(filePath));
10347
+ const home = options ? path19.resolve(stringOption(options.home) || os9.homedir()) : os9.homedir();
9787
10348
  const resolved = await resolveQoderProjectPath(projectDir, home);
9788
10349
  if (resolved) {
9789
- return path18.basename(resolved);
10350
+ return path19.basename(resolved);
9790
10351
  }
9791
10352
  const suffix = qoderEncodedProjectSuffix(projectDir, home);
9792
10353
  if (suffix) {
@@ -9812,7 +10373,7 @@ async function resolveQoderProjectPath(projectDir, home) {
9812
10373
  if (!entry.isDirectory()) {
9813
10374
  continue;
9814
10375
  }
9815
- const candidate = path18.join(current, entry.name);
10376
+ const candidate = path19.join(current, entry.name);
9816
10377
  const candidateVariants = qoderEncodedVariants(candidate);
9817
10378
  if (candidateVariants.includes(projectDir)) {
9818
10379
  return candidate;
@@ -9857,19 +10418,19 @@ function hookConfig7() {
9857
10418
  function qoderConfigDir(home, env) {
9858
10419
  const override = env?.QODER_CONFIG_DIR;
9859
10420
  if (override && override.trim()) {
9860
- return path18.resolve(override);
10421
+ return path19.resolve(override);
9861
10422
  }
9862
- return path18.join(home, ".qoder");
10423
+ return path19.join(home, ".qoder");
9863
10424
  }
9864
10425
  function qwenworkConfigDir(home, env) {
9865
10426
  const override = env?.QWENWORK_CONFIG_DIR;
9866
10427
  if (override && override.trim()) {
9867
- return path18.resolve(override);
10428
+ return path19.resolve(override);
9868
10429
  }
9869
- return path18.join(home, ".qwenworkcn");
10430
+ return path19.join(home, ".qwenworkcn");
9870
10431
  }
9871
10432
  function qoderConfigDirs(home, env) {
9872
- return [...new Set([qoderConfigDir(home, env), qwenworkConfigDir(home, env)].map((dir) => path18.resolve(dir)))];
10433
+ return [...new Set([qoderConfigDir(home, env), qwenworkConfigDir(home, env)].map((dir) => path19.resolve(dir)))];
9873
10434
  }
9874
10435
  function createQoderAdapter() {
9875
10436
  return {
@@ -9881,11 +10442,11 @@ function createQoderAdapter() {
9881
10442
  return qoderConfigDir(home, env);
9882
10443
  },
9883
10444
  installedPath(home, env) {
9884
- return path18.join(qoderConfigDir(home, env), "settings.json");
10445
+ return path19.join(qoderConfigDir(home, env), "settings.json");
9885
10446
  },
9886
10447
  async isInstalled(home, env) {
9887
10448
  return isHooksJsonInstalled(
9888
- path18.join(qoderConfigDir(home, env), "settings.json"),
10449
+ path19.join(qoderConfigDir(home, env), "settings.json"),
9889
10450
  "vibetime hook --agent qoder"
9890
10451
  );
9891
10452
  },
@@ -9894,16 +10455,16 @@ function createQoderAdapter() {
9894
10455
  const targets = [primary, ...variants.filter((dir) => existsSync(dir))];
9895
10456
  return targets.map((base) => ({
9896
10457
  kind: "hooks-json",
9897
- path: path18.join(base, "settings.json"),
10458
+ path: path19.join(base, "settings.json"),
9898
10459
  content: hookConfig7()
9899
10460
  }));
9900
10461
  },
9901
10462
  sourcePaths(home, env) {
9902
- const paths = qoderConfigDirs(home, env).map((base2) => path18.join(base2, "projects"));
10463
+ const paths = qoderConfigDirs(home, env).map((base2) => path19.join(base2, "projects"));
9903
10464
  const base = qoderConfigDir(home, env);
9904
10465
  paths.push(
9905
- path18.join(base, ".qoder.json"),
9906
- path18.join(home, ".qoder.json")
10466
+ path19.join(base, ".qoder.json"),
10467
+ path19.join(home, ".qoder.json")
9907
10468
  );
9908
10469
  return paths;
9909
10470
  },
@@ -9939,27 +10500,27 @@ function normalizeId(id) {
9939
10500
  }
9940
10501
 
9941
10502
  // src/adapters/workbuddy.ts
9942
- import { readdir as readdir9, readFile as readFile12, stat as stat10 } from "node:fs/promises";
9943
- import path19 from "node:path";
10503
+ import { readdir as readdir9, readFile as readFile13, stat as stat10 } from "node:fs/promises";
10504
+ import path20 from "node:path";
9944
10505
  function workbuddyProjectsDir(home, env) {
9945
10506
  const override = env?.WORKBUDDY_PROJECTS_DIR || env?.WORKBUDDY_HOME;
9946
10507
  if (override && override.trim()) {
9947
- return path19.resolve(override, override.endsWith("projects") ? "" : "projects");
10508
+ return path20.resolve(override, override.endsWith("projects") ? "" : "projects");
9948
10509
  }
9949
- return path19.join(home, ".workbuddy", "projects");
10510
+ return path20.join(home, ".workbuddy", "projects");
9950
10511
  }
9951
10512
  function workbuddyBaseDir(home, env) {
9952
10513
  const override = env?.WORKBUDDY_HOME;
9953
10514
  if (override && override.trim()) {
9954
- return path19.resolve(override);
10515
+ return path20.resolve(override);
9955
10516
  }
9956
- return path19.join(home, ".workbuddy");
10517
+ return path20.join(home, ".workbuddy");
9957
10518
  }
9958
10519
  function projectFromCwd(cwd, fallback) {
9959
10520
  if (!cwd) {
9960
10521
  return fallback;
9961
10522
  }
9962
- return path19.basename(cwd) || fallback;
10523
+ return path20.basename(cwd) || fallback;
9963
10524
  }
9964
10525
  function sourceHash(filePath) {
9965
10526
  return `sha256:${createStableHash(filePath)}`;
@@ -10077,7 +10638,7 @@ function toolCallFailed(record) {
10077
10638
  return status === "failed" || status === "incomplete" || record.is_error === true || providerData.error != null || providerData.isError === true;
10078
10639
  }
10079
10640
  async function readWorkbuddyLines(filePath) {
10080
- const text = await readFile12(filePath, "utf8");
10641
+ const text = await readFile13(filePath, "utf8");
10081
10642
  return text.split(/\r?\n/).map((line, index) => {
10082
10643
  if (!line.trim()) {
10083
10644
  return void 0;
@@ -10097,8 +10658,8 @@ async function parseWorkbuddySessionFile(filePath, options) {
10097
10658
  }
10098
10659
  const events = [];
10099
10660
  const first = lines[0].record;
10100
- const sessionId = stringField(first, "sessionId") || path19.basename(filePath, ".jsonl");
10101
- const fallbackProject = path19.basename(path19.dirname(filePath));
10661
+ const sessionId = stringField(first, "sessionId") || path20.basename(filePath, ".jsonl");
10662
+ const fallbackProject = path20.basename(path20.dirname(filePath));
10102
10663
  const cwd = lines.map((line) => stringField(line.record, "cwd")).find(Boolean);
10103
10664
  const project = projectFromCwd(cwd, fallbackProject);
10104
10665
  const workspaceId = createWorkspaceId({ projectName: project, repoRoot: cwd });
@@ -10387,11 +10948,11 @@ async function workbuddyBackfillFiles(sourceRoot, home, env) {
10387
10948
  if (!project.isDirectory()) {
10388
10949
  continue;
10389
10950
  }
10390
- const projectDir = path19.join(base, project.name);
10951
+ const projectDir = path20.join(base, project.name);
10391
10952
  const entries = await readdir9(projectDir, { withFileTypes: true });
10392
10953
  for (const entry of entries) {
10393
10954
  if (entry.isFile() && entry.name.endsWith(".jsonl")) {
10394
- const filePath = path19.join(projectDir, entry.name);
10955
+ const filePath = path20.join(projectDir, entry.name);
10395
10956
  const info = await stat10(filePath);
10396
10957
  files.push({ path: filePath, modifiedAt: info.mtime.toISOString() });
10397
10958
  }
@@ -10429,18 +10990,18 @@ function createWorkbuddyAdapter() {
10429
10990
  return workbuddyProjectsDir(home, env);
10430
10991
  },
10431
10992
  installedPath(home, env) {
10432
- return path19.join(workbuddyBaseDir(home, env), "settings.json");
10993
+ return path20.join(workbuddyBaseDir(home, env), "settings.json");
10433
10994
  },
10434
10995
  async isInstalled(home, env) {
10435
10996
  return isHooksJsonInstalled(
10436
- path19.join(workbuddyBaseDir(home, env), "settings.json"),
10997
+ path20.join(workbuddyBaseDir(home, env), "settings.json"),
10437
10998
  "vibetime hook --agent workbuddy"
10438
10999
  );
10439
11000
  },
10440
11001
  installEntries(home, env) {
10441
11002
  return [{
10442
11003
  kind: "hooks-json",
10443
- path: path19.join(workbuddyBaseDir(home, env), "settings.json"),
11004
+ path: path20.join(workbuddyBaseDir(home, env), "settings.json"),
10444
11005
  content: hookConfig8()
10445
11006
  }];
10446
11007
  },
@@ -10453,20 +11014,20 @@ function createWorkbuddyAdapter() {
10453
11014
 
10454
11015
  // src/adapters/zcode.ts
10455
11016
  import { execFile } from "node:child_process";
10456
- import { readFile as readFile13, stat as stat11 } from "node:fs/promises";
10457
- import path20 from "node:path";
11017
+ import { readFile as readFile14, stat as stat11 } from "node:fs/promises";
11018
+ import path21 from "node:path";
10458
11019
  import { promisify as promisify2 } from "node:util";
10459
11020
  init_fs();
10460
11021
  var execFileAsync = promisify2(execFile);
10461
11022
  function zcodeCliDir(home, env) {
10462
11023
  const override = env?.ZCODE_CLI_DIR || env?.ZCODE_HOME;
10463
11024
  if (override && override.trim()) {
10464
- return path20.resolve(override, override.endsWith("cli") ? "" : "cli");
11025
+ return path21.resolve(override, override.endsWith("cli") ? "" : "cli");
10465
11026
  }
10466
- return path20.join(home, ".zcode", "cli");
11027
+ return path21.join(home, ".zcode", "cli");
10467
11028
  }
10468
11029
  function zcodeDbPath(home, env) {
10469
- return path20.join(zcodeCliDir(home, env), "db", "db.sqlite");
11030
+ return path21.join(zcodeCliDir(home, env), "db", "db.sqlite");
10470
11031
  }
10471
11032
  var providerNameCache = null;
10472
11033
  async function loadProviderNames(configPath2) {
@@ -10482,7 +11043,7 @@ async function loadProviderNames(configPath2) {
10482
11043
  }
10483
11044
  const map = /* @__PURE__ */ new Map();
10484
11045
  try {
10485
- const raw = await readFile13(configPath2, "utf-8");
11046
+ const raw = await readFile14(configPath2, "utf-8");
10486
11047
  const config = JSON.parse(raw);
10487
11048
  const providers = config?.provider;
10488
11049
  if (isPlainObject(providers)) {
@@ -10500,7 +11061,7 @@ function sourceHash2(filePath) {
10500
11061
  return `sha256:${createStableHash(filePath)}`;
10501
11062
  }
10502
11063
  function projectFromDirectory(directory) {
10503
- return directory ? path20.basename(directory) || "zcode" : "zcode";
11064
+ return directory ? path21.basename(directory) || "zcode" : "zcode";
10504
11065
  }
10505
11066
  function isoFromMs(value) {
10506
11067
  return timestampFrom(typeof value === "number" ? value : Number(value));
@@ -10683,16 +11244,16 @@ async function parseZCodeDb(filePath, options) {
10683
11244
  if (rows.length === 0) {
10684
11245
  return [];
10685
11246
  }
10686
- let candidate = path20.resolve(filePath);
11247
+ let candidate = path21.resolve(filePath);
10687
11248
  let configPath2 = "";
10688
11249
  for (let i = 0; i < 12; i++) {
10689
- const probe = path20.join(candidate, ".zcode", "v2", "config.json");
11250
+ const probe = path21.join(candidate, ".zcode", "v2", "config.json");
10690
11251
  try {
10691
11252
  await stat11(probe);
10692
11253
  configPath2 = probe;
10693
11254
  break;
10694
11255
  } catch {
10695
- const parent = path20.dirname(candidate);
11256
+ const parent = path21.dirname(candidate);
10696
11257
  if (parent === candidate) break;
10697
11258
  candidate = parent;
10698
11259
  }
@@ -10908,7 +11469,7 @@ async function parseZCodeDb(filePath, options) {
10908
11469
  }
10909
11470
  async function zcodeBackfillFiles(sourceRoot, home, env) {
10910
11471
  const candidate = sourceRoot || zcodeDbPath(home, env);
10911
- const filePath = candidate.endsWith(".sqlite") ? candidate : path20.join(candidate, "db", "db.sqlite");
11472
+ const filePath = candidate.endsWith(".sqlite") ? candidate : path21.join(candidate, "db", "db.sqlite");
10912
11473
  try {
10913
11474
  const info = await stat11(filePath);
10914
11475
  return [{ path: filePath, modifiedAt: info.mtime.toISOString() }];
@@ -10943,49 +11504,49 @@ function createZCodeAdapter() {
10943
11504
 
10944
11505
  // src/adapters/zed.ts
10945
11506
  import os10 from "node:os";
10946
- import path21 from "node:path";
11507
+ import path22 from "node:path";
10947
11508
  function zedThreadsCandidates(home, env) {
10948
11509
  const candidates = [];
10949
11510
  const platform2 = process.platform;
10950
11511
  if (platform2 === "darwin") {
10951
- candidates.push(path21.join(home, "Library", "Application Support", "Zed", "threads", "threads.db"));
11512
+ candidates.push(path22.join(home, "Library", "Application Support", "Zed", "threads", "threads.db"));
10952
11513
  } else if (platform2 === "win32") {
10953
11514
  const appdata = env?.APPDATA;
10954
11515
  if (appdata && appdata.trim()) {
10955
- candidates.push(path21.join(path21.resolve(appdata), "Zed", "threads", "threads.db"));
11516
+ candidates.push(path22.join(path22.resolve(appdata), "Zed", "threads", "threads.db"));
10956
11517
  }
10957
- candidates.push(path21.join(home, "AppData", "Roaming", "Zed", "threads", "threads.db"));
11518
+ candidates.push(path22.join(home, "AppData", "Roaming", "Zed", "threads", "threads.db"));
10958
11519
  } else {
10959
11520
  const xdgData = env?.XDG_DATA_HOME;
10960
11521
  if (xdgData && xdgData.trim()) {
10961
- candidates.push(path21.join(path21.resolve(xdgData), "zed", "threads", "threads.db"));
11522
+ candidates.push(path22.join(path22.resolve(xdgData), "zed", "threads", "threads.db"));
10962
11523
  }
10963
- candidates.push(path21.join(home, ".local", "share", "zed", "threads", "threads.db"));
11524
+ candidates.push(path22.join(home, ".local", "share", "zed", "threads", "threads.db"));
10964
11525
  const xdgConfig = env?.XDG_CONFIG_HOME;
10965
11526
  if (xdgConfig && xdgConfig.trim()) {
10966
- candidates.push(path21.join(path21.resolve(xdgConfig), "zed", "threads", "threads.db"));
11527
+ candidates.push(path22.join(path22.resolve(xdgConfig), "zed", "threads", "threads.db"));
10967
11528
  }
10968
- candidates.push(path21.join(home, ".config", "zed", "threads", "threads.db"));
11529
+ candidates.push(path22.join(home, ".config", "zed", "threads", "threads.db"));
10969
11530
  }
10970
11531
  return candidates;
10971
11532
  }
10972
11533
  function zedConfigDir(home, env) {
10973
11534
  const platform2 = process.platform;
10974
11535
  if (platform2 === "darwin") {
10975
- return path21.join(home, "Library", "Application Support", "Zed");
11536
+ return path22.join(home, "Library", "Application Support", "Zed");
10976
11537
  }
10977
11538
  if (platform2 === "win32") {
10978
11539
  const appdata = env?.APPDATA;
10979
11540
  if (appdata && appdata.trim()) {
10980
- return path21.join(path21.resolve(appdata), "Zed");
11541
+ return path22.join(path22.resolve(appdata), "Zed");
10981
11542
  }
10982
- return path21.join(home, "AppData", "Roaming", "Zed");
11543
+ return path22.join(home, "AppData", "Roaming", "Zed");
10983
11544
  }
10984
11545
  const xdgConfig = env?.XDG_CONFIG_HOME;
10985
11546
  if (xdgConfig && xdgConfig.trim()) {
10986
- return path21.join(path21.resolve(xdgConfig), "zed");
11547
+ return path22.join(path22.resolve(xdgConfig), "zed");
10987
11548
  }
10988
- return path21.join(home, ".config", "zed");
11549
+ return path22.join(home, ".config", "zed");
10989
11550
  }
10990
11551
  function baseZedEvent(event) {
10991
11552
  return {
@@ -11049,7 +11610,7 @@ async function parseZedSessionFile(dbPath, options) {
11049
11610
  const folderRaw = row.folder_paths || "";
11050
11611
  const folder = folderRaw.split(/[\n,]/).map((s) => s.trim()).find(Boolean);
11051
11612
  const cwd = folder || void 0;
11052
- const project = cwd ? path21.basename(cwd) : row.summary ? row.summary.slice(0, 40) : void 0;
11613
+ const project = cwd ? path22.basename(cwd) : row.summary ? row.summary.slice(0, 40) : void 0;
11053
11614
  let json;
11054
11615
  try {
11055
11616
  const bytes = row.data_type === "zstd" ? decompress2(new Uint8Array(row.data)) : new Uint8Array(row.data);
@@ -11324,7 +11885,7 @@ function createZedAdapter() {
11324
11885
  return zedConfigDir(home, env);
11325
11886
  },
11326
11887
  installedPath(home, env) {
11327
- return path21.join(zedConfigDir(home, env), "vibetime-marker");
11888
+ return path22.join(zedConfigDir(home, env), "vibetime-marker");
11328
11889
  },
11329
11890
  async isInstalled() {
11330
11891
  return false;
@@ -11805,15 +12366,15 @@ function hookCommandFromGroup(group) {
11805
12366
  import { randomUUID } from "node:crypto";
11806
12367
  import { existsSync as existsSync2, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
11807
12368
  import { homedir, hostname } from "node:os";
11808
- import path22 from "node:path";
12369
+ import path23 from "node:path";
11809
12370
  function configDir(home = homedir()) {
11810
- return path22.join(home, ".vibetime");
12371
+ return path23.join(home, ".vibetime");
11811
12372
  }
11812
12373
  function configPath(home = homedir()) {
11813
- return path22.join(configDir(home), "config.json");
12374
+ return path23.join(configDir(home), "config.json");
11814
12375
  }
11815
12376
  function machineIdPath(home = homedir()) {
11816
- return path22.join(configDir(home), "machine-id");
12377
+ return path23.join(configDir(home), "machine-id");
11817
12378
  }
11818
12379
  function readConfig(home = homedir()) {
11819
12380
  const file = configPath(home);
@@ -11862,13 +12423,13 @@ init_fs();
11862
12423
  // src/lib/logger.ts
11863
12424
  import { appendFile, mkdir as mkdir4, rename, stat as stat12 } from "node:fs/promises";
11864
12425
  import { homedir as homedir2 } from "node:os";
11865
- import path23 from "node:path";
12426
+ import path24 from "node:path";
11866
12427
  var MAX_BYTES = 1 * 1024 * 1024;
11867
12428
  function logDir(home = homedir2()) {
11868
- return path23.join(home, ".vibetime", "logs");
12429
+ return path24.join(home, ".vibetime", "logs");
11869
12430
  }
11870
12431
  function logPath(home = homedir2(), name = "cli.log") {
11871
- return path23.join(logDir(home), name);
12432
+ return path24.join(logDir(home), name);
11872
12433
  }
11873
12434
  function serializeError(error) {
11874
12435
  if (error instanceof Error) {
@@ -12043,8 +12604,8 @@ function buildHeaders(token, machine) {
12043
12604
  ...machine?.platform ? { "x-machine-platform": machine.platform } : {}
12044
12605
  };
12045
12606
  }
12046
- function joinUrl(base, path25) {
12047
- return new URL(path25, base.endsWith("/") ? base : `${base}/`).toString();
12607
+ function joinUrl(base, path26) {
12608
+ return new URL(path26, base.endsWith("/") ? base : `${base}/`).toString();
12048
12609
  }
12049
12610
  async function postRollupBatch(remote, rollups, options = {}) {
12050
12611
  const response = await remote.fetchImpl(joinUrl(remote.baseUrl, "/v3/agent/ingest"), {
@@ -12134,6 +12695,7 @@ function createRegistry() {
12134
12695
  registry.register(createZCodeAdapter());
12135
12696
  registry.register(createGrokBuildAdapter());
12136
12697
  registry.register(createZedAdapter());
12698
+ registry.register(createKimiCodeAdapter());
12137
12699
  return registry;
12138
12700
  }
12139
12701
  var defaultContext = {
@@ -13029,13 +13591,13 @@ function selectBackfillFilesForImport(files, watermarkTs) {
13029
13591
  return picked;
13030
13592
  }
13031
13593
  function backfillIncrementalStatePath(home) {
13032
- return path24.join(home, ".vibetime", "backfill-state.json");
13594
+ return path25.join(home, ".vibetime", "backfill-state.json");
13033
13595
  }
13034
13596
  function syncLocalTriggerStatePath(home) {
13035
- return path24.join(home, ".vibetime", "sync-local-trigger.json");
13597
+ return path25.join(home, ".vibetime", "sync-local-trigger.json");
13036
13598
  }
13037
13599
  function syncLocalTriggerLockPath(home) {
13038
- return path24.join(home, ".vibetime", "sync-local-trigger.lock");
13600
+ return path25.join(home, ".vibetime", "sync-local-trigger.lock");
13039
13601
  }
13040
13602
  function backfillRemoteKey(baseUrl) {
13041
13603
  try {
@@ -13097,7 +13659,7 @@ async function readBackfillIncrementalStateFile(home, ctx) {
13097
13659
  }
13098
13660
  async function writeBackfillIncrementalStateFile(home, file) {
13099
13661
  const statePath = backfillIncrementalStatePath(home);
13100
- await mkdir5(path24.dirname(statePath), { recursive: true });
13662
+ await mkdir5(path25.dirname(statePath), { recursive: true });
13101
13663
  await writeFile4(statePath, `${JSON.stringify(file, null, 2)}
13102
13664
  `, "utf8");
13103
13665
  }
@@ -13146,7 +13708,7 @@ async function readSyncLocalTriggerState(statePath) {
13146
13708
  return nextState;
13147
13709
  }
13148
13710
  async function writeSyncLocalTriggerState(statePath, state) {
13149
- await mkdir5(path24.dirname(statePath), { recursive: true });
13711
+ await mkdir5(path25.dirname(statePath), { recursive: true });
13150
13712
  await writeFile4(statePath, `${JSON.stringify(state, null, 2)}
13151
13713
  `, "utf8");
13152
13714
  }
@@ -13161,12 +13723,12 @@ async function readSyncLocalLock(lockPath) {
13161
13723
  return { pid: lock.pid, startedAt: lock.startedAt };
13162
13724
  }
13163
13725
  async function writeSyncLocalLock(lockPath, lock) {
13164
- await mkdir5(path24.dirname(lockPath), { recursive: true });
13726
+ await mkdir5(path25.dirname(lockPath), { recursive: true });
13165
13727
  await writeFile4(lockPath, `${JSON.stringify(lock, null, 2)}
13166
13728
  `, "utf8");
13167
13729
  }
13168
13730
  async function acquireSyncLocalLock(lockPath, lock) {
13169
- await mkdir5(path24.dirname(lockPath), { recursive: true });
13731
+ await mkdir5(path25.dirname(lockPath), { recursive: true });
13170
13732
  try {
13171
13733
  const handle = await open(lockPath, "wx");
13172
13734
  try {
@@ -13246,10 +13808,10 @@ function syncLocalRunnerEntryArgs(cliPath) {
13246
13808
  if (cliPath.endsWith(".ts")) {
13247
13809
  return ["--import", "tsx", cliPath];
13248
13810
  }
13249
- return [path24.resolve(path24.dirname(cliPath), "../bin/vibetime.mjs")];
13811
+ return [path25.resolve(path25.dirname(cliPath), "../bin/vibetime.mjs")];
13250
13812
  }
13251
13813
  function resolveHome3(options, ctx) {
13252
- return path24.resolve(stringOption(options.home) || ctx.env.HOME || os11.homedir());
13814
+ return path25.resolve(stringOption(options.home) || ctx.env.HOME || os11.homedir());
13253
13815
  }
13254
13816
  function requestedTargets(options) {
13255
13817
  const value = options.target || options.targets;