@yhong91/vibetime 0.1.69 → 0.1.71
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 +995 -293
- 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.71" : "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,695 @@ 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
|
+
return timestampFrom(typeof value === "number" ? value : Number(value));
|
|
9084
|
+
}
|
|
9085
|
+
function tableColumns(db, table) {
|
|
9086
|
+
try {
|
|
9087
|
+
const rows = db.prepare(`PRAGMA table_info(${table})`).all();
|
|
9088
|
+
return new Set(rows.map((row) => row.name).filter((name) => Boolean(name)));
|
|
9089
|
+
} catch {
|
|
9090
|
+
return /* @__PURE__ */ new Set();
|
|
9091
|
+
}
|
|
9092
|
+
}
|
|
9093
|
+
function selectExisting(columns, wanted) {
|
|
9094
|
+
return wanted.filter((name) => columns.has(name));
|
|
9095
|
+
}
|
|
9096
|
+
function asRecord(value) {
|
|
9097
|
+
return isPlainObject(value) ? value : {};
|
|
9098
|
+
}
|
|
9099
|
+
function sessionContext(row) {
|
|
9100
|
+
const rawId = stringField(row, "id") || "unknown";
|
|
9101
|
+
const cwd = stringField(row, "cwd");
|
|
9102
|
+
const repoRoot = stringField(row, "git_repo_root");
|
|
9103
|
+
const project = projectFromCwd(cwd, repoRoot);
|
|
9104
|
+
return {
|
|
9105
|
+
rawId,
|
|
9106
|
+
sessionId: `${SOURCE}:${rawId}`,
|
|
9107
|
+
cwd,
|
|
9108
|
+
project,
|
|
9109
|
+
workspaceId: createWorkspaceId({ projectName: project, repoRoot: repoRoot || cwd }),
|
|
9110
|
+
platform: stringField(row, "source"),
|
|
9111
|
+
profileName: stringField(row, "profile_name"),
|
|
9112
|
+
parentSessionId: stringField(row, "parent_session_id"),
|
|
9113
|
+
model: stringField(row, "model"),
|
|
9114
|
+
provider: stringField(row, "billing_provider")
|
|
9115
|
+
};
|
|
9116
|
+
}
|
|
9117
|
+
function makeEvent(event, lineNumber, filePath, options) {
|
|
9118
|
+
const withRefs = withBackfillRefs(event, {
|
|
9119
|
+
filePath,
|
|
9120
|
+
sourcePathHash: sourceHash(filePath),
|
|
9121
|
+
lineNumber,
|
|
9122
|
+
topType: event.type,
|
|
9123
|
+
payloadType: event.refs?.payloadType || event.tool || event.type,
|
|
9124
|
+
options
|
|
9125
|
+
});
|
|
9126
|
+
return validateCanonicalEvent(withRefs).valid ? withRefs : void 0;
|
|
9127
|
+
}
|
|
9128
|
+
function usageMetrics2(row) {
|
|
9129
|
+
const input = numberField(row, "input_tokens") || 0;
|
|
9130
|
+
const output = numberField(row, "output_tokens") || 0;
|
|
9131
|
+
const cacheRead = numberField(row, "cache_read_tokens") || 0;
|
|
9132
|
+
const cacheWrite = numberField(row, "cache_write_tokens") || 0;
|
|
9133
|
+
const reasoning = numberField(row, "reasoning_tokens") || 0;
|
|
9134
|
+
const actualCost = numberField(row, "actual_cost_usd");
|
|
9135
|
+
const estimatedCost = numberField(row, "estimated_cost_usd");
|
|
9136
|
+
const costUsd = actualCost && actualCost > 0 ? actualCost : estimatedCost;
|
|
9137
|
+
return {
|
|
9138
|
+
tokensInput: input || void 0,
|
|
9139
|
+
tokensOutput: output || void 0,
|
|
9140
|
+
tokensCacheReadInput: cacheRead || void 0,
|
|
9141
|
+
tokensCacheCreationInput: cacheWrite || void 0,
|
|
9142
|
+
tokensCachedInput: cacheRead + cacheWrite || void 0,
|
|
9143
|
+
tokensReasoningOutput: reasoning || void 0,
|
|
9144
|
+
tokensTotal: input + output + cacheRead + cacheWrite,
|
|
9145
|
+
modelCalls: numberField(row, "api_call_count") || void 0,
|
|
9146
|
+
costUsd: costUsd && costUsd > 0 ? costUsd : void 0
|
|
9147
|
+
};
|
|
9148
|
+
}
|
|
9149
|
+
function sessionHasWork(row, usageRows) {
|
|
9150
|
+
if (usageRows.some((item) => (numberField(item, "input_tokens") || 0) + (numberField(item, "output_tokens") || 0) > 0)) {
|
|
9151
|
+
return true;
|
|
9152
|
+
}
|
|
9153
|
+
if ((numberField(row, "input_tokens") || 0) + (numberField(row, "output_tokens") || 0) > 0) {
|
|
9154
|
+
return true;
|
|
9155
|
+
}
|
|
9156
|
+
if ((numberField(row, "message_count") || 0) > 0) {
|
|
9157
|
+
return true;
|
|
9158
|
+
}
|
|
9159
|
+
if ((numberField(row, "tool_call_count") || 0) > 0) {
|
|
9160
|
+
return true;
|
|
9161
|
+
}
|
|
9162
|
+
return false;
|
|
9163
|
+
}
|
|
9164
|
+
function parseToolCalls(raw) {
|
|
9165
|
+
let parsed = raw;
|
|
9166
|
+
if (typeof raw === "string" && raw.trim()) {
|
|
9167
|
+
try {
|
|
9168
|
+
parsed = JSON.parse(raw);
|
|
9169
|
+
} catch {
|
|
9170
|
+
return [];
|
|
9171
|
+
}
|
|
9172
|
+
}
|
|
9173
|
+
if (!Array.isArray(parsed)) {
|
|
9174
|
+
return [];
|
|
9175
|
+
}
|
|
9176
|
+
const out = [];
|
|
9177
|
+
for (const item of parsed) {
|
|
9178
|
+
if (!isPlainObject(item)) {
|
|
9179
|
+
continue;
|
|
9180
|
+
}
|
|
9181
|
+
const fn = isPlainObject(item.function) ? item.function : item;
|
|
9182
|
+
const name = stringField(fn, "name") || stringField(item, "name");
|
|
9183
|
+
if (!name) {
|
|
9184
|
+
continue;
|
|
9185
|
+
}
|
|
9186
|
+
let input = {};
|
|
9187
|
+
const args = fn.arguments ?? item.arguments;
|
|
9188
|
+
if (typeof args === "string" && args.trim()) {
|
|
9189
|
+
try {
|
|
9190
|
+
const parsedArgs = JSON.parse(args);
|
|
9191
|
+
if (isPlainObject(parsedArgs)) {
|
|
9192
|
+
input = parsedArgs;
|
|
9193
|
+
}
|
|
9194
|
+
} catch {
|
|
9195
|
+
input = {};
|
|
9196
|
+
}
|
|
9197
|
+
} else if (isPlainObject(args)) {
|
|
9198
|
+
input = args;
|
|
9199
|
+
}
|
|
9200
|
+
out.push({
|
|
9201
|
+
id: stringField(item, "id") || stringField(item, "call_id") || stringField(fn, "id"),
|
|
9202
|
+
name,
|
|
9203
|
+
input
|
|
9204
|
+
});
|
|
9205
|
+
}
|
|
9206
|
+
return out;
|
|
9207
|
+
}
|
|
9208
|
+
function hermesToolAlias(tool) {
|
|
9209
|
+
const normalized = tool.toLowerCase();
|
|
9210
|
+
if (normalized === "write_file") {
|
|
9211
|
+
return "write";
|
|
9212
|
+
}
|
|
9213
|
+
if (normalized === "patch") {
|
|
9214
|
+
return "edit";
|
|
9215
|
+
}
|
|
9216
|
+
if (normalized === "read_file") {
|
|
9217
|
+
return "read";
|
|
9218
|
+
}
|
|
9219
|
+
return tool;
|
|
9220
|
+
}
|
|
9221
|
+
async function sqliteMtime(filePath) {
|
|
9222
|
+
try {
|
|
9223
|
+
const info = await stat11(filePath);
|
|
9224
|
+
let modifiedMs = info.mtimeMs;
|
|
9225
|
+
for (const suffix of ["-wal", "-shm"]) {
|
|
9226
|
+
try {
|
|
9227
|
+
const sidecar = await stat11(`${filePath}${suffix}`);
|
|
9228
|
+
modifiedMs = Math.max(modifiedMs, sidecar.mtimeMs);
|
|
9229
|
+
} catch {
|
|
9230
|
+
}
|
|
9231
|
+
}
|
|
9232
|
+
return new Date(modifiedMs).toISOString();
|
|
9233
|
+
} catch {
|
|
9234
|
+
return void 0;
|
|
9235
|
+
}
|
|
9236
|
+
}
|
|
9237
|
+
async function parseHermesDb(filePath, options) {
|
|
9238
|
+
if (!filePath.endsWith(".db")) {
|
|
9239
|
+
return [];
|
|
9240
|
+
}
|
|
9241
|
+
const { DatabaseSync } = await import("node:sqlite");
|
|
9242
|
+
let db;
|
|
9243
|
+
try {
|
|
9244
|
+
db = new DatabaseSync(filePath, { readOnly: true });
|
|
9245
|
+
} catch {
|
|
9246
|
+
return [];
|
|
9247
|
+
}
|
|
9248
|
+
try {
|
|
9249
|
+
const sessionCols = tableColumns(db, "sessions");
|
|
9250
|
+
if (!sessionCols.has("id") || !sessionCols.has("started_at")) {
|
|
9251
|
+
return [];
|
|
9252
|
+
}
|
|
9253
|
+
const sessionSelect = selectExisting(sessionCols, [
|
|
9254
|
+
"id",
|
|
9255
|
+
"source",
|
|
9256
|
+
"model",
|
|
9257
|
+
"parent_session_id",
|
|
9258
|
+
"started_at",
|
|
9259
|
+
"ended_at",
|
|
9260
|
+
"message_count",
|
|
9261
|
+
"tool_call_count",
|
|
9262
|
+
"input_tokens",
|
|
9263
|
+
"output_tokens",
|
|
9264
|
+
"cache_read_tokens",
|
|
9265
|
+
"cache_write_tokens",
|
|
9266
|
+
"reasoning_tokens",
|
|
9267
|
+
"cwd",
|
|
9268
|
+
"git_repo_root",
|
|
9269
|
+
"billing_provider",
|
|
9270
|
+
"estimated_cost_usd",
|
|
9271
|
+
"actual_cost_usd",
|
|
9272
|
+
"title",
|
|
9273
|
+
"last_activity_at",
|
|
9274
|
+
"profile_name"
|
|
9275
|
+
]);
|
|
9276
|
+
const sessions = db.prepare(
|
|
9277
|
+
`SELECT ${sessionSelect.join(", ")} FROM sessions WHERE started_at IS NOT NULL ORDER BY started_at, id`
|
|
9278
|
+
).all().map(asRecord);
|
|
9279
|
+
const usageCols = tableColumns(db, "session_model_usage");
|
|
9280
|
+
const usageBySession = /* @__PURE__ */ new Map();
|
|
9281
|
+
if (usageCols.has("session_id")) {
|
|
9282
|
+
const usageSelect = selectExisting(usageCols, [
|
|
9283
|
+
"session_id",
|
|
9284
|
+
"model",
|
|
9285
|
+
"billing_provider",
|
|
9286
|
+
"billing_base_url",
|
|
9287
|
+
"billing_mode",
|
|
9288
|
+
"task",
|
|
9289
|
+
"api_call_count",
|
|
9290
|
+
"input_tokens",
|
|
9291
|
+
"output_tokens",
|
|
9292
|
+
"cache_read_tokens",
|
|
9293
|
+
"cache_write_tokens",
|
|
9294
|
+
"reasoning_tokens",
|
|
9295
|
+
"estimated_cost_usd",
|
|
9296
|
+
"actual_cost_usd",
|
|
9297
|
+
"first_seen",
|
|
9298
|
+
"last_seen"
|
|
9299
|
+
]);
|
|
9300
|
+
const usageRows = db.prepare(
|
|
9301
|
+
`SELECT ${usageSelect.join(", ")} FROM session_model_usage`
|
|
9302
|
+
).all().map(asRecord);
|
|
9303
|
+
for (const row of usageRows) {
|
|
9304
|
+
const sessionId = stringField(row, "session_id");
|
|
9305
|
+
if (!sessionId) {
|
|
9306
|
+
continue;
|
|
9307
|
+
}
|
|
9308
|
+
const list = usageBySession.get(sessionId) || [];
|
|
9309
|
+
list.push(row);
|
|
9310
|
+
usageBySession.set(sessionId, list);
|
|
9311
|
+
}
|
|
9312
|
+
}
|
|
9313
|
+
const messageCols = tableColumns(db, "messages");
|
|
9314
|
+
const messagesBySession = /* @__PURE__ */ new Map();
|
|
9315
|
+
if (messageCols.has("session_id") && messageCols.has("role")) {
|
|
9316
|
+
const messageSelect = selectExisting(messageCols, [
|
|
9317
|
+
"id",
|
|
9318
|
+
"session_id",
|
|
9319
|
+
"role",
|
|
9320
|
+
"content",
|
|
9321
|
+
"tool_calls",
|
|
9322
|
+
"timestamp",
|
|
9323
|
+
"token_count",
|
|
9324
|
+
"active"
|
|
9325
|
+
]);
|
|
9326
|
+
const activeFilter = messageCols.has("active") ? " WHERE coalesce(active, 1) = 1" : "";
|
|
9327
|
+
const messageRows = db.prepare(
|
|
9328
|
+
`SELECT ${messageSelect.join(", ")} FROM messages${activeFilter} ORDER BY timestamp, id`
|
|
9329
|
+
).all().map(asRecord);
|
|
9330
|
+
for (const row of messageRows) {
|
|
9331
|
+
const sessionId = stringField(row, "session_id");
|
|
9332
|
+
if (!sessionId) {
|
|
9333
|
+
continue;
|
|
9334
|
+
}
|
|
9335
|
+
const list = messagesBySession.get(sessionId) || [];
|
|
9336
|
+
list.push(row);
|
|
9337
|
+
messagesBySession.set(sessionId, list);
|
|
9338
|
+
}
|
|
9339
|
+
}
|
|
9340
|
+
const events = [];
|
|
9341
|
+
let lineNumber = 0;
|
|
9342
|
+
for (const session of sessions) {
|
|
9343
|
+
const ctx = sessionContext(session);
|
|
9344
|
+
const usageRows = usageBySession.get(ctx.rawId) || [];
|
|
9345
|
+
const messages = messagesBySession.get(ctx.rawId) || [];
|
|
9346
|
+
if (!sessionHasWork(session, usageRows) && messages.length === 0) {
|
|
9347
|
+
continue;
|
|
9348
|
+
}
|
|
9349
|
+
const startedTs = isoFromUnix(session.started_at);
|
|
9350
|
+
if (!startedTs) {
|
|
9351
|
+
continue;
|
|
9352
|
+
}
|
|
9353
|
+
lineNumber += 1;
|
|
9354
|
+
const started = makeEvent({
|
|
9355
|
+
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
9356
|
+
ts: startedTs,
|
|
9357
|
+
type: "session.started",
|
|
9358
|
+
source: SOURCE,
|
|
9359
|
+
workspaceId: ctx.workspaceId,
|
|
9360
|
+
project: ctx.project,
|
|
9361
|
+
cwd: ctx.cwd,
|
|
9362
|
+
sessionId: ctx.sessionId,
|
|
9363
|
+
parentAgentInstanceId: ctx.parentSessionId ? `${SOURCE}:${ctx.parentSessionId}` : void 0,
|
|
9364
|
+
agent: SOURCE,
|
|
9365
|
+
model: ctx.model,
|
|
9366
|
+
provider: ctx.provider,
|
|
9367
|
+
confidence: "exact",
|
|
9368
|
+
refs: refs({
|
|
9369
|
+
sourceId: `${ctx.rawId}:session`,
|
|
9370
|
+
hermesPlatform: ctx.platform,
|
|
9371
|
+
hermesProfile: ctx.profileName,
|
|
9372
|
+
hermesParentSessionId: ctx.parentSessionId
|
|
9373
|
+
})
|
|
9374
|
+
}, lineNumber, filePath, options);
|
|
9375
|
+
if (started) {
|
|
9376
|
+
events.push(started);
|
|
9377
|
+
}
|
|
9378
|
+
const endedTs = isoFromUnix(session.ended_at) || isoFromUnix(session.last_activity_at);
|
|
9379
|
+
if (endedTs && endedTs !== startedTs) {
|
|
9380
|
+
lineNumber += 1;
|
|
9381
|
+
const ended = makeEvent({
|
|
9382
|
+
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
9383
|
+
ts: endedTs,
|
|
9384
|
+
type: "session.ended",
|
|
9385
|
+
source: SOURCE,
|
|
9386
|
+
workspaceId: ctx.workspaceId,
|
|
9387
|
+
project: ctx.project,
|
|
9388
|
+
cwd: ctx.cwd,
|
|
9389
|
+
sessionId: ctx.sessionId,
|
|
9390
|
+
parentAgentInstanceId: ctx.parentSessionId ? `${SOURCE}:${ctx.parentSessionId}` : void 0,
|
|
9391
|
+
agent: SOURCE,
|
|
9392
|
+
model: ctx.model,
|
|
9393
|
+
provider: ctx.provider,
|
|
9394
|
+
confidence: "exact",
|
|
9395
|
+
refs: refs({
|
|
9396
|
+
sourceId: `${ctx.rawId}:session:ended`,
|
|
9397
|
+
hermesPlatform: ctx.platform,
|
|
9398
|
+
hermesProfile: ctx.profileName
|
|
9399
|
+
})
|
|
9400
|
+
}, lineNumber, filePath, options);
|
|
9401
|
+
if (ended) {
|
|
9402
|
+
events.push(ended);
|
|
9403
|
+
}
|
|
9404
|
+
}
|
|
9405
|
+
if (usageRows.length > 0) {
|
|
9406
|
+
for (const usage of usageRows) {
|
|
9407
|
+
const ts = isoFromUnix(usage.last_seen) || isoFromUnix(usage.first_seen) || startedTs;
|
|
9408
|
+
lineNumber += 1;
|
|
9409
|
+
const event = makeEvent({
|
|
9410
|
+
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
9411
|
+
ts,
|
|
9412
|
+
type: "model.usage",
|
|
9413
|
+
source: SOURCE,
|
|
9414
|
+
workspaceId: ctx.workspaceId,
|
|
9415
|
+
project: ctx.project,
|
|
9416
|
+
cwd: ctx.cwd,
|
|
9417
|
+
sessionId: ctx.sessionId,
|
|
9418
|
+
agent: SOURCE,
|
|
9419
|
+
model: stringField(usage, "model") || ctx.model,
|
|
9420
|
+
provider: stringField(usage, "billing_provider") || ctx.provider,
|
|
9421
|
+
success: true,
|
|
9422
|
+
metrics: usageMetrics2(usage),
|
|
9423
|
+
confidence: "exact",
|
|
9424
|
+
refs: refs({
|
|
9425
|
+
sourceId: `${ctx.rawId}:model:${stringField(usage, "model") || "unknown"}:${stringField(usage, "task") || "main"}:${stringField(usage, "billing_provider") || ""}`,
|
|
9426
|
+
hermesPlatform: ctx.platform,
|
|
9427
|
+
hermesProfile: ctx.profileName,
|
|
9428
|
+
hermesTask: stringField(usage, "task"),
|
|
9429
|
+
hermesBillingMode: stringField(usage, "billing_mode")
|
|
9430
|
+
})
|
|
9431
|
+
}, lineNumber, filePath, options);
|
|
9432
|
+
if (event) {
|
|
9433
|
+
events.push(event);
|
|
9434
|
+
}
|
|
9435
|
+
}
|
|
9436
|
+
} else if ((numberField(session, "input_tokens") || 0) + (numberField(session, "output_tokens") || 0) > 0) {
|
|
9437
|
+
lineNumber += 1;
|
|
9438
|
+
const event = makeEvent({
|
|
9439
|
+
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
9440
|
+
ts: endedTs || startedTs,
|
|
9441
|
+
type: "model.usage",
|
|
9442
|
+
source: SOURCE,
|
|
9443
|
+
workspaceId: ctx.workspaceId,
|
|
9444
|
+
project: ctx.project,
|
|
9445
|
+
cwd: ctx.cwd,
|
|
9446
|
+
sessionId: ctx.sessionId,
|
|
9447
|
+
agent: SOURCE,
|
|
9448
|
+
model: ctx.model,
|
|
9449
|
+
provider: ctx.provider,
|
|
9450
|
+
success: true,
|
|
9451
|
+
metrics: usageMetrics2(session),
|
|
9452
|
+
confidence: "partial",
|
|
9453
|
+
refs: refs({
|
|
9454
|
+
sourceId: `${ctx.rawId}:model:session`,
|
|
9455
|
+
hermesPlatform: ctx.platform,
|
|
9456
|
+
hermesProfile: ctx.profileName
|
|
9457
|
+
})
|
|
9458
|
+
}, lineNumber, filePath, options);
|
|
9459
|
+
if (event) {
|
|
9460
|
+
events.push(event);
|
|
9461
|
+
}
|
|
9462
|
+
}
|
|
9463
|
+
let turnIndex = 0;
|
|
9464
|
+
let activeTurnId;
|
|
9465
|
+
for (const message of messages) {
|
|
9466
|
+
const ts = isoFromUnix(message.timestamp);
|
|
9467
|
+
if (!ts) {
|
|
9468
|
+
continue;
|
|
9469
|
+
}
|
|
9470
|
+
const role = stringField(message, "role");
|
|
9471
|
+
if (role === "user") {
|
|
9472
|
+
turnIndex += 1;
|
|
9473
|
+
activeTurnId = `${ctx.sessionId}:turn:${turnIndex}`;
|
|
9474
|
+
lineNumber += 1;
|
|
9475
|
+
const turnStarted = makeEvent({
|
|
9476
|
+
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
9477
|
+
ts,
|
|
9478
|
+
type: "turn.started",
|
|
9479
|
+
source: SOURCE,
|
|
9480
|
+
workspaceId: ctx.workspaceId,
|
|
9481
|
+
project: ctx.project,
|
|
9482
|
+
cwd: ctx.cwd,
|
|
9483
|
+
sessionId: ctx.sessionId,
|
|
9484
|
+
turnId: activeTurnId,
|
|
9485
|
+
agent: SOURCE,
|
|
9486
|
+
confidence: "derived",
|
|
9487
|
+
refs: refs({ sourceId: `${ctx.rawId}:turn:${turnIndex}:start` })
|
|
9488
|
+
}, lineNumber, filePath, options);
|
|
9489
|
+
if (turnStarted) {
|
|
9490
|
+
events.push(turnStarted);
|
|
9491
|
+
}
|
|
9492
|
+
const content = stringField(message, "content");
|
|
9493
|
+
lineNumber += 1;
|
|
9494
|
+
const prompt = makeEvent({
|
|
9495
|
+
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
9496
|
+
ts,
|
|
9497
|
+
type: "prompt.submitted",
|
|
9498
|
+
source: SOURCE,
|
|
9499
|
+
workspaceId: ctx.workspaceId,
|
|
9500
|
+
project: ctx.project,
|
|
9501
|
+
cwd: ctx.cwd,
|
|
9502
|
+
sessionId: ctx.sessionId,
|
|
9503
|
+
turnId: activeTurnId,
|
|
9504
|
+
agent: SOURCE,
|
|
9505
|
+
confidence: "exact",
|
|
9506
|
+
metrics: { promptChars: content?.length, prompts: 1 },
|
|
9507
|
+
refs: refs({ sourceId: `${ctx.rawId}:prompt:${stringField(message, "id") || turnIndex}` })
|
|
9508
|
+
}, lineNumber, filePath, options);
|
|
9509
|
+
if (prompt) {
|
|
9510
|
+
events.push(prompt);
|
|
9511
|
+
}
|
|
9512
|
+
continue;
|
|
9513
|
+
}
|
|
9514
|
+
if (role !== "assistant") {
|
|
9515
|
+
continue;
|
|
9516
|
+
}
|
|
9517
|
+
const tools = parseToolCalls(message.tool_calls);
|
|
9518
|
+
for (const tool of tools) {
|
|
9519
|
+
const toolName = tool.name;
|
|
9520
|
+
const alias = hermesToolAlias(toolName);
|
|
9521
|
+
const toolCallId = tool.id || `${stringField(message, "id") || lineNumber}:${toolName}`;
|
|
9522
|
+
const spanId = `${ctx.sessionId}:tool:${toolCallId}`;
|
|
9523
|
+
const fileActivities = claudeStyleToolFileActivities(alias, tool.input, ts, ctx.cwd);
|
|
9524
|
+
lineNumber += 1;
|
|
9525
|
+
const startedTool = makeEvent({
|
|
9526
|
+
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
9527
|
+
ts,
|
|
9528
|
+
type: "tool.started",
|
|
9529
|
+
source: SOURCE,
|
|
9530
|
+
workspaceId: ctx.workspaceId,
|
|
9531
|
+
project: ctx.project,
|
|
9532
|
+
cwd: ctx.cwd,
|
|
9533
|
+
sessionId: ctx.sessionId,
|
|
9534
|
+
turnId: activeTurnId,
|
|
9535
|
+
spanId,
|
|
9536
|
+
agent: SOURCE,
|
|
9537
|
+
tool: toolName,
|
|
9538
|
+
confidence: "exact",
|
|
9539
|
+
refs: refs({ sourceId: `${toolCallId}:start` })
|
|
9540
|
+
}, lineNumber, filePath, options);
|
|
9541
|
+
if (startedTool) {
|
|
9542
|
+
events.push(startedTool);
|
|
9543
|
+
}
|
|
9544
|
+
lineNumber += 1;
|
|
9545
|
+
const completedTool = makeEvent({
|
|
9546
|
+
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
9547
|
+
ts,
|
|
9548
|
+
type: "tool.completed",
|
|
9549
|
+
source: SOURCE,
|
|
9550
|
+
workspaceId: ctx.workspaceId,
|
|
9551
|
+
project: ctx.project,
|
|
9552
|
+
cwd: ctx.cwd,
|
|
9553
|
+
sessionId: ctx.sessionId,
|
|
9554
|
+
turnId: activeTurnId,
|
|
9555
|
+
spanId,
|
|
9556
|
+
agent: SOURCE,
|
|
9557
|
+
tool: toolName,
|
|
9558
|
+
success: true,
|
|
9559
|
+
confidence: "exact",
|
|
9560
|
+
fileActivities: fileActivities.length > 0 ? fileActivities : void 0,
|
|
9561
|
+
refs: refs({ sourceId: `${toolCallId}:completed` })
|
|
9562
|
+
}, lineNumber, filePath, options);
|
|
9563
|
+
if (completedTool) {
|
|
9564
|
+
events.push(completedTool);
|
|
9565
|
+
}
|
|
9566
|
+
}
|
|
9567
|
+
}
|
|
9568
|
+
}
|
|
9569
|
+
return events.sort((a, b) => a.ts.localeCompare(b.ts) || (a.id || "").localeCompare(b.id || ""));
|
|
9570
|
+
} finally {
|
|
9571
|
+
db.close();
|
|
9572
|
+
}
|
|
9573
|
+
}
|
|
9574
|
+
async function collectStateDb(filePath, seen, out) {
|
|
9575
|
+
const resolved = path15.resolve(filePath);
|
|
9576
|
+
if (seen.has(resolved)) {
|
|
9577
|
+
return;
|
|
9578
|
+
}
|
|
9579
|
+
const modifiedAt = await sqliteMtime(resolved);
|
|
9580
|
+
if (!modifiedAt) {
|
|
9581
|
+
return;
|
|
9582
|
+
}
|
|
9583
|
+
seen.add(resolved);
|
|
9584
|
+
out.push({ path: resolved, modifiedAt });
|
|
9585
|
+
}
|
|
9586
|
+
async function collectHermesHome(root, seen, out) {
|
|
9587
|
+
await collectStateDb(path15.join(root, "state.db"), seen, out);
|
|
9588
|
+
const profilesDir = path15.join(root, "profiles");
|
|
9589
|
+
let entries;
|
|
9590
|
+
try {
|
|
9591
|
+
entries = await readdir8(profilesDir, { withFileTypes: true });
|
|
9592
|
+
} catch {
|
|
9593
|
+
return;
|
|
9594
|
+
}
|
|
9595
|
+
for (const entry of entries) {
|
|
9596
|
+
if (entry.isDirectory()) {
|
|
9597
|
+
await collectStateDb(path15.join(profilesDir, entry.name, "state.db"), seen, out);
|
|
9598
|
+
}
|
|
9599
|
+
}
|
|
9600
|
+
}
|
|
9601
|
+
async function hermesBackfillFiles(sourceRoot, home, env = {}) {
|
|
9602
|
+
const seen = /* @__PURE__ */ new Set();
|
|
9603
|
+
const out = [];
|
|
9604
|
+
if (sourceRoot) {
|
|
9605
|
+
if (sourceRoot.endsWith(".db")) {
|
|
9606
|
+
await collectStateDb(sourceRoot, seen, out);
|
|
9607
|
+
return out;
|
|
9608
|
+
}
|
|
9609
|
+
await collectHermesHome(sourceRoot, seen, out);
|
|
9610
|
+
return out;
|
|
9611
|
+
}
|
|
9612
|
+
const primary = hermesRoot(home, env);
|
|
9613
|
+
await collectHermesHome(primary, seen, out);
|
|
9614
|
+
const defaultRoot = path15.join(home, ".hermes");
|
|
9615
|
+
if (path15.resolve(defaultRoot) !== path15.resolve(primary)) {
|
|
9616
|
+
await collectHermesHome(defaultRoot, seen, out);
|
|
9617
|
+
}
|
|
9618
|
+
return out.sort((a, b) => a.path.localeCompare(b.path));
|
|
9619
|
+
}
|
|
9620
|
+
function pluginYaml() {
|
|
9621
|
+
return `# ${GENERATED_MARKER3}
|
|
9622
|
+
name: vibetime
|
|
9623
|
+
version: "1.0.0"
|
|
9624
|
+
description: "VibeTime session sync \u2014 thin trigger that runs local backfill on Hermes lifecycle events."
|
|
9625
|
+
author: VibeTime
|
|
9626
|
+
hooks:
|
|
9627
|
+
- on_session_start
|
|
9628
|
+
- on_session_end
|
|
9629
|
+
- on_session_finalize
|
|
9630
|
+
- post_tool_call
|
|
9631
|
+
`;
|
|
9632
|
+
}
|
|
9633
|
+
function pluginInit() {
|
|
9634
|
+
return `# ${GENERATED_MARKER3}
|
|
9635
|
+
"""VibeTime observability plugin for Hermes Agent.
|
|
9636
|
+
|
|
9637
|
+
Thin trigger only: spawn \`vibetime hook --agent hermes\` on session/tool
|
|
9638
|
+
lifecycle events. Token usage is read from state.db by vibetime backfill.
|
|
9639
|
+
"""
|
|
9640
|
+
from __future__ import annotations
|
|
9641
|
+
|
|
9642
|
+
import json
|
|
9643
|
+
import os
|
|
9644
|
+
import shutil
|
|
9645
|
+
import subprocess
|
|
9646
|
+
from typing import Any
|
|
9647
|
+
|
|
9648
|
+
|
|
9649
|
+
def _report(payload: dict[str, Any]) -> None:
|
|
9650
|
+
command = shutil.which("vibetime")
|
|
9651
|
+
if not command:
|
|
9652
|
+
return
|
|
9653
|
+
try:
|
|
9654
|
+
subprocess.run(
|
|
9655
|
+
[command, "hook", "--agent", "hermes"],
|
|
9656
|
+
input=json.dumps(payload),
|
|
9657
|
+
text=True,
|
|
9658
|
+
capture_output=True,
|
|
9659
|
+
timeout=10,
|
|
9660
|
+
check=False,
|
|
9661
|
+
env=os.environ.copy(),
|
|
9662
|
+
)
|
|
9663
|
+
except Exception:
|
|
9664
|
+
return
|
|
9665
|
+
|
|
9666
|
+
|
|
9667
|
+
def on_session_start(*, session_id: str = "", **_: Any) -> None:
|
|
9668
|
+
_report({"hook_event_name": "SessionStart", "session_id": session_id})
|
|
9669
|
+
|
|
9670
|
+
|
|
9671
|
+
def on_session_end(*, session_id: str = "", **_: Any) -> None:
|
|
9672
|
+
_report({"hook_event_name": "SessionEnd", "session_id": session_id})
|
|
9673
|
+
|
|
9674
|
+
|
|
9675
|
+
def on_post_tool_call(*, tool_name: str = "", session_id: str = "", **_: Any) -> None:
|
|
9676
|
+
_report({
|
|
9677
|
+
"hook_event_name": "PostToolUse",
|
|
9678
|
+
"tool_name": tool_name or "unknown",
|
|
9679
|
+
"session_id": session_id,
|
|
9680
|
+
})
|
|
9681
|
+
|
|
9682
|
+
|
|
9683
|
+
def register(ctx) -> None:
|
|
9684
|
+
ctx.register_hook("on_session_start", on_session_start)
|
|
9685
|
+
ctx.register_hook("on_session_end", on_session_end)
|
|
9686
|
+
ctx.register_hook("on_session_finalize", on_session_end)
|
|
9687
|
+
ctx.register_hook("post_tool_call", on_post_tool_call)
|
|
9688
|
+
`;
|
|
9689
|
+
}
|
|
9690
|
+
function createHermesAdapter() {
|
|
9691
|
+
return {
|
|
9692
|
+
id: SOURCE,
|
|
9693
|
+
label: "Hermes Agent",
|
|
9694
|
+
agentName: SOURCE,
|
|
9695
|
+
kind: "agent",
|
|
9696
|
+
detectPath(home, env) {
|
|
9697
|
+
return hermesRoot(home, env);
|
|
9698
|
+
},
|
|
9699
|
+
installedPath(home, env) {
|
|
9700
|
+
return hermesPluginManifestPath(home, env);
|
|
9701
|
+
},
|
|
9702
|
+
async isInstalled(home, env) {
|
|
9703
|
+
const manifest = await readTextIfExists(hermesPluginManifestPath(home, env));
|
|
9704
|
+
const init = await readTextIfExists(hermesPluginInitPath(home, env));
|
|
9705
|
+
return Boolean(manifest && init && init.includes(HOOK_COMMAND3));
|
|
9706
|
+
},
|
|
9707
|
+
installEntries(home, env) {
|
|
9708
|
+
return [
|
|
9709
|
+
{
|
|
9710
|
+
kind: "file",
|
|
9711
|
+
path: hermesPluginManifestPath(home, env),
|
|
9712
|
+
content: pluginYaml()
|
|
9713
|
+
},
|
|
9714
|
+
{
|
|
9715
|
+
kind: "file",
|
|
9716
|
+
path: hermesPluginInitPath(home, env),
|
|
9717
|
+
content: pluginInit()
|
|
9718
|
+
}
|
|
9719
|
+
];
|
|
9720
|
+
},
|
|
9721
|
+
sourcePaths(home, env) {
|
|
9722
|
+
return [path15.join(hermesRoot(home, env), "state.db")];
|
|
9723
|
+
},
|
|
9724
|
+
parseSessionFile: parseHermesDb
|
|
9725
|
+
};
|
|
9726
|
+
}
|
|
9727
|
+
|
|
9042
9728
|
// src/adapters/kimi-code.ts
|
|
9043
9729
|
import { readFile as readFile10 } from "node:fs/promises";
|
|
9044
|
-
import
|
|
9730
|
+
import path16 from "node:path";
|
|
9045
9731
|
|
|
9046
9732
|
// src/lib/toml-hooks.ts
|
|
9047
9733
|
init_fs();
|
|
@@ -9219,20 +9905,20 @@ function tomlNumberField(body, key) {
|
|
|
9219
9905
|
}
|
|
9220
9906
|
|
|
9221
9907
|
// src/adapters/kimi-code.ts
|
|
9222
|
-
var
|
|
9908
|
+
var HOOK_COMMAND4 = "vibetime hook --agent kimi-code";
|
|
9223
9909
|
var HOOK_TIMEOUT_SECONDS2 = 10;
|
|
9224
9910
|
function kimiCodeHome(home, env) {
|
|
9225
9911
|
const override = env?.KIMI_CODE_HOME || env?.KIMI_HOME;
|
|
9226
9912
|
if (override && override.trim()) {
|
|
9227
|
-
return
|
|
9913
|
+
return path16.resolve(override);
|
|
9228
9914
|
}
|
|
9229
|
-
return
|
|
9915
|
+
return path16.join(home, ".kimi-code");
|
|
9230
9916
|
}
|
|
9231
9917
|
function kimiCodeSessionsDir(home, env) {
|
|
9232
|
-
return
|
|
9918
|
+
return path16.join(kimiCodeHome(home, env), "sessions");
|
|
9233
9919
|
}
|
|
9234
9920
|
function kimiCodeConfigPath(home, env) {
|
|
9235
|
-
return
|
|
9921
|
+
return path16.join(kimiCodeHome(home, env), "config.toml");
|
|
9236
9922
|
}
|
|
9237
9923
|
function kimiHookRules() {
|
|
9238
9924
|
const events = [
|
|
@@ -9248,7 +9934,7 @@ function kimiHookRules() {
|
|
|
9248
9934
|
];
|
|
9249
9935
|
return events.map((event) => ({
|
|
9250
9936
|
event,
|
|
9251
|
-
command:
|
|
9937
|
+
command: HOOK_COMMAND4,
|
|
9252
9938
|
timeout: HOOK_TIMEOUT_SECONDS2
|
|
9253
9939
|
}));
|
|
9254
9940
|
}
|
|
@@ -9308,8 +9994,8 @@ function sessionIdFromWirePath(filePath) {
|
|
|
9308
9994
|
return match?.[1];
|
|
9309
9995
|
}
|
|
9310
9996
|
async function readSessionState(filePath) {
|
|
9311
|
-
const sessionDir =
|
|
9312
|
-
const statePath =
|
|
9997
|
+
const sessionDir = path16.dirname(path16.dirname(path16.dirname(filePath)));
|
|
9998
|
+
const statePath = path16.join(sessionDir, "state.json");
|
|
9313
9999
|
try {
|
|
9314
10000
|
const text = await readFile10(statePath, "utf8");
|
|
9315
10001
|
const raw = JSON.parse(text);
|
|
@@ -9326,7 +10012,7 @@ async function readSessionState(filePath) {
|
|
|
9326
10012
|
}
|
|
9327
10013
|
}
|
|
9328
10014
|
async function parseKimiCodeSessionFile(filePath, options) {
|
|
9329
|
-
if (
|
|
10015
|
+
if (path16.basename(filePath) !== "wire.jsonl") {
|
|
9330
10016
|
return [];
|
|
9331
10017
|
}
|
|
9332
10018
|
const text = await readFile10(filePath, "utf8");
|
|
@@ -9334,7 +10020,7 @@ async function parseKimiCodeSessionFile(filePath, options) {
|
|
|
9334
10020
|
const stateMeta = await readSessionState(filePath);
|
|
9335
10021
|
let sessionId = stateMeta.sessionId || sessionIdFromWirePath(filePath);
|
|
9336
10022
|
let cwd = stateMeta.cwd;
|
|
9337
|
-
let project = cwd ?
|
|
10023
|
+
let project = cwd ? path16.basename(cwd) : void 0;
|
|
9338
10024
|
let model;
|
|
9339
10025
|
let provider;
|
|
9340
10026
|
let reasoningEffort;
|
|
@@ -9380,7 +10066,7 @@ async function parseKimiCodeSessionFile(filePath, options) {
|
|
|
9380
10066
|
const disclosedCwd = stringField(disclosure, "cwd");
|
|
9381
10067
|
if (disclosedCwd) {
|
|
9382
10068
|
cwd = disclosedCwd;
|
|
9383
|
-
project =
|
|
10069
|
+
project = path16.basename(disclosedCwd);
|
|
9384
10070
|
}
|
|
9385
10071
|
continue;
|
|
9386
10072
|
}
|
|
@@ -9694,7 +10380,7 @@ function createKimiCodeAdapter() {
|
|
|
9694
10380
|
return kimiCodeConfigPath(home, env);
|
|
9695
10381
|
},
|
|
9696
10382
|
async isInstalled(home, env) {
|
|
9697
|
-
return hasTomlHookCommand(kimiCodeConfigPath(home, env),
|
|
10383
|
+
return hasTomlHookCommand(kimiCodeConfigPath(home, env), HOOK_COMMAND4);
|
|
9698
10384
|
},
|
|
9699
10385
|
installEntries(home, env) {
|
|
9700
10386
|
return [{
|
|
@@ -9712,7 +10398,7 @@ function createKimiCodeAdapter() {
|
|
|
9712
10398
|
|
|
9713
10399
|
// src/adapters/opencode.ts
|
|
9714
10400
|
import os8 from "node:os";
|
|
9715
|
-
import
|
|
10401
|
+
import path17 from "node:path";
|
|
9716
10402
|
async function parseOpenCodeSessionFile(dbPath, options) {
|
|
9717
10403
|
const { DatabaseSync } = await import("node:sqlite");
|
|
9718
10404
|
if (!dbPath.endsWith(".db")) {
|
|
@@ -9771,7 +10457,7 @@ async function parseOpenCodeSessionFile(dbPath, options) {
|
|
|
9771
10457
|
const isSubagent = sessionId !== rawSessionId;
|
|
9772
10458
|
const sessionEventStart = events.length;
|
|
9773
10459
|
const cwd = session.directory || session.path || void 0;
|
|
9774
|
-
const project = cwd ?
|
|
10460
|
+
const project = cwd ? path17.basename(cwd) : void 0;
|
|
9775
10461
|
const sessionTs = msToIso(session.time_created);
|
|
9776
10462
|
events.push(baseOpenCodeEvent({
|
|
9777
10463
|
ts: sessionTs,
|
|
@@ -9879,7 +10565,7 @@ async function parseOpenCodeSessionFile(dbPath, options) {
|
|
|
9879
10565
|
const provider = currentProvider;
|
|
9880
10566
|
const pathObj = objectField(info, "path");
|
|
9881
10567
|
const assistantCwd = stringField(pathObj, "cwd") || cwd;
|
|
9882
|
-
const assistantProject = assistantCwd ?
|
|
10568
|
+
const assistantProject = assistantCwd ? path17.basename(assistantCwd) : project;
|
|
9883
10569
|
const completedTs = numberField(objectField(info, "time"), "completed");
|
|
9884
10570
|
const createdTs = timeCreated;
|
|
9885
10571
|
const tokens = opencodeUsageFromInfo(info);
|
|
@@ -10153,33 +10839,33 @@ function opencodeUsageFromInfo(info) {
|
|
|
10153
10839
|
function opencodeConfigDir(home, env) {
|
|
10154
10840
|
const override = env?.OPENCODE_CONFIG_DIR;
|
|
10155
10841
|
if (override && override.trim()) {
|
|
10156
|
-
return
|
|
10842
|
+
return path17.resolve(override);
|
|
10157
10843
|
}
|
|
10158
10844
|
const xdgConfig = env?.XDG_CONFIG_HOME;
|
|
10159
10845
|
if (xdgConfig && xdgConfig.trim()) {
|
|
10160
|
-
return
|
|
10846
|
+
return path17.join(path17.resolve(xdgConfig), "opencode");
|
|
10161
10847
|
}
|
|
10162
|
-
return
|
|
10848
|
+
return path17.join(home, ".config", "opencode");
|
|
10163
10849
|
}
|
|
10164
10850
|
function opencodeDataCandidates(home, env) {
|
|
10165
10851
|
const xdgData = env?.XDG_DATA_HOME;
|
|
10166
|
-
const primary = xdgData && xdgData.trim() ?
|
|
10167
|
-
return [primary,
|
|
10852
|
+
const primary = xdgData && xdgData.trim() ? path17.join(path17.resolve(xdgData), "opencode", "opencode.db") : path17.join(home, ".local", "share", "opencode", "opencode.db");
|
|
10853
|
+
return [primary, path17.join(home, ".opencode", "opencode.db")];
|
|
10168
10854
|
}
|
|
10169
10855
|
async function opencodeBackfillFiles(sourceRoot, home = os8.homedir(), env) {
|
|
10170
|
-
const { stat:
|
|
10856
|
+
const { stat: stat19 } = await import("node:fs/promises");
|
|
10171
10857
|
if (sourceRoot) {
|
|
10172
10858
|
if (!sourceRoot.endsWith(".db")) {
|
|
10173
10859
|
return [];
|
|
10174
10860
|
}
|
|
10175
|
-
const info = await
|
|
10861
|
+
const info = await stat19(sourceRoot).catch(() => null);
|
|
10176
10862
|
if (!info) {
|
|
10177
10863
|
return [];
|
|
10178
10864
|
}
|
|
10179
10865
|
return [{ path: sourceRoot, modifiedAt: info.mtime.toISOString() }];
|
|
10180
10866
|
}
|
|
10181
10867
|
for (const candidatePath of opencodeDataCandidates(home, env)) {
|
|
10182
|
-
const info = await
|
|
10868
|
+
const info = await stat19(candidatePath).catch(() => null);
|
|
10183
10869
|
if (info) {
|
|
10184
10870
|
return [{ path: candidatePath, modifiedAt: info.mtime.toISOString() }];
|
|
10185
10871
|
}
|
|
@@ -10254,12 +10940,12 @@ function createOpenCodeAdapter() {
|
|
|
10254
10940
|
return opencodeConfigDir(home, env);
|
|
10255
10941
|
},
|
|
10256
10942
|
installedPath(home, env) {
|
|
10257
|
-
return
|
|
10943
|
+
return path17.join(opencodeConfigDir(home, env), PLUGIN_PATH);
|
|
10258
10944
|
},
|
|
10259
10945
|
async isInstalled(home, env) {
|
|
10260
10946
|
try {
|
|
10261
10947
|
const { pathExists: pathExists2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
10262
|
-
return await pathExists2(
|
|
10948
|
+
return await pathExists2(path17.join(opencodeConfigDir(home, env), PLUGIN_PATH)) || await pathExists2(path17.join(".opencode", PLUGIN_PATH));
|
|
10263
10949
|
} catch {
|
|
10264
10950
|
return false;
|
|
10265
10951
|
}
|
|
@@ -10267,7 +10953,7 @@ function createOpenCodeAdapter() {
|
|
|
10267
10953
|
installEntries(home, env) {
|
|
10268
10954
|
return [{
|
|
10269
10955
|
kind: "file",
|
|
10270
|
-
path:
|
|
10956
|
+
path: path17.join(opencodeConfigDir(home, env), PLUGIN_PATH),
|
|
10271
10957
|
content: opencodePluginContent()
|
|
10272
10958
|
}];
|
|
10273
10959
|
},
|
|
@@ -10279,9 +10965,9 @@ function createOpenCodeAdapter() {
|
|
|
10279
10965
|
}
|
|
10280
10966
|
|
|
10281
10967
|
// src/adapters/pi.ts
|
|
10282
|
-
import { readdir as
|
|
10968
|
+
import { readdir as readdir9, readFile as readFile11, stat as stat12 } from "node:fs/promises";
|
|
10283
10969
|
import os9 from "node:os";
|
|
10284
|
-
import
|
|
10970
|
+
import path18 from "node:path";
|
|
10285
10971
|
init_fs();
|
|
10286
10972
|
function piHostSessionIdFromBasename(basename) {
|
|
10287
10973
|
const withoutExt = basename.endsWith(".jsonl") ? basename.slice(0, -".jsonl".length) : basename;
|
|
@@ -10296,7 +10982,7 @@ function piHostSessionIdFromBasename(basename) {
|
|
|
10296
10982
|
}
|
|
10297
10983
|
function resolvePiBackfillGroupId(filePath) {
|
|
10298
10984
|
const normalized = filePath.replaceAll("\\", "/");
|
|
10299
|
-
const base =
|
|
10985
|
+
const base = path18.basename(filePath);
|
|
10300
10986
|
const nest = normalized.match(/([^/]+)\/[^/]+\/run-\d+\/session\.jsonl$/);
|
|
10301
10987
|
if (nest) {
|
|
10302
10988
|
return piHostSessionIdFromBasename(nest[1]);
|
|
@@ -10308,8 +10994,8 @@ function resolvePiBackfillGroupId(filePath) {
|
|
|
10308
10994
|
}
|
|
10309
10995
|
function parsePiSubagentLink(filePath, headerParentSession) {
|
|
10310
10996
|
if (headerParentSession) {
|
|
10311
|
-
const parentFile =
|
|
10312
|
-
const parentSessionId2 = parentFile ?
|
|
10997
|
+
const parentFile = path18.isAbsolute(headerParentSession) ? headerParentSession : void 0;
|
|
10998
|
+
const parentSessionId2 = parentFile ? path18.basename(parentFile, ".jsonl") : headerParentSession;
|
|
10313
10999
|
return { parentSessionId: parentSessionId2, parentSessionFile: parentFile, explicit: true };
|
|
10314
11000
|
}
|
|
10315
11001
|
const normalized = filePath.replaceAll("\\", "/");
|
|
@@ -10322,8 +11008,8 @@ function parsePiSubagentLink(filePath, headerParentSession) {
|
|
|
10322
11008
|
return void 0;
|
|
10323
11009
|
}
|
|
10324
11010
|
const parentSessionId = parentBasename.endsWith(".jsonl") ? parentBasename.slice(0, -".jsonl".length) : parentBasename;
|
|
10325
|
-
const parentDir =
|
|
10326
|
-
const parentSessionFile =
|
|
11011
|
+
const parentDir = path18.dirname(path18.dirname(path18.dirname(filePath)));
|
|
11012
|
+
const parentSessionFile = path18.join(path18.dirname(parentDir), `${parentBasename}.jsonl`);
|
|
10327
11013
|
return { parentSessionId, parentSessionFile, explicit: false };
|
|
10328
11014
|
}
|
|
10329
11015
|
async function resolveParentContext(link, options) {
|
|
@@ -10335,7 +11021,7 @@ async function resolveParentContext(link, options) {
|
|
|
10335
11021
|
if (raw) {
|
|
10336
11022
|
const id = stringField(raw, "id");
|
|
10337
11023
|
const cwd = stringField(raw, "cwd");
|
|
10338
|
-
const project = cwd ?
|
|
11024
|
+
const project = cwd ? path18.basename(cwd) : void 0;
|
|
10339
11025
|
if (id || cwd || project) {
|
|
10340
11026
|
return { sessionId: id, cwd, project };
|
|
10341
11027
|
}
|
|
@@ -10416,7 +11102,7 @@ async function parsePiSessionFile(filePath, options) {
|
|
|
10416
11102
|
sessionId = stringField(raw, "id") || state.sessionId;
|
|
10417
11103
|
state.sessionId = sessionId || state.sessionId;
|
|
10418
11104
|
cwd = stringField(raw, "cwd") || cwd;
|
|
10419
|
-
project = cwd ?
|
|
11105
|
+
project = cwd ? path18.basename(cwd) : project;
|
|
10420
11106
|
headerParentSession = stringField(raw, "parentSession") || headerParentSession;
|
|
10421
11107
|
continue;
|
|
10422
11108
|
}
|
|
@@ -10691,17 +11377,17 @@ async function parsePiWorkflowRunFile(filePath, options) {
|
|
|
10691
11377
|
return state.events.filter((event) => matchesBackfillFilters(event, options));
|
|
10692
11378
|
}
|
|
10693
11379
|
async function findPiSessionFileById(sessionId, options) {
|
|
10694
|
-
const sessionsDir = piSessionDir(
|
|
11380
|
+
const sessionsDir = piSessionDir(path18.resolve(stringOption(options.home) || os9.homedir()));
|
|
10695
11381
|
try {
|
|
10696
|
-
const projectDirs = await
|
|
11382
|
+
const projectDirs = await readdir9(sessionsDir, { withFileTypes: true });
|
|
10697
11383
|
for (const dir of projectDirs) {
|
|
10698
11384
|
if (!dir.isDirectory()) {
|
|
10699
11385
|
continue;
|
|
10700
11386
|
}
|
|
10701
|
-
const names = await
|
|
11387
|
+
const names = await readdir9(path18.join(sessionsDir, dir.name));
|
|
10702
11388
|
const hit = names.find((name) => name.endsWith(`_${sessionId}.jsonl`));
|
|
10703
11389
|
if (hit) {
|
|
10704
|
-
return
|
|
11390
|
+
return path18.join(sessionsDir, dir.name, hit);
|
|
10705
11391
|
}
|
|
10706
11392
|
}
|
|
10707
11393
|
} catch {
|
|
@@ -10943,19 +11629,19 @@ export default function (pi: ExtensionAPI) {
|
|
|
10943
11629
|
function piAgentDir(home, env) {
|
|
10944
11630
|
const override = env?.PI_CODING_AGENT_DIR;
|
|
10945
11631
|
if (override && override.trim()) {
|
|
10946
|
-
return
|
|
11632
|
+
return path18.resolve(override);
|
|
10947
11633
|
}
|
|
10948
|
-
return
|
|
11634
|
+
return path18.join(home, ".pi", "agent");
|
|
10949
11635
|
}
|
|
10950
11636
|
function piSessionDir(home, env) {
|
|
10951
11637
|
const override = env?.PI_CODING_AGENT_SESSION_DIR;
|
|
10952
11638
|
if (override && override.trim()) {
|
|
10953
|
-
return
|
|
11639
|
+
return path18.resolve(override);
|
|
10954
11640
|
}
|
|
10955
|
-
return
|
|
11641
|
+
return path18.join(piAgentDir(home, env), "sessions");
|
|
10956
11642
|
}
|
|
10957
11643
|
function piWorkflowProjectsDir(home) {
|
|
10958
|
-
return
|
|
11644
|
+
return path18.join(home, ".pi", "workflows", "projects");
|
|
10959
11645
|
}
|
|
10960
11646
|
async function workflowRunGroupId(filePath) {
|
|
10961
11647
|
try {
|
|
@@ -10975,7 +11661,7 @@ async function piBackfillFiles(sourceRoot, home = os9.homedir(), env) {
|
|
|
10975
11661
|
]);
|
|
10976
11662
|
const files = lists.flat().sort();
|
|
10977
11663
|
return Promise.all(files.map(async (filePath) => {
|
|
10978
|
-
const info = await
|
|
11664
|
+
const info = await stat12(filePath);
|
|
10979
11665
|
let groupId = resolvePiBackfillGroupId(filePath);
|
|
10980
11666
|
if (!groupId && filePath.endsWith(".json")) {
|
|
10981
11667
|
groupId = await workflowRunGroupId(filePath);
|
|
@@ -10997,12 +11683,12 @@ function createPiAdapter() {
|
|
|
10997
11683
|
return piAgentDir(home, env);
|
|
10998
11684
|
},
|
|
10999
11685
|
installedPath(home, env) {
|
|
11000
|
-
return
|
|
11686
|
+
return path18.join(piAgentDir(home, env), "extensions", "vibetime.ts");
|
|
11001
11687
|
},
|
|
11002
11688
|
async isInstalled(home, env) {
|
|
11003
11689
|
try {
|
|
11004
11690
|
const { pathExists: pathExists2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
11005
|
-
return await pathExists2(
|
|
11691
|
+
return await pathExists2(path18.join(piAgentDir(home, env), "extensions", "vibetime.ts"));
|
|
11006
11692
|
} catch {
|
|
11007
11693
|
return false;
|
|
11008
11694
|
}
|
|
@@ -11010,7 +11696,7 @@ function createPiAdapter() {
|
|
|
11010
11696
|
installEntries(home, env) {
|
|
11011
11697
|
return [{
|
|
11012
11698
|
kind: "file",
|
|
11013
|
-
path:
|
|
11699
|
+
path: path18.join(piAgentDir(home, env), "extensions", "vibetime.ts"),
|
|
11014
11700
|
content: piExtensionContent()
|
|
11015
11701
|
}];
|
|
11016
11702
|
},
|
|
@@ -11022,14 +11708,14 @@ function createPiAdapter() {
|
|
|
11022
11708
|
}
|
|
11023
11709
|
|
|
11024
11710
|
// src/adapters/qoder-cn.ts
|
|
11025
|
-
import { readdir as
|
|
11711
|
+
import { readdir as readdir10, readFile as readFile12, stat as stat13 } from "node:fs/promises";
|
|
11026
11712
|
import os11 from "node:os";
|
|
11027
|
-
import
|
|
11713
|
+
import path20 from "node:path";
|
|
11028
11714
|
|
|
11029
11715
|
// src/adapters/qoder-local-db.ts
|
|
11030
11716
|
import { access } from "node:fs/promises";
|
|
11031
11717
|
import os10 from "node:os";
|
|
11032
|
-
import
|
|
11718
|
+
import path19 from "node:path";
|
|
11033
11719
|
function takeQoderDbModelCall(calls, requestId, blockStart) {
|
|
11034
11720
|
if (requestId) {
|
|
11035
11721
|
const call = calls.byRequestId.get(requestId)?.shift();
|
|
@@ -11048,12 +11734,12 @@ function takeQoderDbModelCall(calls, requestId, blockStart) {
|
|
|
11048
11734
|
}
|
|
11049
11735
|
function appDataRoot(appDirName, home = os10.homedir()) {
|
|
11050
11736
|
if (process.platform === "darwin") {
|
|
11051
|
-
return
|
|
11737
|
+
return path19.join(home, "Library", "Application Support", appDirName);
|
|
11052
11738
|
}
|
|
11053
11739
|
if (process.platform === "win32") {
|
|
11054
|
-
return
|
|
11740
|
+
return path19.join(process.env.APPDATA || path19.join(home, "AppData", "Roaming"), appDirName);
|
|
11055
11741
|
}
|
|
11056
|
-
return
|
|
11742
|
+
return path19.join(home, ".config", appDirName);
|
|
11057
11743
|
}
|
|
11058
11744
|
function qoderLocalDbCandidates(appDirName) {
|
|
11059
11745
|
const candidates = [];
|
|
@@ -11063,8 +11749,8 @@ function qoderLocalDbCandidates(appDirName) {
|
|
|
11063
11749
|
}
|
|
11064
11750
|
const configRoot = appDataRoot(appDirName);
|
|
11065
11751
|
candidates.push(
|
|
11066
|
-
|
|
11067
|
-
|
|
11752
|
+
path19.join(configRoot, "SharedClientCache", "cache", "db", "local.db"),
|
|
11753
|
+
path19.join(configRoot, "SharedClientCache", "db", "local.db")
|
|
11068
11754
|
);
|
|
11069
11755
|
return candidates;
|
|
11070
11756
|
}
|
|
@@ -11073,7 +11759,7 @@ async function loadQoderIdeModelCatalog(appDirName, home) {
|
|
|
11073
11759
|
try {
|
|
11074
11760
|
const { DatabaseSync } = await import("node:sqlite");
|
|
11075
11761
|
const db = new DatabaseSync(
|
|
11076
|
-
|
|
11762
|
+
path19.join(appDataRoot(appDirName, home), "User", "globalStorage", "state.vscdb"),
|
|
11077
11763
|
{ readOnly: true }
|
|
11078
11764
|
);
|
|
11079
11765
|
try {
|
|
@@ -11215,7 +11901,7 @@ function resolveSessionPreferredModel(db, sessionId, modelMap) {
|
|
|
11215
11901
|
|
|
11216
11902
|
// src/adapters/qoder-cn.ts
|
|
11217
11903
|
function parseQoderCnPaths(filePath) {
|
|
11218
|
-
const parts = filePath.split(
|
|
11904
|
+
const parts = filePath.split(path20.sep);
|
|
11219
11905
|
const subagentsIdx = parts.lastIndexOf("subagents");
|
|
11220
11906
|
let sessionId = "";
|
|
11221
11907
|
let projectName = "";
|
|
@@ -11225,17 +11911,17 @@ function parseQoderCnPaths(filePath) {
|
|
|
11225
11911
|
sessionId = parts[subagentsIdx - 1];
|
|
11226
11912
|
projectName = parts[subagentsIdx - 2];
|
|
11227
11913
|
const projectsIdx = parts.lastIndexOf("projects");
|
|
11228
|
-
configDir2 = parts.slice(0, projectsIdx).join(
|
|
11229
|
-
mainTranscriptPath = [...parts.slice(0, subagentsIdx - 1), `${sessionId}.jsonl`].join(
|
|
11914
|
+
configDir2 = parts.slice(0, projectsIdx).join(path20.sep);
|
|
11915
|
+
mainTranscriptPath = [...parts.slice(0, subagentsIdx - 1), `${sessionId}.jsonl`].join(path20.sep);
|
|
11230
11916
|
} else {
|
|
11231
11917
|
const filename = parts.at(-1) || "";
|
|
11232
|
-
sessionId =
|
|
11918
|
+
sessionId = path20.basename(filename, ".jsonl");
|
|
11233
11919
|
projectName = parts.at(-2) || "";
|
|
11234
11920
|
if (projectName === "transcript") {
|
|
11235
11921
|
projectName = parts.at(-3) || "";
|
|
11236
11922
|
}
|
|
11237
11923
|
const projectsIdx = parts.lastIndexOf("projects");
|
|
11238
|
-
configDir2 = parts.slice(0, projectsIdx).join(
|
|
11924
|
+
configDir2 = parts.slice(0, projectsIdx).join(path20.sep);
|
|
11239
11925
|
}
|
|
11240
11926
|
return { configDir: configDir2, projectName, sessionId, mainTranscriptPath };
|
|
11241
11927
|
}
|
|
@@ -11274,19 +11960,25 @@ async function parseModelNamesFromDynamicTexts(dynamicTextsPath) {
|
|
|
11274
11960
|
}
|
|
11275
11961
|
}
|
|
11276
11962
|
async function loadQoderCnModelNames(configDir2, home) {
|
|
11277
|
-
const map =
|
|
11278
|
-
const
|
|
11279
|
-
|
|
11280
|
-
const
|
|
11281
|
-
for (const [key, val] of Object.entries(siblingMap)) {
|
|
11963
|
+
const map = {};
|
|
11964
|
+
for (const appDirName of ["QoderCN", "Qoder"]) {
|
|
11965
|
+
const ideMap = await loadQoderIdeModelCatalog(appDirName, home);
|
|
11966
|
+
for (const [key, val] of Object.entries(ideMap)) {
|
|
11282
11967
|
if (!(key in map)) {
|
|
11283
11968
|
map[key] = val;
|
|
11284
11969
|
}
|
|
11285
11970
|
}
|
|
11286
11971
|
}
|
|
11287
|
-
|
|
11288
|
-
|
|
11289
|
-
|
|
11972
|
+
const textsMap = await parseModelNamesFromDynamicTexts(path20.join(configDir2, ".auth", "dynamic-texts.json"));
|
|
11973
|
+
for (const [key, val] of Object.entries(textsMap)) {
|
|
11974
|
+
if (!(key in map)) {
|
|
11975
|
+
map[key] = val;
|
|
11976
|
+
}
|
|
11977
|
+
}
|
|
11978
|
+
const siblingConfigDir = configDir2.replace(/\.qoder-cn$/, ".qoder");
|
|
11979
|
+
if (siblingConfigDir !== configDir2) {
|
|
11980
|
+
const siblingMap = await parseModelNamesFromDynamicTexts(path20.join(siblingConfigDir, ".auth", "dynamic-texts.json"));
|
|
11981
|
+
for (const [key, val] of Object.entries(siblingMap)) {
|
|
11290
11982
|
if (!(key in map)) {
|
|
11291
11983
|
map[key] = val;
|
|
11292
11984
|
}
|
|
@@ -11296,15 +11988,15 @@ async function loadQoderCnModelNames(configDir2, home) {
|
|
|
11296
11988
|
}
|
|
11297
11989
|
async function loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMap) {
|
|
11298
11990
|
const { configDir: configDir2, projectName, sessionId } = parseQoderCnPaths(filePath);
|
|
11299
|
-
const segmentsPath =
|
|
11991
|
+
const segmentsPath = path20.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
|
|
11300
11992
|
const modelCalls = [];
|
|
11301
11993
|
try {
|
|
11302
|
-
const files = await
|
|
11994
|
+
const files = await readdir10(segmentsPath);
|
|
11303
11995
|
for (const file of files) {
|
|
11304
11996
|
if (!file.endsWith(".jsonl")) {
|
|
11305
11997
|
continue;
|
|
11306
11998
|
}
|
|
11307
|
-
const content = await readFile12(
|
|
11999
|
+
const content = await readFile12(path20.join(segmentsPath, file), "utf8");
|
|
11308
12000
|
let currentTurnIsSubagent = false;
|
|
11309
12001
|
for (const line of content.split("\n").filter(Boolean)) {
|
|
11310
12002
|
const raw = parseJsonLine(line);
|
|
@@ -11349,7 +12041,7 @@ async function parseQoderCnSessionFile(filePath, options) {
|
|
|
11349
12041
|
let cwd;
|
|
11350
12042
|
let project = projectContext.project;
|
|
11351
12043
|
let model;
|
|
11352
|
-
const home =
|
|
12044
|
+
const home = path20.resolve(stringOption(options.home) || os11.homedir());
|
|
11353
12045
|
const modelMap = await loadQoderCnModelNames(configDir2, home);
|
|
11354
12046
|
const isSubagentSession = filePath.includes("subagents");
|
|
11355
12047
|
const segmentModelCalls = await loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMap);
|
|
@@ -11384,7 +12076,7 @@ async function parseQoderCnSessionFile(filePath, options) {
|
|
|
11384
12076
|
sessionId = stringField(raw, "sessionId") || sessionId;
|
|
11385
12077
|
state.sessionId = sessionId;
|
|
11386
12078
|
cwd = stringField(raw, "cwd") || cwd;
|
|
11387
|
-
project = projectContext.project || (cwd ?
|
|
12079
|
+
project = projectContext.project || (cwd ? path20.basename(cwd) : project || await qoderCnProjectFromFilePath(filePath, options));
|
|
11388
12080
|
if (!ts) {
|
|
11389
12081
|
continue;
|
|
11390
12082
|
}
|
|
@@ -11720,7 +12412,7 @@ async function parseQoderCnSessionFile(filePath, options) {
|
|
|
11720
12412
|
}
|
|
11721
12413
|
dbModelCalls ??= await loadQoderDbModelCalls("QoderCN", parsedPaths.sessionId, modelMap);
|
|
11722
12414
|
if (dbModelCalls.rootSessionId) {
|
|
11723
|
-
const parentPath =
|
|
12415
|
+
const parentPath = path20.join(path20.dirname(filePath), `${dbModelCalls.rootSessionId}.jsonl`);
|
|
11724
12416
|
const parentSourcePathHash = `sha256:${createStableHash(parentPath)}`;
|
|
11725
12417
|
return withoutSubagentTurnEvents(validEvents).map((event) => rebuildEventIdentity3({
|
|
11726
12418
|
...event,
|
|
@@ -11873,28 +12565,28 @@ function extractQoderAttachedPrompt(content) {
|
|
|
11873
12565
|
}
|
|
11874
12566
|
async function qoderCnProjectContextFromLines(filePath, lines, options, configDir2) {
|
|
11875
12567
|
const { projectName: projectDir, sessionId } = parseQoderCnPaths(filePath);
|
|
11876
|
-
const isSubagent = filePath.includes(`${
|
|
12568
|
+
const isSubagent = filePath.includes(`${path20.sep}subagents${path20.sep}`);
|
|
11877
12569
|
const inherited = isSubagent ? await readPersistedSessionContextFromOptions(options, sessionId) : void 0;
|
|
11878
12570
|
let cwds = [];
|
|
11879
12571
|
for (const line of lines) {
|
|
11880
12572
|
const raw = parseJsonLine(line);
|
|
11881
12573
|
const cwd = raw ? stringField(raw, "cwd") : void 0;
|
|
11882
|
-
if (cwd &&
|
|
12574
|
+
if (cwd && path20.isAbsolute(cwd)) {
|
|
11883
12575
|
cwds.push(cwd);
|
|
11884
12576
|
}
|
|
11885
12577
|
}
|
|
11886
12578
|
if (isSubagent) {
|
|
11887
|
-
if (inherited?.cwd &&
|
|
12579
|
+
if (inherited?.cwd && path20.isAbsolute(inherited.cwd)) {
|
|
11888
12580
|
cwds = [inherited.cwd];
|
|
11889
12581
|
} else {
|
|
11890
|
-
const parentSessionPath =
|
|
12582
|
+
const parentSessionPath = path20.join(configDir2, "projects", projectDir, `${sessionId}.jsonl`);
|
|
11891
12583
|
try {
|
|
11892
12584
|
const parentText = await readFile12(parentSessionPath, "utf8");
|
|
11893
12585
|
const parentCwds = [];
|
|
11894
12586
|
for (const line of parentText.split("\n").filter(Boolean)) {
|
|
11895
12587
|
const raw = parseJsonLine(line);
|
|
11896
12588
|
const cwd = raw ? stringField(raw, "cwd") : void 0;
|
|
11897
|
-
if (cwd &&
|
|
12589
|
+
if (cwd && path20.isAbsolute(cwd)) {
|
|
11898
12590
|
parentCwds.push(cwd);
|
|
11899
12591
|
}
|
|
11900
12592
|
}
|
|
@@ -11906,7 +12598,7 @@ async function qoderCnProjectContextFromLines(filePath, lines, options, configDi
|
|
|
11906
12598
|
}
|
|
11907
12599
|
}
|
|
11908
12600
|
const root = await gitRootFromCwds2(cwds) || qoderCnProjectRootFromCwds(projectDir, cwds);
|
|
11909
|
-
const project = inherited?.project || (cwds.length > 0 ?
|
|
12601
|
+
const project = inherited?.project || (cwds.length > 0 ? path20.basename(cwds[0]) : root ? path20.basename(root) : await qoderCnProjectFromFilePath(filePath, options));
|
|
11910
12602
|
return {
|
|
11911
12603
|
project,
|
|
11912
12604
|
workspaceId: createWorkspaceId({ projectName: project, repoRoot: root })
|
|
@@ -11915,15 +12607,15 @@ async function qoderCnProjectContextFromLines(filePath, lines, options, configDi
|
|
|
11915
12607
|
async function gitRootFromCwds2(cwds) {
|
|
11916
12608
|
const seen = /* @__PURE__ */ new Set();
|
|
11917
12609
|
for (const cwd of cwds) {
|
|
11918
|
-
let current =
|
|
12610
|
+
let current = path20.resolve(cwd);
|
|
11919
12611
|
while (!seen.has(current)) {
|
|
11920
12612
|
seen.add(current);
|
|
11921
12613
|
try {
|
|
11922
|
-
await
|
|
12614
|
+
await stat13(path20.join(current, ".git"));
|
|
11923
12615
|
return current;
|
|
11924
12616
|
} catch {
|
|
11925
12617
|
}
|
|
11926
|
-
const parent =
|
|
12618
|
+
const parent = path20.dirname(current);
|
|
11927
12619
|
if (parent === current) {
|
|
11928
12620
|
break;
|
|
11929
12621
|
}
|
|
@@ -11934,12 +12626,12 @@ async function gitRootFromCwds2(cwds) {
|
|
|
11934
12626
|
}
|
|
11935
12627
|
function qoderCnProjectRootFromCwds(projectDir, cwds) {
|
|
11936
12628
|
for (const cwd of cwds) {
|
|
11937
|
-
let current =
|
|
12629
|
+
let current = path20.resolve(cwd);
|
|
11938
12630
|
while (true) {
|
|
11939
12631
|
if (encodeQoderCnProjectPath(current) === projectDir) {
|
|
11940
12632
|
return current;
|
|
11941
12633
|
}
|
|
11942
|
-
const parent =
|
|
12634
|
+
const parent = path20.dirname(current);
|
|
11943
12635
|
if (parent === current) {
|
|
11944
12636
|
break;
|
|
11945
12637
|
}
|
|
@@ -11949,14 +12641,14 @@ function qoderCnProjectRootFromCwds(projectDir, cwds) {
|
|
|
11949
12641
|
return void 0;
|
|
11950
12642
|
}
|
|
11951
12643
|
function encodeQoderCnProjectPath(value) {
|
|
11952
|
-
return
|
|
12644
|
+
return path20.resolve(value).split(path20.sep).join("-").replaceAll("_", "-");
|
|
11953
12645
|
}
|
|
11954
12646
|
async function qoderCnProjectFromFilePath(filePath, options) {
|
|
11955
|
-
const projectDir =
|
|
11956
|
-
const home = options ?
|
|
12647
|
+
const projectDir = path20.basename(path20.dirname(filePath));
|
|
12648
|
+
const home = options ? path20.resolve(stringOption(options.home) || os11.homedir()) : os11.homedir();
|
|
11957
12649
|
const resolved = await resolveQoderCnProjectPath(projectDir, home);
|
|
11958
12650
|
if (resolved) {
|
|
11959
|
-
return
|
|
12651
|
+
return path20.basename(resolved);
|
|
11960
12652
|
}
|
|
11961
12653
|
const homePrefix = `${encodeQoderCnProjectPath(home)}-`;
|
|
11962
12654
|
if (projectDir.startsWith(homePrefix)) {
|
|
@@ -11976,12 +12668,12 @@ async function resolveQoderCnProjectPath(projectDir, home) {
|
|
|
11976
12668
|
while (projectDir.startsWith(`${currentEncoded}-`)) {
|
|
11977
12669
|
let matchedChild;
|
|
11978
12670
|
try {
|
|
11979
|
-
const entries = await
|
|
12671
|
+
const entries = await readdir10(current, { withFileTypes: true });
|
|
11980
12672
|
for (const entry of entries) {
|
|
11981
12673
|
if (!entry.isDirectory()) {
|
|
11982
12674
|
continue;
|
|
11983
12675
|
}
|
|
11984
|
-
const candidate =
|
|
12676
|
+
const candidate = path20.join(current, entry.name);
|
|
11985
12677
|
const encoded = encodeQoderCnProjectPath(candidate);
|
|
11986
12678
|
if (encoded === projectDir) {
|
|
11987
12679
|
return candidate;
|
|
@@ -12026,9 +12718,9 @@ function hookConfig6() {
|
|
|
12026
12718
|
function qoderCnConfigDir(home, env) {
|
|
12027
12719
|
const override = env?.QODER_CN_CONFIG_DIR;
|
|
12028
12720
|
if (override && override.trim()) {
|
|
12029
|
-
return
|
|
12721
|
+
return path20.resolve(override);
|
|
12030
12722
|
}
|
|
12031
|
-
return
|
|
12723
|
+
return path20.join(home, ".qoder-cn");
|
|
12032
12724
|
}
|
|
12033
12725
|
function createQoderCnAdapter() {
|
|
12034
12726
|
return {
|
|
@@ -12040,27 +12732,27 @@ function createQoderCnAdapter() {
|
|
|
12040
12732
|
return qoderCnConfigDir(home, env);
|
|
12041
12733
|
},
|
|
12042
12734
|
installedPath(home, env) {
|
|
12043
|
-
return
|
|
12735
|
+
return path20.join(qoderCnConfigDir(home, env), "settings.json");
|
|
12044
12736
|
},
|
|
12045
12737
|
async isInstalled(home, env) {
|
|
12046
12738
|
return isHooksJsonInstalled(
|
|
12047
|
-
|
|
12739
|
+
path20.join(qoderCnConfigDir(home, env), "settings.json"),
|
|
12048
12740
|
"vibetime hook --agent qoder-cn"
|
|
12049
12741
|
);
|
|
12050
12742
|
},
|
|
12051
12743
|
installEntries(home, env) {
|
|
12052
12744
|
return [{
|
|
12053
12745
|
kind: "hooks-json",
|
|
12054
|
-
path:
|
|
12746
|
+
path: path20.join(qoderCnConfigDir(home, env), "settings.json"),
|
|
12055
12747
|
content: hookConfig6()
|
|
12056
12748
|
}];
|
|
12057
12749
|
},
|
|
12058
12750
|
sourcePaths(home, env) {
|
|
12059
12751
|
const base = qoderCnConfigDir(home, env);
|
|
12060
12752
|
return [
|
|
12061
|
-
|
|
12062
|
-
|
|
12063
|
-
|
|
12753
|
+
path20.join(base, "projects"),
|
|
12754
|
+
path20.join(base, ".qoder.json"),
|
|
12755
|
+
path20.join(home, ".qoder.json")
|
|
12064
12756
|
];
|
|
12065
12757
|
},
|
|
12066
12758
|
parseSessionFile: parseQoderCnSessionFile
|
|
@@ -12069,11 +12761,11 @@ function createQoderCnAdapter() {
|
|
|
12069
12761
|
|
|
12070
12762
|
// src/adapters/qoder.ts
|
|
12071
12763
|
import { existsSync } from "node:fs";
|
|
12072
|
-
import { readdir as
|
|
12764
|
+
import { readdir as readdir11, readFile as readFile13, stat as stat14 } from "node:fs/promises";
|
|
12073
12765
|
import os12 from "node:os";
|
|
12074
|
-
import
|
|
12766
|
+
import path21 from "node:path";
|
|
12075
12767
|
function parseQoderPaths(filePath) {
|
|
12076
|
-
const parts = filePath.split(
|
|
12768
|
+
const parts = filePath.split(path21.sep);
|
|
12077
12769
|
const subagentsIdx = parts.lastIndexOf("subagents");
|
|
12078
12770
|
let sessionId = "";
|
|
12079
12771
|
let projectName = "";
|
|
@@ -12083,17 +12775,17 @@ function parseQoderPaths(filePath) {
|
|
|
12083
12775
|
sessionId = parts[subagentsIdx - 1];
|
|
12084
12776
|
projectName = parts[subagentsIdx - 2];
|
|
12085
12777
|
const projectsIdx = parts.lastIndexOf("projects");
|
|
12086
|
-
configDir2 = parts.slice(0, projectsIdx).join(
|
|
12087
|
-
mainTranscriptPath = [...parts.slice(0, subagentsIdx - 1), `${sessionId}.jsonl`].join(
|
|
12778
|
+
configDir2 = parts.slice(0, projectsIdx).join(path21.sep);
|
|
12779
|
+
mainTranscriptPath = [...parts.slice(0, subagentsIdx - 1), `${sessionId}.jsonl`].join(path21.sep);
|
|
12088
12780
|
} else {
|
|
12089
12781
|
const filename = parts.at(-1) || "";
|
|
12090
|
-
sessionId =
|
|
12782
|
+
sessionId = path21.basename(filename, ".jsonl");
|
|
12091
12783
|
projectName = parts.at(-2) || "";
|
|
12092
12784
|
if (projectName === "transcript") {
|
|
12093
12785
|
projectName = parts.at(-3) || "";
|
|
12094
12786
|
}
|
|
12095
12787
|
const projectsIdx = parts.lastIndexOf("projects");
|
|
12096
|
-
configDir2 = parts.slice(0, projectsIdx).join(
|
|
12788
|
+
configDir2 = parts.slice(0, projectsIdx).join(path21.sep);
|
|
12097
12789
|
}
|
|
12098
12790
|
return { configDir: configDir2, projectName, sessionId, mainTranscriptPath };
|
|
12099
12791
|
}
|
|
@@ -12132,10 +12824,24 @@ async function parseModelNamesFromDynamicTexts2(dynamicTextsPath) {
|
|
|
12132
12824
|
}
|
|
12133
12825
|
}
|
|
12134
12826
|
async function loadQoderModelNames(configDir2, home) {
|
|
12135
|
-
const map =
|
|
12827
|
+
const map = {};
|
|
12828
|
+
for (const appDirName of ["Qoder", "QoderCN"]) {
|
|
12829
|
+
const ideMap = await loadQoderIdeModelCatalog(appDirName, home);
|
|
12830
|
+
for (const [key, val] of Object.entries(ideMap)) {
|
|
12831
|
+
if (!(key in map)) {
|
|
12832
|
+
map[key] = val;
|
|
12833
|
+
}
|
|
12834
|
+
}
|
|
12835
|
+
}
|
|
12836
|
+
const textsMap = await parseModelNamesFromDynamicTexts2(path21.join(configDir2, ".auth", "dynamic-texts.json"));
|
|
12837
|
+
for (const [key, val] of Object.entries(textsMap)) {
|
|
12838
|
+
if (!(key in map)) {
|
|
12839
|
+
map[key] = val;
|
|
12840
|
+
}
|
|
12841
|
+
}
|
|
12136
12842
|
const siblingConfigDir = configDir2.replace(/\.qoder$/, ".qoder-cn");
|
|
12137
12843
|
if (siblingConfigDir !== configDir2) {
|
|
12138
|
-
const siblingMap = await parseModelNamesFromDynamicTexts2(
|
|
12844
|
+
const siblingMap = await parseModelNamesFromDynamicTexts2(path21.join(siblingConfigDir, ".auth", "dynamic-texts.json"));
|
|
12139
12845
|
for (const [key, val] of Object.entries(siblingMap)) {
|
|
12140
12846
|
if (!(key in map)) {
|
|
12141
12847
|
map[key] = val;
|
|
@@ -12143,11 +12849,11 @@ async function loadQoderModelNames(configDir2, home) {
|
|
|
12143
12849
|
}
|
|
12144
12850
|
}
|
|
12145
12851
|
if (isQwenworkConfigRoot(configDir2)) {
|
|
12146
|
-
for (const dir of [
|
|
12147
|
-
if (
|
|
12852
|
+
for (const dir of [path21.join(home, ".qoder"), path21.join(home, ".qoder-cn")]) {
|
|
12853
|
+
if (path21.resolve(dir) === path21.resolve(configDir2)) {
|
|
12148
12854
|
continue;
|
|
12149
12855
|
}
|
|
12150
|
-
const fallbackMap = await parseModelNamesFromDynamicTexts2(
|
|
12856
|
+
const fallbackMap = await parseModelNamesFromDynamicTexts2(path21.join(dir, ".auth", "dynamic-texts.json"));
|
|
12151
12857
|
for (const [key, val] of Object.entries(fallbackMap)) {
|
|
12152
12858
|
if (!(key in map)) {
|
|
12153
12859
|
map[key] = val;
|
|
@@ -12155,36 +12861,28 @@ async function loadQoderModelNames(configDir2, home) {
|
|
|
12155
12861
|
}
|
|
12156
12862
|
}
|
|
12157
12863
|
}
|
|
12158
|
-
for (const appDirName of ["Qoder", "QoderCN"]) {
|
|
12159
|
-
const ideMap = await loadQoderIdeModelCatalog(appDirName, home);
|
|
12160
|
-
for (const [key, val] of Object.entries(ideMap)) {
|
|
12161
|
-
if (!(key in map)) {
|
|
12162
|
-
map[key] = val;
|
|
12163
|
-
}
|
|
12164
|
-
}
|
|
12165
|
-
}
|
|
12166
12864
|
return map;
|
|
12167
12865
|
}
|
|
12168
12866
|
function isQwenworkConfigRoot(configDir2) {
|
|
12169
|
-
const name =
|
|
12867
|
+
const name = path21.basename(path21.resolve(configDir2));
|
|
12170
12868
|
if (name === ".qwenworkcn" || name === ".qwenwork") {
|
|
12171
12869
|
return true;
|
|
12172
12870
|
}
|
|
12173
12871
|
const override = process.env.QWENWORK_CONFIG_DIR;
|
|
12174
|
-
return Boolean(override && override.trim() &&
|
|
12872
|
+
return Boolean(override && override.trim() && path21.basename(path21.resolve(override)) === name);
|
|
12175
12873
|
}
|
|
12176
12874
|
var FAILED_SEGMENT_STOP_REASONS = /* @__PURE__ */ new Set(["cancelled", "canceled", "error", "failed", "refusal"]);
|
|
12177
12875
|
async function loadQoderSegmentModelCalls(filePath, isSubagentSession, modelMap) {
|
|
12178
12876
|
const { configDir: configDir2, projectName, sessionId } = parseQoderPaths(filePath);
|
|
12179
|
-
const segmentsPath =
|
|
12877
|
+
const segmentsPath = path21.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
|
|
12180
12878
|
const modelCalls = [];
|
|
12181
12879
|
try {
|
|
12182
|
-
const files = await
|
|
12880
|
+
const files = await readdir11(segmentsPath);
|
|
12183
12881
|
for (const file of files) {
|
|
12184
12882
|
if (!file.endsWith(".jsonl")) {
|
|
12185
12883
|
continue;
|
|
12186
12884
|
}
|
|
12187
|
-
const content = await readFile13(
|
|
12885
|
+
const content = await readFile13(path21.join(segmentsPath, file), "utf8");
|
|
12188
12886
|
let currentTurnIsSubagent = false;
|
|
12189
12887
|
for (const line of content.split("\n").filter(Boolean)) {
|
|
12190
12888
|
const raw = parseJsonLine(line);
|
|
@@ -12229,7 +12927,7 @@ async function parseQoderSessionFile(filePath, options) {
|
|
|
12229
12927
|
let cwd;
|
|
12230
12928
|
let project = projectContext.project;
|
|
12231
12929
|
let model;
|
|
12232
|
-
const home =
|
|
12930
|
+
const home = path21.resolve(stringOption(options.home) || os12.homedir());
|
|
12233
12931
|
const modelMap = await loadQoderModelNames(configDir2, home);
|
|
12234
12932
|
const qwenworkRoot = isQwenworkConfigRoot(configDir2);
|
|
12235
12933
|
const isSubagentSession = filePath.includes("subagents");
|
|
@@ -12265,7 +12963,7 @@ async function parseQoderSessionFile(filePath, options) {
|
|
|
12265
12963
|
sessionId = stringField(raw, "sessionId") || sessionId;
|
|
12266
12964
|
state.sessionId = sessionId;
|
|
12267
12965
|
cwd = stringField(raw, "cwd") || cwd;
|
|
12268
|
-
project = projectContext.project || (cwd ?
|
|
12966
|
+
project = projectContext.project || (cwd ? path21.basename(cwd) : project || await qoderProjectFromFilePath(filePath, options));
|
|
12269
12967
|
if (!ts) {
|
|
12270
12968
|
continue;
|
|
12271
12969
|
}
|
|
@@ -12576,7 +13274,7 @@ async function parseQoderSessionFile(filePath, options) {
|
|
|
12576
13274
|
}
|
|
12577
13275
|
dbModelCalls ??= await loadQoderDbModelCalls("Qoder", parsedPaths.sessionId, modelMap);
|
|
12578
13276
|
if (dbModelCalls.rootSessionId) {
|
|
12579
|
-
const parentPath =
|
|
13277
|
+
const parentPath = path21.join(path21.dirname(filePath), `${dbModelCalls.rootSessionId}.jsonl`);
|
|
12580
13278
|
const parentSourcePathHash = `sha256:${createStableHash(parentPath)}`;
|
|
12581
13279
|
return withoutSubagentTurnEvents(validEvents).map((event) => rebuildEventIdentity4({
|
|
12582
13280
|
...event,
|
|
@@ -12693,41 +13391,41 @@ function qoderExtractText(value) {
|
|
|
12693
13391
|
}
|
|
12694
13392
|
async function qoderProjectContextFromLines(filePath, lines, options, configDir2) {
|
|
12695
13393
|
const { projectName: projectDir, sessionId } = parseQoderPaths(filePath);
|
|
12696
|
-
const isSubagent = filePath.includes(`${
|
|
13394
|
+
const isSubagent = filePath.includes(`${path21.sep}subagents${path21.sep}`);
|
|
12697
13395
|
const inherited = isSubagent ? await readPersistedSessionContextFromOptions(options, sessionId) : void 0;
|
|
12698
13396
|
let cwds = [];
|
|
12699
13397
|
const workspaceDirs = [];
|
|
12700
13398
|
for (const line of lines) {
|
|
12701
13399
|
const raw = parseJsonLine(line);
|
|
12702
13400
|
const cwd = raw ? stringField(raw, "cwd") : void 0;
|
|
12703
|
-
if (cwd &&
|
|
13401
|
+
if (cwd && path21.isAbsolute(cwd)) {
|
|
12704
13402
|
cwds.push(cwd);
|
|
12705
13403
|
}
|
|
12706
13404
|
if (raw && stringField(raw, "type") === "workspace-directories") {
|
|
12707
13405
|
for (const dir of arrayField5(raw, "directories")) {
|
|
12708
|
-
if (typeof dir === "string" &&
|
|
13406
|
+
if (typeof dir === "string" && path21.isAbsolute(dir)) {
|
|
12709
13407
|
workspaceDirs.push(dir);
|
|
12710
13408
|
}
|
|
12711
13409
|
}
|
|
12712
13410
|
}
|
|
12713
13411
|
}
|
|
12714
13412
|
if (isSubagent) {
|
|
12715
|
-
if (inherited?.cwd &&
|
|
13413
|
+
if (inherited?.cwd && path21.isAbsolute(inherited.cwd)) {
|
|
12716
13414
|
cwds = [inherited.cwd];
|
|
12717
13415
|
} else {
|
|
12718
|
-
const parentSessionPath =
|
|
13416
|
+
const parentSessionPath = path21.join(configDir2, "projects", projectDir, `${sessionId}.jsonl`);
|
|
12719
13417
|
try {
|
|
12720
13418
|
const parentText = await readFile13(parentSessionPath, "utf8");
|
|
12721
13419
|
const parentCwds = [];
|
|
12722
13420
|
for (const line of parentText.split("\n").filter(Boolean)) {
|
|
12723
13421
|
const raw = parseJsonLine(line);
|
|
12724
13422
|
const cwd = raw ? stringField(raw, "cwd") : void 0;
|
|
12725
|
-
if (cwd &&
|
|
13423
|
+
if (cwd && path21.isAbsolute(cwd)) {
|
|
12726
13424
|
parentCwds.push(cwd);
|
|
12727
13425
|
}
|
|
12728
13426
|
if (workspaceDirs.length === 0 && raw && stringField(raw, "type") === "workspace-directories") {
|
|
12729
13427
|
for (const dir of arrayField5(raw, "directories")) {
|
|
12730
|
-
if (typeof dir === "string" &&
|
|
13428
|
+
if (typeof dir === "string" && path21.isAbsolute(dir)) {
|
|
12731
13429
|
workspaceDirs.push(dir);
|
|
12732
13430
|
}
|
|
12733
13431
|
}
|
|
@@ -12747,29 +13445,29 @@ async function qoderProjectContextFromLines(filePath, lines, options, configDir2
|
|
|
12747
13445
|
}
|
|
12748
13446
|
}
|
|
12749
13447
|
const root = await gitRootFromCwds3(cwds) || qoderProjectRootFromCwds(projectDir, cwds);
|
|
12750
|
-
const project = inherited?.project || (cwds.length > 0 ?
|
|
13448
|
+
const project = inherited?.project || (cwds.length > 0 ? path21.basename(cwds[0]) : root ? path21.basename(root) : await qoderProjectFromFilePath(filePath, options));
|
|
12751
13449
|
return {
|
|
12752
13450
|
project,
|
|
12753
13451
|
workspaceId: createWorkspaceId({ projectName: project, repoRoot: root })
|
|
12754
13452
|
};
|
|
12755
13453
|
}
|
|
12756
13454
|
function pathInsideDir(candidate, dir) {
|
|
12757
|
-
const resolvedDir =
|
|
12758
|
-
const resolved =
|
|
12759
|
-
return resolved === resolvedDir || resolved.startsWith(`${resolvedDir}${
|
|
13455
|
+
const resolvedDir = path21.resolve(dir);
|
|
13456
|
+
const resolved = path21.resolve(candidate);
|
|
13457
|
+
return resolved === resolvedDir || resolved.startsWith(`${resolvedDir}${path21.sep}`);
|
|
12760
13458
|
}
|
|
12761
13459
|
async function gitRootFromCwds3(cwds) {
|
|
12762
13460
|
const seen = /* @__PURE__ */ new Set();
|
|
12763
13461
|
for (const cwd of cwds) {
|
|
12764
|
-
let current =
|
|
13462
|
+
let current = path21.resolve(cwd);
|
|
12765
13463
|
while (!seen.has(current)) {
|
|
12766
13464
|
seen.add(current);
|
|
12767
13465
|
try {
|
|
12768
|
-
await
|
|
13466
|
+
await stat14(path21.join(current, ".git"));
|
|
12769
13467
|
return current;
|
|
12770
13468
|
} catch {
|
|
12771
13469
|
}
|
|
12772
|
-
const parent =
|
|
13470
|
+
const parent = path21.dirname(current);
|
|
12773
13471
|
if (parent === current) {
|
|
12774
13472
|
break;
|
|
12775
13473
|
}
|
|
@@ -12780,12 +13478,12 @@ async function gitRootFromCwds3(cwds) {
|
|
|
12780
13478
|
}
|
|
12781
13479
|
function qoderProjectRootFromCwds(projectDir, cwds) {
|
|
12782
13480
|
for (const cwd of cwds) {
|
|
12783
|
-
let current =
|
|
13481
|
+
let current = path21.resolve(cwd);
|
|
12784
13482
|
while (true) {
|
|
12785
13483
|
if (qoderEncodedVariants(current).includes(projectDir)) {
|
|
12786
13484
|
return current;
|
|
12787
13485
|
}
|
|
12788
|
-
const parent =
|
|
13486
|
+
const parent = path21.dirname(current);
|
|
12789
13487
|
if (parent === current) {
|
|
12790
13488
|
break;
|
|
12791
13489
|
}
|
|
@@ -12795,7 +13493,7 @@ function qoderProjectRootFromCwds(projectDir, cwds) {
|
|
|
12795
13493
|
return void 0;
|
|
12796
13494
|
}
|
|
12797
13495
|
function rawQoderProjectPath(value) {
|
|
12798
|
-
return
|
|
13496
|
+
return path21.resolve(value).split(path21.sep).join("-");
|
|
12799
13497
|
}
|
|
12800
13498
|
function qoderEncodedVariants(value) {
|
|
12801
13499
|
const raw = rawQoderProjectPath(value);
|
|
@@ -12816,11 +13514,11 @@ function qoderEncodedProjectSuffix(projectDir, home) {
|
|
|
12816
13514
|
return void 0;
|
|
12817
13515
|
}
|
|
12818
13516
|
async function qoderProjectFromFilePath(filePath, options) {
|
|
12819
|
-
const projectDir =
|
|
12820
|
-
const home = options ?
|
|
13517
|
+
const projectDir = path21.basename(path21.dirname(filePath));
|
|
13518
|
+
const home = options ? path21.resolve(stringOption(options.home) || os12.homedir()) : os12.homedir();
|
|
12821
13519
|
const resolved = await resolveQoderProjectPath(projectDir, home);
|
|
12822
13520
|
if (resolved) {
|
|
12823
|
-
return
|
|
13521
|
+
return path21.basename(resolved);
|
|
12824
13522
|
}
|
|
12825
13523
|
const suffix = qoderEncodedProjectSuffix(projectDir, home);
|
|
12826
13524
|
if (suffix) {
|
|
@@ -12841,12 +13539,12 @@ async function resolveQoderProjectPath(projectDir, home) {
|
|
|
12841
13539
|
while (currentEncodedVariants.some((prefix) => projectDir.startsWith(`${prefix}-`))) {
|
|
12842
13540
|
let matchedChild;
|
|
12843
13541
|
try {
|
|
12844
|
-
const entries = await
|
|
13542
|
+
const entries = await readdir11(current, { withFileTypes: true });
|
|
12845
13543
|
for (const entry of entries) {
|
|
12846
13544
|
if (!entry.isDirectory()) {
|
|
12847
13545
|
continue;
|
|
12848
13546
|
}
|
|
12849
|
-
const candidate =
|
|
13547
|
+
const candidate = path21.join(current, entry.name);
|
|
12850
13548
|
const candidateVariants = qoderEncodedVariants(candidate);
|
|
12851
13549
|
if (candidateVariants.includes(projectDir)) {
|
|
12852
13550
|
return candidate;
|
|
@@ -12891,19 +13589,19 @@ function hookConfig7() {
|
|
|
12891
13589
|
function qoderConfigDir(home, env) {
|
|
12892
13590
|
const override = env?.QODER_CONFIG_DIR;
|
|
12893
13591
|
if (override && override.trim()) {
|
|
12894
|
-
return
|
|
13592
|
+
return path21.resolve(override);
|
|
12895
13593
|
}
|
|
12896
|
-
return
|
|
13594
|
+
return path21.join(home, ".qoder");
|
|
12897
13595
|
}
|
|
12898
13596
|
function qwenworkConfigDir(home, env) {
|
|
12899
13597
|
const override = env?.QWENWORK_CONFIG_DIR;
|
|
12900
13598
|
if (override && override.trim()) {
|
|
12901
|
-
return
|
|
13599
|
+
return path21.resolve(override);
|
|
12902
13600
|
}
|
|
12903
|
-
return
|
|
13601
|
+
return path21.join(home, ".qwenworkcn");
|
|
12904
13602
|
}
|
|
12905
13603
|
function qoderConfigDirs(home, env) {
|
|
12906
|
-
return [...new Set([qoderConfigDir(home, env), qwenworkConfigDir(home, env)].map((dir) =>
|
|
13604
|
+
return [...new Set([qoderConfigDir(home, env), qwenworkConfigDir(home, env)].map((dir) => path21.resolve(dir)))];
|
|
12907
13605
|
}
|
|
12908
13606
|
function createQoderAdapter() {
|
|
12909
13607
|
return {
|
|
@@ -12915,11 +13613,11 @@ function createQoderAdapter() {
|
|
|
12915
13613
|
return qoderConfigDir(home, env);
|
|
12916
13614
|
},
|
|
12917
13615
|
installedPath(home, env) {
|
|
12918
|
-
return
|
|
13616
|
+
return path21.join(qoderConfigDir(home, env), "settings.json");
|
|
12919
13617
|
},
|
|
12920
13618
|
async isInstalled(home, env) {
|
|
12921
13619
|
return isHooksJsonInstalled(
|
|
12922
|
-
|
|
13620
|
+
path21.join(qoderConfigDir(home, env), "settings.json"),
|
|
12923
13621
|
"vibetime hook --agent qoder"
|
|
12924
13622
|
);
|
|
12925
13623
|
},
|
|
@@ -12928,16 +13626,16 @@ function createQoderAdapter() {
|
|
|
12928
13626
|
const targets = [primary, ...variants.filter((dir) => existsSync(dir))];
|
|
12929
13627
|
return targets.map((base) => ({
|
|
12930
13628
|
kind: "hooks-json",
|
|
12931
|
-
path:
|
|
13629
|
+
path: path21.join(base, "settings.json"),
|
|
12932
13630
|
content: hookConfig7()
|
|
12933
13631
|
}));
|
|
12934
13632
|
},
|
|
12935
13633
|
sourcePaths(home, env) {
|
|
12936
|
-
const paths = qoderConfigDirs(home, env).map((base2) =>
|
|
13634
|
+
const paths = qoderConfigDirs(home, env).map((base2) => path21.join(base2, "projects"));
|
|
12937
13635
|
const base = qoderConfigDir(home, env);
|
|
12938
13636
|
paths.push(
|
|
12939
|
-
|
|
12940
|
-
|
|
13637
|
+
path21.join(base, ".qoder.json"),
|
|
13638
|
+
path21.join(home, ".qoder.json")
|
|
12941
13639
|
);
|
|
12942
13640
|
return paths;
|
|
12943
13641
|
},
|
|
@@ -12973,35 +13671,35 @@ function normalizeId(id) {
|
|
|
12973
13671
|
}
|
|
12974
13672
|
|
|
12975
13673
|
// src/adapters/workbuddy.ts
|
|
12976
|
-
import { readdir as
|
|
12977
|
-
import
|
|
13674
|
+
import { readdir as readdir12, readFile as readFile14, stat as stat15 } from "node:fs/promises";
|
|
13675
|
+
import path22 from "node:path";
|
|
12978
13676
|
function workbuddyProjectsDir(home, env) {
|
|
12979
13677
|
const override = env?.WORKBUDDY_PROJECTS_DIR || env?.WORKBUDDY_HOME;
|
|
12980
13678
|
if (override && override.trim()) {
|
|
12981
|
-
return
|
|
13679
|
+
return path22.resolve(override, override.endsWith("projects") ? "" : "projects");
|
|
12982
13680
|
}
|
|
12983
|
-
return
|
|
13681
|
+
return path22.join(home, ".workbuddy", "projects");
|
|
12984
13682
|
}
|
|
12985
13683
|
function workbuddyBaseDir(home, env) {
|
|
12986
13684
|
const override = env?.WORKBUDDY_HOME;
|
|
12987
13685
|
if (override && override.trim()) {
|
|
12988
|
-
return
|
|
13686
|
+
return path22.resolve(override);
|
|
12989
13687
|
}
|
|
12990
|
-
return
|
|
13688
|
+
return path22.join(home, ".workbuddy");
|
|
12991
13689
|
}
|
|
12992
|
-
function
|
|
13690
|
+
function projectFromCwd2(cwd, fallback) {
|
|
12993
13691
|
if (!cwd) {
|
|
12994
13692
|
return fallback;
|
|
12995
13693
|
}
|
|
12996
|
-
return
|
|
13694
|
+
return path22.basename(cwd) || fallback;
|
|
12997
13695
|
}
|
|
12998
|
-
function
|
|
13696
|
+
function sourceHash2(filePath) {
|
|
12999
13697
|
return `sha256:${createStableHash(filePath)}`;
|
|
13000
13698
|
}
|
|
13001
|
-
function
|
|
13699
|
+
function makeEvent2(event, line, filePath, options) {
|
|
13002
13700
|
const withRefs = withBackfillRefs(event, {
|
|
13003
13701
|
filePath,
|
|
13004
|
-
sourcePathHash:
|
|
13702
|
+
sourcePathHash: sourceHash2(filePath),
|
|
13005
13703
|
lineNumber: line.lineNumber,
|
|
13006
13704
|
topType: stringField(line.record, "type"),
|
|
13007
13705
|
payloadType: stringField(line.record, "role") || stringField(line.record, "name"),
|
|
@@ -13081,7 +13779,7 @@ function isHiddenUserMessage(record) {
|
|
|
13081
13779
|
return providerData.skipRun === true || providerData.isMeta === true || providerData.isCompactInternal === true || providerData.isCompact === true || providerData.isTeammateMessage === true || (stringField(providerData, "agentPurpose") || "").toLowerCase().includes("compact");
|
|
13082
13780
|
}
|
|
13083
13781
|
function workbuddySubagentRefs(lines) {
|
|
13084
|
-
const
|
|
13782
|
+
const refs3 = {};
|
|
13085
13783
|
const keys = [
|
|
13086
13784
|
["parentSessionId", ["parent_session_id", "parentSessionId"]],
|
|
13087
13785
|
["parentToolCallId", ["parent_tool_call_id", "parentToolCallId"]],
|
|
@@ -13091,19 +13789,19 @@ function workbuddySubagentRefs(lines) {
|
|
|
13091
13789
|
for (const line of lines) {
|
|
13092
13790
|
const providerData = objectField(line.record, "providerData");
|
|
13093
13791
|
for (const [ref, aliases] of keys) {
|
|
13094
|
-
if (
|
|
13792
|
+
if (refs3[ref]) {
|
|
13095
13793
|
continue;
|
|
13096
13794
|
}
|
|
13097
13795
|
for (const alias of aliases) {
|
|
13098
13796
|
const value = stringField(line.record, alias) || stringField(providerData, alias);
|
|
13099
13797
|
if (value) {
|
|
13100
|
-
|
|
13798
|
+
refs3[ref] = value;
|
|
13101
13799
|
break;
|
|
13102
13800
|
}
|
|
13103
13801
|
}
|
|
13104
13802
|
}
|
|
13105
13803
|
}
|
|
13106
|
-
return
|
|
13804
|
+
return refs3;
|
|
13107
13805
|
}
|
|
13108
13806
|
function toolCallFailed(record) {
|
|
13109
13807
|
const providerData = objectField(record, "providerData");
|
|
@@ -13131,10 +13829,10 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
13131
13829
|
}
|
|
13132
13830
|
const events = [];
|
|
13133
13831
|
const first = lines[0].record;
|
|
13134
|
-
const sessionId = stringField(first, "sessionId") ||
|
|
13135
|
-
const fallbackProject =
|
|
13832
|
+
const sessionId = stringField(first, "sessionId") || path22.basename(filePath, ".jsonl");
|
|
13833
|
+
const fallbackProject = path22.basename(path22.dirname(filePath));
|
|
13136
13834
|
const cwd = lines.map((line) => stringField(line.record, "cwd")).find(Boolean);
|
|
13137
|
-
const project =
|
|
13835
|
+
const project = projectFromCwd2(cwd, fallbackProject);
|
|
13138
13836
|
const workspaceId = createWorkspaceId({ projectName: project, repoRoot: cwd });
|
|
13139
13837
|
const sessionPrefix = `workbuddy:${sessionId}`;
|
|
13140
13838
|
const toolStarts = /* @__PURE__ */ new Map();
|
|
@@ -13149,7 +13847,7 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
13149
13847
|
return void 0;
|
|
13150
13848
|
}
|
|
13151
13849
|
const failed = turnLastAssistantStatus !== void 0 && ["incomplete", "failed", "cancelled"].includes(turnLastAssistantStatus);
|
|
13152
|
-
return
|
|
13850
|
+
return makeEvent2({
|
|
13153
13851
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13154
13852
|
ts: turnLastTs,
|
|
13155
13853
|
type: failed ? "turn.failed" : "turn.completed",
|
|
@@ -13166,7 +13864,7 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
13166
13864
|
};
|
|
13167
13865
|
const firstTs = lines.map((line) => timestampFrom(numberField(line.record, "timestamp"))).find(Boolean);
|
|
13168
13866
|
if (firstTs) {
|
|
13169
|
-
const event =
|
|
13867
|
+
const event = makeEvent2({
|
|
13170
13868
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13171
13869
|
ts: firstTs,
|
|
13172
13870
|
type: "session.started",
|
|
@@ -13206,7 +13904,7 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
13206
13904
|
turnLastAssistantStatus = void 0;
|
|
13207
13905
|
const promptChars = contentLength(record.content);
|
|
13208
13906
|
for (const event of [
|
|
13209
|
-
|
|
13907
|
+
makeEvent2({
|
|
13210
13908
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13211
13909
|
ts,
|
|
13212
13910
|
type: "turn.started",
|
|
@@ -13220,7 +13918,7 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
13220
13918
|
confidence: "derived",
|
|
13221
13919
|
refs: { sourceId: `${sourceId}:turn` }
|
|
13222
13920
|
}, line, filePath, options),
|
|
13223
|
-
|
|
13921
|
+
makeEvent2({
|
|
13224
13922
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13225
13923
|
ts,
|
|
13226
13924
|
type: "prompt.submitted",
|
|
@@ -13249,7 +13947,7 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
13249
13947
|
const metrics = workbuddyUsageMetrics(record);
|
|
13250
13948
|
if (metrics) {
|
|
13251
13949
|
const model = stringField(objectField(record, "providerData"), "model");
|
|
13252
|
-
const usage =
|
|
13950
|
+
const usage = makeEvent2({
|
|
13253
13951
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13254
13952
|
ts,
|
|
13255
13953
|
type: "model.usage",
|
|
@@ -13278,7 +13976,7 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
13278
13976
|
const callId = stringField(record, "callId");
|
|
13279
13977
|
if (tool && callId) {
|
|
13280
13978
|
toolStarts.set(`${sessionId}:${callId}`, { line, ts, tool, callId });
|
|
13281
|
-
const started =
|
|
13979
|
+
const started = makeEvent2({
|
|
13282
13980
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13283
13981
|
ts,
|
|
13284
13982
|
type: "tool.started",
|
|
@@ -13306,7 +14004,7 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
13306
14004
|
if (isPlainObject(toolInput)) {
|
|
13307
14005
|
const fileActivities = claudeStyleToolFileActivities(tool, toolInput, ts, cwd);
|
|
13308
14006
|
if (fileActivities.length > 0) {
|
|
13309
|
-
const fileEvent =
|
|
14007
|
+
const fileEvent = makeEvent2({
|
|
13310
14008
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13311
14009
|
ts,
|
|
13312
14010
|
type: eventTypeFromFileActivities(fileActivities),
|
|
@@ -13332,7 +14030,7 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
13332
14030
|
const metrics = workbuddyUsageMetrics(record);
|
|
13333
14031
|
const model = stringField(objectField(record, "providerData"), "model");
|
|
13334
14032
|
if (metrics || model) {
|
|
13335
|
-
const usage =
|
|
14033
|
+
const usage = makeEvent2({
|
|
13336
14034
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13337
14035
|
ts,
|
|
13338
14036
|
type: "model.usage",
|
|
@@ -13361,7 +14059,7 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
13361
14059
|
const start = toolStarts.get(`${sessionId}:${callId}`);
|
|
13362
14060
|
const durationMs = start?.ts ? Math.max(0, Date.parse(ts) - Date.parse(start.ts)) : void 0;
|
|
13363
14061
|
const failed = toolCallFailed(record);
|
|
13364
|
-
const completed =
|
|
14062
|
+
const completed = makeEvent2({
|
|
13365
14063
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13366
14064
|
ts,
|
|
13367
14065
|
type: failed ? "tool.failed" : "tool.completed",
|
|
@@ -13393,7 +14091,7 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
13393
14091
|
}
|
|
13394
14092
|
const lastTs = lastLine ? timestampFrom(numberField(lastLine.record, "timestamp")) : void 0;
|
|
13395
14093
|
if (lastLine && lastTs) {
|
|
13396
|
-
const event =
|
|
14094
|
+
const event = makeEvent2({
|
|
13397
14095
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13398
14096
|
ts: lastTs,
|
|
13399
14097
|
type: "session.ended",
|
|
@@ -13416,17 +14114,17 @@ async function workbuddyBackfillFiles(sourceRoot, home, env) {
|
|
|
13416
14114
|
const base = sourceRoot || workbuddyProjectsDir(home, env);
|
|
13417
14115
|
const files = [];
|
|
13418
14116
|
try {
|
|
13419
|
-
const projects = await
|
|
14117
|
+
const projects = await readdir12(base, { withFileTypes: true });
|
|
13420
14118
|
for (const project of projects) {
|
|
13421
14119
|
if (!project.isDirectory()) {
|
|
13422
14120
|
continue;
|
|
13423
14121
|
}
|
|
13424
|
-
const projectDir =
|
|
13425
|
-
const entries = await
|
|
14122
|
+
const projectDir = path22.join(base, project.name);
|
|
14123
|
+
const entries = await readdir12(projectDir, { withFileTypes: true });
|
|
13426
14124
|
for (const entry of entries) {
|
|
13427
14125
|
if (entry.isFile() && entry.name.endsWith(".jsonl")) {
|
|
13428
|
-
const filePath =
|
|
13429
|
-
const info = await
|
|
14126
|
+
const filePath = path22.join(projectDir, entry.name);
|
|
14127
|
+
const info = await stat15(filePath);
|
|
13430
14128
|
files.push({ path: filePath, modifiedAt: info.mtime.toISOString() });
|
|
13431
14129
|
}
|
|
13432
14130
|
}
|
|
@@ -13463,18 +14161,18 @@ function createWorkbuddyAdapter() {
|
|
|
13463
14161
|
return workbuddyProjectsDir(home, env);
|
|
13464
14162
|
},
|
|
13465
14163
|
installedPath(home, env) {
|
|
13466
|
-
return
|
|
14164
|
+
return path22.join(workbuddyBaseDir(home, env), "settings.json");
|
|
13467
14165
|
},
|
|
13468
14166
|
async isInstalled(home, env) {
|
|
13469
14167
|
return isHooksJsonInstalled(
|
|
13470
|
-
|
|
14168
|
+
path22.join(workbuddyBaseDir(home, env), "settings.json"),
|
|
13471
14169
|
"vibetime hook --agent workbuddy"
|
|
13472
14170
|
);
|
|
13473
14171
|
},
|
|
13474
14172
|
installEntries(home, env) {
|
|
13475
14173
|
return [{
|
|
13476
14174
|
kind: "hooks-json",
|
|
13477
|
-
path:
|
|
14175
|
+
path: path22.join(workbuddyBaseDir(home, env), "settings.json"),
|
|
13478
14176
|
content: hookConfig8()
|
|
13479
14177
|
}];
|
|
13480
14178
|
},
|
|
@@ -13487,22 +14185,22 @@ function createWorkbuddyAdapter() {
|
|
|
13487
14185
|
|
|
13488
14186
|
// src/adapters/zcode.ts
|
|
13489
14187
|
import { execFile } from "node:child_process";
|
|
13490
|
-
import { readFile as readFile15, stat as
|
|
13491
|
-
import
|
|
14188
|
+
import { readFile as readFile15, stat as stat16 } from "node:fs/promises";
|
|
14189
|
+
import path23 from "node:path";
|
|
13492
14190
|
import { promisify as promisify2 } from "node:util";
|
|
13493
14191
|
var execFileAsync = promisify2(execFile);
|
|
13494
14192
|
function zcodeCliDir(home, env) {
|
|
13495
14193
|
const override = env?.ZCODE_CLI_DIR || env?.ZCODE_HOME;
|
|
13496
14194
|
if (override && override.trim()) {
|
|
13497
|
-
return
|
|
14195
|
+
return path23.resolve(override, override.endsWith("cli") ? "" : "cli");
|
|
13498
14196
|
}
|
|
13499
|
-
return
|
|
14197
|
+
return path23.join(home, ".zcode", "cli");
|
|
13500
14198
|
}
|
|
13501
14199
|
function zcodeDbPath(home, env) {
|
|
13502
|
-
return
|
|
14200
|
+
return path23.join(zcodeCliDir(home, env), "db", "db.sqlite");
|
|
13503
14201
|
}
|
|
13504
14202
|
function zcodeConfigPath(home, env) {
|
|
13505
|
-
return
|
|
14203
|
+
return path23.join(zcodeCliDir(home, env), "config.json");
|
|
13506
14204
|
}
|
|
13507
14205
|
var zcodeHandler = (msg) => hookHandler("zcode", msg);
|
|
13508
14206
|
function hookConfig9() {
|
|
@@ -13526,7 +14224,7 @@ var providerNameCache = null;
|
|
|
13526
14224
|
async function loadProviderNames(configPath2) {
|
|
13527
14225
|
let fileMtime = 0;
|
|
13528
14226
|
try {
|
|
13529
|
-
const info = await
|
|
14227
|
+
const info = await stat16(configPath2);
|
|
13530
14228
|
fileMtime = info.mtimeMs;
|
|
13531
14229
|
} catch {
|
|
13532
14230
|
return /* @__PURE__ */ new Map();
|
|
@@ -13550,19 +14248,19 @@ async function loadProviderNames(configPath2) {
|
|
|
13550
14248
|
providerNameCache = { path: configPath2, mtimeMs: fileMtime, map };
|
|
13551
14249
|
return map;
|
|
13552
14250
|
}
|
|
13553
|
-
function
|
|
14251
|
+
function sourceHash3(filePath) {
|
|
13554
14252
|
return `sha256:${createStableHash(filePath)}`;
|
|
13555
14253
|
}
|
|
13556
14254
|
function projectFromDirectory(directory) {
|
|
13557
|
-
return directory ?
|
|
14255
|
+
return directory ? path23.basename(directory) || "zcode" : "zcode";
|
|
13558
14256
|
}
|
|
13559
14257
|
function isoFromMs(value) {
|
|
13560
14258
|
return timestampFrom(typeof value === "number" ? value : Number(value));
|
|
13561
14259
|
}
|
|
13562
|
-
function
|
|
14260
|
+
function makeEvent3(event, row, rowNumber, filePath, options) {
|
|
13563
14261
|
const withRefs = withBackfillRefs(event, {
|
|
13564
14262
|
filePath,
|
|
13565
|
-
sourcePathHash:
|
|
14263
|
+
sourcePathHash: sourceHash3(filePath),
|
|
13566
14264
|
lineNumber: rowNumber,
|
|
13567
14265
|
topType: row.kind,
|
|
13568
14266
|
payloadType: stringField(row, "status") || stringField(row, "query_source") || stringField(row, "tool_name"),
|
|
@@ -13570,7 +14268,7 @@ function makeEvent2(event, row, rowNumber, filePath, options) {
|
|
|
13570
14268
|
});
|
|
13571
14269
|
return validateCanonicalEvent(withRefs).valid ? withRefs : void 0;
|
|
13572
14270
|
}
|
|
13573
|
-
function
|
|
14271
|
+
function refs2(values) {
|
|
13574
14272
|
const out = {};
|
|
13575
14273
|
for (const [key, value] of Object.entries(values)) {
|
|
13576
14274
|
if (value !== void 0 && value !== "") {
|
|
@@ -13727,7 +14425,7 @@ function resolveRootSessionId2(sessionId, sessions) {
|
|
|
13727
14425
|
}
|
|
13728
14426
|
return current;
|
|
13729
14427
|
}
|
|
13730
|
-
function
|
|
14428
|
+
function sessionContext2(row, sessions) {
|
|
13731
14429
|
const sessionId = stringField(row, "session_id") || stringField(row, "id") || "unknown";
|
|
13732
14430
|
const session = sessions.get(sessionId);
|
|
13733
14431
|
const cwd = stringField(session, "directory");
|
|
@@ -13749,16 +14447,16 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13749
14447
|
if (rows.length === 0) {
|
|
13750
14448
|
return [];
|
|
13751
14449
|
}
|
|
13752
|
-
let candidate =
|
|
14450
|
+
let candidate = path23.resolve(filePath);
|
|
13753
14451
|
let configPath2 = "";
|
|
13754
14452
|
for (let i = 0; i < 12; i++) {
|
|
13755
|
-
const probe =
|
|
14453
|
+
const probe = path23.join(candidate, ".zcode", "v2", "config.json");
|
|
13756
14454
|
try {
|
|
13757
|
-
await
|
|
14455
|
+
await stat16(probe);
|
|
13758
14456
|
configPath2 = probe;
|
|
13759
14457
|
break;
|
|
13760
14458
|
} catch {
|
|
13761
|
-
const parent =
|
|
14459
|
+
const parent = path23.dirname(candidate);
|
|
13762
14460
|
if (parent === candidate) break;
|
|
13763
14461
|
candidate = parent;
|
|
13764
14462
|
}
|
|
@@ -13782,8 +14480,8 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13782
14480
|
if (!id || !ts) {
|
|
13783
14481
|
return;
|
|
13784
14482
|
}
|
|
13785
|
-
const ctx =
|
|
13786
|
-
const event =
|
|
14483
|
+
const ctx = sessionContext2(row, sessions);
|
|
14484
|
+
const event = makeEvent3({
|
|
13787
14485
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13788
14486
|
ts,
|
|
13789
14487
|
type: "session.started",
|
|
@@ -13795,7 +14493,7 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13795
14493
|
parentAgentInstanceId: ctx.parentSessionId,
|
|
13796
14494
|
agent: "zcode",
|
|
13797
14495
|
confidence: "exact",
|
|
13798
|
-
refs:
|
|
14496
|
+
refs: refs2({
|
|
13799
14497
|
sourceId: `${id}:session`,
|
|
13800
14498
|
zcodeTaskType: stringField(row, "task_type"),
|
|
13801
14499
|
zcodeTitleHash: stringField(row, "title") ? `sha256:${createStableHash(stringField(row, "title"))}` : void 0
|
|
@@ -13807,7 +14505,7 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13807
14505
|
const linesAdded = numberField(row, "summary_additions");
|
|
13808
14506
|
const linesRemoved = numberField(row, "summary_deletions");
|
|
13809
14507
|
const filesChanged = numberField(row, "summary_files");
|
|
13810
|
-
const completed =
|
|
14508
|
+
const completed = makeEvent3({
|
|
13811
14509
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13812
14510
|
ts: completedTs,
|
|
13813
14511
|
type: "session.ended",
|
|
@@ -13832,12 +14530,12 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13832
14530
|
if (!rawTurnId || !ts) {
|
|
13833
14531
|
return;
|
|
13834
14532
|
}
|
|
13835
|
-
const ctx =
|
|
14533
|
+
const ctx = sessionContext2(row, sessions);
|
|
13836
14534
|
if (ctx.isSubagent) {
|
|
13837
14535
|
return;
|
|
13838
14536
|
}
|
|
13839
14537
|
const turnId = `zcode:${rawTurnId}`;
|
|
13840
|
-
const started =
|
|
14538
|
+
const started = makeEvent3({
|
|
13841
14539
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13842
14540
|
ts,
|
|
13843
14541
|
type: "turn.started",
|
|
@@ -13855,7 +14553,7 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13855
14553
|
const completedTs = isoFromMs(numberField(row, "completed_at"));
|
|
13856
14554
|
if (completedTs) {
|
|
13857
14555
|
const status = stringField(row, "status");
|
|
13858
|
-
const completed =
|
|
14556
|
+
const completed = makeEvent3({
|
|
13859
14557
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13860
14558
|
ts: completedTs,
|
|
13861
14559
|
type: "turn.completed",
|
|
@@ -13874,7 +14572,7 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13874
14572
|
toolCalls: numberField(row, "tool_call_count")
|
|
13875
14573
|
},
|
|
13876
14574
|
confidence: "exact",
|
|
13877
|
-
refs:
|
|
14575
|
+
refs: refs2({ sourceId: `${rawTurnId}:completed`, zcodeStatus: status })
|
|
13878
14576
|
}, row, rowNumber, filePath, options);
|
|
13879
14577
|
if (completed) events.push(completed);
|
|
13880
14578
|
}
|
|
@@ -13885,9 +14583,9 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13885
14583
|
if (!ts) {
|
|
13886
14584
|
return;
|
|
13887
14585
|
}
|
|
13888
|
-
const ctx =
|
|
14586
|
+
const ctx = sessionContext2(row, sessions);
|
|
13889
14587
|
const modelId = stringField(row, "model_id");
|
|
13890
|
-
const usage =
|
|
14588
|
+
const usage = makeEvent3({
|
|
13891
14589
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13892
14590
|
ts,
|
|
13893
14591
|
type: "model.usage",
|
|
@@ -13904,7 +14602,7 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13904
14602
|
success: stringField(row, "status") === "completed",
|
|
13905
14603
|
metrics: modelMetrics(row),
|
|
13906
14604
|
confidence: "exact",
|
|
13907
|
-
refs:
|
|
14605
|
+
refs: refs2({
|
|
13908
14606
|
sourceId: stringField(row, "id") || `${ctx.rawSessionId}:model:${rowNumber}`,
|
|
13909
14607
|
zcodeQuerySource: stringField(row, "query_source"),
|
|
13910
14608
|
zcodeMode: stringField(row, "mode"),
|
|
@@ -13925,10 +14623,10 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13925
14623
|
if (!startedTs) {
|
|
13926
14624
|
return;
|
|
13927
14625
|
}
|
|
13928
|
-
const ctx =
|
|
14626
|
+
const ctx = sessionContext2(row, sessions);
|
|
13929
14627
|
const turnId = !ctx.isSubagent && stringField(row, "turn_id") ? `zcode:${stringField(row, "turn_id")}` : void 0;
|
|
13930
14628
|
const spanId = `${ctx.sessionId}:tool:${toolCallId}`;
|
|
13931
|
-
const started =
|
|
14629
|
+
const started = makeEvent3({
|
|
13932
14630
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13933
14631
|
ts: startedTs,
|
|
13934
14632
|
type: "tool.started",
|
|
@@ -13942,7 +14640,7 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13942
14640
|
agent: "zcode",
|
|
13943
14641
|
tool,
|
|
13944
14642
|
confidence: "exact",
|
|
13945
|
-
refs:
|
|
14643
|
+
refs: refs2({
|
|
13946
14644
|
sourceId: `${toolCallId}:start`,
|
|
13947
14645
|
zcodeSideEffectScope: stringField(row, "side_effect_scope"),
|
|
13948
14646
|
zcodeApprovalStatus: stringField(row, "approval_status")
|
|
@@ -13951,7 +14649,7 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13951
14649
|
if (started) events.push(started);
|
|
13952
14650
|
if (completedTs) {
|
|
13953
14651
|
const status = stringField(row, "status");
|
|
13954
|
-
const completed =
|
|
14652
|
+
const completed = makeEvent3({
|
|
13955
14653
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13956
14654
|
ts: completedTs,
|
|
13957
14655
|
type: status === "completed" ? "tool.completed" : "tool.failed",
|
|
@@ -13971,7 +14669,7 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13971
14669
|
bytesRead: numberField(row, "output_bytes")
|
|
13972
14670
|
},
|
|
13973
14671
|
confidence: "exact",
|
|
13974
|
-
refs:
|
|
14672
|
+
refs: refs2({
|
|
13975
14673
|
sourceId: `${toolCallId}:completed`,
|
|
13976
14674
|
zcodeStatus: status,
|
|
13977
14675
|
zcodeExitCode: numberField(row, "exit_code"),
|
|
@@ -13986,13 +14684,13 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13986
14684
|
}
|
|
13987
14685
|
async function zcodeBackfillFiles(sourceRoot, home, env) {
|
|
13988
14686
|
const candidate = sourceRoot || zcodeDbPath(home, env);
|
|
13989
|
-
const filePath = candidate.endsWith(".sqlite") ? candidate :
|
|
14687
|
+
const filePath = candidate.endsWith(".sqlite") ? candidate : path23.join(candidate, "db", "db.sqlite");
|
|
13990
14688
|
try {
|
|
13991
|
-
const info = await
|
|
14689
|
+
const info = await stat16(filePath);
|
|
13992
14690
|
let modifiedMs = info.mtimeMs;
|
|
13993
14691
|
for (const suffix of ["-wal", "-shm"]) {
|
|
13994
14692
|
try {
|
|
13995
|
-
const sidecar = await
|
|
14693
|
+
const sidecar = await stat16(`${filePath}${suffix}`);
|
|
13996
14694
|
modifiedMs = Math.max(modifiedMs, sidecar.mtimeMs);
|
|
13997
14695
|
} catch {
|
|
13998
14696
|
}
|
|
@@ -14036,49 +14734,49 @@ function createZCodeAdapter() {
|
|
|
14036
14734
|
|
|
14037
14735
|
// src/adapters/zed.ts
|
|
14038
14736
|
import os13 from "node:os";
|
|
14039
|
-
import
|
|
14737
|
+
import path24 from "node:path";
|
|
14040
14738
|
function zedThreadsCandidates(home, env) {
|
|
14041
14739
|
const candidates = [];
|
|
14042
14740
|
const platform2 = process.platform;
|
|
14043
14741
|
if (platform2 === "darwin") {
|
|
14044
|
-
candidates.push(
|
|
14742
|
+
candidates.push(path24.join(home, "Library", "Application Support", "Zed", "threads", "threads.db"));
|
|
14045
14743
|
} else if (platform2 === "win32") {
|
|
14046
14744
|
const appdata = env?.APPDATA;
|
|
14047
14745
|
if (appdata && appdata.trim()) {
|
|
14048
|
-
candidates.push(
|
|
14746
|
+
candidates.push(path24.join(path24.resolve(appdata), "Zed", "threads", "threads.db"));
|
|
14049
14747
|
}
|
|
14050
|
-
candidates.push(
|
|
14748
|
+
candidates.push(path24.join(home, "AppData", "Roaming", "Zed", "threads", "threads.db"));
|
|
14051
14749
|
} else {
|
|
14052
14750
|
const xdgData = env?.XDG_DATA_HOME;
|
|
14053
14751
|
if (xdgData && xdgData.trim()) {
|
|
14054
|
-
candidates.push(
|
|
14752
|
+
candidates.push(path24.join(path24.resolve(xdgData), "zed", "threads", "threads.db"));
|
|
14055
14753
|
}
|
|
14056
|
-
candidates.push(
|
|
14754
|
+
candidates.push(path24.join(home, ".local", "share", "zed", "threads", "threads.db"));
|
|
14057
14755
|
const xdgConfig = env?.XDG_CONFIG_HOME;
|
|
14058
14756
|
if (xdgConfig && xdgConfig.trim()) {
|
|
14059
|
-
candidates.push(
|
|
14757
|
+
candidates.push(path24.join(path24.resolve(xdgConfig), "zed", "threads", "threads.db"));
|
|
14060
14758
|
}
|
|
14061
|
-
candidates.push(
|
|
14759
|
+
candidates.push(path24.join(home, ".config", "zed", "threads", "threads.db"));
|
|
14062
14760
|
}
|
|
14063
14761
|
return candidates;
|
|
14064
14762
|
}
|
|
14065
14763
|
function zedConfigDir(home, env) {
|
|
14066
14764
|
const platform2 = process.platform;
|
|
14067
14765
|
if (platform2 === "darwin") {
|
|
14068
|
-
return
|
|
14766
|
+
return path24.join(home, "Library", "Application Support", "Zed");
|
|
14069
14767
|
}
|
|
14070
14768
|
if (platform2 === "win32") {
|
|
14071
14769
|
const appdata = env?.APPDATA;
|
|
14072
14770
|
if (appdata && appdata.trim()) {
|
|
14073
|
-
return
|
|
14771
|
+
return path24.join(path24.resolve(appdata), "Zed");
|
|
14074
14772
|
}
|
|
14075
|
-
return
|
|
14773
|
+
return path24.join(home, "AppData", "Roaming", "Zed");
|
|
14076
14774
|
}
|
|
14077
14775
|
const xdgConfig = env?.XDG_CONFIG_HOME;
|
|
14078
14776
|
if (xdgConfig && xdgConfig.trim()) {
|
|
14079
|
-
return
|
|
14777
|
+
return path24.join(path24.resolve(xdgConfig), "zed");
|
|
14080
14778
|
}
|
|
14081
|
-
return
|
|
14779
|
+
return path24.join(home, ".config", "zed");
|
|
14082
14780
|
}
|
|
14083
14781
|
function baseZedEvent(event) {
|
|
14084
14782
|
return {
|
|
@@ -14142,7 +14840,7 @@ async function parseZedSessionFile(dbPath, options) {
|
|
|
14142
14840
|
const folderRaw = row.folder_paths || "";
|
|
14143
14841
|
const folder = folderRaw.split(/[\n,]/).map((s) => s.trim()).find(Boolean);
|
|
14144
14842
|
const cwd = folder || void 0;
|
|
14145
|
-
const project = cwd ?
|
|
14843
|
+
const project = cwd ? path24.basename(cwd) : row.summary ? row.summary.slice(0, 40) : void 0;
|
|
14146
14844
|
let json;
|
|
14147
14845
|
try {
|
|
14148
14846
|
const bytes = row.data_type === "zstd" ? decompress2(new Uint8Array(row.data)) : new Uint8Array(row.data);
|
|
@@ -14388,19 +15086,19 @@ async function parseZedSessionFile(dbPath, options) {
|
|
|
14388
15086
|
return events.filter((event) => matchesBackfillFilters(event, options));
|
|
14389
15087
|
}
|
|
14390
15088
|
async function zedBackfillFiles(sourceRoot, home = os13.homedir(), env) {
|
|
14391
|
-
const { stat:
|
|
15089
|
+
const { stat: stat19 } = await import("node:fs/promises");
|
|
14392
15090
|
if (sourceRoot) {
|
|
14393
15091
|
if (!sourceRoot.endsWith(".db")) {
|
|
14394
15092
|
return [];
|
|
14395
15093
|
}
|
|
14396
|
-
const info = await
|
|
15094
|
+
const info = await stat19(sourceRoot).catch(() => null);
|
|
14397
15095
|
if (!info) {
|
|
14398
15096
|
return [];
|
|
14399
15097
|
}
|
|
14400
15098
|
return [{ path: sourceRoot, modifiedAt: info.mtime.toISOString() }];
|
|
14401
15099
|
}
|
|
14402
15100
|
for (const candidatePath of zedThreadsCandidates(home, env)) {
|
|
14403
|
-
const info = await
|
|
15101
|
+
const info = await stat19(candidatePath).catch(() => null);
|
|
14404
15102
|
if (info) {
|
|
14405
15103
|
return [{ path: candidatePath, modifiedAt: info.mtime.toISOString() }];
|
|
14406
15104
|
}
|
|
@@ -14417,7 +15115,7 @@ function createZedAdapter() {
|
|
|
14417
15115
|
return zedConfigDir(home, env);
|
|
14418
15116
|
},
|
|
14419
15117
|
installedPath(home, env) {
|
|
14420
|
-
return
|
|
15118
|
+
return path24.join(zedConfigDir(home, env), "vibetime-marker");
|
|
14421
15119
|
},
|
|
14422
15120
|
async isInstalled() {
|
|
14423
15121
|
return false;
|
|
@@ -15232,19 +15930,19 @@ async function uninstallGeneratedFile(filePath, { dryRun, onWrite }) {
|
|
|
15232
15930
|
import { randomUUID } from "node:crypto";
|
|
15233
15931
|
import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, rmSync, writeFileSync } from "node:fs";
|
|
15234
15932
|
import { homedir, hostname } from "node:os";
|
|
15235
|
-
import
|
|
15933
|
+
import path25 from "node:path";
|
|
15236
15934
|
function disabledBackfillSourceSet(config) {
|
|
15237
15935
|
const list = Array.isArray(config.disabledSources) ? config.disabledSources : [];
|
|
15238
15936
|
return new Set(list.map((id) => String(id).trim()).filter(Boolean));
|
|
15239
15937
|
}
|
|
15240
15938
|
function configDir(home = homedir()) {
|
|
15241
|
-
return
|
|
15939
|
+
return path25.join(home, ".vibetime");
|
|
15242
15940
|
}
|
|
15243
15941
|
function configPath(home = homedir()) {
|
|
15244
|
-
return
|
|
15942
|
+
return path25.join(configDir(home), "config.json");
|
|
15245
15943
|
}
|
|
15246
15944
|
function machineIdPath(home = homedir()) {
|
|
15247
|
-
return
|
|
15945
|
+
return path25.join(configDir(home), "machine-id");
|
|
15248
15946
|
}
|
|
15249
15947
|
function readConfig(home = homedir()) {
|
|
15250
15948
|
const file = configPath(home);
|
|
@@ -15291,15 +15989,15 @@ function defaultMachineName() {
|
|
|
15291
15989
|
init_fs();
|
|
15292
15990
|
|
|
15293
15991
|
// src/lib/logger.ts
|
|
15294
|
-
import { appendFile, mkdir as mkdir5, rename as rename2, stat as
|
|
15992
|
+
import { appendFile, mkdir as mkdir5, rename as rename2, stat as stat17 } from "node:fs/promises";
|
|
15295
15993
|
import { homedir as homedir2 } from "node:os";
|
|
15296
|
-
import
|
|
15994
|
+
import path26 from "node:path";
|
|
15297
15995
|
var MAX_BYTES = 1 * 1024 * 1024;
|
|
15298
15996
|
function logDir(home = homedir2()) {
|
|
15299
|
-
return
|
|
15997
|
+
return path26.join(home, ".vibetime", "logs");
|
|
15300
15998
|
}
|
|
15301
15999
|
function logPath(home = homedir2(), name = "cli.log") {
|
|
15302
|
-
return
|
|
16000
|
+
return path26.join(logDir(home), name);
|
|
15303
16001
|
}
|
|
15304
16002
|
function serializeError(error) {
|
|
15305
16003
|
if (error instanceof Error) {
|
|
@@ -15309,7 +16007,7 @@ function serializeError(error) {
|
|
|
15309
16007
|
}
|
|
15310
16008
|
async function rotateIfNeeded(file) {
|
|
15311
16009
|
try {
|
|
15312
|
-
const info = await
|
|
16010
|
+
const info = await stat17(file);
|
|
15313
16011
|
if (info.size > MAX_BYTES) {
|
|
15314
16012
|
await rename2(file, `${file}.1`).catch(() => {
|
|
15315
16013
|
});
|
|
@@ -15474,8 +16172,8 @@ function buildHeaders(token, machine) {
|
|
|
15474
16172
|
...machine?.platform ? { "x-machine-platform": machine.platform } : {}
|
|
15475
16173
|
};
|
|
15476
16174
|
}
|
|
15477
|
-
function joinUrl(base,
|
|
15478
|
-
return new URL(
|
|
16175
|
+
function joinUrl(base, path28) {
|
|
16176
|
+
return new URL(path28, base.endsWith("/") ? base : `${base}/`).toString();
|
|
15479
16177
|
}
|
|
15480
16178
|
async function postRollupBatch(remote, rollups, options = {}) {
|
|
15481
16179
|
const response = await remote.fetchImpl(joinUrl(remote.baseUrl, "/v3/agent/ingest"), {
|
|
@@ -15567,6 +16265,7 @@ function createRegistry() {
|
|
|
15567
16265
|
registry.register(createKimiCodeAdapter());
|
|
15568
16266
|
registry.register(createCursorAdapter());
|
|
15569
16267
|
registry.register(createGrokBotAdapter());
|
|
16268
|
+
registry.register(createHermesAdapter());
|
|
15570
16269
|
return registry;
|
|
15571
16270
|
}
|
|
15572
16271
|
var defaultContext = {
|
|
@@ -16131,6 +16830,9 @@ async function listBackfillSourceFiles(source, options, ctx) {
|
|
|
16131
16830
|
if (source.id === "grok-bot") {
|
|
16132
16831
|
return grokBotBackfillFiles(stringOption(options["source-root"]), resolveHome3(options, ctx), ctx.env, options);
|
|
16133
16832
|
}
|
|
16833
|
+
if (source.id === "hermes") {
|
|
16834
|
+
return hermesBackfillFiles(stringOption(options["source-root"]), resolveHome3(options, ctx), ctx.env);
|
|
16835
|
+
}
|
|
16134
16836
|
if (source.id === "pi") {
|
|
16135
16837
|
return piBackfillFiles(stringOption(options["source-root"]), resolveHome3(options, ctx), ctx.env);
|
|
16136
16838
|
}
|
|
@@ -16138,7 +16840,7 @@ async function listBackfillSourceFiles(source, options, ctx) {
|
|
|
16138
16840
|
const fileLists = await Promise.all(roots.map((r) => listJsonlFiles(r)));
|
|
16139
16841
|
const files = fileLists.flat().sort().slice(0, numberOption(options.limit) || void 0);
|
|
16140
16842
|
return Promise.all(files.map(async (filePath) => {
|
|
16141
|
-
const info = await
|
|
16843
|
+
const info = await stat18(filePath);
|
|
16142
16844
|
return { path: filePath, modifiedAt: info.mtime.toISOString() };
|
|
16143
16845
|
}));
|
|
16144
16846
|
}
|
|
@@ -16470,13 +17172,13 @@ function selectBackfillFilesForImport(files, watermarkTs) {
|
|
|
16470
17172
|
return picked;
|
|
16471
17173
|
}
|
|
16472
17174
|
function backfillIncrementalStatePath(home) {
|
|
16473
|
-
return
|
|
17175
|
+
return path27.join(home, ".vibetime", "backfill-state.json");
|
|
16474
17176
|
}
|
|
16475
17177
|
function syncLocalTriggerStatePath(home) {
|
|
16476
|
-
return
|
|
17178
|
+
return path27.join(home, ".vibetime", "sync-local-trigger.json");
|
|
16477
17179
|
}
|
|
16478
17180
|
function syncLocalTriggerLockPath(home) {
|
|
16479
|
-
return
|
|
17181
|
+
return path27.join(home, ".vibetime", "sync-local-trigger.lock");
|
|
16480
17182
|
}
|
|
16481
17183
|
function backfillRemoteKey(baseUrl) {
|
|
16482
17184
|
try {
|
|
@@ -16538,7 +17240,7 @@ async function readBackfillIncrementalStateFile(home, ctx) {
|
|
|
16538
17240
|
}
|
|
16539
17241
|
async function writeBackfillIncrementalStateFile(home, file) {
|
|
16540
17242
|
const statePath = backfillIncrementalStatePath(home);
|
|
16541
|
-
await mkdir6(
|
|
17243
|
+
await mkdir6(path27.dirname(statePath), { recursive: true });
|
|
16542
17244
|
await writeFile5(statePath, `${JSON.stringify(file, null, 2)}
|
|
16543
17245
|
`, "utf8");
|
|
16544
17246
|
}
|
|
@@ -16587,7 +17289,7 @@ async function readSyncLocalTriggerState(statePath) {
|
|
|
16587
17289
|
return nextState;
|
|
16588
17290
|
}
|
|
16589
17291
|
async function writeSyncLocalTriggerState(statePath, state) {
|
|
16590
|
-
await mkdir6(
|
|
17292
|
+
await mkdir6(path27.dirname(statePath), { recursive: true });
|
|
16591
17293
|
await writeFile5(statePath, `${JSON.stringify(state, null, 2)}
|
|
16592
17294
|
`, "utf8");
|
|
16593
17295
|
}
|
|
@@ -16602,12 +17304,12 @@ async function readSyncLocalLock(lockPath) {
|
|
|
16602
17304
|
return { pid: lock.pid, startedAt: lock.startedAt };
|
|
16603
17305
|
}
|
|
16604
17306
|
async function writeSyncLocalLock(lockPath, lock) {
|
|
16605
|
-
await mkdir6(
|
|
17307
|
+
await mkdir6(path27.dirname(lockPath), { recursive: true });
|
|
16606
17308
|
await writeFile5(lockPath, `${JSON.stringify(lock, null, 2)}
|
|
16607
17309
|
`, "utf8");
|
|
16608
17310
|
}
|
|
16609
17311
|
async function acquireSyncLocalLock(lockPath, lock) {
|
|
16610
|
-
await mkdir6(
|
|
17312
|
+
await mkdir6(path27.dirname(lockPath), { recursive: true });
|
|
16611
17313
|
try {
|
|
16612
17314
|
const handle = await open(lockPath, "wx");
|
|
16613
17315
|
try {
|
|
@@ -16687,10 +17389,10 @@ function syncLocalRunnerEntryArgs(cliPath) {
|
|
|
16687
17389
|
if (cliPath.endsWith(".ts")) {
|
|
16688
17390
|
return ["--import", "tsx", cliPath];
|
|
16689
17391
|
}
|
|
16690
|
-
return [
|
|
17392
|
+
return [path27.resolve(path27.dirname(cliPath), "../bin/vibetime.mjs")];
|
|
16691
17393
|
}
|
|
16692
17394
|
function resolveHome3(options, ctx) {
|
|
16693
|
-
return
|
|
17395
|
+
return path27.resolve(stringOption(options.home) || ctx.env.HOME || os14.homedir());
|
|
16694
17396
|
}
|
|
16695
17397
|
function requestedTargets(options) {
|
|
16696
17398
|
const value = options.target || options.targets;
|