@yhong91/vibetime 0.1.70 → 0.1.72
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.
- package/bin/vibetime.mjs +972 -279
- package/package.json +1 -1
package/bin/vibetime.mjs
CHANGED
|
@@ -884,9 +884,9 @@ var init_esm = __esm({
|
|
|
884
884
|
|
|
885
885
|
// src/cli.ts
|
|
886
886
|
import { spawn as spawn2, spawnSync } from "node:child_process";
|
|
887
|
-
import { mkdir as mkdir6, open, rm, stat as
|
|
887
|
+
import { mkdir as mkdir6, open, rm, stat as stat18, writeFile as writeFile5 } from "node:fs/promises";
|
|
888
888
|
import os14 from "node:os";
|
|
889
|
-
import
|
|
889
|
+
import path27 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", "kimi-code", "cursor", "grok-bot"];
|
|
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", "cursor", "grok-bot", "hermes"];
|
|
928
928
|
function createWorkspaceId(input) {
|
|
929
929
|
const basis = input.repoUrl || input.repoRoot || input.projectName || "unknown";
|
|
930
930
|
return `workspace_${fnv1a(basis)}`;
|
|
@@ -1082,9 +1082,9 @@ function removeVolatileHashFields(value) {
|
|
|
1082
1082
|
continue;
|
|
1083
1083
|
}
|
|
1084
1084
|
if (key === "refs" && isRecord(item)) {
|
|
1085
|
-
const
|
|
1086
|
-
delete
|
|
1087
|
-
result[key] = removeVolatileHashFields(
|
|
1085
|
+
const refs3 = { ...item };
|
|
1086
|
+
delete refs3.payloadHash;
|
|
1087
|
+
result[key] = removeVolatileHashFields(refs3);
|
|
1088
1088
|
continue;
|
|
1089
1089
|
}
|
|
1090
1090
|
result[key] = removeVolatileHashFields(item);
|
|
@@ -1747,13 +1747,13 @@ function isPlainObject(value) {
|
|
|
1747
1747
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
1748
1748
|
}
|
|
1749
1749
|
function stringRefs(value) {
|
|
1750
|
-
const
|
|
1750
|
+
const refs3 = {};
|
|
1751
1751
|
for (const [key, item] of Object.entries(value || {})) {
|
|
1752
1752
|
if (typeof item === "string" && item.length > 0) {
|
|
1753
|
-
|
|
1753
|
+
refs3[key] = item;
|
|
1754
1754
|
}
|
|
1755
1755
|
}
|
|
1756
|
-
return
|
|
1756
|
+
return refs3;
|
|
1757
1757
|
}
|
|
1758
1758
|
function stringOption(value) {
|
|
1759
1759
|
if (Array.isArray(value)) {
|
|
@@ -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.
|
|
2050
|
+
var PACKAGE_VERSION = true ? "0.1.72" : "0.1.1";
|
|
2051
2051
|
var GENERATED_MARKER = "Generated by vibetime.";
|
|
2052
2052
|
var DEFAULT_API_URL = "http://121.196.224.82:3001";
|
|
2053
2053
|
var DEFAULT_BACKFILL_BATCH_SIZE = 50;
|
|
@@ -2111,7 +2111,7 @@ function withBackfillRefs(event, context) {
|
|
|
2111
2111
|
event.type,
|
|
2112
2112
|
event.refs?.sourceId
|
|
2113
2113
|
]);
|
|
2114
|
-
const
|
|
2114
|
+
const refs3 = {
|
|
2115
2115
|
...stringRefs(event.refs),
|
|
2116
2116
|
importKey,
|
|
2117
2117
|
sourcePathHash: context.sourcePathHash,
|
|
@@ -2121,12 +2121,12 @@ function withBackfillRefs(event, context) {
|
|
|
2121
2121
|
parserVersion: PACKAGE_VERSION
|
|
2122
2122
|
};
|
|
2123
2123
|
if (context.options.includeSourcePath) {
|
|
2124
|
-
|
|
2124
|
+
refs3.transcriptPath = context.filePath;
|
|
2125
2125
|
}
|
|
2126
2126
|
return {
|
|
2127
2127
|
...event,
|
|
2128
2128
|
id: createStableEventId(importKey),
|
|
2129
|
-
refs:
|
|
2129
|
+
refs: refs3
|
|
2130
2130
|
};
|
|
2131
2131
|
}
|
|
2132
2132
|
function matchesBackfillFilters(event, options) {
|
|
@@ -4186,12 +4186,12 @@ async function parseClaudeCoworkSessionFile(filePath, options) {
|
|
|
4186
4186
|
const sessionId = parentSessionId || prefixCoworkId(event.sessionId);
|
|
4187
4187
|
const turnId = prefixCoworkId(event.turnId);
|
|
4188
4188
|
const workspaceId = createWorkspaceId({ projectName: project, repoRoot: cwd });
|
|
4189
|
-
const
|
|
4189
|
+
const refs3 = { ...event.refs };
|
|
4190
4190
|
if (metadata.title) {
|
|
4191
|
-
|
|
4191
|
+
refs3.coworkTitleHash = `sha256:${createStableHash(metadata.title)}`;
|
|
4192
4192
|
}
|
|
4193
4193
|
if (parentSourcePathHash) {
|
|
4194
|
-
|
|
4194
|
+
refs3.sourcePathHash = parentSourcePathHash;
|
|
4195
4195
|
}
|
|
4196
4196
|
const mapped = {
|
|
4197
4197
|
...event,
|
|
@@ -4203,7 +4203,7 @@ async function parseClaudeCoworkSessionFile(filePath, options) {
|
|
|
4203
4203
|
project,
|
|
4204
4204
|
sessionId,
|
|
4205
4205
|
turnId,
|
|
4206
|
-
refs:
|
|
4206
|
+
refs: refs3
|
|
4207
4207
|
};
|
|
4208
4208
|
return rebuildEventIdentity(mapped);
|
|
4209
4209
|
});
|
|
@@ -4936,8 +4936,8 @@ async function codebuddyBackfillFiles(sourceRoot, home, env) {
|
|
|
4936
4936
|
}
|
|
4937
4937
|
const filePath = path9.join(traceDir, entry);
|
|
4938
4938
|
try {
|
|
4939
|
-
const
|
|
4940
|
-
files.push({ path: filePath, modifiedAt:
|
|
4939
|
+
const stat19 = await import("node:fs/promises").then((fs) => fs.stat(filePath));
|
|
4940
|
+
files.push({ path: filePath, modifiedAt: stat19.mtime.toISOString(), groupId: pidDir.name });
|
|
4941
4941
|
} catch {
|
|
4942
4942
|
}
|
|
4943
4943
|
}
|
|
@@ -9039,9 +9039,698 @@ function createGrokBuildAdapter() {
|
|
|
9039
9039
|
};
|
|
9040
9040
|
}
|
|
9041
9041
|
|
|
9042
|
+
// src/adapters/hermes.ts
|
|
9043
|
+
import { readdir as readdir8, stat as stat11 } from "node:fs/promises";
|
|
9044
|
+
import path15 from "node:path";
|
|
9045
|
+
init_fs();
|
|
9046
|
+
var SOURCE = "hermes";
|
|
9047
|
+
var PLUGIN_DIR = ["plugins", "vibetime"];
|
|
9048
|
+
var GENERATED_MARKER3 = "Generated by vibetime.";
|
|
9049
|
+
var HOOK_COMMAND3 = "vibetime hook --agent hermes";
|
|
9050
|
+
function hermesRoot(home, env) {
|
|
9051
|
+
const override = env?.HERMES_HOME;
|
|
9052
|
+
if (override && override.trim()) {
|
|
9053
|
+
return path15.resolve(override);
|
|
9054
|
+
}
|
|
9055
|
+
return path15.join(home, ".hermes");
|
|
9056
|
+
}
|
|
9057
|
+
function hermesPluginDir(home, env) {
|
|
9058
|
+
return path15.join(hermesRoot(home, env), ...PLUGIN_DIR);
|
|
9059
|
+
}
|
|
9060
|
+
function hermesPluginManifestPath(home, env) {
|
|
9061
|
+
return path15.join(hermesPluginDir(home, env), "plugin.yaml");
|
|
9062
|
+
}
|
|
9063
|
+
function hermesPluginInitPath(home, env) {
|
|
9064
|
+
return path15.join(hermesPluginDir(home, env), "__init__.py");
|
|
9065
|
+
}
|
|
9066
|
+
function sourceHash(filePath) {
|
|
9067
|
+
return `sha256:${createStableHash(filePath)}`;
|
|
9068
|
+
}
|
|
9069
|
+
function refs(values) {
|
|
9070
|
+
const out = {};
|
|
9071
|
+
for (const [key, value] of Object.entries(values)) {
|
|
9072
|
+
if (value !== void 0 && value !== "") {
|
|
9073
|
+
out[key] = String(value);
|
|
9074
|
+
}
|
|
9075
|
+
}
|
|
9076
|
+
return out;
|
|
9077
|
+
}
|
|
9078
|
+
function projectFromCwd(cwd, repoRoot) {
|
|
9079
|
+
const basis = repoRoot || cwd;
|
|
9080
|
+
return basis ? path15.basename(basis) || SOURCE : SOURCE;
|
|
9081
|
+
}
|
|
9082
|
+
function isoFromUnix(value) {
|
|
9083
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
|
|
9084
|
+
return void 0;
|
|
9085
|
+
}
|
|
9086
|
+
return timestampFrom(value);
|
|
9087
|
+
}
|
|
9088
|
+
function tableColumns(db, table) {
|
|
9089
|
+
try {
|
|
9090
|
+
const rows = db.prepare(`PRAGMA table_info(${table})`).all();
|
|
9091
|
+
return new Set(rows.map((row) => row.name).filter((name) => Boolean(name)));
|
|
9092
|
+
} catch {
|
|
9093
|
+
return /* @__PURE__ */ new Set();
|
|
9094
|
+
}
|
|
9095
|
+
}
|
|
9096
|
+
function selectExisting(columns, wanted) {
|
|
9097
|
+
return wanted.filter((name) => columns.has(name));
|
|
9098
|
+
}
|
|
9099
|
+
function asRecord(value) {
|
|
9100
|
+
return isPlainObject(value) ? value : {};
|
|
9101
|
+
}
|
|
9102
|
+
function sessionContext(row) {
|
|
9103
|
+
const rawId = stringField(row, "id") || "unknown";
|
|
9104
|
+
const cwd = stringField(row, "cwd");
|
|
9105
|
+
const repoRoot = stringField(row, "git_repo_root");
|
|
9106
|
+
const project = projectFromCwd(cwd, repoRoot);
|
|
9107
|
+
return {
|
|
9108
|
+
rawId,
|
|
9109
|
+
sessionId: `${SOURCE}:${rawId}`,
|
|
9110
|
+
cwd,
|
|
9111
|
+
project,
|
|
9112
|
+
workspaceId: createWorkspaceId({ projectName: project, repoRoot: repoRoot || cwd }),
|
|
9113
|
+
platform: stringField(row, "source"),
|
|
9114
|
+
profileName: stringField(row, "profile_name"),
|
|
9115
|
+
parentSessionId: stringField(row, "parent_session_id"),
|
|
9116
|
+
model: stringField(row, "model"),
|
|
9117
|
+
provider: stringField(row, "billing_provider")
|
|
9118
|
+
};
|
|
9119
|
+
}
|
|
9120
|
+
function makeEvent(event, lineNumber, filePath, options) {
|
|
9121
|
+
const withRefs = withBackfillRefs(event, {
|
|
9122
|
+
filePath,
|
|
9123
|
+
sourcePathHash: sourceHash(filePath),
|
|
9124
|
+
lineNumber,
|
|
9125
|
+
topType: event.type,
|
|
9126
|
+
payloadType: event.refs?.payloadType || event.tool || event.type,
|
|
9127
|
+
options
|
|
9128
|
+
});
|
|
9129
|
+
return validateCanonicalEvent(withRefs).valid ? withRefs : void 0;
|
|
9130
|
+
}
|
|
9131
|
+
function usageMetrics2(row) {
|
|
9132
|
+
const input = numberField(row, "input_tokens") || 0;
|
|
9133
|
+
const output = numberField(row, "output_tokens") || 0;
|
|
9134
|
+
const cacheRead = numberField(row, "cache_read_tokens") || 0;
|
|
9135
|
+
const cacheWrite = numberField(row, "cache_write_tokens") || 0;
|
|
9136
|
+
const reasoning = numberField(row, "reasoning_tokens") || 0;
|
|
9137
|
+
const actualCost = numberField(row, "actual_cost_usd");
|
|
9138
|
+
const estimatedCost = numberField(row, "estimated_cost_usd");
|
|
9139
|
+
const costUsd = actualCost && actualCost > 0 ? actualCost : estimatedCost;
|
|
9140
|
+
return {
|
|
9141
|
+
tokensInput: input || void 0,
|
|
9142
|
+
tokensOutput: output || void 0,
|
|
9143
|
+
tokensCacheReadInput: cacheRead || void 0,
|
|
9144
|
+
tokensCacheCreationInput: cacheWrite || void 0,
|
|
9145
|
+
tokensCachedInput: cacheRead + cacheWrite || void 0,
|
|
9146
|
+
tokensReasoningOutput: reasoning || void 0,
|
|
9147
|
+
tokensTotal: input + output + cacheRead + cacheWrite,
|
|
9148
|
+
modelCalls: numberField(row, "api_call_count") || void 0,
|
|
9149
|
+
costUsd: costUsd && costUsd > 0 ? costUsd : void 0
|
|
9150
|
+
};
|
|
9151
|
+
}
|
|
9152
|
+
function sessionHasWork(row, usageRows) {
|
|
9153
|
+
if (usageRows.some((item) => (numberField(item, "input_tokens") || 0) + (numberField(item, "output_tokens") || 0) > 0)) {
|
|
9154
|
+
return true;
|
|
9155
|
+
}
|
|
9156
|
+
if ((numberField(row, "input_tokens") || 0) + (numberField(row, "output_tokens") || 0) > 0) {
|
|
9157
|
+
return true;
|
|
9158
|
+
}
|
|
9159
|
+
if ((numberField(row, "message_count") || 0) > 0) {
|
|
9160
|
+
return true;
|
|
9161
|
+
}
|
|
9162
|
+
if ((numberField(row, "tool_call_count") || 0) > 0) {
|
|
9163
|
+
return true;
|
|
9164
|
+
}
|
|
9165
|
+
return false;
|
|
9166
|
+
}
|
|
9167
|
+
function parseToolCalls(raw) {
|
|
9168
|
+
let parsed = raw;
|
|
9169
|
+
if (typeof raw === "string" && raw.trim()) {
|
|
9170
|
+
try {
|
|
9171
|
+
parsed = JSON.parse(raw);
|
|
9172
|
+
} catch {
|
|
9173
|
+
return [];
|
|
9174
|
+
}
|
|
9175
|
+
}
|
|
9176
|
+
if (!Array.isArray(parsed)) {
|
|
9177
|
+
return [];
|
|
9178
|
+
}
|
|
9179
|
+
const out = [];
|
|
9180
|
+
for (const item of parsed) {
|
|
9181
|
+
if (!isPlainObject(item)) {
|
|
9182
|
+
continue;
|
|
9183
|
+
}
|
|
9184
|
+
const fn = isPlainObject(item.function) ? item.function : item;
|
|
9185
|
+
const name = stringField(fn, "name") || stringField(item, "name");
|
|
9186
|
+
if (!name) {
|
|
9187
|
+
continue;
|
|
9188
|
+
}
|
|
9189
|
+
let input = {};
|
|
9190
|
+
const args = fn.arguments ?? item.arguments;
|
|
9191
|
+
if (typeof args === "string" && args.trim()) {
|
|
9192
|
+
try {
|
|
9193
|
+
const parsedArgs = JSON.parse(args);
|
|
9194
|
+
if (isPlainObject(parsedArgs)) {
|
|
9195
|
+
input = parsedArgs;
|
|
9196
|
+
}
|
|
9197
|
+
} catch {
|
|
9198
|
+
input = {};
|
|
9199
|
+
}
|
|
9200
|
+
} else if (isPlainObject(args)) {
|
|
9201
|
+
input = args;
|
|
9202
|
+
}
|
|
9203
|
+
out.push({
|
|
9204
|
+
id: stringField(item, "id") || stringField(item, "call_id") || stringField(fn, "id"),
|
|
9205
|
+
name,
|
|
9206
|
+
input
|
|
9207
|
+
});
|
|
9208
|
+
}
|
|
9209
|
+
return out;
|
|
9210
|
+
}
|
|
9211
|
+
function hermesToolAlias(tool) {
|
|
9212
|
+
const normalized = tool.toLowerCase();
|
|
9213
|
+
if (normalized === "write_file") {
|
|
9214
|
+
return "write";
|
|
9215
|
+
}
|
|
9216
|
+
if (normalized === "patch") {
|
|
9217
|
+
return "edit";
|
|
9218
|
+
}
|
|
9219
|
+
if (normalized === "read_file") {
|
|
9220
|
+
return "read";
|
|
9221
|
+
}
|
|
9222
|
+
return tool;
|
|
9223
|
+
}
|
|
9224
|
+
async function sqliteMtime(filePath) {
|
|
9225
|
+
try {
|
|
9226
|
+
const info = await stat11(filePath);
|
|
9227
|
+
let modifiedMs = info.mtimeMs;
|
|
9228
|
+
for (const suffix of ["-wal", "-shm"]) {
|
|
9229
|
+
try {
|
|
9230
|
+
const sidecar = await stat11(`${filePath}${suffix}`);
|
|
9231
|
+
modifiedMs = Math.max(modifiedMs, sidecar.mtimeMs);
|
|
9232
|
+
} catch {
|
|
9233
|
+
}
|
|
9234
|
+
}
|
|
9235
|
+
return new Date(modifiedMs).toISOString();
|
|
9236
|
+
} catch {
|
|
9237
|
+
return void 0;
|
|
9238
|
+
}
|
|
9239
|
+
}
|
|
9240
|
+
async function parseHermesDb(filePath, options) {
|
|
9241
|
+
if (!filePath.endsWith(".db")) {
|
|
9242
|
+
return [];
|
|
9243
|
+
}
|
|
9244
|
+
const { DatabaseSync } = await import("node:sqlite");
|
|
9245
|
+
let db;
|
|
9246
|
+
try {
|
|
9247
|
+
db = new DatabaseSync(filePath, { readOnly: true });
|
|
9248
|
+
} catch {
|
|
9249
|
+
return [];
|
|
9250
|
+
}
|
|
9251
|
+
try {
|
|
9252
|
+
const sessionCols = tableColumns(db, "sessions");
|
|
9253
|
+
if (!sessionCols.has("id") || !sessionCols.has("started_at")) {
|
|
9254
|
+
return [];
|
|
9255
|
+
}
|
|
9256
|
+
const sessionSelect = selectExisting(sessionCols, [
|
|
9257
|
+
"id",
|
|
9258
|
+
"source",
|
|
9259
|
+
"model",
|
|
9260
|
+
"parent_session_id",
|
|
9261
|
+
"started_at",
|
|
9262
|
+
"ended_at",
|
|
9263
|
+
"message_count",
|
|
9264
|
+
"tool_call_count",
|
|
9265
|
+
"input_tokens",
|
|
9266
|
+
"output_tokens",
|
|
9267
|
+
"cache_read_tokens",
|
|
9268
|
+
"cache_write_tokens",
|
|
9269
|
+
"reasoning_tokens",
|
|
9270
|
+
"cwd",
|
|
9271
|
+
"git_repo_root",
|
|
9272
|
+
"billing_provider",
|
|
9273
|
+
"estimated_cost_usd",
|
|
9274
|
+
"actual_cost_usd",
|
|
9275
|
+
"title",
|
|
9276
|
+
"last_activity_at",
|
|
9277
|
+
"profile_name"
|
|
9278
|
+
]);
|
|
9279
|
+
const sessions = db.prepare(
|
|
9280
|
+
`SELECT ${sessionSelect.join(", ")} FROM sessions WHERE started_at IS NOT NULL ORDER BY started_at, id`
|
|
9281
|
+
).all().map(asRecord);
|
|
9282
|
+
const usageCols = tableColumns(db, "session_model_usage");
|
|
9283
|
+
const usageBySession = /* @__PURE__ */ new Map();
|
|
9284
|
+
if (usageCols.has("session_id")) {
|
|
9285
|
+
const usageSelect = selectExisting(usageCols, [
|
|
9286
|
+
"session_id",
|
|
9287
|
+
"model",
|
|
9288
|
+
"billing_provider",
|
|
9289
|
+
"billing_base_url",
|
|
9290
|
+
"billing_mode",
|
|
9291
|
+
"task",
|
|
9292
|
+
"api_call_count",
|
|
9293
|
+
"input_tokens",
|
|
9294
|
+
"output_tokens",
|
|
9295
|
+
"cache_read_tokens",
|
|
9296
|
+
"cache_write_tokens",
|
|
9297
|
+
"reasoning_tokens",
|
|
9298
|
+
"estimated_cost_usd",
|
|
9299
|
+
"actual_cost_usd",
|
|
9300
|
+
"first_seen",
|
|
9301
|
+
"last_seen"
|
|
9302
|
+
]);
|
|
9303
|
+
const usageRows = db.prepare(
|
|
9304
|
+
`SELECT ${usageSelect.join(", ")} FROM session_model_usage`
|
|
9305
|
+
).all().map(asRecord);
|
|
9306
|
+
for (const row of usageRows) {
|
|
9307
|
+
const sessionId = stringField(row, "session_id");
|
|
9308
|
+
if (!sessionId) {
|
|
9309
|
+
continue;
|
|
9310
|
+
}
|
|
9311
|
+
const list = usageBySession.get(sessionId) || [];
|
|
9312
|
+
list.push(row);
|
|
9313
|
+
usageBySession.set(sessionId, list);
|
|
9314
|
+
}
|
|
9315
|
+
}
|
|
9316
|
+
const messageCols = tableColumns(db, "messages");
|
|
9317
|
+
const messagesBySession = /* @__PURE__ */ new Map();
|
|
9318
|
+
if (messageCols.has("session_id") && messageCols.has("role")) {
|
|
9319
|
+
const messageSelect = selectExisting(messageCols, [
|
|
9320
|
+
"id",
|
|
9321
|
+
"session_id",
|
|
9322
|
+
"role",
|
|
9323
|
+
"content",
|
|
9324
|
+
"tool_calls",
|
|
9325
|
+
"timestamp",
|
|
9326
|
+
"token_count",
|
|
9327
|
+
"active"
|
|
9328
|
+
]);
|
|
9329
|
+
const activeFilter = messageCols.has("active") ? " WHERE coalesce(active, 1) = 1" : "";
|
|
9330
|
+
const messageRows = db.prepare(
|
|
9331
|
+
`SELECT ${messageSelect.join(", ")} FROM messages${activeFilter} ORDER BY timestamp, id`
|
|
9332
|
+
).all().map(asRecord);
|
|
9333
|
+
for (const row of messageRows) {
|
|
9334
|
+
const sessionId = stringField(row, "session_id");
|
|
9335
|
+
if (!sessionId) {
|
|
9336
|
+
continue;
|
|
9337
|
+
}
|
|
9338
|
+
const list = messagesBySession.get(sessionId) || [];
|
|
9339
|
+
list.push(row);
|
|
9340
|
+
messagesBySession.set(sessionId, list);
|
|
9341
|
+
}
|
|
9342
|
+
}
|
|
9343
|
+
const events = [];
|
|
9344
|
+
let lineNumber = 0;
|
|
9345
|
+
for (const session of sessions) {
|
|
9346
|
+
const ctx = sessionContext(session);
|
|
9347
|
+
const usageRows = usageBySession.get(ctx.rawId) || [];
|
|
9348
|
+
const messages = messagesBySession.get(ctx.rawId) || [];
|
|
9349
|
+
if (!sessionHasWork(session, usageRows) && messages.length === 0) {
|
|
9350
|
+
continue;
|
|
9351
|
+
}
|
|
9352
|
+
const startedTs = isoFromUnix(session.started_at);
|
|
9353
|
+
if (!startedTs) {
|
|
9354
|
+
continue;
|
|
9355
|
+
}
|
|
9356
|
+
lineNumber += 1;
|
|
9357
|
+
const started = makeEvent({
|
|
9358
|
+
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
9359
|
+
ts: startedTs,
|
|
9360
|
+
type: "session.started",
|
|
9361
|
+
source: SOURCE,
|
|
9362
|
+
workspaceId: ctx.workspaceId,
|
|
9363
|
+
project: ctx.project,
|
|
9364
|
+
cwd: ctx.cwd,
|
|
9365
|
+
sessionId: ctx.sessionId,
|
|
9366
|
+
parentAgentInstanceId: ctx.parentSessionId ? `${SOURCE}:${ctx.parentSessionId}` : void 0,
|
|
9367
|
+
agent: SOURCE,
|
|
9368
|
+
model: ctx.model,
|
|
9369
|
+
provider: ctx.provider,
|
|
9370
|
+
confidence: "exact",
|
|
9371
|
+
refs: refs({
|
|
9372
|
+
sourceId: `${ctx.rawId}:session`,
|
|
9373
|
+
hermesPlatform: ctx.platform,
|
|
9374
|
+
hermesProfile: ctx.profileName,
|
|
9375
|
+
hermesParentSessionId: ctx.parentSessionId
|
|
9376
|
+
})
|
|
9377
|
+
}, lineNumber, filePath, options);
|
|
9378
|
+
if (started) {
|
|
9379
|
+
events.push(started);
|
|
9380
|
+
}
|
|
9381
|
+
const endedTs = isoFromUnix(session.ended_at) || isoFromUnix(session.last_activity_at);
|
|
9382
|
+
if (endedTs && endedTs !== startedTs) {
|
|
9383
|
+
lineNumber += 1;
|
|
9384
|
+
const ended = makeEvent({
|
|
9385
|
+
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
9386
|
+
ts: endedTs,
|
|
9387
|
+
type: "session.ended",
|
|
9388
|
+
source: SOURCE,
|
|
9389
|
+
workspaceId: ctx.workspaceId,
|
|
9390
|
+
project: ctx.project,
|
|
9391
|
+
cwd: ctx.cwd,
|
|
9392
|
+
sessionId: ctx.sessionId,
|
|
9393
|
+
parentAgentInstanceId: ctx.parentSessionId ? `${SOURCE}:${ctx.parentSessionId}` : void 0,
|
|
9394
|
+
agent: SOURCE,
|
|
9395
|
+
model: ctx.model,
|
|
9396
|
+
provider: ctx.provider,
|
|
9397
|
+
confidence: "exact",
|
|
9398
|
+
refs: refs({
|
|
9399
|
+
sourceId: `${ctx.rawId}:session:ended`,
|
|
9400
|
+
hermesPlatform: ctx.platform,
|
|
9401
|
+
hermesProfile: ctx.profileName
|
|
9402
|
+
})
|
|
9403
|
+
}, lineNumber, filePath, options);
|
|
9404
|
+
if (ended) {
|
|
9405
|
+
events.push(ended);
|
|
9406
|
+
}
|
|
9407
|
+
}
|
|
9408
|
+
if (usageRows.length > 0) {
|
|
9409
|
+
for (const usage of usageRows) {
|
|
9410
|
+
const ts = isoFromUnix(usage.last_seen) || isoFromUnix(usage.first_seen) || startedTs;
|
|
9411
|
+
lineNumber += 1;
|
|
9412
|
+
const event = makeEvent({
|
|
9413
|
+
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
9414
|
+
ts,
|
|
9415
|
+
type: "model.usage",
|
|
9416
|
+
source: SOURCE,
|
|
9417
|
+
workspaceId: ctx.workspaceId,
|
|
9418
|
+
project: ctx.project,
|
|
9419
|
+
cwd: ctx.cwd,
|
|
9420
|
+
sessionId: ctx.sessionId,
|
|
9421
|
+
agent: SOURCE,
|
|
9422
|
+
model: stringField(usage, "model") || ctx.model,
|
|
9423
|
+
provider: stringField(usage, "billing_provider") || ctx.provider,
|
|
9424
|
+
success: true,
|
|
9425
|
+
metrics: usageMetrics2(usage),
|
|
9426
|
+
confidence: "exact",
|
|
9427
|
+
refs: refs({
|
|
9428
|
+
sourceId: `${ctx.rawId}:model:${stringField(usage, "model") || "unknown"}:${stringField(usage, "task") || "main"}:${stringField(usage, "billing_provider") || ""}`,
|
|
9429
|
+
hermesPlatform: ctx.platform,
|
|
9430
|
+
hermesProfile: ctx.profileName,
|
|
9431
|
+
hermesTask: stringField(usage, "task"),
|
|
9432
|
+
hermesBillingMode: stringField(usage, "billing_mode")
|
|
9433
|
+
})
|
|
9434
|
+
}, lineNumber, filePath, options);
|
|
9435
|
+
if (event) {
|
|
9436
|
+
events.push(event);
|
|
9437
|
+
}
|
|
9438
|
+
}
|
|
9439
|
+
} else if ((numberField(session, "input_tokens") || 0) + (numberField(session, "output_tokens") || 0) > 0) {
|
|
9440
|
+
lineNumber += 1;
|
|
9441
|
+
const event = makeEvent({
|
|
9442
|
+
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
9443
|
+
ts: endedTs || startedTs,
|
|
9444
|
+
type: "model.usage",
|
|
9445
|
+
source: SOURCE,
|
|
9446
|
+
workspaceId: ctx.workspaceId,
|
|
9447
|
+
project: ctx.project,
|
|
9448
|
+
cwd: ctx.cwd,
|
|
9449
|
+
sessionId: ctx.sessionId,
|
|
9450
|
+
agent: SOURCE,
|
|
9451
|
+
model: ctx.model,
|
|
9452
|
+
provider: ctx.provider,
|
|
9453
|
+
success: true,
|
|
9454
|
+
metrics: usageMetrics2(session),
|
|
9455
|
+
confidence: "partial",
|
|
9456
|
+
refs: refs({
|
|
9457
|
+
sourceId: `${ctx.rawId}:model:session`,
|
|
9458
|
+
hermesPlatform: ctx.platform,
|
|
9459
|
+
hermesProfile: ctx.profileName
|
|
9460
|
+
})
|
|
9461
|
+
}, lineNumber, filePath, options);
|
|
9462
|
+
if (event) {
|
|
9463
|
+
events.push(event);
|
|
9464
|
+
}
|
|
9465
|
+
}
|
|
9466
|
+
let turnIndex = 0;
|
|
9467
|
+
let activeTurnId;
|
|
9468
|
+
for (const message of messages) {
|
|
9469
|
+
const ts = isoFromUnix(message.timestamp);
|
|
9470
|
+
if (!ts) {
|
|
9471
|
+
continue;
|
|
9472
|
+
}
|
|
9473
|
+
const role = stringField(message, "role");
|
|
9474
|
+
if (role === "user") {
|
|
9475
|
+
turnIndex += 1;
|
|
9476
|
+
activeTurnId = `${ctx.sessionId}:turn:${turnIndex}`;
|
|
9477
|
+
lineNumber += 1;
|
|
9478
|
+
const turnStarted = makeEvent({
|
|
9479
|
+
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
9480
|
+
ts,
|
|
9481
|
+
type: "turn.started",
|
|
9482
|
+
source: SOURCE,
|
|
9483
|
+
workspaceId: ctx.workspaceId,
|
|
9484
|
+
project: ctx.project,
|
|
9485
|
+
cwd: ctx.cwd,
|
|
9486
|
+
sessionId: ctx.sessionId,
|
|
9487
|
+
turnId: activeTurnId,
|
|
9488
|
+
agent: SOURCE,
|
|
9489
|
+
confidence: "derived",
|
|
9490
|
+
refs: refs({ sourceId: `${ctx.rawId}:turn:${turnIndex}:start` })
|
|
9491
|
+
}, lineNumber, filePath, options);
|
|
9492
|
+
if (turnStarted) {
|
|
9493
|
+
events.push(turnStarted);
|
|
9494
|
+
}
|
|
9495
|
+
const content = stringField(message, "content");
|
|
9496
|
+
lineNumber += 1;
|
|
9497
|
+
const prompt = makeEvent({
|
|
9498
|
+
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
9499
|
+
ts,
|
|
9500
|
+
type: "prompt.submitted",
|
|
9501
|
+
source: SOURCE,
|
|
9502
|
+
workspaceId: ctx.workspaceId,
|
|
9503
|
+
project: ctx.project,
|
|
9504
|
+
cwd: ctx.cwd,
|
|
9505
|
+
sessionId: ctx.sessionId,
|
|
9506
|
+
turnId: activeTurnId,
|
|
9507
|
+
agent: SOURCE,
|
|
9508
|
+
confidence: "exact",
|
|
9509
|
+
metrics: { promptChars: content?.length, prompts: 1 },
|
|
9510
|
+
refs: refs({ sourceId: `${ctx.rawId}:prompt:${stringField(message, "id") || turnIndex}` })
|
|
9511
|
+
}, lineNumber, filePath, options);
|
|
9512
|
+
if (prompt) {
|
|
9513
|
+
events.push(prompt);
|
|
9514
|
+
}
|
|
9515
|
+
continue;
|
|
9516
|
+
}
|
|
9517
|
+
if (role !== "assistant") {
|
|
9518
|
+
continue;
|
|
9519
|
+
}
|
|
9520
|
+
const tools = parseToolCalls(message.tool_calls);
|
|
9521
|
+
for (const tool of tools) {
|
|
9522
|
+
const toolName = tool.name;
|
|
9523
|
+
const alias = hermesToolAlias(toolName);
|
|
9524
|
+
const toolCallId = tool.id || `${stringField(message, "id") || lineNumber}:${toolName}`;
|
|
9525
|
+
const spanId = `${ctx.sessionId}:tool:${toolCallId}`;
|
|
9526
|
+
const fileActivities = claudeStyleToolFileActivities(alias, tool.input, ts, ctx.cwd);
|
|
9527
|
+
lineNumber += 1;
|
|
9528
|
+
const startedTool = makeEvent({
|
|
9529
|
+
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
9530
|
+
ts,
|
|
9531
|
+
type: "tool.started",
|
|
9532
|
+
source: SOURCE,
|
|
9533
|
+
workspaceId: ctx.workspaceId,
|
|
9534
|
+
project: ctx.project,
|
|
9535
|
+
cwd: ctx.cwd,
|
|
9536
|
+
sessionId: ctx.sessionId,
|
|
9537
|
+
turnId: activeTurnId,
|
|
9538
|
+
spanId,
|
|
9539
|
+
agent: SOURCE,
|
|
9540
|
+
tool: toolName,
|
|
9541
|
+
confidence: "exact",
|
|
9542
|
+
refs: refs({ sourceId: `${toolCallId}:start` })
|
|
9543
|
+
}, lineNumber, filePath, options);
|
|
9544
|
+
if (startedTool) {
|
|
9545
|
+
events.push(startedTool);
|
|
9546
|
+
}
|
|
9547
|
+
lineNumber += 1;
|
|
9548
|
+
const completedTool = makeEvent({
|
|
9549
|
+
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
9550
|
+
ts,
|
|
9551
|
+
type: "tool.completed",
|
|
9552
|
+
source: SOURCE,
|
|
9553
|
+
workspaceId: ctx.workspaceId,
|
|
9554
|
+
project: ctx.project,
|
|
9555
|
+
cwd: ctx.cwd,
|
|
9556
|
+
sessionId: ctx.sessionId,
|
|
9557
|
+
turnId: activeTurnId,
|
|
9558
|
+
spanId,
|
|
9559
|
+
agent: SOURCE,
|
|
9560
|
+
tool: toolName,
|
|
9561
|
+
success: true,
|
|
9562
|
+
confidence: "exact",
|
|
9563
|
+
fileActivities: fileActivities.length > 0 ? fileActivities : void 0,
|
|
9564
|
+
refs: refs({ sourceId: `${toolCallId}:completed` })
|
|
9565
|
+
}, lineNumber, filePath, options);
|
|
9566
|
+
if (completedTool) {
|
|
9567
|
+
events.push(completedTool);
|
|
9568
|
+
}
|
|
9569
|
+
}
|
|
9570
|
+
}
|
|
9571
|
+
}
|
|
9572
|
+
return events.sort((a, b) => a.ts.localeCompare(b.ts) || (a.id || "").localeCompare(b.id || ""));
|
|
9573
|
+
} finally {
|
|
9574
|
+
db.close();
|
|
9575
|
+
}
|
|
9576
|
+
}
|
|
9577
|
+
async function collectStateDb(filePath, seen, out) {
|
|
9578
|
+
const resolved = path15.resolve(filePath);
|
|
9579
|
+
if (seen.has(resolved)) {
|
|
9580
|
+
return;
|
|
9581
|
+
}
|
|
9582
|
+
const modifiedAt = await sqliteMtime(resolved);
|
|
9583
|
+
if (!modifiedAt) {
|
|
9584
|
+
return;
|
|
9585
|
+
}
|
|
9586
|
+
seen.add(resolved);
|
|
9587
|
+
out.push({ path: resolved, modifiedAt });
|
|
9588
|
+
}
|
|
9589
|
+
async function collectHermesHome(root, seen, out) {
|
|
9590
|
+
await collectStateDb(path15.join(root, "state.db"), seen, out);
|
|
9591
|
+
const profilesDir = path15.join(root, "profiles");
|
|
9592
|
+
let entries;
|
|
9593
|
+
try {
|
|
9594
|
+
entries = await readdir8(profilesDir, { withFileTypes: true });
|
|
9595
|
+
} catch {
|
|
9596
|
+
return;
|
|
9597
|
+
}
|
|
9598
|
+
for (const entry of entries) {
|
|
9599
|
+
if (entry.isDirectory()) {
|
|
9600
|
+
await collectStateDb(path15.join(profilesDir, entry.name, "state.db"), seen, out);
|
|
9601
|
+
}
|
|
9602
|
+
}
|
|
9603
|
+
}
|
|
9604
|
+
async function hermesBackfillFiles(sourceRoot, home, env = {}) {
|
|
9605
|
+
const seen = /* @__PURE__ */ new Set();
|
|
9606
|
+
const out = [];
|
|
9607
|
+
if (sourceRoot) {
|
|
9608
|
+
if (sourceRoot.endsWith(".db")) {
|
|
9609
|
+
await collectStateDb(sourceRoot, seen, out);
|
|
9610
|
+
return out;
|
|
9611
|
+
}
|
|
9612
|
+
await collectHermesHome(sourceRoot, seen, out);
|
|
9613
|
+
return out;
|
|
9614
|
+
}
|
|
9615
|
+
const primary = hermesRoot(home, env);
|
|
9616
|
+
await collectHermesHome(primary, seen, out);
|
|
9617
|
+
const defaultRoot = path15.join(home, ".hermes");
|
|
9618
|
+
if (path15.resolve(defaultRoot) !== path15.resolve(primary)) {
|
|
9619
|
+
await collectHermesHome(defaultRoot, seen, out);
|
|
9620
|
+
}
|
|
9621
|
+
return out.sort((a, b) => a.path.localeCompare(b.path));
|
|
9622
|
+
}
|
|
9623
|
+
function pluginYaml() {
|
|
9624
|
+
return `# ${GENERATED_MARKER3}
|
|
9625
|
+
name: vibetime
|
|
9626
|
+
version: "1.0.0"
|
|
9627
|
+
description: "VibeTime session sync \u2014 thin trigger that runs local backfill on Hermes lifecycle events."
|
|
9628
|
+
author: VibeTime
|
|
9629
|
+
hooks:
|
|
9630
|
+
- on_session_start
|
|
9631
|
+
- on_session_end
|
|
9632
|
+
- on_session_finalize
|
|
9633
|
+
- post_tool_call
|
|
9634
|
+
`;
|
|
9635
|
+
}
|
|
9636
|
+
function pluginInit() {
|
|
9637
|
+
return `# ${GENERATED_MARKER3}
|
|
9638
|
+
"""VibeTime observability plugin for Hermes Agent.
|
|
9639
|
+
|
|
9640
|
+
Thin trigger only: spawn \`vibetime hook --agent hermes\` on session/tool
|
|
9641
|
+
lifecycle events. Token usage is read from state.db by vibetime backfill.
|
|
9642
|
+
"""
|
|
9643
|
+
from __future__ import annotations
|
|
9644
|
+
|
|
9645
|
+
import json
|
|
9646
|
+
import os
|
|
9647
|
+
import shutil
|
|
9648
|
+
import subprocess
|
|
9649
|
+
from typing import Any
|
|
9650
|
+
|
|
9651
|
+
|
|
9652
|
+
def _report(payload: dict[str, Any]) -> None:
|
|
9653
|
+
command = shutil.which("vibetime")
|
|
9654
|
+
if not command:
|
|
9655
|
+
return
|
|
9656
|
+
try:
|
|
9657
|
+
subprocess.run(
|
|
9658
|
+
[command, "hook", "--agent", "hermes"],
|
|
9659
|
+
input=json.dumps(payload),
|
|
9660
|
+
text=True,
|
|
9661
|
+
capture_output=True,
|
|
9662
|
+
timeout=10,
|
|
9663
|
+
check=False,
|
|
9664
|
+
env=os.environ.copy(),
|
|
9665
|
+
)
|
|
9666
|
+
except Exception:
|
|
9667
|
+
return
|
|
9668
|
+
|
|
9669
|
+
|
|
9670
|
+
def on_session_start(*, session_id: str = "", **_: Any) -> None:
|
|
9671
|
+
_report({"hook_event_name": "SessionStart", "session_id": session_id})
|
|
9672
|
+
|
|
9673
|
+
|
|
9674
|
+
def on_session_end(*, session_id: str = "", **_: Any) -> None:
|
|
9675
|
+
_report({"hook_event_name": "SessionEnd", "session_id": session_id})
|
|
9676
|
+
|
|
9677
|
+
|
|
9678
|
+
def on_post_tool_call(*, tool_name: str = "", session_id: str = "", **_: Any) -> None:
|
|
9679
|
+
_report({
|
|
9680
|
+
"hook_event_name": "PostToolUse",
|
|
9681
|
+
"tool_name": tool_name or "unknown",
|
|
9682
|
+
"session_id": session_id,
|
|
9683
|
+
})
|
|
9684
|
+
|
|
9685
|
+
|
|
9686
|
+
def register(ctx) -> None:
|
|
9687
|
+
ctx.register_hook("on_session_start", on_session_start)
|
|
9688
|
+
ctx.register_hook("on_session_end", on_session_end)
|
|
9689
|
+
ctx.register_hook("on_session_finalize", on_session_end)
|
|
9690
|
+
ctx.register_hook("post_tool_call", on_post_tool_call)
|
|
9691
|
+
`;
|
|
9692
|
+
}
|
|
9693
|
+
function createHermesAdapter() {
|
|
9694
|
+
return {
|
|
9695
|
+
id: SOURCE,
|
|
9696
|
+
label: "Hermes Agent",
|
|
9697
|
+
agentName: SOURCE,
|
|
9698
|
+
kind: "agent",
|
|
9699
|
+
detectPath(home, env) {
|
|
9700
|
+
return hermesRoot(home, env);
|
|
9701
|
+
},
|
|
9702
|
+
installedPath(home, env) {
|
|
9703
|
+
return hermesPluginManifestPath(home, env);
|
|
9704
|
+
},
|
|
9705
|
+
async isInstalled(home, env) {
|
|
9706
|
+
const manifest = await readTextIfExists(hermesPluginManifestPath(home, env));
|
|
9707
|
+
const init = await readTextIfExists(hermesPluginInitPath(home, env));
|
|
9708
|
+
return Boolean(manifest && init && init.includes(HOOK_COMMAND3));
|
|
9709
|
+
},
|
|
9710
|
+
installEntries(home, env) {
|
|
9711
|
+
return [
|
|
9712
|
+
{
|
|
9713
|
+
kind: "file",
|
|
9714
|
+
path: hermesPluginManifestPath(home, env),
|
|
9715
|
+
content: pluginYaml()
|
|
9716
|
+
},
|
|
9717
|
+
{
|
|
9718
|
+
kind: "file",
|
|
9719
|
+
path: hermesPluginInitPath(home, env),
|
|
9720
|
+
content: pluginInit()
|
|
9721
|
+
}
|
|
9722
|
+
];
|
|
9723
|
+
},
|
|
9724
|
+
sourcePaths(home, env) {
|
|
9725
|
+
return [path15.join(hermesRoot(home, env), "state.db")];
|
|
9726
|
+
},
|
|
9727
|
+
parseSessionFile: parseHermesDb
|
|
9728
|
+
};
|
|
9729
|
+
}
|
|
9730
|
+
|
|
9042
9731
|
// src/adapters/kimi-code.ts
|
|
9043
9732
|
import { readFile as readFile10 } from "node:fs/promises";
|
|
9044
|
-
import
|
|
9733
|
+
import path16 from "node:path";
|
|
9045
9734
|
|
|
9046
9735
|
// src/lib/toml-hooks.ts
|
|
9047
9736
|
init_fs();
|
|
@@ -9219,20 +9908,20 @@ function tomlNumberField(body, key) {
|
|
|
9219
9908
|
}
|
|
9220
9909
|
|
|
9221
9910
|
// src/adapters/kimi-code.ts
|
|
9222
|
-
var
|
|
9911
|
+
var HOOK_COMMAND4 = "vibetime hook --agent kimi-code";
|
|
9223
9912
|
var HOOK_TIMEOUT_SECONDS2 = 10;
|
|
9224
9913
|
function kimiCodeHome(home, env) {
|
|
9225
9914
|
const override = env?.KIMI_CODE_HOME || env?.KIMI_HOME;
|
|
9226
9915
|
if (override && override.trim()) {
|
|
9227
|
-
return
|
|
9916
|
+
return path16.resolve(override);
|
|
9228
9917
|
}
|
|
9229
|
-
return
|
|
9918
|
+
return path16.join(home, ".kimi-code");
|
|
9230
9919
|
}
|
|
9231
9920
|
function kimiCodeSessionsDir(home, env) {
|
|
9232
|
-
return
|
|
9921
|
+
return path16.join(kimiCodeHome(home, env), "sessions");
|
|
9233
9922
|
}
|
|
9234
9923
|
function kimiCodeConfigPath(home, env) {
|
|
9235
|
-
return
|
|
9924
|
+
return path16.join(kimiCodeHome(home, env), "config.toml");
|
|
9236
9925
|
}
|
|
9237
9926
|
function kimiHookRules() {
|
|
9238
9927
|
const events = [
|
|
@@ -9248,7 +9937,7 @@ function kimiHookRules() {
|
|
|
9248
9937
|
];
|
|
9249
9938
|
return events.map((event) => ({
|
|
9250
9939
|
event,
|
|
9251
|
-
command:
|
|
9940
|
+
command: HOOK_COMMAND4,
|
|
9252
9941
|
timeout: HOOK_TIMEOUT_SECONDS2
|
|
9253
9942
|
}));
|
|
9254
9943
|
}
|
|
@@ -9308,8 +9997,8 @@ function sessionIdFromWirePath(filePath) {
|
|
|
9308
9997
|
return match?.[1];
|
|
9309
9998
|
}
|
|
9310
9999
|
async function readSessionState(filePath) {
|
|
9311
|
-
const sessionDir =
|
|
9312
|
-
const statePath =
|
|
10000
|
+
const sessionDir = path16.dirname(path16.dirname(path16.dirname(filePath)));
|
|
10001
|
+
const statePath = path16.join(sessionDir, "state.json");
|
|
9313
10002
|
try {
|
|
9314
10003
|
const text = await readFile10(statePath, "utf8");
|
|
9315
10004
|
const raw = JSON.parse(text);
|
|
@@ -9326,7 +10015,7 @@ async function readSessionState(filePath) {
|
|
|
9326
10015
|
}
|
|
9327
10016
|
}
|
|
9328
10017
|
async function parseKimiCodeSessionFile(filePath, options) {
|
|
9329
|
-
if (
|
|
10018
|
+
if (path16.basename(filePath) !== "wire.jsonl") {
|
|
9330
10019
|
return [];
|
|
9331
10020
|
}
|
|
9332
10021
|
const text = await readFile10(filePath, "utf8");
|
|
@@ -9334,7 +10023,7 @@ async function parseKimiCodeSessionFile(filePath, options) {
|
|
|
9334
10023
|
const stateMeta = await readSessionState(filePath);
|
|
9335
10024
|
let sessionId = stateMeta.sessionId || sessionIdFromWirePath(filePath);
|
|
9336
10025
|
let cwd = stateMeta.cwd;
|
|
9337
|
-
let project = cwd ?
|
|
10026
|
+
let project = cwd ? path16.basename(cwd) : void 0;
|
|
9338
10027
|
let model;
|
|
9339
10028
|
let provider;
|
|
9340
10029
|
let reasoningEffort;
|
|
@@ -9380,7 +10069,7 @@ async function parseKimiCodeSessionFile(filePath, options) {
|
|
|
9380
10069
|
const disclosedCwd = stringField(disclosure, "cwd");
|
|
9381
10070
|
if (disclosedCwd) {
|
|
9382
10071
|
cwd = disclosedCwd;
|
|
9383
|
-
project =
|
|
10072
|
+
project = path16.basename(disclosedCwd);
|
|
9384
10073
|
}
|
|
9385
10074
|
continue;
|
|
9386
10075
|
}
|
|
@@ -9694,7 +10383,7 @@ function createKimiCodeAdapter() {
|
|
|
9694
10383
|
return kimiCodeConfigPath(home, env);
|
|
9695
10384
|
},
|
|
9696
10385
|
async isInstalled(home, env) {
|
|
9697
|
-
return hasTomlHookCommand(kimiCodeConfigPath(home, env),
|
|
10386
|
+
return hasTomlHookCommand(kimiCodeConfigPath(home, env), HOOK_COMMAND4);
|
|
9698
10387
|
},
|
|
9699
10388
|
installEntries(home, env) {
|
|
9700
10389
|
return [{
|
|
@@ -9712,7 +10401,7 @@ function createKimiCodeAdapter() {
|
|
|
9712
10401
|
|
|
9713
10402
|
// src/adapters/opencode.ts
|
|
9714
10403
|
import os8 from "node:os";
|
|
9715
|
-
import
|
|
10404
|
+
import path17 from "node:path";
|
|
9716
10405
|
async function parseOpenCodeSessionFile(dbPath, options) {
|
|
9717
10406
|
const { DatabaseSync } = await import("node:sqlite");
|
|
9718
10407
|
if (!dbPath.endsWith(".db")) {
|
|
@@ -9771,7 +10460,7 @@ async function parseOpenCodeSessionFile(dbPath, options) {
|
|
|
9771
10460
|
const isSubagent = sessionId !== rawSessionId;
|
|
9772
10461
|
const sessionEventStart = events.length;
|
|
9773
10462
|
const cwd = session.directory || session.path || void 0;
|
|
9774
|
-
const project = cwd ?
|
|
10463
|
+
const project = cwd ? path17.basename(cwd) : void 0;
|
|
9775
10464
|
const sessionTs = msToIso(session.time_created);
|
|
9776
10465
|
events.push(baseOpenCodeEvent({
|
|
9777
10466
|
ts: sessionTs,
|
|
@@ -9879,7 +10568,7 @@ async function parseOpenCodeSessionFile(dbPath, options) {
|
|
|
9879
10568
|
const provider = currentProvider;
|
|
9880
10569
|
const pathObj = objectField(info, "path");
|
|
9881
10570
|
const assistantCwd = stringField(pathObj, "cwd") || cwd;
|
|
9882
|
-
const assistantProject = assistantCwd ?
|
|
10571
|
+
const assistantProject = assistantCwd ? path17.basename(assistantCwd) : project;
|
|
9883
10572
|
const completedTs = numberField(objectField(info, "time"), "completed");
|
|
9884
10573
|
const createdTs = timeCreated;
|
|
9885
10574
|
const tokens = opencodeUsageFromInfo(info);
|
|
@@ -10153,33 +10842,33 @@ function opencodeUsageFromInfo(info) {
|
|
|
10153
10842
|
function opencodeConfigDir(home, env) {
|
|
10154
10843
|
const override = env?.OPENCODE_CONFIG_DIR;
|
|
10155
10844
|
if (override && override.trim()) {
|
|
10156
|
-
return
|
|
10845
|
+
return path17.resolve(override);
|
|
10157
10846
|
}
|
|
10158
10847
|
const xdgConfig = env?.XDG_CONFIG_HOME;
|
|
10159
10848
|
if (xdgConfig && xdgConfig.trim()) {
|
|
10160
|
-
return
|
|
10849
|
+
return path17.join(path17.resolve(xdgConfig), "opencode");
|
|
10161
10850
|
}
|
|
10162
|
-
return
|
|
10851
|
+
return path17.join(home, ".config", "opencode");
|
|
10163
10852
|
}
|
|
10164
10853
|
function opencodeDataCandidates(home, env) {
|
|
10165
10854
|
const xdgData = env?.XDG_DATA_HOME;
|
|
10166
|
-
const primary = xdgData && xdgData.trim() ?
|
|
10167
|
-
return [primary,
|
|
10855
|
+
const primary = xdgData && xdgData.trim() ? path17.join(path17.resolve(xdgData), "opencode", "opencode.db") : path17.join(home, ".local", "share", "opencode", "opencode.db");
|
|
10856
|
+
return [primary, path17.join(home, ".opencode", "opencode.db")];
|
|
10168
10857
|
}
|
|
10169
10858
|
async function opencodeBackfillFiles(sourceRoot, home = os8.homedir(), env) {
|
|
10170
|
-
const { stat:
|
|
10859
|
+
const { stat: stat19 } = await import("node:fs/promises");
|
|
10171
10860
|
if (sourceRoot) {
|
|
10172
10861
|
if (!sourceRoot.endsWith(".db")) {
|
|
10173
10862
|
return [];
|
|
10174
10863
|
}
|
|
10175
|
-
const info = await
|
|
10864
|
+
const info = await stat19(sourceRoot).catch(() => null);
|
|
10176
10865
|
if (!info) {
|
|
10177
10866
|
return [];
|
|
10178
10867
|
}
|
|
10179
10868
|
return [{ path: sourceRoot, modifiedAt: info.mtime.toISOString() }];
|
|
10180
10869
|
}
|
|
10181
10870
|
for (const candidatePath of opencodeDataCandidates(home, env)) {
|
|
10182
|
-
const info = await
|
|
10871
|
+
const info = await stat19(candidatePath).catch(() => null);
|
|
10183
10872
|
if (info) {
|
|
10184
10873
|
return [{ path: candidatePath, modifiedAt: info.mtime.toISOString() }];
|
|
10185
10874
|
}
|
|
@@ -10254,12 +10943,12 @@ function createOpenCodeAdapter() {
|
|
|
10254
10943
|
return opencodeConfigDir(home, env);
|
|
10255
10944
|
},
|
|
10256
10945
|
installedPath(home, env) {
|
|
10257
|
-
return
|
|
10946
|
+
return path17.join(opencodeConfigDir(home, env), PLUGIN_PATH);
|
|
10258
10947
|
},
|
|
10259
10948
|
async isInstalled(home, env) {
|
|
10260
10949
|
try {
|
|
10261
10950
|
const { pathExists: pathExists2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
10262
|
-
return await pathExists2(
|
|
10951
|
+
return await pathExists2(path17.join(opencodeConfigDir(home, env), PLUGIN_PATH)) || await pathExists2(path17.join(".opencode", PLUGIN_PATH));
|
|
10263
10952
|
} catch {
|
|
10264
10953
|
return false;
|
|
10265
10954
|
}
|
|
@@ -10267,7 +10956,7 @@ function createOpenCodeAdapter() {
|
|
|
10267
10956
|
installEntries(home, env) {
|
|
10268
10957
|
return [{
|
|
10269
10958
|
kind: "file",
|
|
10270
|
-
path:
|
|
10959
|
+
path: path17.join(opencodeConfigDir(home, env), PLUGIN_PATH),
|
|
10271
10960
|
content: opencodePluginContent()
|
|
10272
10961
|
}];
|
|
10273
10962
|
},
|
|
@@ -10279,9 +10968,9 @@ function createOpenCodeAdapter() {
|
|
|
10279
10968
|
}
|
|
10280
10969
|
|
|
10281
10970
|
// src/adapters/pi.ts
|
|
10282
|
-
import { readdir as
|
|
10971
|
+
import { readdir as readdir9, readFile as readFile11, stat as stat12 } from "node:fs/promises";
|
|
10283
10972
|
import os9 from "node:os";
|
|
10284
|
-
import
|
|
10973
|
+
import path18 from "node:path";
|
|
10285
10974
|
init_fs();
|
|
10286
10975
|
function piHostSessionIdFromBasename(basename) {
|
|
10287
10976
|
const withoutExt = basename.endsWith(".jsonl") ? basename.slice(0, -".jsonl".length) : basename;
|
|
@@ -10296,7 +10985,7 @@ function piHostSessionIdFromBasename(basename) {
|
|
|
10296
10985
|
}
|
|
10297
10986
|
function resolvePiBackfillGroupId(filePath) {
|
|
10298
10987
|
const normalized = filePath.replaceAll("\\", "/");
|
|
10299
|
-
const base =
|
|
10988
|
+
const base = path18.basename(filePath);
|
|
10300
10989
|
const nest = normalized.match(/([^/]+)\/[^/]+\/run-\d+\/session\.jsonl$/);
|
|
10301
10990
|
if (nest) {
|
|
10302
10991
|
return piHostSessionIdFromBasename(nest[1]);
|
|
@@ -10308,8 +10997,8 @@ function resolvePiBackfillGroupId(filePath) {
|
|
|
10308
10997
|
}
|
|
10309
10998
|
function parsePiSubagentLink(filePath, headerParentSession) {
|
|
10310
10999
|
if (headerParentSession) {
|
|
10311
|
-
const parentFile =
|
|
10312
|
-
const parentSessionId2 = parentFile ?
|
|
11000
|
+
const parentFile = path18.isAbsolute(headerParentSession) ? headerParentSession : void 0;
|
|
11001
|
+
const parentSessionId2 = parentFile ? path18.basename(parentFile, ".jsonl") : headerParentSession;
|
|
10313
11002
|
return { parentSessionId: parentSessionId2, parentSessionFile: parentFile, explicit: true };
|
|
10314
11003
|
}
|
|
10315
11004
|
const normalized = filePath.replaceAll("\\", "/");
|
|
@@ -10322,8 +11011,8 @@ function parsePiSubagentLink(filePath, headerParentSession) {
|
|
|
10322
11011
|
return void 0;
|
|
10323
11012
|
}
|
|
10324
11013
|
const parentSessionId = parentBasename.endsWith(".jsonl") ? parentBasename.slice(0, -".jsonl".length) : parentBasename;
|
|
10325
|
-
const parentDir =
|
|
10326
|
-
const parentSessionFile =
|
|
11014
|
+
const parentDir = path18.dirname(path18.dirname(path18.dirname(filePath)));
|
|
11015
|
+
const parentSessionFile = path18.join(path18.dirname(parentDir), `${parentBasename}.jsonl`);
|
|
10327
11016
|
return { parentSessionId, parentSessionFile, explicit: false };
|
|
10328
11017
|
}
|
|
10329
11018
|
async function resolveParentContext(link, options) {
|
|
@@ -10335,7 +11024,7 @@ async function resolveParentContext(link, options) {
|
|
|
10335
11024
|
if (raw) {
|
|
10336
11025
|
const id = stringField(raw, "id");
|
|
10337
11026
|
const cwd = stringField(raw, "cwd");
|
|
10338
|
-
const project = cwd ?
|
|
11027
|
+
const project = cwd ? path18.basename(cwd) : void 0;
|
|
10339
11028
|
if (id || cwd || project) {
|
|
10340
11029
|
return { sessionId: id, cwd, project };
|
|
10341
11030
|
}
|
|
@@ -10416,7 +11105,7 @@ async function parsePiSessionFile(filePath, options) {
|
|
|
10416
11105
|
sessionId = stringField(raw, "id") || state.sessionId;
|
|
10417
11106
|
state.sessionId = sessionId || state.sessionId;
|
|
10418
11107
|
cwd = stringField(raw, "cwd") || cwd;
|
|
10419
|
-
project = cwd ?
|
|
11108
|
+
project = cwd ? path18.basename(cwd) : project;
|
|
10420
11109
|
headerParentSession = stringField(raw, "parentSession") || headerParentSession;
|
|
10421
11110
|
continue;
|
|
10422
11111
|
}
|
|
@@ -10691,17 +11380,17 @@ async function parsePiWorkflowRunFile(filePath, options) {
|
|
|
10691
11380
|
return state.events.filter((event) => matchesBackfillFilters(event, options));
|
|
10692
11381
|
}
|
|
10693
11382
|
async function findPiSessionFileById(sessionId, options) {
|
|
10694
|
-
const sessionsDir = piSessionDir(
|
|
11383
|
+
const sessionsDir = piSessionDir(path18.resolve(stringOption(options.home) || os9.homedir()));
|
|
10695
11384
|
try {
|
|
10696
|
-
const projectDirs = await
|
|
11385
|
+
const projectDirs = await readdir9(sessionsDir, { withFileTypes: true });
|
|
10697
11386
|
for (const dir of projectDirs) {
|
|
10698
11387
|
if (!dir.isDirectory()) {
|
|
10699
11388
|
continue;
|
|
10700
11389
|
}
|
|
10701
|
-
const names = await
|
|
11390
|
+
const names = await readdir9(path18.join(sessionsDir, dir.name));
|
|
10702
11391
|
const hit = names.find((name) => name.endsWith(`_${sessionId}.jsonl`));
|
|
10703
11392
|
if (hit) {
|
|
10704
|
-
return
|
|
11393
|
+
return path18.join(sessionsDir, dir.name, hit);
|
|
10705
11394
|
}
|
|
10706
11395
|
}
|
|
10707
11396
|
} catch {
|
|
@@ -10943,19 +11632,19 @@ export default function (pi: ExtensionAPI) {
|
|
|
10943
11632
|
function piAgentDir(home, env) {
|
|
10944
11633
|
const override = env?.PI_CODING_AGENT_DIR;
|
|
10945
11634
|
if (override && override.trim()) {
|
|
10946
|
-
return
|
|
11635
|
+
return path18.resolve(override);
|
|
10947
11636
|
}
|
|
10948
|
-
return
|
|
11637
|
+
return path18.join(home, ".pi", "agent");
|
|
10949
11638
|
}
|
|
10950
11639
|
function piSessionDir(home, env) {
|
|
10951
11640
|
const override = env?.PI_CODING_AGENT_SESSION_DIR;
|
|
10952
11641
|
if (override && override.trim()) {
|
|
10953
|
-
return
|
|
11642
|
+
return path18.resolve(override);
|
|
10954
11643
|
}
|
|
10955
|
-
return
|
|
11644
|
+
return path18.join(piAgentDir(home, env), "sessions");
|
|
10956
11645
|
}
|
|
10957
11646
|
function piWorkflowProjectsDir(home) {
|
|
10958
|
-
return
|
|
11647
|
+
return path18.join(home, ".pi", "workflows", "projects");
|
|
10959
11648
|
}
|
|
10960
11649
|
async function workflowRunGroupId(filePath) {
|
|
10961
11650
|
try {
|
|
@@ -10975,7 +11664,7 @@ async function piBackfillFiles(sourceRoot, home = os9.homedir(), env) {
|
|
|
10975
11664
|
]);
|
|
10976
11665
|
const files = lists.flat().sort();
|
|
10977
11666
|
return Promise.all(files.map(async (filePath) => {
|
|
10978
|
-
const info = await
|
|
11667
|
+
const info = await stat12(filePath);
|
|
10979
11668
|
let groupId = resolvePiBackfillGroupId(filePath);
|
|
10980
11669
|
if (!groupId && filePath.endsWith(".json")) {
|
|
10981
11670
|
groupId = await workflowRunGroupId(filePath);
|
|
@@ -10997,12 +11686,12 @@ function createPiAdapter() {
|
|
|
10997
11686
|
return piAgentDir(home, env);
|
|
10998
11687
|
},
|
|
10999
11688
|
installedPath(home, env) {
|
|
11000
|
-
return
|
|
11689
|
+
return path18.join(piAgentDir(home, env), "extensions", "vibetime.ts");
|
|
11001
11690
|
},
|
|
11002
11691
|
async isInstalled(home, env) {
|
|
11003
11692
|
try {
|
|
11004
11693
|
const { pathExists: pathExists2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
11005
|
-
return await pathExists2(
|
|
11694
|
+
return await pathExists2(path18.join(piAgentDir(home, env), "extensions", "vibetime.ts"));
|
|
11006
11695
|
} catch {
|
|
11007
11696
|
return false;
|
|
11008
11697
|
}
|
|
@@ -11010,7 +11699,7 @@ function createPiAdapter() {
|
|
|
11010
11699
|
installEntries(home, env) {
|
|
11011
11700
|
return [{
|
|
11012
11701
|
kind: "file",
|
|
11013
|
-
path:
|
|
11702
|
+
path: path18.join(piAgentDir(home, env), "extensions", "vibetime.ts"),
|
|
11014
11703
|
content: piExtensionContent()
|
|
11015
11704
|
}];
|
|
11016
11705
|
},
|
|
@@ -11022,14 +11711,14 @@ function createPiAdapter() {
|
|
|
11022
11711
|
}
|
|
11023
11712
|
|
|
11024
11713
|
// src/adapters/qoder-cn.ts
|
|
11025
|
-
import { readdir as
|
|
11714
|
+
import { readdir as readdir10, readFile as readFile12, stat as stat13 } from "node:fs/promises";
|
|
11026
11715
|
import os11 from "node:os";
|
|
11027
|
-
import
|
|
11716
|
+
import path20 from "node:path";
|
|
11028
11717
|
|
|
11029
11718
|
// src/adapters/qoder-local-db.ts
|
|
11030
11719
|
import { access } from "node:fs/promises";
|
|
11031
11720
|
import os10 from "node:os";
|
|
11032
|
-
import
|
|
11721
|
+
import path19 from "node:path";
|
|
11033
11722
|
function takeQoderDbModelCall(calls, requestId, blockStart) {
|
|
11034
11723
|
if (requestId) {
|
|
11035
11724
|
const call = calls.byRequestId.get(requestId)?.shift();
|
|
@@ -11048,12 +11737,12 @@ function takeQoderDbModelCall(calls, requestId, blockStart) {
|
|
|
11048
11737
|
}
|
|
11049
11738
|
function appDataRoot(appDirName, home = os10.homedir()) {
|
|
11050
11739
|
if (process.platform === "darwin") {
|
|
11051
|
-
return
|
|
11740
|
+
return path19.join(home, "Library", "Application Support", appDirName);
|
|
11052
11741
|
}
|
|
11053
11742
|
if (process.platform === "win32") {
|
|
11054
|
-
return
|
|
11743
|
+
return path19.join(process.env.APPDATA || path19.join(home, "AppData", "Roaming"), appDirName);
|
|
11055
11744
|
}
|
|
11056
|
-
return
|
|
11745
|
+
return path19.join(home, ".config", appDirName);
|
|
11057
11746
|
}
|
|
11058
11747
|
function qoderLocalDbCandidates(appDirName) {
|
|
11059
11748
|
const candidates = [];
|
|
@@ -11063,8 +11752,8 @@ function qoderLocalDbCandidates(appDirName) {
|
|
|
11063
11752
|
}
|
|
11064
11753
|
const configRoot = appDataRoot(appDirName);
|
|
11065
11754
|
candidates.push(
|
|
11066
|
-
|
|
11067
|
-
|
|
11755
|
+
path19.join(configRoot, "SharedClientCache", "cache", "db", "local.db"),
|
|
11756
|
+
path19.join(configRoot, "SharedClientCache", "db", "local.db")
|
|
11068
11757
|
);
|
|
11069
11758
|
return candidates;
|
|
11070
11759
|
}
|
|
@@ -11073,7 +11762,7 @@ async function loadQoderIdeModelCatalog(appDirName, home) {
|
|
|
11073
11762
|
try {
|
|
11074
11763
|
const { DatabaseSync } = await import("node:sqlite");
|
|
11075
11764
|
const db = new DatabaseSync(
|
|
11076
|
-
|
|
11765
|
+
path19.join(appDataRoot(appDirName, home), "User", "globalStorage", "state.vscdb"),
|
|
11077
11766
|
{ readOnly: true }
|
|
11078
11767
|
);
|
|
11079
11768
|
try {
|
|
@@ -11215,7 +11904,7 @@ function resolveSessionPreferredModel(db, sessionId, modelMap) {
|
|
|
11215
11904
|
|
|
11216
11905
|
// src/adapters/qoder-cn.ts
|
|
11217
11906
|
function parseQoderCnPaths(filePath) {
|
|
11218
|
-
const parts = filePath.split(
|
|
11907
|
+
const parts = filePath.split(path20.sep);
|
|
11219
11908
|
const subagentsIdx = parts.lastIndexOf("subagents");
|
|
11220
11909
|
let sessionId = "";
|
|
11221
11910
|
let projectName = "";
|
|
@@ -11225,17 +11914,17 @@ function parseQoderCnPaths(filePath) {
|
|
|
11225
11914
|
sessionId = parts[subagentsIdx - 1];
|
|
11226
11915
|
projectName = parts[subagentsIdx - 2];
|
|
11227
11916
|
const projectsIdx = parts.lastIndexOf("projects");
|
|
11228
|
-
configDir2 = parts.slice(0, projectsIdx).join(
|
|
11229
|
-
mainTranscriptPath = [...parts.slice(0, subagentsIdx - 1), `${sessionId}.jsonl`].join(
|
|
11917
|
+
configDir2 = parts.slice(0, projectsIdx).join(path20.sep);
|
|
11918
|
+
mainTranscriptPath = [...parts.slice(0, subagentsIdx - 1), `${sessionId}.jsonl`].join(path20.sep);
|
|
11230
11919
|
} else {
|
|
11231
11920
|
const filename = parts.at(-1) || "";
|
|
11232
|
-
sessionId =
|
|
11921
|
+
sessionId = path20.basename(filename, ".jsonl");
|
|
11233
11922
|
projectName = parts.at(-2) || "";
|
|
11234
11923
|
if (projectName === "transcript") {
|
|
11235
11924
|
projectName = parts.at(-3) || "";
|
|
11236
11925
|
}
|
|
11237
11926
|
const projectsIdx = parts.lastIndexOf("projects");
|
|
11238
|
-
configDir2 = parts.slice(0, projectsIdx).join(
|
|
11927
|
+
configDir2 = parts.slice(0, projectsIdx).join(path20.sep);
|
|
11239
11928
|
}
|
|
11240
11929
|
return { configDir: configDir2, projectName, sessionId, mainTranscriptPath };
|
|
11241
11930
|
}
|
|
@@ -11283,7 +11972,7 @@ async function loadQoderCnModelNames(configDir2, home) {
|
|
|
11283
11972
|
}
|
|
11284
11973
|
}
|
|
11285
11974
|
}
|
|
11286
|
-
const textsMap = await parseModelNamesFromDynamicTexts(
|
|
11975
|
+
const textsMap = await parseModelNamesFromDynamicTexts(path20.join(configDir2, ".auth", "dynamic-texts.json"));
|
|
11287
11976
|
for (const [key, val] of Object.entries(textsMap)) {
|
|
11288
11977
|
if (!(key in map)) {
|
|
11289
11978
|
map[key] = val;
|
|
@@ -11291,7 +11980,7 @@ async function loadQoderCnModelNames(configDir2, home) {
|
|
|
11291
11980
|
}
|
|
11292
11981
|
const siblingConfigDir = configDir2.replace(/\.qoder-cn$/, ".qoder");
|
|
11293
11982
|
if (siblingConfigDir !== configDir2) {
|
|
11294
|
-
const siblingMap = await parseModelNamesFromDynamicTexts(
|
|
11983
|
+
const siblingMap = await parseModelNamesFromDynamicTexts(path20.join(siblingConfigDir, ".auth", "dynamic-texts.json"));
|
|
11295
11984
|
for (const [key, val] of Object.entries(siblingMap)) {
|
|
11296
11985
|
if (!(key in map)) {
|
|
11297
11986
|
map[key] = val;
|
|
@@ -11302,15 +11991,15 @@ async function loadQoderCnModelNames(configDir2, home) {
|
|
|
11302
11991
|
}
|
|
11303
11992
|
async function loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMap) {
|
|
11304
11993
|
const { configDir: configDir2, projectName, sessionId } = parseQoderCnPaths(filePath);
|
|
11305
|
-
const segmentsPath =
|
|
11994
|
+
const segmentsPath = path20.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
|
|
11306
11995
|
const modelCalls = [];
|
|
11307
11996
|
try {
|
|
11308
|
-
const files = await
|
|
11997
|
+
const files = await readdir10(segmentsPath);
|
|
11309
11998
|
for (const file of files) {
|
|
11310
11999
|
if (!file.endsWith(".jsonl")) {
|
|
11311
12000
|
continue;
|
|
11312
12001
|
}
|
|
11313
|
-
const content = await readFile12(
|
|
12002
|
+
const content = await readFile12(path20.join(segmentsPath, file), "utf8");
|
|
11314
12003
|
let currentTurnIsSubagent = false;
|
|
11315
12004
|
for (const line of content.split("\n").filter(Boolean)) {
|
|
11316
12005
|
const raw = parseJsonLine(line);
|
|
@@ -11355,7 +12044,7 @@ async function parseQoderCnSessionFile(filePath, options) {
|
|
|
11355
12044
|
let cwd;
|
|
11356
12045
|
let project = projectContext.project;
|
|
11357
12046
|
let model;
|
|
11358
|
-
const home =
|
|
12047
|
+
const home = path20.resolve(stringOption(options.home) || os11.homedir());
|
|
11359
12048
|
const modelMap = await loadQoderCnModelNames(configDir2, home);
|
|
11360
12049
|
const isSubagentSession = filePath.includes("subagents");
|
|
11361
12050
|
const segmentModelCalls = await loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMap);
|
|
@@ -11390,7 +12079,7 @@ async function parseQoderCnSessionFile(filePath, options) {
|
|
|
11390
12079
|
sessionId = stringField(raw, "sessionId") || sessionId;
|
|
11391
12080
|
state.sessionId = sessionId;
|
|
11392
12081
|
cwd = stringField(raw, "cwd") || cwd;
|
|
11393
|
-
project = projectContext.project || (cwd ?
|
|
12082
|
+
project = projectContext.project || (cwd ? path20.basename(cwd) : project || await qoderCnProjectFromFilePath(filePath, options));
|
|
11394
12083
|
if (!ts) {
|
|
11395
12084
|
continue;
|
|
11396
12085
|
}
|
|
@@ -11726,7 +12415,7 @@ async function parseQoderCnSessionFile(filePath, options) {
|
|
|
11726
12415
|
}
|
|
11727
12416
|
dbModelCalls ??= await loadQoderDbModelCalls("QoderCN", parsedPaths.sessionId, modelMap);
|
|
11728
12417
|
if (dbModelCalls.rootSessionId) {
|
|
11729
|
-
const parentPath =
|
|
12418
|
+
const parentPath = path20.join(path20.dirname(filePath), `${dbModelCalls.rootSessionId}.jsonl`);
|
|
11730
12419
|
const parentSourcePathHash = `sha256:${createStableHash(parentPath)}`;
|
|
11731
12420
|
return withoutSubagentTurnEvents(validEvents).map((event) => rebuildEventIdentity3({
|
|
11732
12421
|
...event,
|
|
@@ -11879,28 +12568,28 @@ function extractQoderAttachedPrompt(content) {
|
|
|
11879
12568
|
}
|
|
11880
12569
|
async function qoderCnProjectContextFromLines(filePath, lines, options, configDir2) {
|
|
11881
12570
|
const { projectName: projectDir, sessionId } = parseQoderCnPaths(filePath);
|
|
11882
|
-
const isSubagent = filePath.includes(`${
|
|
12571
|
+
const isSubagent = filePath.includes(`${path20.sep}subagents${path20.sep}`);
|
|
11883
12572
|
const inherited = isSubagent ? await readPersistedSessionContextFromOptions(options, sessionId) : void 0;
|
|
11884
12573
|
let cwds = [];
|
|
11885
12574
|
for (const line of lines) {
|
|
11886
12575
|
const raw = parseJsonLine(line);
|
|
11887
12576
|
const cwd = raw ? stringField(raw, "cwd") : void 0;
|
|
11888
|
-
if (cwd &&
|
|
12577
|
+
if (cwd && path20.isAbsolute(cwd)) {
|
|
11889
12578
|
cwds.push(cwd);
|
|
11890
12579
|
}
|
|
11891
12580
|
}
|
|
11892
12581
|
if (isSubagent) {
|
|
11893
|
-
if (inherited?.cwd &&
|
|
12582
|
+
if (inherited?.cwd && path20.isAbsolute(inherited.cwd)) {
|
|
11894
12583
|
cwds = [inherited.cwd];
|
|
11895
12584
|
} else {
|
|
11896
|
-
const parentSessionPath =
|
|
12585
|
+
const parentSessionPath = path20.join(configDir2, "projects", projectDir, `${sessionId}.jsonl`);
|
|
11897
12586
|
try {
|
|
11898
12587
|
const parentText = await readFile12(parentSessionPath, "utf8");
|
|
11899
12588
|
const parentCwds = [];
|
|
11900
12589
|
for (const line of parentText.split("\n").filter(Boolean)) {
|
|
11901
12590
|
const raw = parseJsonLine(line);
|
|
11902
12591
|
const cwd = raw ? stringField(raw, "cwd") : void 0;
|
|
11903
|
-
if (cwd &&
|
|
12592
|
+
if (cwd && path20.isAbsolute(cwd)) {
|
|
11904
12593
|
parentCwds.push(cwd);
|
|
11905
12594
|
}
|
|
11906
12595
|
}
|
|
@@ -11912,7 +12601,7 @@ async function qoderCnProjectContextFromLines(filePath, lines, options, configDi
|
|
|
11912
12601
|
}
|
|
11913
12602
|
}
|
|
11914
12603
|
const root = await gitRootFromCwds2(cwds) || qoderCnProjectRootFromCwds(projectDir, cwds);
|
|
11915
|
-
const project = inherited?.project || (cwds.length > 0 ?
|
|
12604
|
+
const project = inherited?.project || (cwds.length > 0 ? path20.basename(cwds[0]) : root ? path20.basename(root) : await qoderCnProjectFromFilePath(filePath, options));
|
|
11916
12605
|
return {
|
|
11917
12606
|
project,
|
|
11918
12607
|
workspaceId: createWorkspaceId({ projectName: project, repoRoot: root })
|
|
@@ -11921,15 +12610,15 @@ async function qoderCnProjectContextFromLines(filePath, lines, options, configDi
|
|
|
11921
12610
|
async function gitRootFromCwds2(cwds) {
|
|
11922
12611
|
const seen = /* @__PURE__ */ new Set();
|
|
11923
12612
|
for (const cwd of cwds) {
|
|
11924
|
-
let current =
|
|
12613
|
+
let current = path20.resolve(cwd);
|
|
11925
12614
|
while (!seen.has(current)) {
|
|
11926
12615
|
seen.add(current);
|
|
11927
12616
|
try {
|
|
11928
|
-
await
|
|
12617
|
+
await stat13(path20.join(current, ".git"));
|
|
11929
12618
|
return current;
|
|
11930
12619
|
} catch {
|
|
11931
12620
|
}
|
|
11932
|
-
const parent =
|
|
12621
|
+
const parent = path20.dirname(current);
|
|
11933
12622
|
if (parent === current) {
|
|
11934
12623
|
break;
|
|
11935
12624
|
}
|
|
@@ -11940,12 +12629,12 @@ async function gitRootFromCwds2(cwds) {
|
|
|
11940
12629
|
}
|
|
11941
12630
|
function qoderCnProjectRootFromCwds(projectDir, cwds) {
|
|
11942
12631
|
for (const cwd of cwds) {
|
|
11943
|
-
let current =
|
|
12632
|
+
let current = path20.resolve(cwd);
|
|
11944
12633
|
while (true) {
|
|
11945
12634
|
if (encodeQoderCnProjectPath(current) === projectDir) {
|
|
11946
12635
|
return current;
|
|
11947
12636
|
}
|
|
11948
|
-
const parent =
|
|
12637
|
+
const parent = path20.dirname(current);
|
|
11949
12638
|
if (parent === current) {
|
|
11950
12639
|
break;
|
|
11951
12640
|
}
|
|
@@ -11955,14 +12644,14 @@ function qoderCnProjectRootFromCwds(projectDir, cwds) {
|
|
|
11955
12644
|
return void 0;
|
|
11956
12645
|
}
|
|
11957
12646
|
function encodeQoderCnProjectPath(value) {
|
|
11958
|
-
return
|
|
12647
|
+
return path20.resolve(value).split(path20.sep).join("-").replaceAll("_", "-");
|
|
11959
12648
|
}
|
|
11960
12649
|
async function qoderCnProjectFromFilePath(filePath, options) {
|
|
11961
|
-
const projectDir =
|
|
11962
|
-
const home = options ?
|
|
12650
|
+
const projectDir = path20.basename(path20.dirname(filePath));
|
|
12651
|
+
const home = options ? path20.resolve(stringOption(options.home) || os11.homedir()) : os11.homedir();
|
|
11963
12652
|
const resolved = await resolveQoderCnProjectPath(projectDir, home);
|
|
11964
12653
|
if (resolved) {
|
|
11965
|
-
return
|
|
12654
|
+
return path20.basename(resolved);
|
|
11966
12655
|
}
|
|
11967
12656
|
const homePrefix = `${encodeQoderCnProjectPath(home)}-`;
|
|
11968
12657
|
if (projectDir.startsWith(homePrefix)) {
|
|
@@ -11982,12 +12671,12 @@ async function resolveQoderCnProjectPath(projectDir, home) {
|
|
|
11982
12671
|
while (projectDir.startsWith(`${currentEncoded}-`)) {
|
|
11983
12672
|
let matchedChild;
|
|
11984
12673
|
try {
|
|
11985
|
-
const entries = await
|
|
12674
|
+
const entries = await readdir10(current, { withFileTypes: true });
|
|
11986
12675
|
for (const entry of entries) {
|
|
11987
12676
|
if (!entry.isDirectory()) {
|
|
11988
12677
|
continue;
|
|
11989
12678
|
}
|
|
11990
|
-
const candidate =
|
|
12679
|
+
const candidate = path20.join(current, entry.name);
|
|
11991
12680
|
const encoded = encodeQoderCnProjectPath(candidate);
|
|
11992
12681
|
if (encoded === projectDir) {
|
|
11993
12682
|
return candidate;
|
|
@@ -12032,9 +12721,9 @@ function hookConfig6() {
|
|
|
12032
12721
|
function qoderCnConfigDir(home, env) {
|
|
12033
12722
|
const override = env?.QODER_CN_CONFIG_DIR;
|
|
12034
12723
|
if (override && override.trim()) {
|
|
12035
|
-
return
|
|
12724
|
+
return path20.resolve(override);
|
|
12036
12725
|
}
|
|
12037
|
-
return
|
|
12726
|
+
return path20.join(home, ".qoder-cn");
|
|
12038
12727
|
}
|
|
12039
12728
|
function createQoderCnAdapter() {
|
|
12040
12729
|
return {
|
|
@@ -12046,27 +12735,27 @@ function createQoderCnAdapter() {
|
|
|
12046
12735
|
return qoderCnConfigDir(home, env);
|
|
12047
12736
|
},
|
|
12048
12737
|
installedPath(home, env) {
|
|
12049
|
-
return
|
|
12738
|
+
return path20.join(qoderCnConfigDir(home, env), "settings.json");
|
|
12050
12739
|
},
|
|
12051
12740
|
async isInstalled(home, env) {
|
|
12052
12741
|
return isHooksJsonInstalled(
|
|
12053
|
-
|
|
12742
|
+
path20.join(qoderCnConfigDir(home, env), "settings.json"),
|
|
12054
12743
|
"vibetime hook --agent qoder-cn"
|
|
12055
12744
|
);
|
|
12056
12745
|
},
|
|
12057
12746
|
installEntries(home, env) {
|
|
12058
12747
|
return [{
|
|
12059
12748
|
kind: "hooks-json",
|
|
12060
|
-
path:
|
|
12749
|
+
path: path20.join(qoderCnConfigDir(home, env), "settings.json"),
|
|
12061
12750
|
content: hookConfig6()
|
|
12062
12751
|
}];
|
|
12063
12752
|
},
|
|
12064
12753
|
sourcePaths(home, env) {
|
|
12065
12754
|
const base = qoderCnConfigDir(home, env);
|
|
12066
12755
|
return [
|
|
12067
|
-
|
|
12068
|
-
|
|
12069
|
-
|
|
12756
|
+
path20.join(base, "projects"),
|
|
12757
|
+
path20.join(base, ".qoder.json"),
|
|
12758
|
+
path20.join(home, ".qoder.json")
|
|
12070
12759
|
];
|
|
12071
12760
|
},
|
|
12072
12761
|
parseSessionFile: parseQoderCnSessionFile
|
|
@@ -12075,11 +12764,11 @@ function createQoderCnAdapter() {
|
|
|
12075
12764
|
|
|
12076
12765
|
// src/adapters/qoder.ts
|
|
12077
12766
|
import { existsSync } from "node:fs";
|
|
12078
|
-
import { readdir as
|
|
12767
|
+
import { readdir as readdir11, readFile as readFile13, stat as stat14 } from "node:fs/promises";
|
|
12079
12768
|
import os12 from "node:os";
|
|
12080
|
-
import
|
|
12769
|
+
import path21 from "node:path";
|
|
12081
12770
|
function parseQoderPaths(filePath) {
|
|
12082
|
-
const parts = filePath.split(
|
|
12771
|
+
const parts = filePath.split(path21.sep);
|
|
12083
12772
|
const subagentsIdx = parts.lastIndexOf("subagents");
|
|
12084
12773
|
let sessionId = "";
|
|
12085
12774
|
let projectName = "";
|
|
@@ -12089,17 +12778,17 @@ function parseQoderPaths(filePath) {
|
|
|
12089
12778
|
sessionId = parts[subagentsIdx - 1];
|
|
12090
12779
|
projectName = parts[subagentsIdx - 2];
|
|
12091
12780
|
const projectsIdx = parts.lastIndexOf("projects");
|
|
12092
|
-
configDir2 = parts.slice(0, projectsIdx).join(
|
|
12093
|
-
mainTranscriptPath = [...parts.slice(0, subagentsIdx - 1), `${sessionId}.jsonl`].join(
|
|
12781
|
+
configDir2 = parts.slice(0, projectsIdx).join(path21.sep);
|
|
12782
|
+
mainTranscriptPath = [...parts.slice(0, subagentsIdx - 1), `${sessionId}.jsonl`].join(path21.sep);
|
|
12094
12783
|
} else {
|
|
12095
12784
|
const filename = parts.at(-1) || "";
|
|
12096
|
-
sessionId =
|
|
12785
|
+
sessionId = path21.basename(filename, ".jsonl");
|
|
12097
12786
|
projectName = parts.at(-2) || "";
|
|
12098
12787
|
if (projectName === "transcript") {
|
|
12099
12788
|
projectName = parts.at(-3) || "";
|
|
12100
12789
|
}
|
|
12101
12790
|
const projectsIdx = parts.lastIndexOf("projects");
|
|
12102
|
-
configDir2 = parts.slice(0, projectsIdx).join(
|
|
12791
|
+
configDir2 = parts.slice(0, projectsIdx).join(path21.sep);
|
|
12103
12792
|
}
|
|
12104
12793
|
return { configDir: configDir2, projectName, sessionId, mainTranscriptPath };
|
|
12105
12794
|
}
|
|
@@ -12147,7 +12836,7 @@ async function loadQoderModelNames(configDir2, home) {
|
|
|
12147
12836
|
}
|
|
12148
12837
|
}
|
|
12149
12838
|
}
|
|
12150
|
-
const textsMap = await parseModelNamesFromDynamicTexts2(
|
|
12839
|
+
const textsMap = await parseModelNamesFromDynamicTexts2(path21.join(configDir2, ".auth", "dynamic-texts.json"));
|
|
12151
12840
|
for (const [key, val] of Object.entries(textsMap)) {
|
|
12152
12841
|
if (!(key in map)) {
|
|
12153
12842
|
map[key] = val;
|
|
@@ -12155,7 +12844,7 @@ async function loadQoderModelNames(configDir2, home) {
|
|
|
12155
12844
|
}
|
|
12156
12845
|
const siblingConfigDir = configDir2.replace(/\.qoder$/, ".qoder-cn");
|
|
12157
12846
|
if (siblingConfigDir !== configDir2) {
|
|
12158
|
-
const siblingMap = await parseModelNamesFromDynamicTexts2(
|
|
12847
|
+
const siblingMap = await parseModelNamesFromDynamicTexts2(path21.join(siblingConfigDir, ".auth", "dynamic-texts.json"));
|
|
12159
12848
|
for (const [key, val] of Object.entries(siblingMap)) {
|
|
12160
12849
|
if (!(key in map)) {
|
|
12161
12850
|
map[key] = val;
|
|
@@ -12163,11 +12852,11 @@ async function loadQoderModelNames(configDir2, home) {
|
|
|
12163
12852
|
}
|
|
12164
12853
|
}
|
|
12165
12854
|
if (isQwenworkConfigRoot(configDir2)) {
|
|
12166
|
-
for (const dir of [
|
|
12167
|
-
if (
|
|
12855
|
+
for (const dir of [path21.join(home, ".qoder"), path21.join(home, ".qoder-cn")]) {
|
|
12856
|
+
if (path21.resolve(dir) === path21.resolve(configDir2)) {
|
|
12168
12857
|
continue;
|
|
12169
12858
|
}
|
|
12170
|
-
const fallbackMap = await parseModelNamesFromDynamicTexts2(
|
|
12859
|
+
const fallbackMap = await parseModelNamesFromDynamicTexts2(path21.join(dir, ".auth", "dynamic-texts.json"));
|
|
12171
12860
|
for (const [key, val] of Object.entries(fallbackMap)) {
|
|
12172
12861
|
if (!(key in map)) {
|
|
12173
12862
|
map[key] = val;
|
|
@@ -12178,25 +12867,25 @@ async function loadQoderModelNames(configDir2, home) {
|
|
|
12178
12867
|
return map;
|
|
12179
12868
|
}
|
|
12180
12869
|
function isQwenworkConfigRoot(configDir2) {
|
|
12181
|
-
const name =
|
|
12870
|
+
const name = path21.basename(path21.resolve(configDir2));
|
|
12182
12871
|
if (name === ".qwenworkcn" || name === ".qwenwork") {
|
|
12183
12872
|
return true;
|
|
12184
12873
|
}
|
|
12185
12874
|
const override = process.env.QWENWORK_CONFIG_DIR;
|
|
12186
|
-
return Boolean(override && override.trim() &&
|
|
12875
|
+
return Boolean(override && override.trim() && path21.basename(path21.resolve(override)) === name);
|
|
12187
12876
|
}
|
|
12188
12877
|
var FAILED_SEGMENT_STOP_REASONS = /* @__PURE__ */ new Set(["cancelled", "canceled", "error", "failed", "refusal"]);
|
|
12189
12878
|
async function loadQoderSegmentModelCalls(filePath, isSubagentSession, modelMap) {
|
|
12190
12879
|
const { configDir: configDir2, projectName, sessionId } = parseQoderPaths(filePath);
|
|
12191
|
-
const segmentsPath =
|
|
12880
|
+
const segmentsPath = path21.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
|
|
12192
12881
|
const modelCalls = [];
|
|
12193
12882
|
try {
|
|
12194
|
-
const files = await
|
|
12883
|
+
const files = await readdir11(segmentsPath);
|
|
12195
12884
|
for (const file of files) {
|
|
12196
12885
|
if (!file.endsWith(".jsonl")) {
|
|
12197
12886
|
continue;
|
|
12198
12887
|
}
|
|
12199
|
-
const content = await readFile13(
|
|
12888
|
+
const content = await readFile13(path21.join(segmentsPath, file), "utf8");
|
|
12200
12889
|
let currentTurnIsSubagent = false;
|
|
12201
12890
|
for (const line of content.split("\n").filter(Boolean)) {
|
|
12202
12891
|
const raw = parseJsonLine(line);
|
|
@@ -12241,7 +12930,7 @@ async function parseQoderSessionFile(filePath, options) {
|
|
|
12241
12930
|
let cwd;
|
|
12242
12931
|
let project = projectContext.project;
|
|
12243
12932
|
let model;
|
|
12244
|
-
const home =
|
|
12933
|
+
const home = path21.resolve(stringOption(options.home) || os12.homedir());
|
|
12245
12934
|
const modelMap = await loadQoderModelNames(configDir2, home);
|
|
12246
12935
|
const qwenworkRoot = isQwenworkConfigRoot(configDir2);
|
|
12247
12936
|
const isSubagentSession = filePath.includes("subagents");
|
|
@@ -12277,7 +12966,7 @@ async function parseQoderSessionFile(filePath, options) {
|
|
|
12277
12966
|
sessionId = stringField(raw, "sessionId") || sessionId;
|
|
12278
12967
|
state.sessionId = sessionId;
|
|
12279
12968
|
cwd = stringField(raw, "cwd") || cwd;
|
|
12280
|
-
project = projectContext.project || (cwd ?
|
|
12969
|
+
project = projectContext.project || (cwd ? path21.basename(cwd) : project || await qoderProjectFromFilePath(filePath, options));
|
|
12281
12970
|
if (!ts) {
|
|
12282
12971
|
continue;
|
|
12283
12972
|
}
|
|
@@ -12588,7 +13277,7 @@ async function parseQoderSessionFile(filePath, options) {
|
|
|
12588
13277
|
}
|
|
12589
13278
|
dbModelCalls ??= await loadQoderDbModelCalls("Qoder", parsedPaths.sessionId, modelMap);
|
|
12590
13279
|
if (dbModelCalls.rootSessionId) {
|
|
12591
|
-
const parentPath =
|
|
13280
|
+
const parentPath = path21.join(path21.dirname(filePath), `${dbModelCalls.rootSessionId}.jsonl`);
|
|
12592
13281
|
const parentSourcePathHash = `sha256:${createStableHash(parentPath)}`;
|
|
12593
13282
|
return withoutSubagentTurnEvents(validEvents).map((event) => rebuildEventIdentity4({
|
|
12594
13283
|
...event,
|
|
@@ -12705,41 +13394,41 @@ function qoderExtractText(value) {
|
|
|
12705
13394
|
}
|
|
12706
13395
|
async function qoderProjectContextFromLines(filePath, lines, options, configDir2) {
|
|
12707
13396
|
const { projectName: projectDir, sessionId } = parseQoderPaths(filePath);
|
|
12708
|
-
const isSubagent = filePath.includes(`${
|
|
13397
|
+
const isSubagent = filePath.includes(`${path21.sep}subagents${path21.sep}`);
|
|
12709
13398
|
const inherited = isSubagent ? await readPersistedSessionContextFromOptions(options, sessionId) : void 0;
|
|
12710
13399
|
let cwds = [];
|
|
12711
13400
|
const workspaceDirs = [];
|
|
12712
13401
|
for (const line of lines) {
|
|
12713
13402
|
const raw = parseJsonLine(line);
|
|
12714
13403
|
const cwd = raw ? stringField(raw, "cwd") : void 0;
|
|
12715
|
-
if (cwd &&
|
|
13404
|
+
if (cwd && path21.isAbsolute(cwd)) {
|
|
12716
13405
|
cwds.push(cwd);
|
|
12717
13406
|
}
|
|
12718
13407
|
if (raw && stringField(raw, "type") === "workspace-directories") {
|
|
12719
13408
|
for (const dir of arrayField5(raw, "directories")) {
|
|
12720
|
-
if (typeof dir === "string" &&
|
|
13409
|
+
if (typeof dir === "string" && path21.isAbsolute(dir)) {
|
|
12721
13410
|
workspaceDirs.push(dir);
|
|
12722
13411
|
}
|
|
12723
13412
|
}
|
|
12724
13413
|
}
|
|
12725
13414
|
}
|
|
12726
13415
|
if (isSubagent) {
|
|
12727
|
-
if (inherited?.cwd &&
|
|
13416
|
+
if (inherited?.cwd && path21.isAbsolute(inherited.cwd)) {
|
|
12728
13417
|
cwds = [inherited.cwd];
|
|
12729
13418
|
} else {
|
|
12730
|
-
const parentSessionPath =
|
|
13419
|
+
const parentSessionPath = path21.join(configDir2, "projects", projectDir, `${sessionId}.jsonl`);
|
|
12731
13420
|
try {
|
|
12732
13421
|
const parentText = await readFile13(parentSessionPath, "utf8");
|
|
12733
13422
|
const parentCwds = [];
|
|
12734
13423
|
for (const line of parentText.split("\n").filter(Boolean)) {
|
|
12735
13424
|
const raw = parseJsonLine(line);
|
|
12736
13425
|
const cwd = raw ? stringField(raw, "cwd") : void 0;
|
|
12737
|
-
if (cwd &&
|
|
13426
|
+
if (cwd && path21.isAbsolute(cwd)) {
|
|
12738
13427
|
parentCwds.push(cwd);
|
|
12739
13428
|
}
|
|
12740
13429
|
if (workspaceDirs.length === 0 && raw && stringField(raw, "type") === "workspace-directories") {
|
|
12741
13430
|
for (const dir of arrayField5(raw, "directories")) {
|
|
12742
|
-
if (typeof dir === "string" &&
|
|
13431
|
+
if (typeof dir === "string" && path21.isAbsolute(dir)) {
|
|
12743
13432
|
workspaceDirs.push(dir);
|
|
12744
13433
|
}
|
|
12745
13434
|
}
|
|
@@ -12759,29 +13448,29 @@ async function qoderProjectContextFromLines(filePath, lines, options, configDir2
|
|
|
12759
13448
|
}
|
|
12760
13449
|
}
|
|
12761
13450
|
const root = await gitRootFromCwds3(cwds) || qoderProjectRootFromCwds(projectDir, cwds);
|
|
12762
|
-
const project = inherited?.project || (cwds.length > 0 ?
|
|
13451
|
+
const project = inherited?.project || (cwds.length > 0 ? path21.basename(cwds[0]) : root ? path21.basename(root) : await qoderProjectFromFilePath(filePath, options));
|
|
12763
13452
|
return {
|
|
12764
13453
|
project,
|
|
12765
13454
|
workspaceId: createWorkspaceId({ projectName: project, repoRoot: root })
|
|
12766
13455
|
};
|
|
12767
13456
|
}
|
|
12768
13457
|
function pathInsideDir(candidate, dir) {
|
|
12769
|
-
const resolvedDir =
|
|
12770
|
-
const resolved =
|
|
12771
|
-
return resolved === resolvedDir || resolved.startsWith(`${resolvedDir}${
|
|
13458
|
+
const resolvedDir = path21.resolve(dir);
|
|
13459
|
+
const resolved = path21.resolve(candidate);
|
|
13460
|
+
return resolved === resolvedDir || resolved.startsWith(`${resolvedDir}${path21.sep}`);
|
|
12772
13461
|
}
|
|
12773
13462
|
async function gitRootFromCwds3(cwds) {
|
|
12774
13463
|
const seen = /* @__PURE__ */ new Set();
|
|
12775
13464
|
for (const cwd of cwds) {
|
|
12776
|
-
let current =
|
|
13465
|
+
let current = path21.resolve(cwd);
|
|
12777
13466
|
while (!seen.has(current)) {
|
|
12778
13467
|
seen.add(current);
|
|
12779
13468
|
try {
|
|
12780
|
-
await
|
|
13469
|
+
await stat14(path21.join(current, ".git"));
|
|
12781
13470
|
return current;
|
|
12782
13471
|
} catch {
|
|
12783
13472
|
}
|
|
12784
|
-
const parent =
|
|
13473
|
+
const parent = path21.dirname(current);
|
|
12785
13474
|
if (parent === current) {
|
|
12786
13475
|
break;
|
|
12787
13476
|
}
|
|
@@ -12792,12 +13481,12 @@ async function gitRootFromCwds3(cwds) {
|
|
|
12792
13481
|
}
|
|
12793
13482
|
function qoderProjectRootFromCwds(projectDir, cwds) {
|
|
12794
13483
|
for (const cwd of cwds) {
|
|
12795
|
-
let current =
|
|
13484
|
+
let current = path21.resolve(cwd);
|
|
12796
13485
|
while (true) {
|
|
12797
13486
|
if (qoderEncodedVariants(current).includes(projectDir)) {
|
|
12798
13487
|
return current;
|
|
12799
13488
|
}
|
|
12800
|
-
const parent =
|
|
13489
|
+
const parent = path21.dirname(current);
|
|
12801
13490
|
if (parent === current) {
|
|
12802
13491
|
break;
|
|
12803
13492
|
}
|
|
@@ -12807,7 +13496,7 @@ function qoderProjectRootFromCwds(projectDir, cwds) {
|
|
|
12807
13496
|
return void 0;
|
|
12808
13497
|
}
|
|
12809
13498
|
function rawQoderProjectPath(value) {
|
|
12810
|
-
return
|
|
13499
|
+
return path21.resolve(value).split(path21.sep).join("-");
|
|
12811
13500
|
}
|
|
12812
13501
|
function qoderEncodedVariants(value) {
|
|
12813
13502
|
const raw = rawQoderProjectPath(value);
|
|
@@ -12828,11 +13517,11 @@ function qoderEncodedProjectSuffix(projectDir, home) {
|
|
|
12828
13517
|
return void 0;
|
|
12829
13518
|
}
|
|
12830
13519
|
async function qoderProjectFromFilePath(filePath, options) {
|
|
12831
|
-
const projectDir =
|
|
12832
|
-
const home = options ?
|
|
13520
|
+
const projectDir = path21.basename(path21.dirname(filePath));
|
|
13521
|
+
const home = options ? path21.resolve(stringOption(options.home) || os12.homedir()) : os12.homedir();
|
|
12833
13522
|
const resolved = await resolveQoderProjectPath(projectDir, home);
|
|
12834
13523
|
if (resolved) {
|
|
12835
|
-
return
|
|
13524
|
+
return path21.basename(resolved);
|
|
12836
13525
|
}
|
|
12837
13526
|
const suffix = qoderEncodedProjectSuffix(projectDir, home);
|
|
12838
13527
|
if (suffix) {
|
|
@@ -12853,12 +13542,12 @@ async function resolveQoderProjectPath(projectDir, home) {
|
|
|
12853
13542
|
while (currentEncodedVariants.some((prefix) => projectDir.startsWith(`${prefix}-`))) {
|
|
12854
13543
|
let matchedChild;
|
|
12855
13544
|
try {
|
|
12856
|
-
const entries = await
|
|
13545
|
+
const entries = await readdir11(current, { withFileTypes: true });
|
|
12857
13546
|
for (const entry of entries) {
|
|
12858
13547
|
if (!entry.isDirectory()) {
|
|
12859
13548
|
continue;
|
|
12860
13549
|
}
|
|
12861
|
-
const candidate =
|
|
13550
|
+
const candidate = path21.join(current, entry.name);
|
|
12862
13551
|
const candidateVariants = qoderEncodedVariants(candidate);
|
|
12863
13552
|
if (candidateVariants.includes(projectDir)) {
|
|
12864
13553
|
return candidate;
|
|
@@ -12903,19 +13592,19 @@ function hookConfig7() {
|
|
|
12903
13592
|
function qoderConfigDir(home, env) {
|
|
12904
13593
|
const override = env?.QODER_CONFIG_DIR;
|
|
12905
13594
|
if (override && override.trim()) {
|
|
12906
|
-
return
|
|
13595
|
+
return path21.resolve(override);
|
|
12907
13596
|
}
|
|
12908
|
-
return
|
|
13597
|
+
return path21.join(home, ".qoder");
|
|
12909
13598
|
}
|
|
12910
13599
|
function qwenworkConfigDir(home, env) {
|
|
12911
13600
|
const override = env?.QWENWORK_CONFIG_DIR;
|
|
12912
13601
|
if (override && override.trim()) {
|
|
12913
|
-
return
|
|
13602
|
+
return path21.resolve(override);
|
|
12914
13603
|
}
|
|
12915
|
-
return
|
|
13604
|
+
return path21.join(home, ".qwenworkcn");
|
|
12916
13605
|
}
|
|
12917
13606
|
function qoderConfigDirs(home, env) {
|
|
12918
|
-
return [...new Set([qoderConfigDir(home, env), qwenworkConfigDir(home, env)].map((dir) =>
|
|
13607
|
+
return [...new Set([qoderConfigDir(home, env), qwenworkConfigDir(home, env)].map((dir) => path21.resolve(dir)))];
|
|
12919
13608
|
}
|
|
12920
13609
|
function createQoderAdapter() {
|
|
12921
13610
|
return {
|
|
@@ -12927,11 +13616,11 @@ function createQoderAdapter() {
|
|
|
12927
13616
|
return qoderConfigDir(home, env);
|
|
12928
13617
|
},
|
|
12929
13618
|
installedPath(home, env) {
|
|
12930
|
-
return
|
|
13619
|
+
return path21.join(qoderConfigDir(home, env), "settings.json");
|
|
12931
13620
|
},
|
|
12932
13621
|
async isInstalled(home, env) {
|
|
12933
13622
|
return isHooksJsonInstalled(
|
|
12934
|
-
|
|
13623
|
+
path21.join(qoderConfigDir(home, env), "settings.json"),
|
|
12935
13624
|
"vibetime hook --agent qoder"
|
|
12936
13625
|
);
|
|
12937
13626
|
},
|
|
@@ -12940,16 +13629,16 @@ function createQoderAdapter() {
|
|
|
12940
13629
|
const targets = [primary, ...variants.filter((dir) => existsSync(dir))];
|
|
12941
13630
|
return targets.map((base) => ({
|
|
12942
13631
|
kind: "hooks-json",
|
|
12943
|
-
path:
|
|
13632
|
+
path: path21.join(base, "settings.json"),
|
|
12944
13633
|
content: hookConfig7()
|
|
12945
13634
|
}));
|
|
12946
13635
|
},
|
|
12947
13636
|
sourcePaths(home, env) {
|
|
12948
|
-
const paths = qoderConfigDirs(home, env).map((base2) =>
|
|
13637
|
+
const paths = qoderConfigDirs(home, env).map((base2) => path21.join(base2, "projects"));
|
|
12949
13638
|
const base = qoderConfigDir(home, env);
|
|
12950
13639
|
paths.push(
|
|
12951
|
-
|
|
12952
|
-
|
|
13640
|
+
path21.join(base, ".qoder.json"),
|
|
13641
|
+
path21.join(home, ".qoder.json")
|
|
12953
13642
|
);
|
|
12954
13643
|
return paths;
|
|
12955
13644
|
},
|
|
@@ -12985,35 +13674,35 @@ function normalizeId(id) {
|
|
|
12985
13674
|
}
|
|
12986
13675
|
|
|
12987
13676
|
// src/adapters/workbuddy.ts
|
|
12988
|
-
import { readdir as
|
|
12989
|
-
import
|
|
13677
|
+
import { readdir as readdir12, readFile as readFile14, stat as stat15 } from "node:fs/promises";
|
|
13678
|
+
import path22 from "node:path";
|
|
12990
13679
|
function workbuddyProjectsDir(home, env) {
|
|
12991
13680
|
const override = env?.WORKBUDDY_PROJECTS_DIR || env?.WORKBUDDY_HOME;
|
|
12992
13681
|
if (override && override.trim()) {
|
|
12993
|
-
return
|
|
13682
|
+
return path22.resolve(override, override.endsWith("projects") ? "" : "projects");
|
|
12994
13683
|
}
|
|
12995
|
-
return
|
|
13684
|
+
return path22.join(home, ".workbuddy", "projects");
|
|
12996
13685
|
}
|
|
12997
13686
|
function workbuddyBaseDir(home, env) {
|
|
12998
13687
|
const override = env?.WORKBUDDY_HOME;
|
|
12999
13688
|
if (override && override.trim()) {
|
|
13000
|
-
return
|
|
13689
|
+
return path22.resolve(override);
|
|
13001
13690
|
}
|
|
13002
|
-
return
|
|
13691
|
+
return path22.join(home, ".workbuddy");
|
|
13003
13692
|
}
|
|
13004
|
-
function
|
|
13693
|
+
function projectFromCwd2(cwd, fallback) {
|
|
13005
13694
|
if (!cwd) {
|
|
13006
13695
|
return fallback;
|
|
13007
13696
|
}
|
|
13008
|
-
return
|
|
13697
|
+
return path22.basename(cwd) || fallback;
|
|
13009
13698
|
}
|
|
13010
|
-
function
|
|
13699
|
+
function sourceHash2(filePath) {
|
|
13011
13700
|
return `sha256:${createStableHash(filePath)}`;
|
|
13012
13701
|
}
|
|
13013
|
-
function
|
|
13702
|
+
function makeEvent2(event, line, filePath, options) {
|
|
13014
13703
|
const withRefs = withBackfillRefs(event, {
|
|
13015
13704
|
filePath,
|
|
13016
|
-
sourcePathHash:
|
|
13705
|
+
sourcePathHash: sourceHash2(filePath),
|
|
13017
13706
|
lineNumber: line.lineNumber,
|
|
13018
13707
|
topType: stringField(line.record, "type"),
|
|
13019
13708
|
payloadType: stringField(line.record, "role") || stringField(line.record, "name"),
|
|
@@ -13093,7 +13782,7 @@ function isHiddenUserMessage(record) {
|
|
|
13093
13782
|
return providerData.skipRun === true || providerData.isMeta === true || providerData.isCompactInternal === true || providerData.isCompact === true || providerData.isTeammateMessage === true || (stringField(providerData, "agentPurpose") || "").toLowerCase().includes("compact");
|
|
13094
13783
|
}
|
|
13095
13784
|
function workbuddySubagentRefs(lines) {
|
|
13096
|
-
const
|
|
13785
|
+
const refs3 = {};
|
|
13097
13786
|
const keys = [
|
|
13098
13787
|
["parentSessionId", ["parent_session_id", "parentSessionId"]],
|
|
13099
13788
|
["parentToolCallId", ["parent_tool_call_id", "parentToolCallId"]],
|
|
@@ -13103,19 +13792,19 @@ function workbuddySubagentRefs(lines) {
|
|
|
13103
13792
|
for (const line of lines) {
|
|
13104
13793
|
const providerData = objectField(line.record, "providerData");
|
|
13105
13794
|
for (const [ref, aliases] of keys) {
|
|
13106
|
-
if (
|
|
13795
|
+
if (refs3[ref]) {
|
|
13107
13796
|
continue;
|
|
13108
13797
|
}
|
|
13109
13798
|
for (const alias of aliases) {
|
|
13110
13799
|
const value = stringField(line.record, alias) || stringField(providerData, alias);
|
|
13111
13800
|
if (value) {
|
|
13112
|
-
|
|
13801
|
+
refs3[ref] = value;
|
|
13113
13802
|
break;
|
|
13114
13803
|
}
|
|
13115
13804
|
}
|
|
13116
13805
|
}
|
|
13117
13806
|
}
|
|
13118
|
-
return
|
|
13807
|
+
return refs3;
|
|
13119
13808
|
}
|
|
13120
13809
|
function toolCallFailed(record) {
|
|
13121
13810
|
const providerData = objectField(record, "providerData");
|
|
@@ -13143,10 +13832,10 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
13143
13832
|
}
|
|
13144
13833
|
const events = [];
|
|
13145
13834
|
const first = lines[0].record;
|
|
13146
|
-
const sessionId = stringField(first, "sessionId") ||
|
|
13147
|
-
const fallbackProject =
|
|
13835
|
+
const sessionId = stringField(first, "sessionId") || path22.basename(filePath, ".jsonl");
|
|
13836
|
+
const fallbackProject = path22.basename(path22.dirname(filePath));
|
|
13148
13837
|
const cwd = lines.map((line) => stringField(line.record, "cwd")).find(Boolean);
|
|
13149
|
-
const project =
|
|
13838
|
+
const project = projectFromCwd2(cwd, fallbackProject);
|
|
13150
13839
|
const workspaceId = createWorkspaceId({ projectName: project, repoRoot: cwd });
|
|
13151
13840
|
const sessionPrefix = `workbuddy:${sessionId}`;
|
|
13152
13841
|
const toolStarts = /* @__PURE__ */ new Map();
|
|
@@ -13161,7 +13850,7 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
13161
13850
|
return void 0;
|
|
13162
13851
|
}
|
|
13163
13852
|
const failed = turnLastAssistantStatus !== void 0 && ["incomplete", "failed", "cancelled"].includes(turnLastAssistantStatus);
|
|
13164
|
-
return
|
|
13853
|
+
return makeEvent2({
|
|
13165
13854
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13166
13855
|
ts: turnLastTs,
|
|
13167
13856
|
type: failed ? "turn.failed" : "turn.completed",
|
|
@@ -13178,7 +13867,7 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
13178
13867
|
};
|
|
13179
13868
|
const firstTs = lines.map((line) => timestampFrom(numberField(line.record, "timestamp"))).find(Boolean);
|
|
13180
13869
|
if (firstTs) {
|
|
13181
|
-
const event =
|
|
13870
|
+
const event = makeEvent2({
|
|
13182
13871
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13183
13872
|
ts: firstTs,
|
|
13184
13873
|
type: "session.started",
|
|
@@ -13218,7 +13907,7 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
13218
13907
|
turnLastAssistantStatus = void 0;
|
|
13219
13908
|
const promptChars = contentLength(record.content);
|
|
13220
13909
|
for (const event of [
|
|
13221
|
-
|
|
13910
|
+
makeEvent2({
|
|
13222
13911
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13223
13912
|
ts,
|
|
13224
13913
|
type: "turn.started",
|
|
@@ -13232,7 +13921,7 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
13232
13921
|
confidence: "derived",
|
|
13233
13922
|
refs: { sourceId: `${sourceId}:turn` }
|
|
13234
13923
|
}, line, filePath, options),
|
|
13235
|
-
|
|
13924
|
+
makeEvent2({
|
|
13236
13925
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13237
13926
|
ts,
|
|
13238
13927
|
type: "prompt.submitted",
|
|
@@ -13261,7 +13950,7 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
13261
13950
|
const metrics = workbuddyUsageMetrics(record);
|
|
13262
13951
|
if (metrics) {
|
|
13263
13952
|
const model = stringField(objectField(record, "providerData"), "model");
|
|
13264
|
-
const usage =
|
|
13953
|
+
const usage = makeEvent2({
|
|
13265
13954
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13266
13955
|
ts,
|
|
13267
13956
|
type: "model.usage",
|
|
@@ -13290,7 +13979,7 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
13290
13979
|
const callId = stringField(record, "callId");
|
|
13291
13980
|
if (tool && callId) {
|
|
13292
13981
|
toolStarts.set(`${sessionId}:${callId}`, { line, ts, tool, callId });
|
|
13293
|
-
const started =
|
|
13982
|
+
const started = makeEvent2({
|
|
13294
13983
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13295
13984
|
ts,
|
|
13296
13985
|
type: "tool.started",
|
|
@@ -13318,7 +14007,7 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
13318
14007
|
if (isPlainObject(toolInput)) {
|
|
13319
14008
|
const fileActivities = claudeStyleToolFileActivities(tool, toolInput, ts, cwd);
|
|
13320
14009
|
if (fileActivities.length > 0) {
|
|
13321
|
-
const fileEvent =
|
|
14010
|
+
const fileEvent = makeEvent2({
|
|
13322
14011
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13323
14012
|
ts,
|
|
13324
14013
|
type: eventTypeFromFileActivities(fileActivities),
|
|
@@ -13344,7 +14033,7 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
13344
14033
|
const metrics = workbuddyUsageMetrics(record);
|
|
13345
14034
|
const model = stringField(objectField(record, "providerData"), "model");
|
|
13346
14035
|
if (metrics || model) {
|
|
13347
|
-
const usage =
|
|
14036
|
+
const usage = makeEvent2({
|
|
13348
14037
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13349
14038
|
ts,
|
|
13350
14039
|
type: "model.usage",
|
|
@@ -13373,7 +14062,7 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
13373
14062
|
const start = toolStarts.get(`${sessionId}:${callId}`);
|
|
13374
14063
|
const durationMs = start?.ts ? Math.max(0, Date.parse(ts) - Date.parse(start.ts)) : void 0;
|
|
13375
14064
|
const failed = toolCallFailed(record);
|
|
13376
|
-
const completed =
|
|
14065
|
+
const completed = makeEvent2({
|
|
13377
14066
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13378
14067
|
ts,
|
|
13379
14068
|
type: failed ? "tool.failed" : "tool.completed",
|
|
@@ -13405,7 +14094,7 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
13405
14094
|
}
|
|
13406
14095
|
const lastTs = lastLine ? timestampFrom(numberField(lastLine.record, "timestamp")) : void 0;
|
|
13407
14096
|
if (lastLine && lastTs) {
|
|
13408
|
-
const event =
|
|
14097
|
+
const event = makeEvent2({
|
|
13409
14098
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13410
14099
|
ts: lastTs,
|
|
13411
14100
|
type: "session.ended",
|
|
@@ -13428,17 +14117,17 @@ async function workbuddyBackfillFiles(sourceRoot, home, env) {
|
|
|
13428
14117
|
const base = sourceRoot || workbuddyProjectsDir(home, env);
|
|
13429
14118
|
const files = [];
|
|
13430
14119
|
try {
|
|
13431
|
-
const projects = await
|
|
14120
|
+
const projects = await readdir12(base, { withFileTypes: true });
|
|
13432
14121
|
for (const project of projects) {
|
|
13433
14122
|
if (!project.isDirectory()) {
|
|
13434
14123
|
continue;
|
|
13435
14124
|
}
|
|
13436
|
-
const projectDir =
|
|
13437
|
-
const entries = await
|
|
14125
|
+
const projectDir = path22.join(base, project.name);
|
|
14126
|
+
const entries = await readdir12(projectDir, { withFileTypes: true });
|
|
13438
14127
|
for (const entry of entries) {
|
|
13439
14128
|
if (entry.isFile() && entry.name.endsWith(".jsonl")) {
|
|
13440
|
-
const filePath =
|
|
13441
|
-
const info = await
|
|
14129
|
+
const filePath = path22.join(projectDir, entry.name);
|
|
14130
|
+
const info = await stat15(filePath);
|
|
13442
14131
|
files.push({ path: filePath, modifiedAt: info.mtime.toISOString() });
|
|
13443
14132
|
}
|
|
13444
14133
|
}
|
|
@@ -13475,18 +14164,18 @@ function createWorkbuddyAdapter() {
|
|
|
13475
14164
|
return workbuddyProjectsDir(home, env);
|
|
13476
14165
|
},
|
|
13477
14166
|
installedPath(home, env) {
|
|
13478
|
-
return
|
|
14167
|
+
return path22.join(workbuddyBaseDir(home, env), "settings.json");
|
|
13479
14168
|
},
|
|
13480
14169
|
async isInstalled(home, env) {
|
|
13481
14170
|
return isHooksJsonInstalled(
|
|
13482
|
-
|
|
14171
|
+
path22.join(workbuddyBaseDir(home, env), "settings.json"),
|
|
13483
14172
|
"vibetime hook --agent workbuddy"
|
|
13484
14173
|
);
|
|
13485
14174
|
},
|
|
13486
14175
|
installEntries(home, env) {
|
|
13487
14176
|
return [{
|
|
13488
14177
|
kind: "hooks-json",
|
|
13489
|
-
path:
|
|
14178
|
+
path: path22.join(workbuddyBaseDir(home, env), "settings.json"),
|
|
13490
14179
|
content: hookConfig8()
|
|
13491
14180
|
}];
|
|
13492
14181
|
},
|
|
@@ -13499,22 +14188,22 @@ function createWorkbuddyAdapter() {
|
|
|
13499
14188
|
|
|
13500
14189
|
// src/adapters/zcode.ts
|
|
13501
14190
|
import { execFile } from "node:child_process";
|
|
13502
|
-
import { readFile as readFile15, stat as
|
|
13503
|
-
import
|
|
14191
|
+
import { readFile as readFile15, stat as stat16 } from "node:fs/promises";
|
|
14192
|
+
import path23 from "node:path";
|
|
13504
14193
|
import { promisify as promisify2 } from "node:util";
|
|
13505
14194
|
var execFileAsync = promisify2(execFile);
|
|
13506
14195
|
function zcodeCliDir(home, env) {
|
|
13507
14196
|
const override = env?.ZCODE_CLI_DIR || env?.ZCODE_HOME;
|
|
13508
14197
|
if (override && override.trim()) {
|
|
13509
|
-
return
|
|
14198
|
+
return path23.resolve(override, override.endsWith("cli") ? "" : "cli");
|
|
13510
14199
|
}
|
|
13511
|
-
return
|
|
14200
|
+
return path23.join(home, ".zcode", "cli");
|
|
13512
14201
|
}
|
|
13513
14202
|
function zcodeDbPath(home, env) {
|
|
13514
|
-
return
|
|
14203
|
+
return path23.join(zcodeCliDir(home, env), "db", "db.sqlite");
|
|
13515
14204
|
}
|
|
13516
14205
|
function zcodeConfigPath(home, env) {
|
|
13517
|
-
return
|
|
14206
|
+
return path23.join(zcodeCliDir(home, env), "config.json");
|
|
13518
14207
|
}
|
|
13519
14208
|
var zcodeHandler = (msg) => hookHandler("zcode", msg);
|
|
13520
14209
|
function hookConfig9() {
|
|
@@ -13538,7 +14227,7 @@ var providerNameCache = null;
|
|
|
13538
14227
|
async function loadProviderNames(configPath2) {
|
|
13539
14228
|
let fileMtime = 0;
|
|
13540
14229
|
try {
|
|
13541
|
-
const info = await
|
|
14230
|
+
const info = await stat16(configPath2);
|
|
13542
14231
|
fileMtime = info.mtimeMs;
|
|
13543
14232
|
} catch {
|
|
13544
14233
|
return /* @__PURE__ */ new Map();
|
|
@@ -13562,19 +14251,19 @@ async function loadProviderNames(configPath2) {
|
|
|
13562
14251
|
providerNameCache = { path: configPath2, mtimeMs: fileMtime, map };
|
|
13563
14252
|
return map;
|
|
13564
14253
|
}
|
|
13565
|
-
function
|
|
14254
|
+
function sourceHash3(filePath) {
|
|
13566
14255
|
return `sha256:${createStableHash(filePath)}`;
|
|
13567
14256
|
}
|
|
13568
14257
|
function projectFromDirectory(directory) {
|
|
13569
|
-
return directory ?
|
|
14258
|
+
return directory ? path23.basename(directory) || "zcode" : "zcode";
|
|
13570
14259
|
}
|
|
13571
14260
|
function isoFromMs(value) {
|
|
13572
14261
|
return timestampFrom(typeof value === "number" ? value : Number(value));
|
|
13573
14262
|
}
|
|
13574
|
-
function
|
|
14263
|
+
function makeEvent3(event, row, rowNumber, filePath, options) {
|
|
13575
14264
|
const withRefs = withBackfillRefs(event, {
|
|
13576
14265
|
filePath,
|
|
13577
|
-
sourcePathHash:
|
|
14266
|
+
sourcePathHash: sourceHash3(filePath),
|
|
13578
14267
|
lineNumber: rowNumber,
|
|
13579
14268
|
topType: row.kind,
|
|
13580
14269
|
payloadType: stringField(row, "status") || stringField(row, "query_source") || stringField(row, "tool_name"),
|
|
@@ -13582,7 +14271,7 @@ function makeEvent2(event, row, rowNumber, filePath, options) {
|
|
|
13582
14271
|
});
|
|
13583
14272
|
return validateCanonicalEvent(withRefs).valid ? withRefs : void 0;
|
|
13584
14273
|
}
|
|
13585
|
-
function
|
|
14274
|
+
function refs2(values) {
|
|
13586
14275
|
const out = {};
|
|
13587
14276
|
for (const [key, value] of Object.entries(values)) {
|
|
13588
14277
|
if (value !== void 0 && value !== "") {
|
|
@@ -13739,7 +14428,7 @@ function resolveRootSessionId2(sessionId, sessions) {
|
|
|
13739
14428
|
}
|
|
13740
14429
|
return current;
|
|
13741
14430
|
}
|
|
13742
|
-
function
|
|
14431
|
+
function sessionContext2(row, sessions) {
|
|
13743
14432
|
const sessionId = stringField(row, "session_id") || stringField(row, "id") || "unknown";
|
|
13744
14433
|
const session = sessions.get(sessionId);
|
|
13745
14434
|
const cwd = stringField(session, "directory");
|
|
@@ -13761,16 +14450,16 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13761
14450
|
if (rows.length === 0) {
|
|
13762
14451
|
return [];
|
|
13763
14452
|
}
|
|
13764
|
-
let candidate =
|
|
14453
|
+
let candidate = path23.resolve(filePath);
|
|
13765
14454
|
let configPath2 = "";
|
|
13766
14455
|
for (let i = 0; i < 12; i++) {
|
|
13767
|
-
const probe =
|
|
14456
|
+
const probe = path23.join(candidate, ".zcode", "v2", "config.json");
|
|
13768
14457
|
try {
|
|
13769
|
-
await
|
|
14458
|
+
await stat16(probe);
|
|
13770
14459
|
configPath2 = probe;
|
|
13771
14460
|
break;
|
|
13772
14461
|
} catch {
|
|
13773
|
-
const parent =
|
|
14462
|
+
const parent = path23.dirname(candidate);
|
|
13774
14463
|
if (parent === candidate) break;
|
|
13775
14464
|
candidate = parent;
|
|
13776
14465
|
}
|
|
@@ -13794,8 +14483,8 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13794
14483
|
if (!id || !ts) {
|
|
13795
14484
|
return;
|
|
13796
14485
|
}
|
|
13797
|
-
const ctx =
|
|
13798
|
-
const event =
|
|
14486
|
+
const ctx = sessionContext2(row, sessions);
|
|
14487
|
+
const event = makeEvent3({
|
|
13799
14488
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13800
14489
|
ts,
|
|
13801
14490
|
type: "session.started",
|
|
@@ -13807,7 +14496,7 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13807
14496
|
parentAgentInstanceId: ctx.parentSessionId,
|
|
13808
14497
|
agent: "zcode",
|
|
13809
14498
|
confidence: "exact",
|
|
13810
|
-
refs:
|
|
14499
|
+
refs: refs2({
|
|
13811
14500
|
sourceId: `${id}:session`,
|
|
13812
14501
|
zcodeTaskType: stringField(row, "task_type"),
|
|
13813
14502
|
zcodeTitleHash: stringField(row, "title") ? `sha256:${createStableHash(stringField(row, "title"))}` : void 0
|
|
@@ -13819,7 +14508,7 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13819
14508
|
const linesAdded = numberField(row, "summary_additions");
|
|
13820
14509
|
const linesRemoved = numberField(row, "summary_deletions");
|
|
13821
14510
|
const filesChanged = numberField(row, "summary_files");
|
|
13822
|
-
const completed =
|
|
14511
|
+
const completed = makeEvent3({
|
|
13823
14512
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13824
14513
|
ts: completedTs,
|
|
13825
14514
|
type: "session.ended",
|
|
@@ -13844,12 +14533,12 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13844
14533
|
if (!rawTurnId || !ts) {
|
|
13845
14534
|
return;
|
|
13846
14535
|
}
|
|
13847
|
-
const ctx =
|
|
14536
|
+
const ctx = sessionContext2(row, sessions);
|
|
13848
14537
|
if (ctx.isSubagent) {
|
|
13849
14538
|
return;
|
|
13850
14539
|
}
|
|
13851
14540
|
const turnId = `zcode:${rawTurnId}`;
|
|
13852
|
-
const started =
|
|
14541
|
+
const started = makeEvent3({
|
|
13853
14542
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13854
14543
|
ts,
|
|
13855
14544
|
type: "turn.started",
|
|
@@ -13867,7 +14556,7 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13867
14556
|
const completedTs = isoFromMs(numberField(row, "completed_at"));
|
|
13868
14557
|
if (completedTs) {
|
|
13869
14558
|
const status = stringField(row, "status");
|
|
13870
|
-
const completed =
|
|
14559
|
+
const completed = makeEvent3({
|
|
13871
14560
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13872
14561
|
ts: completedTs,
|
|
13873
14562
|
type: "turn.completed",
|
|
@@ -13886,7 +14575,7 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13886
14575
|
toolCalls: numberField(row, "tool_call_count")
|
|
13887
14576
|
},
|
|
13888
14577
|
confidence: "exact",
|
|
13889
|
-
refs:
|
|
14578
|
+
refs: refs2({ sourceId: `${rawTurnId}:completed`, zcodeStatus: status })
|
|
13890
14579
|
}, row, rowNumber, filePath, options);
|
|
13891
14580
|
if (completed) events.push(completed);
|
|
13892
14581
|
}
|
|
@@ -13897,9 +14586,9 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13897
14586
|
if (!ts) {
|
|
13898
14587
|
return;
|
|
13899
14588
|
}
|
|
13900
|
-
const ctx =
|
|
14589
|
+
const ctx = sessionContext2(row, sessions);
|
|
13901
14590
|
const modelId = stringField(row, "model_id");
|
|
13902
|
-
const usage =
|
|
14591
|
+
const usage = makeEvent3({
|
|
13903
14592
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13904
14593
|
ts,
|
|
13905
14594
|
type: "model.usage",
|
|
@@ -13916,7 +14605,7 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13916
14605
|
success: stringField(row, "status") === "completed",
|
|
13917
14606
|
metrics: modelMetrics(row),
|
|
13918
14607
|
confidence: "exact",
|
|
13919
|
-
refs:
|
|
14608
|
+
refs: refs2({
|
|
13920
14609
|
sourceId: stringField(row, "id") || `${ctx.rawSessionId}:model:${rowNumber}`,
|
|
13921
14610
|
zcodeQuerySource: stringField(row, "query_source"),
|
|
13922
14611
|
zcodeMode: stringField(row, "mode"),
|
|
@@ -13937,10 +14626,10 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13937
14626
|
if (!startedTs) {
|
|
13938
14627
|
return;
|
|
13939
14628
|
}
|
|
13940
|
-
const ctx =
|
|
14629
|
+
const ctx = sessionContext2(row, sessions);
|
|
13941
14630
|
const turnId = !ctx.isSubagent && stringField(row, "turn_id") ? `zcode:${stringField(row, "turn_id")}` : void 0;
|
|
13942
14631
|
const spanId = `${ctx.sessionId}:tool:${toolCallId}`;
|
|
13943
|
-
const started =
|
|
14632
|
+
const started = makeEvent3({
|
|
13944
14633
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13945
14634
|
ts: startedTs,
|
|
13946
14635
|
type: "tool.started",
|
|
@@ -13954,7 +14643,7 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13954
14643
|
agent: "zcode",
|
|
13955
14644
|
tool,
|
|
13956
14645
|
confidence: "exact",
|
|
13957
|
-
refs:
|
|
14646
|
+
refs: refs2({
|
|
13958
14647
|
sourceId: `${toolCallId}:start`,
|
|
13959
14648
|
zcodeSideEffectScope: stringField(row, "side_effect_scope"),
|
|
13960
14649
|
zcodeApprovalStatus: stringField(row, "approval_status")
|
|
@@ -13963,7 +14652,7 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13963
14652
|
if (started) events.push(started);
|
|
13964
14653
|
if (completedTs) {
|
|
13965
14654
|
const status = stringField(row, "status");
|
|
13966
|
-
const completed =
|
|
14655
|
+
const completed = makeEvent3({
|
|
13967
14656
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13968
14657
|
ts: completedTs,
|
|
13969
14658
|
type: status === "completed" ? "tool.completed" : "tool.failed",
|
|
@@ -13983,7 +14672,7 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13983
14672
|
bytesRead: numberField(row, "output_bytes")
|
|
13984
14673
|
},
|
|
13985
14674
|
confidence: "exact",
|
|
13986
|
-
refs:
|
|
14675
|
+
refs: refs2({
|
|
13987
14676
|
sourceId: `${toolCallId}:completed`,
|
|
13988
14677
|
zcodeStatus: status,
|
|
13989
14678
|
zcodeExitCode: numberField(row, "exit_code"),
|
|
@@ -13998,13 +14687,13 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13998
14687
|
}
|
|
13999
14688
|
async function zcodeBackfillFiles(sourceRoot, home, env) {
|
|
14000
14689
|
const candidate = sourceRoot || zcodeDbPath(home, env);
|
|
14001
|
-
const filePath = candidate.endsWith(".sqlite") ? candidate :
|
|
14690
|
+
const filePath = candidate.endsWith(".sqlite") ? candidate : path23.join(candidate, "db", "db.sqlite");
|
|
14002
14691
|
try {
|
|
14003
|
-
const info = await
|
|
14692
|
+
const info = await stat16(filePath);
|
|
14004
14693
|
let modifiedMs = info.mtimeMs;
|
|
14005
14694
|
for (const suffix of ["-wal", "-shm"]) {
|
|
14006
14695
|
try {
|
|
14007
|
-
const sidecar = await
|
|
14696
|
+
const sidecar = await stat16(`${filePath}${suffix}`);
|
|
14008
14697
|
modifiedMs = Math.max(modifiedMs, sidecar.mtimeMs);
|
|
14009
14698
|
} catch {
|
|
14010
14699
|
}
|
|
@@ -14048,49 +14737,49 @@ function createZCodeAdapter() {
|
|
|
14048
14737
|
|
|
14049
14738
|
// src/adapters/zed.ts
|
|
14050
14739
|
import os13 from "node:os";
|
|
14051
|
-
import
|
|
14740
|
+
import path24 from "node:path";
|
|
14052
14741
|
function zedThreadsCandidates(home, env) {
|
|
14053
14742
|
const candidates = [];
|
|
14054
14743
|
const platform2 = process.platform;
|
|
14055
14744
|
if (platform2 === "darwin") {
|
|
14056
|
-
candidates.push(
|
|
14745
|
+
candidates.push(path24.join(home, "Library", "Application Support", "Zed", "threads", "threads.db"));
|
|
14057
14746
|
} else if (platform2 === "win32") {
|
|
14058
14747
|
const appdata = env?.APPDATA;
|
|
14059
14748
|
if (appdata && appdata.trim()) {
|
|
14060
|
-
candidates.push(
|
|
14749
|
+
candidates.push(path24.join(path24.resolve(appdata), "Zed", "threads", "threads.db"));
|
|
14061
14750
|
}
|
|
14062
|
-
candidates.push(
|
|
14751
|
+
candidates.push(path24.join(home, "AppData", "Roaming", "Zed", "threads", "threads.db"));
|
|
14063
14752
|
} else {
|
|
14064
14753
|
const xdgData = env?.XDG_DATA_HOME;
|
|
14065
14754
|
if (xdgData && xdgData.trim()) {
|
|
14066
|
-
candidates.push(
|
|
14755
|
+
candidates.push(path24.join(path24.resolve(xdgData), "zed", "threads", "threads.db"));
|
|
14067
14756
|
}
|
|
14068
|
-
candidates.push(
|
|
14757
|
+
candidates.push(path24.join(home, ".local", "share", "zed", "threads", "threads.db"));
|
|
14069
14758
|
const xdgConfig = env?.XDG_CONFIG_HOME;
|
|
14070
14759
|
if (xdgConfig && xdgConfig.trim()) {
|
|
14071
|
-
candidates.push(
|
|
14760
|
+
candidates.push(path24.join(path24.resolve(xdgConfig), "zed", "threads", "threads.db"));
|
|
14072
14761
|
}
|
|
14073
|
-
candidates.push(
|
|
14762
|
+
candidates.push(path24.join(home, ".config", "zed", "threads", "threads.db"));
|
|
14074
14763
|
}
|
|
14075
14764
|
return candidates;
|
|
14076
14765
|
}
|
|
14077
14766
|
function zedConfigDir(home, env) {
|
|
14078
14767
|
const platform2 = process.platform;
|
|
14079
14768
|
if (platform2 === "darwin") {
|
|
14080
|
-
return
|
|
14769
|
+
return path24.join(home, "Library", "Application Support", "Zed");
|
|
14081
14770
|
}
|
|
14082
14771
|
if (platform2 === "win32") {
|
|
14083
14772
|
const appdata = env?.APPDATA;
|
|
14084
14773
|
if (appdata && appdata.trim()) {
|
|
14085
|
-
return
|
|
14774
|
+
return path24.join(path24.resolve(appdata), "Zed");
|
|
14086
14775
|
}
|
|
14087
|
-
return
|
|
14776
|
+
return path24.join(home, "AppData", "Roaming", "Zed");
|
|
14088
14777
|
}
|
|
14089
14778
|
const xdgConfig = env?.XDG_CONFIG_HOME;
|
|
14090
14779
|
if (xdgConfig && xdgConfig.trim()) {
|
|
14091
|
-
return
|
|
14780
|
+
return path24.join(path24.resolve(xdgConfig), "zed");
|
|
14092
14781
|
}
|
|
14093
|
-
return
|
|
14782
|
+
return path24.join(home, ".config", "zed");
|
|
14094
14783
|
}
|
|
14095
14784
|
function baseZedEvent(event) {
|
|
14096
14785
|
return {
|
|
@@ -14154,7 +14843,7 @@ async function parseZedSessionFile(dbPath, options) {
|
|
|
14154
14843
|
const folderRaw = row.folder_paths || "";
|
|
14155
14844
|
const folder = folderRaw.split(/[\n,]/).map((s) => s.trim()).find(Boolean);
|
|
14156
14845
|
const cwd = folder || void 0;
|
|
14157
|
-
const project = cwd ?
|
|
14846
|
+
const project = cwd ? path24.basename(cwd) : row.summary ? row.summary.slice(0, 40) : void 0;
|
|
14158
14847
|
let json;
|
|
14159
14848
|
try {
|
|
14160
14849
|
const bytes = row.data_type === "zstd" ? decompress2(new Uint8Array(row.data)) : new Uint8Array(row.data);
|
|
@@ -14400,19 +15089,19 @@ async function parseZedSessionFile(dbPath, options) {
|
|
|
14400
15089
|
return events.filter((event) => matchesBackfillFilters(event, options));
|
|
14401
15090
|
}
|
|
14402
15091
|
async function zedBackfillFiles(sourceRoot, home = os13.homedir(), env) {
|
|
14403
|
-
const { stat:
|
|
15092
|
+
const { stat: stat19 } = await import("node:fs/promises");
|
|
14404
15093
|
if (sourceRoot) {
|
|
14405
15094
|
if (!sourceRoot.endsWith(".db")) {
|
|
14406
15095
|
return [];
|
|
14407
15096
|
}
|
|
14408
|
-
const info = await
|
|
15097
|
+
const info = await stat19(sourceRoot).catch(() => null);
|
|
14409
15098
|
if (!info) {
|
|
14410
15099
|
return [];
|
|
14411
15100
|
}
|
|
14412
15101
|
return [{ path: sourceRoot, modifiedAt: info.mtime.toISOString() }];
|
|
14413
15102
|
}
|
|
14414
15103
|
for (const candidatePath of zedThreadsCandidates(home, env)) {
|
|
14415
|
-
const info = await
|
|
15104
|
+
const info = await stat19(candidatePath).catch(() => null);
|
|
14416
15105
|
if (info) {
|
|
14417
15106
|
return [{ path: candidatePath, modifiedAt: info.mtime.toISOString() }];
|
|
14418
15107
|
}
|
|
@@ -14429,7 +15118,7 @@ function createZedAdapter() {
|
|
|
14429
15118
|
return zedConfigDir(home, env);
|
|
14430
15119
|
},
|
|
14431
15120
|
installedPath(home, env) {
|
|
14432
|
-
return
|
|
15121
|
+
return path24.join(zedConfigDir(home, env), "vibetime-marker");
|
|
14433
15122
|
},
|
|
14434
15123
|
async isInstalled() {
|
|
14435
15124
|
return false;
|
|
@@ -15244,19 +15933,19 @@ async function uninstallGeneratedFile(filePath, { dryRun, onWrite }) {
|
|
|
15244
15933
|
import { randomUUID } from "node:crypto";
|
|
15245
15934
|
import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, rmSync, writeFileSync } from "node:fs";
|
|
15246
15935
|
import { homedir, hostname } from "node:os";
|
|
15247
|
-
import
|
|
15936
|
+
import path25 from "node:path";
|
|
15248
15937
|
function disabledBackfillSourceSet(config) {
|
|
15249
15938
|
const list = Array.isArray(config.disabledSources) ? config.disabledSources : [];
|
|
15250
15939
|
return new Set(list.map((id) => String(id).trim()).filter(Boolean));
|
|
15251
15940
|
}
|
|
15252
15941
|
function configDir(home = homedir()) {
|
|
15253
|
-
return
|
|
15942
|
+
return path25.join(home, ".vibetime");
|
|
15254
15943
|
}
|
|
15255
15944
|
function configPath(home = homedir()) {
|
|
15256
|
-
return
|
|
15945
|
+
return path25.join(configDir(home), "config.json");
|
|
15257
15946
|
}
|
|
15258
15947
|
function machineIdPath(home = homedir()) {
|
|
15259
|
-
return
|
|
15948
|
+
return path25.join(configDir(home), "machine-id");
|
|
15260
15949
|
}
|
|
15261
15950
|
function readConfig(home = homedir()) {
|
|
15262
15951
|
const file = configPath(home);
|
|
@@ -15303,15 +15992,15 @@ function defaultMachineName() {
|
|
|
15303
15992
|
init_fs();
|
|
15304
15993
|
|
|
15305
15994
|
// src/lib/logger.ts
|
|
15306
|
-
import { appendFile, mkdir as mkdir5, rename as rename2, stat as
|
|
15995
|
+
import { appendFile, mkdir as mkdir5, rename as rename2, stat as stat17 } from "node:fs/promises";
|
|
15307
15996
|
import { homedir as homedir2 } from "node:os";
|
|
15308
|
-
import
|
|
15997
|
+
import path26 from "node:path";
|
|
15309
15998
|
var MAX_BYTES = 1 * 1024 * 1024;
|
|
15310
15999
|
function logDir(home = homedir2()) {
|
|
15311
|
-
return
|
|
16000
|
+
return path26.join(home, ".vibetime", "logs");
|
|
15312
16001
|
}
|
|
15313
16002
|
function logPath(home = homedir2(), name = "cli.log") {
|
|
15314
|
-
return
|
|
16003
|
+
return path26.join(logDir(home), name);
|
|
15315
16004
|
}
|
|
15316
16005
|
function serializeError(error) {
|
|
15317
16006
|
if (error instanceof Error) {
|
|
@@ -15321,7 +16010,7 @@ function serializeError(error) {
|
|
|
15321
16010
|
}
|
|
15322
16011
|
async function rotateIfNeeded(file) {
|
|
15323
16012
|
try {
|
|
15324
|
-
const info = await
|
|
16013
|
+
const info = await stat17(file);
|
|
15325
16014
|
if (info.size > MAX_BYTES) {
|
|
15326
16015
|
await rename2(file, `${file}.1`).catch(() => {
|
|
15327
16016
|
});
|
|
@@ -15486,8 +16175,8 @@ function buildHeaders(token, machine) {
|
|
|
15486
16175
|
...machine?.platform ? { "x-machine-platform": machine.platform } : {}
|
|
15487
16176
|
};
|
|
15488
16177
|
}
|
|
15489
|
-
function joinUrl(base,
|
|
15490
|
-
return new URL(
|
|
16178
|
+
function joinUrl(base, path28) {
|
|
16179
|
+
return new URL(path28, base.endsWith("/") ? base : `${base}/`).toString();
|
|
15491
16180
|
}
|
|
15492
16181
|
async function postRollupBatch(remote, rollups, options = {}) {
|
|
15493
16182
|
const response = await remote.fetchImpl(joinUrl(remote.baseUrl, "/v3/agent/ingest"), {
|
|
@@ -15579,6 +16268,7 @@ function createRegistry() {
|
|
|
15579
16268
|
registry.register(createKimiCodeAdapter());
|
|
15580
16269
|
registry.register(createCursorAdapter());
|
|
15581
16270
|
registry.register(createGrokBotAdapter());
|
|
16271
|
+
registry.register(createHermesAdapter());
|
|
15582
16272
|
return registry;
|
|
15583
16273
|
}
|
|
15584
16274
|
var defaultContext = {
|
|
@@ -16143,6 +16833,9 @@ async function listBackfillSourceFiles(source, options, ctx) {
|
|
|
16143
16833
|
if (source.id === "grok-bot") {
|
|
16144
16834
|
return grokBotBackfillFiles(stringOption(options["source-root"]), resolveHome3(options, ctx), ctx.env, options);
|
|
16145
16835
|
}
|
|
16836
|
+
if (source.id === "hermes") {
|
|
16837
|
+
return hermesBackfillFiles(stringOption(options["source-root"]), resolveHome3(options, ctx), ctx.env);
|
|
16838
|
+
}
|
|
16146
16839
|
if (source.id === "pi") {
|
|
16147
16840
|
return piBackfillFiles(stringOption(options["source-root"]), resolveHome3(options, ctx), ctx.env);
|
|
16148
16841
|
}
|
|
@@ -16150,7 +16843,7 @@ async function listBackfillSourceFiles(source, options, ctx) {
|
|
|
16150
16843
|
const fileLists = await Promise.all(roots.map((r) => listJsonlFiles(r)));
|
|
16151
16844
|
const files = fileLists.flat().sort().slice(0, numberOption(options.limit) || void 0);
|
|
16152
16845
|
return Promise.all(files.map(async (filePath) => {
|
|
16153
|
-
const info = await
|
|
16846
|
+
const info = await stat18(filePath);
|
|
16154
16847
|
return { path: filePath, modifiedAt: info.mtime.toISOString() };
|
|
16155
16848
|
}));
|
|
16156
16849
|
}
|
|
@@ -16482,13 +17175,13 @@ function selectBackfillFilesForImport(files, watermarkTs) {
|
|
|
16482
17175
|
return picked;
|
|
16483
17176
|
}
|
|
16484
17177
|
function backfillIncrementalStatePath(home) {
|
|
16485
|
-
return
|
|
17178
|
+
return path27.join(home, ".vibetime", "backfill-state.json");
|
|
16486
17179
|
}
|
|
16487
17180
|
function syncLocalTriggerStatePath(home) {
|
|
16488
|
-
return
|
|
17181
|
+
return path27.join(home, ".vibetime", "sync-local-trigger.json");
|
|
16489
17182
|
}
|
|
16490
17183
|
function syncLocalTriggerLockPath(home) {
|
|
16491
|
-
return
|
|
17184
|
+
return path27.join(home, ".vibetime", "sync-local-trigger.lock");
|
|
16492
17185
|
}
|
|
16493
17186
|
function backfillRemoteKey(baseUrl) {
|
|
16494
17187
|
try {
|
|
@@ -16550,7 +17243,7 @@ async function readBackfillIncrementalStateFile(home, ctx) {
|
|
|
16550
17243
|
}
|
|
16551
17244
|
async function writeBackfillIncrementalStateFile(home, file) {
|
|
16552
17245
|
const statePath = backfillIncrementalStatePath(home);
|
|
16553
|
-
await mkdir6(
|
|
17246
|
+
await mkdir6(path27.dirname(statePath), { recursive: true });
|
|
16554
17247
|
await writeFile5(statePath, `${JSON.stringify(file, null, 2)}
|
|
16555
17248
|
`, "utf8");
|
|
16556
17249
|
}
|
|
@@ -16599,7 +17292,7 @@ async function readSyncLocalTriggerState(statePath) {
|
|
|
16599
17292
|
return nextState;
|
|
16600
17293
|
}
|
|
16601
17294
|
async function writeSyncLocalTriggerState(statePath, state) {
|
|
16602
|
-
await mkdir6(
|
|
17295
|
+
await mkdir6(path27.dirname(statePath), { recursive: true });
|
|
16603
17296
|
await writeFile5(statePath, `${JSON.stringify(state, null, 2)}
|
|
16604
17297
|
`, "utf8");
|
|
16605
17298
|
}
|
|
@@ -16614,12 +17307,12 @@ async function readSyncLocalLock(lockPath) {
|
|
|
16614
17307
|
return { pid: lock.pid, startedAt: lock.startedAt };
|
|
16615
17308
|
}
|
|
16616
17309
|
async function writeSyncLocalLock(lockPath, lock) {
|
|
16617
|
-
await mkdir6(
|
|
17310
|
+
await mkdir6(path27.dirname(lockPath), { recursive: true });
|
|
16618
17311
|
await writeFile5(lockPath, `${JSON.stringify(lock, null, 2)}
|
|
16619
17312
|
`, "utf8");
|
|
16620
17313
|
}
|
|
16621
17314
|
async function acquireSyncLocalLock(lockPath, lock) {
|
|
16622
|
-
await mkdir6(
|
|
17315
|
+
await mkdir6(path27.dirname(lockPath), { recursive: true });
|
|
16623
17316
|
try {
|
|
16624
17317
|
const handle = await open(lockPath, "wx");
|
|
16625
17318
|
try {
|
|
@@ -16699,10 +17392,10 @@ function syncLocalRunnerEntryArgs(cliPath) {
|
|
|
16699
17392
|
if (cliPath.endsWith(".ts")) {
|
|
16700
17393
|
return ["--import", "tsx", cliPath];
|
|
16701
17394
|
}
|
|
16702
|
-
return [
|
|
17395
|
+
return [path27.resolve(path27.dirname(cliPath), "../bin/vibetime.mjs")];
|
|
16703
17396
|
}
|
|
16704
17397
|
function resolveHome3(options, ctx) {
|
|
16705
|
-
return
|
|
17398
|
+
return path27.resolve(stringOption(options.home) || ctx.env.HOME || os14.homedir());
|
|
16706
17399
|
}
|
|
16707
17400
|
function requestedTargets(options) {
|
|
16708
17401
|
const value = options.target || options.targets;
|