@yhong91/vibetime 0.1.70 → 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 +969 -279
- package/package.json +1 -1
package/bin/vibetime.mjs
CHANGED
|
@@ -884,9 +884,9 @@ var init_esm = __esm({
|
|
|
884
884
|
|
|
885
885
|
// src/cli.ts
|
|
886
886
|
import { spawn as spawn2, spawnSync } from "node:child_process";
|
|
887
|
-
import { mkdir as mkdir6, open, rm, stat as
|
|
887
|
+
import { mkdir as mkdir6, open, rm, stat as stat18, writeFile as writeFile5 } from "node:fs/promises";
|
|
888
888
|
import os14 from "node:os";
|
|
889
|
-
import
|
|
889
|
+
import path27 from "node:path";
|
|
890
890
|
import { fileURLToPath } from "node:url";
|
|
891
891
|
|
|
892
892
|
// ../shared/src/index.ts
|
|
@@ -924,7 +924,7 @@ var TELEMETRY_EVENT_TYPES = [
|
|
|
924
924
|
"agent.operation"
|
|
925
925
|
];
|
|
926
926
|
var FILE_ACTIVITY_OPERATIONS = ["read", "search", "create", "write", "edit", "delete"];
|
|
927
|
-
var BACKFILL_SOURCE_IDS = ["codex", "claude-code", "claude-cowork", "copilot", "opencode", "pi", "agy", "codebuddy", "qoder", "qoder-cn", "workbuddy", "zcode", "grok-build", "zed", "kimi-code", "cursor", "grok-bot"];
|
|
927
|
+
var BACKFILL_SOURCE_IDS = ["codex", "claude-code", "claude-cowork", "copilot", "opencode", "pi", "agy", "codebuddy", "qoder", "qoder-cn", "workbuddy", "zcode", "grok-build", "zed", "kimi-code", "cursor", "grok-bot", "hermes"];
|
|
928
928
|
function createWorkspaceId(input) {
|
|
929
929
|
const basis = input.repoUrl || input.repoRoot || input.projectName || "unknown";
|
|
930
930
|
return `workspace_${fnv1a(basis)}`;
|
|
@@ -1082,9 +1082,9 @@ function removeVolatileHashFields(value) {
|
|
|
1082
1082
|
continue;
|
|
1083
1083
|
}
|
|
1084
1084
|
if (key === "refs" && isRecord(item)) {
|
|
1085
|
-
const
|
|
1086
|
-
delete
|
|
1087
|
-
result[key] = removeVolatileHashFields(
|
|
1085
|
+
const refs3 = { ...item };
|
|
1086
|
+
delete refs3.payloadHash;
|
|
1087
|
+
result[key] = removeVolatileHashFields(refs3);
|
|
1088
1088
|
continue;
|
|
1089
1089
|
}
|
|
1090
1090
|
result[key] = removeVolatileHashFields(item);
|
|
@@ -1747,13 +1747,13 @@ function isPlainObject(value) {
|
|
|
1747
1747
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
1748
1748
|
}
|
|
1749
1749
|
function stringRefs(value) {
|
|
1750
|
-
const
|
|
1750
|
+
const refs3 = {};
|
|
1751
1751
|
for (const [key, item] of Object.entries(value || {})) {
|
|
1752
1752
|
if (typeof item === "string" && item.length > 0) {
|
|
1753
|
-
|
|
1753
|
+
refs3[key] = item;
|
|
1754
1754
|
}
|
|
1755
1755
|
}
|
|
1756
|
-
return
|
|
1756
|
+
return refs3;
|
|
1757
1757
|
}
|
|
1758
1758
|
function stringOption(value) {
|
|
1759
1759
|
if (Array.isArray(value)) {
|
|
@@ -2047,7 +2047,7 @@ function claudeStyleFileMetrics(tool, input) {
|
|
|
2047
2047
|
}
|
|
2048
2048
|
|
|
2049
2049
|
// src/lib/constants.ts
|
|
2050
|
-
var PACKAGE_VERSION = true ? "0.1.
|
|
2050
|
+
var PACKAGE_VERSION = true ? "0.1.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
|
}
|
|
@@ -11283,7 +11969,7 @@ async function loadQoderCnModelNames(configDir2, home) {
|
|
|
11283
11969
|
}
|
|
11284
11970
|
}
|
|
11285
11971
|
}
|
|
11286
|
-
const textsMap = await parseModelNamesFromDynamicTexts(
|
|
11972
|
+
const textsMap = await parseModelNamesFromDynamicTexts(path20.join(configDir2, ".auth", "dynamic-texts.json"));
|
|
11287
11973
|
for (const [key, val] of Object.entries(textsMap)) {
|
|
11288
11974
|
if (!(key in map)) {
|
|
11289
11975
|
map[key] = val;
|
|
@@ -11291,7 +11977,7 @@ async function loadQoderCnModelNames(configDir2, home) {
|
|
|
11291
11977
|
}
|
|
11292
11978
|
const siblingConfigDir = configDir2.replace(/\.qoder-cn$/, ".qoder");
|
|
11293
11979
|
if (siblingConfigDir !== configDir2) {
|
|
11294
|
-
const siblingMap = await parseModelNamesFromDynamicTexts(
|
|
11980
|
+
const siblingMap = await parseModelNamesFromDynamicTexts(path20.join(siblingConfigDir, ".auth", "dynamic-texts.json"));
|
|
11295
11981
|
for (const [key, val] of Object.entries(siblingMap)) {
|
|
11296
11982
|
if (!(key in map)) {
|
|
11297
11983
|
map[key] = val;
|
|
@@ -11302,15 +11988,15 @@ async function loadQoderCnModelNames(configDir2, home) {
|
|
|
11302
11988
|
}
|
|
11303
11989
|
async function loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMap) {
|
|
11304
11990
|
const { configDir: configDir2, projectName, sessionId } = parseQoderCnPaths(filePath);
|
|
11305
|
-
const segmentsPath =
|
|
11991
|
+
const segmentsPath = path20.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
|
|
11306
11992
|
const modelCalls = [];
|
|
11307
11993
|
try {
|
|
11308
|
-
const files = await
|
|
11994
|
+
const files = await readdir10(segmentsPath);
|
|
11309
11995
|
for (const file of files) {
|
|
11310
11996
|
if (!file.endsWith(".jsonl")) {
|
|
11311
11997
|
continue;
|
|
11312
11998
|
}
|
|
11313
|
-
const content = await readFile12(
|
|
11999
|
+
const content = await readFile12(path20.join(segmentsPath, file), "utf8");
|
|
11314
12000
|
let currentTurnIsSubagent = false;
|
|
11315
12001
|
for (const line of content.split("\n").filter(Boolean)) {
|
|
11316
12002
|
const raw = parseJsonLine(line);
|
|
@@ -11355,7 +12041,7 @@ async function parseQoderCnSessionFile(filePath, options) {
|
|
|
11355
12041
|
let cwd;
|
|
11356
12042
|
let project = projectContext.project;
|
|
11357
12043
|
let model;
|
|
11358
|
-
const home =
|
|
12044
|
+
const home = path20.resolve(stringOption(options.home) || os11.homedir());
|
|
11359
12045
|
const modelMap = await loadQoderCnModelNames(configDir2, home);
|
|
11360
12046
|
const isSubagentSession = filePath.includes("subagents");
|
|
11361
12047
|
const segmentModelCalls = await loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMap);
|
|
@@ -11390,7 +12076,7 @@ async function parseQoderCnSessionFile(filePath, options) {
|
|
|
11390
12076
|
sessionId = stringField(raw, "sessionId") || sessionId;
|
|
11391
12077
|
state.sessionId = sessionId;
|
|
11392
12078
|
cwd = stringField(raw, "cwd") || cwd;
|
|
11393
|
-
project = projectContext.project || (cwd ?
|
|
12079
|
+
project = projectContext.project || (cwd ? path20.basename(cwd) : project || await qoderCnProjectFromFilePath(filePath, options));
|
|
11394
12080
|
if (!ts) {
|
|
11395
12081
|
continue;
|
|
11396
12082
|
}
|
|
@@ -11726,7 +12412,7 @@ async function parseQoderCnSessionFile(filePath, options) {
|
|
|
11726
12412
|
}
|
|
11727
12413
|
dbModelCalls ??= await loadQoderDbModelCalls("QoderCN", parsedPaths.sessionId, modelMap);
|
|
11728
12414
|
if (dbModelCalls.rootSessionId) {
|
|
11729
|
-
const parentPath =
|
|
12415
|
+
const parentPath = path20.join(path20.dirname(filePath), `${dbModelCalls.rootSessionId}.jsonl`);
|
|
11730
12416
|
const parentSourcePathHash = `sha256:${createStableHash(parentPath)}`;
|
|
11731
12417
|
return withoutSubagentTurnEvents(validEvents).map((event) => rebuildEventIdentity3({
|
|
11732
12418
|
...event,
|
|
@@ -11879,28 +12565,28 @@ function extractQoderAttachedPrompt(content) {
|
|
|
11879
12565
|
}
|
|
11880
12566
|
async function qoderCnProjectContextFromLines(filePath, lines, options, configDir2) {
|
|
11881
12567
|
const { projectName: projectDir, sessionId } = parseQoderCnPaths(filePath);
|
|
11882
|
-
const isSubagent = filePath.includes(`${
|
|
12568
|
+
const isSubagent = filePath.includes(`${path20.sep}subagents${path20.sep}`);
|
|
11883
12569
|
const inherited = isSubagent ? await readPersistedSessionContextFromOptions(options, sessionId) : void 0;
|
|
11884
12570
|
let cwds = [];
|
|
11885
12571
|
for (const line of lines) {
|
|
11886
12572
|
const raw = parseJsonLine(line);
|
|
11887
12573
|
const cwd = raw ? stringField(raw, "cwd") : void 0;
|
|
11888
|
-
if (cwd &&
|
|
12574
|
+
if (cwd && path20.isAbsolute(cwd)) {
|
|
11889
12575
|
cwds.push(cwd);
|
|
11890
12576
|
}
|
|
11891
12577
|
}
|
|
11892
12578
|
if (isSubagent) {
|
|
11893
|
-
if (inherited?.cwd &&
|
|
12579
|
+
if (inherited?.cwd && path20.isAbsolute(inherited.cwd)) {
|
|
11894
12580
|
cwds = [inherited.cwd];
|
|
11895
12581
|
} else {
|
|
11896
|
-
const parentSessionPath =
|
|
12582
|
+
const parentSessionPath = path20.join(configDir2, "projects", projectDir, `${sessionId}.jsonl`);
|
|
11897
12583
|
try {
|
|
11898
12584
|
const parentText = await readFile12(parentSessionPath, "utf8");
|
|
11899
12585
|
const parentCwds = [];
|
|
11900
12586
|
for (const line of parentText.split("\n").filter(Boolean)) {
|
|
11901
12587
|
const raw = parseJsonLine(line);
|
|
11902
12588
|
const cwd = raw ? stringField(raw, "cwd") : void 0;
|
|
11903
|
-
if (cwd &&
|
|
12589
|
+
if (cwd && path20.isAbsolute(cwd)) {
|
|
11904
12590
|
parentCwds.push(cwd);
|
|
11905
12591
|
}
|
|
11906
12592
|
}
|
|
@@ -11912,7 +12598,7 @@ async function qoderCnProjectContextFromLines(filePath, lines, options, configDi
|
|
|
11912
12598
|
}
|
|
11913
12599
|
}
|
|
11914
12600
|
const root = await gitRootFromCwds2(cwds) || qoderCnProjectRootFromCwds(projectDir, cwds);
|
|
11915
|
-
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));
|
|
11916
12602
|
return {
|
|
11917
12603
|
project,
|
|
11918
12604
|
workspaceId: createWorkspaceId({ projectName: project, repoRoot: root })
|
|
@@ -11921,15 +12607,15 @@ async function qoderCnProjectContextFromLines(filePath, lines, options, configDi
|
|
|
11921
12607
|
async function gitRootFromCwds2(cwds) {
|
|
11922
12608
|
const seen = /* @__PURE__ */ new Set();
|
|
11923
12609
|
for (const cwd of cwds) {
|
|
11924
|
-
let current =
|
|
12610
|
+
let current = path20.resolve(cwd);
|
|
11925
12611
|
while (!seen.has(current)) {
|
|
11926
12612
|
seen.add(current);
|
|
11927
12613
|
try {
|
|
11928
|
-
await
|
|
12614
|
+
await stat13(path20.join(current, ".git"));
|
|
11929
12615
|
return current;
|
|
11930
12616
|
} catch {
|
|
11931
12617
|
}
|
|
11932
|
-
const parent =
|
|
12618
|
+
const parent = path20.dirname(current);
|
|
11933
12619
|
if (parent === current) {
|
|
11934
12620
|
break;
|
|
11935
12621
|
}
|
|
@@ -11940,12 +12626,12 @@ async function gitRootFromCwds2(cwds) {
|
|
|
11940
12626
|
}
|
|
11941
12627
|
function qoderCnProjectRootFromCwds(projectDir, cwds) {
|
|
11942
12628
|
for (const cwd of cwds) {
|
|
11943
|
-
let current =
|
|
12629
|
+
let current = path20.resolve(cwd);
|
|
11944
12630
|
while (true) {
|
|
11945
12631
|
if (encodeQoderCnProjectPath(current) === projectDir) {
|
|
11946
12632
|
return current;
|
|
11947
12633
|
}
|
|
11948
|
-
const parent =
|
|
12634
|
+
const parent = path20.dirname(current);
|
|
11949
12635
|
if (parent === current) {
|
|
11950
12636
|
break;
|
|
11951
12637
|
}
|
|
@@ -11955,14 +12641,14 @@ function qoderCnProjectRootFromCwds(projectDir, cwds) {
|
|
|
11955
12641
|
return void 0;
|
|
11956
12642
|
}
|
|
11957
12643
|
function encodeQoderCnProjectPath(value) {
|
|
11958
|
-
return
|
|
12644
|
+
return path20.resolve(value).split(path20.sep).join("-").replaceAll("_", "-");
|
|
11959
12645
|
}
|
|
11960
12646
|
async function qoderCnProjectFromFilePath(filePath, options) {
|
|
11961
|
-
const projectDir =
|
|
11962
|
-
const home = options ?
|
|
12647
|
+
const projectDir = path20.basename(path20.dirname(filePath));
|
|
12648
|
+
const home = options ? path20.resolve(stringOption(options.home) || os11.homedir()) : os11.homedir();
|
|
11963
12649
|
const resolved = await resolveQoderCnProjectPath(projectDir, home);
|
|
11964
12650
|
if (resolved) {
|
|
11965
|
-
return
|
|
12651
|
+
return path20.basename(resolved);
|
|
11966
12652
|
}
|
|
11967
12653
|
const homePrefix = `${encodeQoderCnProjectPath(home)}-`;
|
|
11968
12654
|
if (projectDir.startsWith(homePrefix)) {
|
|
@@ -11982,12 +12668,12 @@ async function resolveQoderCnProjectPath(projectDir, home) {
|
|
|
11982
12668
|
while (projectDir.startsWith(`${currentEncoded}-`)) {
|
|
11983
12669
|
let matchedChild;
|
|
11984
12670
|
try {
|
|
11985
|
-
const entries = await
|
|
12671
|
+
const entries = await readdir10(current, { withFileTypes: true });
|
|
11986
12672
|
for (const entry of entries) {
|
|
11987
12673
|
if (!entry.isDirectory()) {
|
|
11988
12674
|
continue;
|
|
11989
12675
|
}
|
|
11990
|
-
const candidate =
|
|
12676
|
+
const candidate = path20.join(current, entry.name);
|
|
11991
12677
|
const encoded = encodeQoderCnProjectPath(candidate);
|
|
11992
12678
|
if (encoded === projectDir) {
|
|
11993
12679
|
return candidate;
|
|
@@ -12032,9 +12718,9 @@ function hookConfig6() {
|
|
|
12032
12718
|
function qoderCnConfigDir(home, env) {
|
|
12033
12719
|
const override = env?.QODER_CN_CONFIG_DIR;
|
|
12034
12720
|
if (override && override.trim()) {
|
|
12035
|
-
return
|
|
12721
|
+
return path20.resolve(override);
|
|
12036
12722
|
}
|
|
12037
|
-
return
|
|
12723
|
+
return path20.join(home, ".qoder-cn");
|
|
12038
12724
|
}
|
|
12039
12725
|
function createQoderCnAdapter() {
|
|
12040
12726
|
return {
|
|
@@ -12046,27 +12732,27 @@ function createQoderCnAdapter() {
|
|
|
12046
12732
|
return qoderCnConfigDir(home, env);
|
|
12047
12733
|
},
|
|
12048
12734
|
installedPath(home, env) {
|
|
12049
|
-
return
|
|
12735
|
+
return path20.join(qoderCnConfigDir(home, env), "settings.json");
|
|
12050
12736
|
},
|
|
12051
12737
|
async isInstalled(home, env) {
|
|
12052
12738
|
return isHooksJsonInstalled(
|
|
12053
|
-
|
|
12739
|
+
path20.join(qoderCnConfigDir(home, env), "settings.json"),
|
|
12054
12740
|
"vibetime hook --agent qoder-cn"
|
|
12055
12741
|
);
|
|
12056
12742
|
},
|
|
12057
12743
|
installEntries(home, env) {
|
|
12058
12744
|
return [{
|
|
12059
12745
|
kind: "hooks-json",
|
|
12060
|
-
path:
|
|
12746
|
+
path: path20.join(qoderCnConfigDir(home, env), "settings.json"),
|
|
12061
12747
|
content: hookConfig6()
|
|
12062
12748
|
}];
|
|
12063
12749
|
},
|
|
12064
12750
|
sourcePaths(home, env) {
|
|
12065
12751
|
const base = qoderCnConfigDir(home, env);
|
|
12066
12752
|
return [
|
|
12067
|
-
|
|
12068
|
-
|
|
12069
|
-
|
|
12753
|
+
path20.join(base, "projects"),
|
|
12754
|
+
path20.join(base, ".qoder.json"),
|
|
12755
|
+
path20.join(home, ".qoder.json")
|
|
12070
12756
|
];
|
|
12071
12757
|
},
|
|
12072
12758
|
parseSessionFile: parseQoderCnSessionFile
|
|
@@ -12075,11 +12761,11 @@ function createQoderCnAdapter() {
|
|
|
12075
12761
|
|
|
12076
12762
|
// src/adapters/qoder.ts
|
|
12077
12763
|
import { existsSync } from "node:fs";
|
|
12078
|
-
import { readdir as
|
|
12764
|
+
import { readdir as readdir11, readFile as readFile13, stat as stat14 } from "node:fs/promises";
|
|
12079
12765
|
import os12 from "node:os";
|
|
12080
|
-
import
|
|
12766
|
+
import path21 from "node:path";
|
|
12081
12767
|
function parseQoderPaths(filePath) {
|
|
12082
|
-
const parts = filePath.split(
|
|
12768
|
+
const parts = filePath.split(path21.sep);
|
|
12083
12769
|
const subagentsIdx = parts.lastIndexOf("subagents");
|
|
12084
12770
|
let sessionId = "";
|
|
12085
12771
|
let projectName = "";
|
|
@@ -12089,17 +12775,17 @@ function parseQoderPaths(filePath) {
|
|
|
12089
12775
|
sessionId = parts[subagentsIdx - 1];
|
|
12090
12776
|
projectName = parts[subagentsIdx - 2];
|
|
12091
12777
|
const projectsIdx = parts.lastIndexOf("projects");
|
|
12092
|
-
configDir2 = parts.slice(0, projectsIdx).join(
|
|
12093
|
-
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);
|
|
12094
12780
|
} else {
|
|
12095
12781
|
const filename = parts.at(-1) || "";
|
|
12096
|
-
sessionId =
|
|
12782
|
+
sessionId = path21.basename(filename, ".jsonl");
|
|
12097
12783
|
projectName = parts.at(-2) || "";
|
|
12098
12784
|
if (projectName === "transcript") {
|
|
12099
12785
|
projectName = parts.at(-3) || "";
|
|
12100
12786
|
}
|
|
12101
12787
|
const projectsIdx = parts.lastIndexOf("projects");
|
|
12102
|
-
configDir2 = parts.slice(0, projectsIdx).join(
|
|
12788
|
+
configDir2 = parts.slice(0, projectsIdx).join(path21.sep);
|
|
12103
12789
|
}
|
|
12104
12790
|
return { configDir: configDir2, projectName, sessionId, mainTranscriptPath };
|
|
12105
12791
|
}
|
|
@@ -12147,7 +12833,7 @@ async function loadQoderModelNames(configDir2, home) {
|
|
|
12147
12833
|
}
|
|
12148
12834
|
}
|
|
12149
12835
|
}
|
|
12150
|
-
const textsMap = await parseModelNamesFromDynamicTexts2(
|
|
12836
|
+
const textsMap = await parseModelNamesFromDynamicTexts2(path21.join(configDir2, ".auth", "dynamic-texts.json"));
|
|
12151
12837
|
for (const [key, val] of Object.entries(textsMap)) {
|
|
12152
12838
|
if (!(key in map)) {
|
|
12153
12839
|
map[key] = val;
|
|
@@ -12155,7 +12841,7 @@ async function loadQoderModelNames(configDir2, home) {
|
|
|
12155
12841
|
}
|
|
12156
12842
|
const siblingConfigDir = configDir2.replace(/\.qoder$/, ".qoder-cn");
|
|
12157
12843
|
if (siblingConfigDir !== configDir2) {
|
|
12158
|
-
const siblingMap = await parseModelNamesFromDynamicTexts2(
|
|
12844
|
+
const siblingMap = await parseModelNamesFromDynamicTexts2(path21.join(siblingConfigDir, ".auth", "dynamic-texts.json"));
|
|
12159
12845
|
for (const [key, val] of Object.entries(siblingMap)) {
|
|
12160
12846
|
if (!(key in map)) {
|
|
12161
12847
|
map[key] = val;
|
|
@@ -12163,11 +12849,11 @@ async function loadQoderModelNames(configDir2, home) {
|
|
|
12163
12849
|
}
|
|
12164
12850
|
}
|
|
12165
12851
|
if (isQwenworkConfigRoot(configDir2)) {
|
|
12166
|
-
for (const dir of [
|
|
12167
|
-
if (
|
|
12852
|
+
for (const dir of [path21.join(home, ".qoder"), path21.join(home, ".qoder-cn")]) {
|
|
12853
|
+
if (path21.resolve(dir) === path21.resolve(configDir2)) {
|
|
12168
12854
|
continue;
|
|
12169
12855
|
}
|
|
12170
|
-
const fallbackMap = await parseModelNamesFromDynamicTexts2(
|
|
12856
|
+
const fallbackMap = await parseModelNamesFromDynamicTexts2(path21.join(dir, ".auth", "dynamic-texts.json"));
|
|
12171
12857
|
for (const [key, val] of Object.entries(fallbackMap)) {
|
|
12172
12858
|
if (!(key in map)) {
|
|
12173
12859
|
map[key] = val;
|
|
@@ -12178,25 +12864,25 @@ async function loadQoderModelNames(configDir2, home) {
|
|
|
12178
12864
|
return map;
|
|
12179
12865
|
}
|
|
12180
12866
|
function isQwenworkConfigRoot(configDir2) {
|
|
12181
|
-
const name =
|
|
12867
|
+
const name = path21.basename(path21.resolve(configDir2));
|
|
12182
12868
|
if (name === ".qwenworkcn" || name === ".qwenwork") {
|
|
12183
12869
|
return true;
|
|
12184
12870
|
}
|
|
12185
12871
|
const override = process.env.QWENWORK_CONFIG_DIR;
|
|
12186
|
-
return Boolean(override && override.trim() &&
|
|
12872
|
+
return Boolean(override && override.trim() && path21.basename(path21.resolve(override)) === name);
|
|
12187
12873
|
}
|
|
12188
12874
|
var FAILED_SEGMENT_STOP_REASONS = /* @__PURE__ */ new Set(["cancelled", "canceled", "error", "failed", "refusal"]);
|
|
12189
12875
|
async function loadQoderSegmentModelCalls(filePath, isSubagentSession, modelMap) {
|
|
12190
12876
|
const { configDir: configDir2, projectName, sessionId } = parseQoderPaths(filePath);
|
|
12191
|
-
const segmentsPath =
|
|
12877
|
+
const segmentsPath = path21.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
|
|
12192
12878
|
const modelCalls = [];
|
|
12193
12879
|
try {
|
|
12194
|
-
const files = await
|
|
12880
|
+
const files = await readdir11(segmentsPath);
|
|
12195
12881
|
for (const file of files) {
|
|
12196
12882
|
if (!file.endsWith(".jsonl")) {
|
|
12197
12883
|
continue;
|
|
12198
12884
|
}
|
|
12199
|
-
const content = await readFile13(
|
|
12885
|
+
const content = await readFile13(path21.join(segmentsPath, file), "utf8");
|
|
12200
12886
|
let currentTurnIsSubagent = false;
|
|
12201
12887
|
for (const line of content.split("\n").filter(Boolean)) {
|
|
12202
12888
|
const raw = parseJsonLine(line);
|
|
@@ -12241,7 +12927,7 @@ async function parseQoderSessionFile(filePath, options) {
|
|
|
12241
12927
|
let cwd;
|
|
12242
12928
|
let project = projectContext.project;
|
|
12243
12929
|
let model;
|
|
12244
|
-
const home =
|
|
12930
|
+
const home = path21.resolve(stringOption(options.home) || os12.homedir());
|
|
12245
12931
|
const modelMap = await loadQoderModelNames(configDir2, home);
|
|
12246
12932
|
const qwenworkRoot = isQwenworkConfigRoot(configDir2);
|
|
12247
12933
|
const isSubagentSession = filePath.includes("subagents");
|
|
@@ -12277,7 +12963,7 @@ async function parseQoderSessionFile(filePath, options) {
|
|
|
12277
12963
|
sessionId = stringField(raw, "sessionId") || sessionId;
|
|
12278
12964
|
state.sessionId = sessionId;
|
|
12279
12965
|
cwd = stringField(raw, "cwd") || cwd;
|
|
12280
|
-
project = projectContext.project || (cwd ?
|
|
12966
|
+
project = projectContext.project || (cwd ? path21.basename(cwd) : project || await qoderProjectFromFilePath(filePath, options));
|
|
12281
12967
|
if (!ts) {
|
|
12282
12968
|
continue;
|
|
12283
12969
|
}
|
|
@@ -12588,7 +13274,7 @@ async function parseQoderSessionFile(filePath, options) {
|
|
|
12588
13274
|
}
|
|
12589
13275
|
dbModelCalls ??= await loadQoderDbModelCalls("Qoder", parsedPaths.sessionId, modelMap);
|
|
12590
13276
|
if (dbModelCalls.rootSessionId) {
|
|
12591
|
-
const parentPath =
|
|
13277
|
+
const parentPath = path21.join(path21.dirname(filePath), `${dbModelCalls.rootSessionId}.jsonl`);
|
|
12592
13278
|
const parentSourcePathHash = `sha256:${createStableHash(parentPath)}`;
|
|
12593
13279
|
return withoutSubagentTurnEvents(validEvents).map((event) => rebuildEventIdentity4({
|
|
12594
13280
|
...event,
|
|
@@ -12705,41 +13391,41 @@ function qoderExtractText(value) {
|
|
|
12705
13391
|
}
|
|
12706
13392
|
async function qoderProjectContextFromLines(filePath, lines, options, configDir2) {
|
|
12707
13393
|
const { projectName: projectDir, sessionId } = parseQoderPaths(filePath);
|
|
12708
|
-
const isSubagent = filePath.includes(`${
|
|
13394
|
+
const isSubagent = filePath.includes(`${path21.sep}subagents${path21.sep}`);
|
|
12709
13395
|
const inherited = isSubagent ? await readPersistedSessionContextFromOptions(options, sessionId) : void 0;
|
|
12710
13396
|
let cwds = [];
|
|
12711
13397
|
const workspaceDirs = [];
|
|
12712
13398
|
for (const line of lines) {
|
|
12713
13399
|
const raw = parseJsonLine(line);
|
|
12714
13400
|
const cwd = raw ? stringField(raw, "cwd") : void 0;
|
|
12715
|
-
if (cwd &&
|
|
13401
|
+
if (cwd && path21.isAbsolute(cwd)) {
|
|
12716
13402
|
cwds.push(cwd);
|
|
12717
13403
|
}
|
|
12718
13404
|
if (raw && stringField(raw, "type") === "workspace-directories") {
|
|
12719
13405
|
for (const dir of arrayField5(raw, "directories")) {
|
|
12720
|
-
if (typeof dir === "string" &&
|
|
13406
|
+
if (typeof dir === "string" && path21.isAbsolute(dir)) {
|
|
12721
13407
|
workspaceDirs.push(dir);
|
|
12722
13408
|
}
|
|
12723
13409
|
}
|
|
12724
13410
|
}
|
|
12725
13411
|
}
|
|
12726
13412
|
if (isSubagent) {
|
|
12727
|
-
if (inherited?.cwd &&
|
|
13413
|
+
if (inherited?.cwd && path21.isAbsolute(inherited.cwd)) {
|
|
12728
13414
|
cwds = [inherited.cwd];
|
|
12729
13415
|
} else {
|
|
12730
|
-
const parentSessionPath =
|
|
13416
|
+
const parentSessionPath = path21.join(configDir2, "projects", projectDir, `${sessionId}.jsonl`);
|
|
12731
13417
|
try {
|
|
12732
13418
|
const parentText = await readFile13(parentSessionPath, "utf8");
|
|
12733
13419
|
const parentCwds = [];
|
|
12734
13420
|
for (const line of parentText.split("\n").filter(Boolean)) {
|
|
12735
13421
|
const raw = parseJsonLine(line);
|
|
12736
13422
|
const cwd = raw ? stringField(raw, "cwd") : void 0;
|
|
12737
|
-
if (cwd &&
|
|
13423
|
+
if (cwd && path21.isAbsolute(cwd)) {
|
|
12738
13424
|
parentCwds.push(cwd);
|
|
12739
13425
|
}
|
|
12740
13426
|
if (workspaceDirs.length === 0 && raw && stringField(raw, "type") === "workspace-directories") {
|
|
12741
13427
|
for (const dir of arrayField5(raw, "directories")) {
|
|
12742
|
-
if (typeof dir === "string" &&
|
|
13428
|
+
if (typeof dir === "string" && path21.isAbsolute(dir)) {
|
|
12743
13429
|
workspaceDirs.push(dir);
|
|
12744
13430
|
}
|
|
12745
13431
|
}
|
|
@@ -12759,29 +13445,29 @@ async function qoderProjectContextFromLines(filePath, lines, options, configDir2
|
|
|
12759
13445
|
}
|
|
12760
13446
|
}
|
|
12761
13447
|
const root = await gitRootFromCwds3(cwds) || qoderProjectRootFromCwds(projectDir, cwds);
|
|
12762
|
-
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));
|
|
12763
13449
|
return {
|
|
12764
13450
|
project,
|
|
12765
13451
|
workspaceId: createWorkspaceId({ projectName: project, repoRoot: root })
|
|
12766
13452
|
};
|
|
12767
13453
|
}
|
|
12768
13454
|
function pathInsideDir(candidate, dir) {
|
|
12769
|
-
const resolvedDir =
|
|
12770
|
-
const resolved =
|
|
12771
|
-
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}`);
|
|
12772
13458
|
}
|
|
12773
13459
|
async function gitRootFromCwds3(cwds) {
|
|
12774
13460
|
const seen = /* @__PURE__ */ new Set();
|
|
12775
13461
|
for (const cwd of cwds) {
|
|
12776
|
-
let current =
|
|
13462
|
+
let current = path21.resolve(cwd);
|
|
12777
13463
|
while (!seen.has(current)) {
|
|
12778
13464
|
seen.add(current);
|
|
12779
13465
|
try {
|
|
12780
|
-
await
|
|
13466
|
+
await stat14(path21.join(current, ".git"));
|
|
12781
13467
|
return current;
|
|
12782
13468
|
} catch {
|
|
12783
13469
|
}
|
|
12784
|
-
const parent =
|
|
13470
|
+
const parent = path21.dirname(current);
|
|
12785
13471
|
if (parent === current) {
|
|
12786
13472
|
break;
|
|
12787
13473
|
}
|
|
@@ -12792,12 +13478,12 @@ async function gitRootFromCwds3(cwds) {
|
|
|
12792
13478
|
}
|
|
12793
13479
|
function qoderProjectRootFromCwds(projectDir, cwds) {
|
|
12794
13480
|
for (const cwd of cwds) {
|
|
12795
|
-
let current =
|
|
13481
|
+
let current = path21.resolve(cwd);
|
|
12796
13482
|
while (true) {
|
|
12797
13483
|
if (qoderEncodedVariants(current).includes(projectDir)) {
|
|
12798
13484
|
return current;
|
|
12799
13485
|
}
|
|
12800
|
-
const parent =
|
|
13486
|
+
const parent = path21.dirname(current);
|
|
12801
13487
|
if (parent === current) {
|
|
12802
13488
|
break;
|
|
12803
13489
|
}
|
|
@@ -12807,7 +13493,7 @@ function qoderProjectRootFromCwds(projectDir, cwds) {
|
|
|
12807
13493
|
return void 0;
|
|
12808
13494
|
}
|
|
12809
13495
|
function rawQoderProjectPath(value) {
|
|
12810
|
-
return
|
|
13496
|
+
return path21.resolve(value).split(path21.sep).join("-");
|
|
12811
13497
|
}
|
|
12812
13498
|
function qoderEncodedVariants(value) {
|
|
12813
13499
|
const raw = rawQoderProjectPath(value);
|
|
@@ -12828,11 +13514,11 @@ function qoderEncodedProjectSuffix(projectDir, home) {
|
|
|
12828
13514
|
return void 0;
|
|
12829
13515
|
}
|
|
12830
13516
|
async function qoderProjectFromFilePath(filePath, options) {
|
|
12831
|
-
const projectDir =
|
|
12832
|
-
const home = options ?
|
|
13517
|
+
const projectDir = path21.basename(path21.dirname(filePath));
|
|
13518
|
+
const home = options ? path21.resolve(stringOption(options.home) || os12.homedir()) : os12.homedir();
|
|
12833
13519
|
const resolved = await resolveQoderProjectPath(projectDir, home);
|
|
12834
13520
|
if (resolved) {
|
|
12835
|
-
return
|
|
13521
|
+
return path21.basename(resolved);
|
|
12836
13522
|
}
|
|
12837
13523
|
const suffix = qoderEncodedProjectSuffix(projectDir, home);
|
|
12838
13524
|
if (suffix) {
|
|
@@ -12853,12 +13539,12 @@ async function resolveQoderProjectPath(projectDir, home) {
|
|
|
12853
13539
|
while (currentEncodedVariants.some((prefix) => projectDir.startsWith(`${prefix}-`))) {
|
|
12854
13540
|
let matchedChild;
|
|
12855
13541
|
try {
|
|
12856
|
-
const entries = await
|
|
13542
|
+
const entries = await readdir11(current, { withFileTypes: true });
|
|
12857
13543
|
for (const entry of entries) {
|
|
12858
13544
|
if (!entry.isDirectory()) {
|
|
12859
13545
|
continue;
|
|
12860
13546
|
}
|
|
12861
|
-
const candidate =
|
|
13547
|
+
const candidate = path21.join(current, entry.name);
|
|
12862
13548
|
const candidateVariants = qoderEncodedVariants(candidate);
|
|
12863
13549
|
if (candidateVariants.includes(projectDir)) {
|
|
12864
13550
|
return candidate;
|
|
@@ -12903,19 +13589,19 @@ function hookConfig7() {
|
|
|
12903
13589
|
function qoderConfigDir(home, env) {
|
|
12904
13590
|
const override = env?.QODER_CONFIG_DIR;
|
|
12905
13591
|
if (override && override.trim()) {
|
|
12906
|
-
return
|
|
13592
|
+
return path21.resolve(override);
|
|
12907
13593
|
}
|
|
12908
|
-
return
|
|
13594
|
+
return path21.join(home, ".qoder");
|
|
12909
13595
|
}
|
|
12910
13596
|
function qwenworkConfigDir(home, env) {
|
|
12911
13597
|
const override = env?.QWENWORK_CONFIG_DIR;
|
|
12912
13598
|
if (override && override.trim()) {
|
|
12913
|
-
return
|
|
13599
|
+
return path21.resolve(override);
|
|
12914
13600
|
}
|
|
12915
|
-
return
|
|
13601
|
+
return path21.join(home, ".qwenworkcn");
|
|
12916
13602
|
}
|
|
12917
13603
|
function qoderConfigDirs(home, env) {
|
|
12918
|
-
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)))];
|
|
12919
13605
|
}
|
|
12920
13606
|
function createQoderAdapter() {
|
|
12921
13607
|
return {
|
|
@@ -12927,11 +13613,11 @@ function createQoderAdapter() {
|
|
|
12927
13613
|
return qoderConfigDir(home, env);
|
|
12928
13614
|
},
|
|
12929
13615
|
installedPath(home, env) {
|
|
12930
|
-
return
|
|
13616
|
+
return path21.join(qoderConfigDir(home, env), "settings.json");
|
|
12931
13617
|
},
|
|
12932
13618
|
async isInstalled(home, env) {
|
|
12933
13619
|
return isHooksJsonInstalled(
|
|
12934
|
-
|
|
13620
|
+
path21.join(qoderConfigDir(home, env), "settings.json"),
|
|
12935
13621
|
"vibetime hook --agent qoder"
|
|
12936
13622
|
);
|
|
12937
13623
|
},
|
|
@@ -12940,16 +13626,16 @@ function createQoderAdapter() {
|
|
|
12940
13626
|
const targets = [primary, ...variants.filter((dir) => existsSync(dir))];
|
|
12941
13627
|
return targets.map((base) => ({
|
|
12942
13628
|
kind: "hooks-json",
|
|
12943
|
-
path:
|
|
13629
|
+
path: path21.join(base, "settings.json"),
|
|
12944
13630
|
content: hookConfig7()
|
|
12945
13631
|
}));
|
|
12946
13632
|
},
|
|
12947
13633
|
sourcePaths(home, env) {
|
|
12948
|
-
const paths = qoderConfigDirs(home, env).map((base2) =>
|
|
13634
|
+
const paths = qoderConfigDirs(home, env).map((base2) => path21.join(base2, "projects"));
|
|
12949
13635
|
const base = qoderConfigDir(home, env);
|
|
12950
13636
|
paths.push(
|
|
12951
|
-
|
|
12952
|
-
|
|
13637
|
+
path21.join(base, ".qoder.json"),
|
|
13638
|
+
path21.join(home, ".qoder.json")
|
|
12953
13639
|
);
|
|
12954
13640
|
return paths;
|
|
12955
13641
|
},
|
|
@@ -12985,35 +13671,35 @@ function normalizeId(id) {
|
|
|
12985
13671
|
}
|
|
12986
13672
|
|
|
12987
13673
|
// src/adapters/workbuddy.ts
|
|
12988
|
-
import { readdir as
|
|
12989
|
-
import
|
|
13674
|
+
import { readdir as readdir12, readFile as readFile14, stat as stat15 } from "node:fs/promises";
|
|
13675
|
+
import path22 from "node:path";
|
|
12990
13676
|
function workbuddyProjectsDir(home, env) {
|
|
12991
13677
|
const override = env?.WORKBUDDY_PROJECTS_DIR || env?.WORKBUDDY_HOME;
|
|
12992
13678
|
if (override && override.trim()) {
|
|
12993
|
-
return
|
|
13679
|
+
return path22.resolve(override, override.endsWith("projects") ? "" : "projects");
|
|
12994
13680
|
}
|
|
12995
|
-
return
|
|
13681
|
+
return path22.join(home, ".workbuddy", "projects");
|
|
12996
13682
|
}
|
|
12997
13683
|
function workbuddyBaseDir(home, env) {
|
|
12998
13684
|
const override = env?.WORKBUDDY_HOME;
|
|
12999
13685
|
if (override && override.trim()) {
|
|
13000
|
-
return
|
|
13686
|
+
return path22.resolve(override);
|
|
13001
13687
|
}
|
|
13002
|
-
return
|
|
13688
|
+
return path22.join(home, ".workbuddy");
|
|
13003
13689
|
}
|
|
13004
|
-
function
|
|
13690
|
+
function projectFromCwd2(cwd, fallback) {
|
|
13005
13691
|
if (!cwd) {
|
|
13006
13692
|
return fallback;
|
|
13007
13693
|
}
|
|
13008
|
-
return
|
|
13694
|
+
return path22.basename(cwd) || fallback;
|
|
13009
13695
|
}
|
|
13010
|
-
function
|
|
13696
|
+
function sourceHash2(filePath) {
|
|
13011
13697
|
return `sha256:${createStableHash(filePath)}`;
|
|
13012
13698
|
}
|
|
13013
|
-
function
|
|
13699
|
+
function makeEvent2(event, line, filePath, options) {
|
|
13014
13700
|
const withRefs = withBackfillRefs(event, {
|
|
13015
13701
|
filePath,
|
|
13016
|
-
sourcePathHash:
|
|
13702
|
+
sourcePathHash: sourceHash2(filePath),
|
|
13017
13703
|
lineNumber: line.lineNumber,
|
|
13018
13704
|
topType: stringField(line.record, "type"),
|
|
13019
13705
|
payloadType: stringField(line.record, "role") || stringField(line.record, "name"),
|
|
@@ -13093,7 +13779,7 @@ function isHiddenUserMessage(record) {
|
|
|
13093
13779
|
return providerData.skipRun === true || providerData.isMeta === true || providerData.isCompactInternal === true || providerData.isCompact === true || providerData.isTeammateMessage === true || (stringField(providerData, "agentPurpose") || "").toLowerCase().includes("compact");
|
|
13094
13780
|
}
|
|
13095
13781
|
function workbuddySubagentRefs(lines) {
|
|
13096
|
-
const
|
|
13782
|
+
const refs3 = {};
|
|
13097
13783
|
const keys = [
|
|
13098
13784
|
["parentSessionId", ["parent_session_id", "parentSessionId"]],
|
|
13099
13785
|
["parentToolCallId", ["parent_tool_call_id", "parentToolCallId"]],
|
|
@@ -13103,19 +13789,19 @@ function workbuddySubagentRefs(lines) {
|
|
|
13103
13789
|
for (const line of lines) {
|
|
13104
13790
|
const providerData = objectField(line.record, "providerData");
|
|
13105
13791
|
for (const [ref, aliases] of keys) {
|
|
13106
|
-
if (
|
|
13792
|
+
if (refs3[ref]) {
|
|
13107
13793
|
continue;
|
|
13108
13794
|
}
|
|
13109
13795
|
for (const alias of aliases) {
|
|
13110
13796
|
const value = stringField(line.record, alias) || stringField(providerData, alias);
|
|
13111
13797
|
if (value) {
|
|
13112
|
-
|
|
13798
|
+
refs3[ref] = value;
|
|
13113
13799
|
break;
|
|
13114
13800
|
}
|
|
13115
13801
|
}
|
|
13116
13802
|
}
|
|
13117
13803
|
}
|
|
13118
|
-
return
|
|
13804
|
+
return refs3;
|
|
13119
13805
|
}
|
|
13120
13806
|
function toolCallFailed(record) {
|
|
13121
13807
|
const providerData = objectField(record, "providerData");
|
|
@@ -13143,10 +13829,10 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
13143
13829
|
}
|
|
13144
13830
|
const events = [];
|
|
13145
13831
|
const first = lines[0].record;
|
|
13146
|
-
const sessionId = stringField(first, "sessionId") ||
|
|
13147
|
-
const fallbackProject =
|
|
13832
|
+
const sessionId = stringField(first, "sessionId") || path22.basename(filePath, ".jsonl");
|
|
13833
|
+
const fallbackProject = path22.basename(path22.dirname(filePath));
|
|
13148
13834
|
const cwd = lines.map((line) => stringField(line.record, "cwd")).find(Boolean);
|
|
13149
|
-
const project =
|
|
13835
|
+
const project = projectFromCwd2(cwd, fallbackProject);
|
|
13150
13836
|
const workspaceId = createWorkspaceId({ projectName: project, repoRoot: cwd });
|
|
13151
13837
|
const sessionPrefix = `workbuddy:${sessionId}`;
|
|
13152
13838
|
const toolStarts = /* @__PURE__ */ new Map();
|
|
@@ -13161,7 +13847,7 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
13161
13847
|
return void 0;
|
|
13162
13848
|
}
|
|
13163
13849
|
const failed = turnLastAssistantStatus !== void 0 && ["incomplete", "failed", "cancelled"].includes(turnLastAssistantStatus);
|
|
13164
|
-
return
|
|
13850
|
+
return makeEvent2({
|
|
13165
13851
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13166
13852
|
ts: turnLastTs,
|
|
13167
13853
|
type: failed ? "turn.failed" : "turn.completed",
|
|
@@ -13178,7 +13864,7 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
13178
13864
|
};
|
|
13179
13865
|
const firstTs = lines.map((line) => timestampFrom(numberField(line.record, "timestamp"))).find(Boolean);
|
|
13180
13866
|
if (firstTs) {
|
|
13181
|
-
const event =
|
|
13867
|
+
const event = makeEvent2({
|
|
13182
13868
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13183
13869
|
ts: firstTs,
|
|
13184
13870
|
type: "session.started",
|
|
@@ -13218,7 +13904,7 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
13218
13904
|
turnLastAssistantStatus = void 0;
|
|
13219
13905
|
const promptChars = contentLength(record.content);
|
|
13220
13906
|
for (const event of [
|
|
13221
|
-
|
|
13907
|
+
makeEvent2({
|
|
13222
13908
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13223
13909
|
ts,
|
|
13224
13910
|
type: "turn.started",
|
|
@@ -13232,7 +13918,7 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
13232
13918
|
confidence: "derived",
|
|
13233
13919
|
refs: { sourceId: `${sourceId}:turn` }
|
|
13234
13920
|
}, line, filePath, options),
|
|
13235
|
-
|
|
13921
|
+
makeEvent2({
|
|
13236
13922
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13237
13923
|
ts,
|
|
13238
13924
|
type: "prompt.submitted",
|
|
@@ -13261,7 +13947,7 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
13261
13947
|
const metrics = workbuddyUsageMetrics(record);
|
|
13262
13948
|
if (metrics) {
|
|
13263
13949
|
const model = stringField(objectField(record, "providerData"), "model");
|
|
13264
|
-
const usage =
|
|
13950
|
+
const usage = makeEvent2({
|
|
13265
13951
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13266
13952
|
ts,
|
|
13267
13953
|
type: "model.usage",
|
|
@@ -13290,7 +13976,7 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
13290
13976
|
const callId = stringField(record, "callId");
|
|
13291
13977
|
if (tool && callId) {
|
|
13292
13978
|
toolStarts.set(`${sessionId}:${callId}`, { line, ts, tool, callId });
|
|
13293
|
-
const started =
|
|
13979
|
+
const started = makeEvent2({
|
|
13294
13980
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13295
13981
|
ts,
|
|
13296
13982
|
type: "tool.started",
|
|
@@ -13318,7 +14004,7 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
13318
14004
|
if (isPlainObject(toolInput)) {
|
|
13319
14005
|
const fileActivities = claudeStyleToolFileActivities(tool, toolInput, ts, cwd);
|
|
13320
14006
|
if (fileActivities.length > 0) {
|
|
13321
|
-
const fileEvent =
|
|
14007
|
+
const fileEvent = makeEvent2({
|
|
13322
14008
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13323
14009
|
ts,
|
|
13324
14010
|
type: eventTypeFromFileActivities(fileActivities),
|
|
@@ -13344,7 +14030,7 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
13344
14030
|
const metrics = workbuddyUsageMetrics(record);
|
|
13345
14031
|
const model = stringField(objectField(record, "providerData"), "model");
|
|
13346
14032
|
if (metrics || model) {
|
|
13347
|
-
const usage =
|
|
14033
|
+
const usage = makeEvent2({
|
|
13348
14034
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13349
14035
|
ts,
|
|
13350
14036
|
type: "model.usage",
|
|
@@ -13373,7 +14059,7 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
13373
14059
|
const start = toolStarts.get(`${sessionId}:${callId}`);
|
|
13374
14060
|
const durationMs = start?.ts ? Math.max(0, Date.parse(ts) - Date.parse(start.ts)) : void 0;
|
|
13375
14061
|
const failed = toolCallFailed(record);
|
|
13376
|
-
const completed =
|
|
14062
|
+
const completed = makeEvent2({
|
|
13377
14063
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13378
14064
|
ts,
|
|
13379
14065
|
type: failed ? "tool.failed" : "tool.completed",
|
|
@@ -13405,7 +14091,7 @@ async function parseWorkbuddySessionFile(filePath, options) {
|
|
|
13405
14091
|
}
|
|
13406
14092
|
const lastTs = lastLine ? timestampFrom(numberField(lastLine.record, "timestamp")) : void 0;
|
|
13407
14093
|
if (lastLine && lastTs) {
|
|
13408
|
-
const event =
|
|
14094
|
+
const event = makeEvent2({
|
|
13409
14095
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13410
14096
|
ts: lastTs,
|
|
13411
14097
|
type: "session.ended",
|
|
@@ -13428,17 +14114,17 @@ async function workbuddyBackfillFiles(sourceRoot, home, env) {
|
|
|
13428
14114
|
const base = sourceRoot || workbuddyProjectsDir(home, env);
|
|
13429
14115
|
const files = [];
|
|
13430
14116
|
try {
|
|
13431
|
-
const projects = await
|
|
14117
|
+
const projects = await readdir12(base, { withFileTypes: true });
|
|
13432
14118
|
for (const project of projects) {
|
|
13433
14119
|
if (!project.isDirectory()) {
|
|
13434
14120
|
continue;
|
|
13435
14121
|
}
|
|
13436
|
-
const projectDir =
|
|
13437
|
-
const entries = await
|
|
14122
|
+
const projectDir = path22.join(base, project.name);
|
|
14123
|
+
const entries = await readdir12(projectDir, { withFileTypes: true });
|
|
13438
14124
|
for (const entry of entries) {
|
|
13439
14125
|
if (entry.isFile() && entry.name.endsWith(".jsonl")) {
|
|
13440
|
-
const filePath =
|
|
13441
|
-
const info = await
|
|
14126
|
+
const filePath = path22.join(projectDir, entry.name);
|
|
14127
|
+
const info = await stat15(filePath);
|
|
13442
14128
|
files.push({ path: filePath, modifiedAt: info.mtime.toISOString() });
|
|
13443
14129
|
}
|
|
13444
14130
|
}
|
|
@@ -13475,18 +14161,18 @@ function createWorkbuddyAdapter() {
|
|
|
13475
14161
|
return workbuddyProjectsDir(home, env);
|
|
13476
14162
|
},
|
|
13477
14163
|
installedPath(home, env) {
|
|
13478
|
-
return
|
|
14164
|
+
return path22.join(workbuddyBaseDir(home, env), "settings.json");
|
|
13479
14165
|
},
|
|
13480
14166
|
async isInstalled(home, env) {
|
|
13481
14167
|
return isHooksJsonInstalled(
|
|
13482
|
-
|
|
14168
|
+
path22.join(workbuddyBaseDir(home, env), "settings.json"),
|
|
13483
14169
|
"vibetime hook --agent workbuddy"
|
|
13484
14170
|
);
|
|
13485
14171
|
},
|
|
13486
14172
|
installEntries(home, env) {
|
|
13487
14173
|
return [{
|
|
13488
14174
|
kind: "hooks-json",
|
|
13489
|
-
path:
|
|
14175
|
+
path: path22.join(workbuddyBaseDir(home, env), "settings.json"),
|
|
13490
14176
|
content: hookConfig8()
|
|
13491
14177
|
}];
|
|
13492
14178
|
},
|
|
@@ -13499,22 +14185,22 @@ function createWorkbuddyAdapter() {
|
|
|
13499
14185
|
|
|
13500
14186
|
// src/adapters/zcode.ts
|
|
13501
14187
|
import { execFile } from "node:child_process";
|
|
13502
|
-
import { readFile as readFile15, stat as
|
|
13503
|
-
import
|
|
14188
|
+
import { readFile as readFile15, stat as stat16 } from "node:fs/promises";
|
|
14189
|
+
import path23 from "node:path";
|
|
13504
14190
|
import { promisify as promisify2 } from "node:util";
|
|
13505
14191
|
var execFileAsync = promisify2(execFile);
|
|
13506
14192
|
function zcodeCliDir(home, env) {
|
|
13507
14193
|
const override = env?.ZCODE_CLI_DIR || env?.ZCODE_HOME;
|
|
13508
14194
|
if (override && override.trim()) {
|
|
13509
|
-
return
|
|
14195
|
+
return path23.resolve(override, override.endsWith("cli") ? "" : "cli");
|
|
13510
14196
|
}
|
|
13511
|
-
return
|
|
14197
|
+
return path23.join(home, ".zcode", "cli");
|
|
13512
14198
|
}
|
|
13513
14199
|
function zcodeDbPath(home, env) {
|
|
13514
|
-
return
|
|
14200
|
+
return path23.join(zcodeCliDir(home, env), "db", "db.sqlite");
|
|
13515
14201
|
}
|
|
13516
14202
|
function zcodeConfigPath(home, env) {
|
|
13517
|
-
return
|
|
14203
|
+
return path23.join(zcodeCliDir(home, env), "config.json");
|
|
13518
14204
|
}
|
|
13519
14205
|
var zcodeHandler = (msg) => hookHandler("zcode", msg);
|
|
13520
14206
|
function hookConfig9() {
|
|
@@ -13538,7 +14224,7 @@ var providerNameCache = null;
|
|
|
13538
14224
|
async function loadProviderNames(configPath2) {
|
|
13539
14225
|
let fileMtime = 0;
|
|
13540
14226
|
try {
|
|
13541
|
-
const info = await
|
|
14227
|
+
const info = await stat16(configPath2);
|
|
13542
14228
|
fileMtime = info.mtimeMs;
|
|
13543
14229
|
} catch {
|
|
13544
14230
|
return /* @__PURE__ */ new Map();
|
|
@@ -13562,19 +14248,19 @@ async function loadProviderNames(configPath2) {
|
|
|
13562
14248
|
providerNameCache = { path: configPath2, mtimeMs: fileMtime, map };
|
|
13563
14249
|
return map;
|
|
13564
14250
|
}
|
|
13565
|
-
function
|
|
14251
|
+
function sourceHash3(filePath) {
|
|
13566
14252
|
return `sha256:${createStableHash(filePath)}`;
|
|
13567
14253
|
}
|
|
13568
14254
|
function projectFromDirectory(directory) {
|
|
13569
|
-
return directory ?
|
|
14255
|
+
return directory ? path23.basename(directory) || "zcode" : "zcode";
|
|
13570
14256
|
}
|
|
13571
14257
|
function isoFromMs(value) {
|
|
13572
14258
|
return timestampFrom(typeof value === "number" ? value : Number(value));
|
|
13573
14259
|
}
|
|
13574
|
-
function
|
|
14260
|
+
function makeEvent3(event, row, rowNumber, filePath, options) {
|
|
13575
14261
|
const withRefs = withBackfillRefs(event, {
|
|
13576
14262
|
filePath,
|
|
13577
|
-
sourcePathHash:
|
|
14263
|
+
sourcePathHash: sourceHash3(filePath),
|
|
13578
14264
|
lineNumber: rowNumber,
|
|
13579
14265
|
topType: row.kind,
|
|
13580
14266
|
payloadType: stringField(row, "status") || stringField(row, "query_source") || stringField(row, "tool_name"),
|
|
@@ -13582,7 +14268,7 @@ function makeEvent2(event, row, rowNumber, filePath, options) {
|
|
|
13582
14268
|
});
|
|
13583
14269
|
return validateCanonicalEvent(withRefs).valid ? withRefs : void 0;
|
|
13584
14270
|
}
|
|
13585
|
-
function
|
|
14271
|
+
function refs2(values) {
|
|
13586
14272
|
const out = {};
|
|
13587
14273
|
for (const [key, value] of Object.entries(values)) {
|
|
13588
14274
|
if (value !== void 0 && value !== "") {
|
|
@@ -13739,7 +14425,7 @@ function resolveRootSessionId2(sessionId, sessions) {
|
|
|
13739
14425
|
}
|
|
13740
14426
|
return current;
|
|
13741
14427
|
}
|
|
13742
|
-
function
|
|
14428
|
+
function sessionContext2(row, sessions) {
|
|
13743
14429
|
const sessionId = stringField(row, "session_id") || stringField(row, "id") || "unknown";
|
|
13744
14430
|
const session = sessions.get(sessionId);
|
|
13745
14431
|
const cwd = stringField(session, "directory");
|
|
@@ -13761,16 +14447,16 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13761
14447
|
if (rows.length === 0) {
|
|
13762
14448
|
return [];
|
|
13763
14449
|
}
|
|
13764
|
-
let candidate =
|
|
14450
|
+
let candidate = path23.resolve(filePath);
|
|
13765
14451
|
let configPath2 = "";
|
|
13766
14452
|
for (let i = 0; i < 12; i++) {
|
|
13767
|
-
const probe =
|
|
14453
|
+
const probe = path23.join(candidate, ".zcode", "v2", "config.json");
|
|
13768
14454
|
try {
|
|
13769
|
-
await
|
|
14455
|
+
await stat16(probe);
|
|
13770
14456
|
configPath2 = probe;
|
|
13771
14457
|
break;
|
|
13772
14458
|
} catch {
|
|
13773
|
-
const parent =
|
|
14459
|
+
const parent = path23.dirname(candidate);
|
|
13774
14460
|
if (parent === candidate) break;
|
|
13775
14461
|
candidate = parent;
|
|
13776
14462
|
}
|
|
@@ -13794,8 +14480,8 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13794
14480
|
if (!id || !ts) {
|
|
13795
14481
|
return;
|
|
13796
14482
|
}
|
|
13797
|
-
const ctx =
|
|
13798
|
-
const event =
|
|
14483
|
+
const ctx = sessionContext2(row, sessions);
|
|
14484
|
+
const event = makeEvent3({
|
|
13799
14485
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13800
14486
|
ts,
|
|
13801
14487
|
type: "session.started",
|
|
@@ -13807,7 +14493,7 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13807
14493
|
parentAgentInstanceId: ctx.parentSessionId,
|
|
13808
14494
|
agent: "zcode",
|
|
13809
14495
|
confidence: "exact",
|
|
13810
|
-
refs:
|
|
14496
|
+
refs: refs2({
|
|
13811
14497
|
sourceId: `${id}:session`,
|
|
13812
14498
|
zcodeTaskType: stringField(row, "task_type"),
|
|
13813
14499
|
zcodeTitleHash: stringField(row, "title") ? `sha256:${createStableHash(stringField(row, "title"))}` : void 0
|
|
@@ -13819,7 +14505,7 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13819
14505
|
const linesAdded = numberField(row, "summary_additions");
|
|
13820
14506
|
const linesRemoved = numberField(row, "summary_deletions");
|
|
13821
14507
|
const filesChanged = numberField(row, "summary_files");
|
|
13822
|
-
const completed =
|
|
14508
|
+
const completed = makeEvent3({
|
|
13823
14509
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13824
14510
|
ts: completedTs,
|
|
13825
14511
|
type: "session.ended",
|
|
@@ -13844,12 +14530,12 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13844
14530
|
if (!rawTurnId || !ts) {
|
|
13845
14531
|
return;
|
|
13846
14532
|
}
|
|
13847
|
-
const ctx =
|
|
14533
|
+
const ctx = sessionContext2(row, sessions);
|
|
13848
14534
|
if (ctx.isSubagent) {
|
|
13849
14535
|
return;
|
|
13850
14536
|
}
|
|
13851
14537
|
const turnId = `zcode:${rawTurnId}`;
|
|
13852
|
-
const started =
|
|
14538
|
+
const started = makeEvent3({
|
|
13853
14539
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13854
14540
|
ts,
|
|
13855
14541
|
type: "turn.started",
|
|
@@ -13867,7 +14553,7 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13867
14553
|
const completedTs = isoFromMs(numberField(row, "completed_at"));
|
|
13868
14554
|
if (completedTs) {
|
|
13869
14555
|
const status = stringField(row, "status");
|
|
13870
|
-
const completed =
|
|
14556
|
+
const completed = makeEvent3({
|
|
13871
14557
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13872
14558
|
ts: completedTs,
|
|
13873
14559
|
type: "turn.completed",
|
|
@@ -13886,7 +14572,7 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13886
14572
|
toolCalls: numberField(row, "tool_call_count")
|
|
13887
14573
|
},
|
|
13888
14574
|
confidence: "exact",
|
|
13889
|
-
refs:
|
|
14575
|
+
refs: refs2({ sourceId: `${rawTurnId}:completed`, zcodeStatus: status })
|
|
13890
14576
|
}, row, rowNumber, filePath, options);
|
|
13891
14577
|
if (completed) events.push(completed);
|
|
13892
14578
|
}
|
|
@@ -13897,9 +14583,9 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13897
14583
|
if (!ts) {
|
|
13898
14584
|
return;
|
|
13899
14585
|
}
|
|
13900
|
-
const ctx =
|
|
14586
|
+
const ctx = sessionContext2(row, sessions);
|
|
13901
14587
|
const modelId = stringField(row, "model_id");
|
|
13902
|
-
const usage =
|
|
14588
|
+
const usage = makeEvent3({
|
|
13903
14589
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13904
14590
|
ts,
|
|
13905
14591
|
type: "model.usage",
|
|
@@ -13916,7 +14602,7 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13916
14602
|
success: stringField(row, "status") === "completed",
|
|
13917
14603
|
metrics: modelMetrics(row),
|
|
13918
14604
|
confidence: "exact",
|
|
13919
|
-
refs:
|
|
14605
|
+
refs: refs2({
|
|
13920
14606
|
sourceId: stringField(row, "id") || `${ctx.rawSessionId}:model:${rowNumber}`,
|
|
13921
14607
|
zcodeQuerySource: stringField(row, "query_source"),
|
|
13922
14608
|
zcodeMode: stringField(row, "mode"),
|
|
@@ -13937,10 +14623,10 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13937
14623
|
if (!startedTs) {
|
|
13938
14624
|
return;
|
|
13939
14625
|
}
|
|
13940
|
-
const ctx =
|
|
14626
|
+
const ctx = sessionContext2(row, sessions);
|
|
13941
14627
|
const turnId = !ctx.isSubagent && stringField(row, "turn_id") ? `zcode:${stringField(row, "turn_id")}` : void 0;
|
|
13942
14628
|
const spanId = `${ctx.sessionId}:tool:${toolCallId}`;
|
|
13943
|
-
const started =
|
|
14629
|
+
const started = makeEvent3({
|
|
13944
14630
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13945
14631
|
ts: startedTs,
|
|
13946
14632
|
type: "tool.started",
|
|
@@ -13954,7 +14640,7 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13954
14640
|
agent: "zcode",
|
|
13955
14641
|
tool,
|
|
13956
14642
|
confidence: "exact",
|
|
13957
|
-
refs:
|
|
14643
|
+
refs: refs2({
|
|
13958
14644
|
sourceId: `${toolCallId}:start`,
|
|
13959
14645
|
zcodeSideEffectScope: stringField(row, "side_effect_scope"),
|
|
13960
14646
|
zcodeApprovalStatus: stringField(row, "approval_status")
|
|
@@ -13963,7 +14649,7 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13963
14649
|
if (started) events.push(started);
|
|
13964
14650
|
if (completedTs) {
|
|
13965
14651
|
const status = stringField(row, "status");
|
|
13966
|
-
const completed =
|
|
14652
|
+
const completed = makeEvent3({
|
|
13967
14653
|
schemaVersion: AGENT_TIME_SCHEMA_VERSION,
|
|
13968
14654
|
ts: completedTs,
|
|
13969
14655
|
type: status === "completed" ? "tool.completed" : "tool.failed",
|
|
@@ -13983,7 +14669,7 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13983
14669
|
bytesRead: numberField(row, "output_bytes")
|
|
13984
14670
|
},
|
|
13985
14671
|
confidence: "exact",
|
|
13986
|
-
refs:
|
|
14672
|
+
refs: refs2({
|
|
13987
14673
|
sourceId: `${toolCallId}:completed`,
|
|
13988
14674
|
zcodeStatus: status,
|
|
13989
14675
|
zcodeExitCode: numberField(row, "exit_code"),
|
|
@@ -13998,13 +14684,13 @@ async function parseZCodeDb(filePath, options) {
|
|
|
13998
14684
|
}
|
|
13999
14685
|
async function zcodeBackfillFiles(sourceRoot, home, env) {
|
|
14000
14686
|
const candidate = sourceRoot || zcodeDbPath(home, env);
|
|
14001
|
-
const filePath = candidate.endsWith(".sqlite") ? candidate :
|
|
14687
|
+
const filePath = candidate.endsWith(".sqlite") ? candidate : path23.join(candidate, "db", "db.sqlite");
|
|
14002
14688
|
try {
|
|
14003
|
-
const info = await
|
|
14689
|
+
const info = await stat16(filePath);
|
|
14004
14690
|
let modifiedMs = info.mtimeMs;
|
|
14005
14691
|
for (const suffix of ["-wal", "-shm"]) {
|
|
14006
14692
|
try {
|
|
14007
|
-
const sidecar = await
|
|
14693
|
+
const sidecar = await stat16(`${filePath}${suffix}`);
|
|
14008
14694
|
modifiedMs = Math.max(modifiedMs, sidecar.mtimeMs);
|
|
14009
14695
|
} catch {
|
|
14010
14696
|
}
|
|
@@ -14048,49 +14734,49 @@ function createZCodeAdapter() {
|
|
|
14048
14734
|
|
|
14049
14735
|
// src/adapters/zed.ts
|
|
14050
14736
|
import os13 from "node:os";
|
|
14051
|
-
import
|
|
14737
|
+
import path24 from "node:path";
|
|
14052
14738
|
function zedThreadsCandidates(home, env) {
|
|
14053
14739
|
const candidates = [];
|
|
14054
14740
|
const platform2 = process.platform;
|
|
14055
14741
|
if (platform2 === "darwin") {
|
|
14056
|
-
candidates.push(
|
|
14742
|
+
candidates.push(path24.join(home, "Library", "Application Support", "Zed", "threads", "threads.db"));
|
|
14057
14743
|
} else if (platform2 === "win32") {
|
|
14058
14744
|
const appdata = env?.APPDATA;
|
|
14059
14745
|
if (appdata && appdata.trim()) {
|
|
14060
|
-
candidates.push(
|
|
14746
|
+
candidates.push(path24.join(path24.resolve(appdata), "Zed", "threads", "threads.db"));
|
|
14061
14747
|
}
|
|
14062
|
-
candidates.push(
|
|
14748
|
+
candidates.push(path24.join(home, "AppData", "Roaming", "Zed", "threads", "threads.db"));
|
|
14063
14749
|
} else {
|
|
14064
14750
|
const xdgData = env?.XDG_DATA_HOME;
|
|
14065
14751
|
if (xdgData && xdgData.trim()) {
|
|
14066
|
-
candidates.push(
|
|
14752
|
+
candidates.push(path24.join(path24.resolve(xdgData), "zed", "threads", "threads.db"));
|
|
14067
14753
|
}
|
|
14068
|
-
candidates.push(
|
|
14754
|
+
candidates.push(path24.join(home, ".local", "share", "zed", "threads", "threads.db"));
|
|
14069
14755
|
const xdgConfig = env?.XDG_CONFIG_HOME;
|
|
14070
14756
|
if (xdgConfig && xdgConfig.trim()) {
|
|
14071
|
-
candidates.push(
|
|
14757
|
+
candidates.push(path24.join(path24.resolve(xdgConfig), "zed", "threads", "threads.db"));
|
|
14072
14758
|
}
|
|
14073
|
-
candidates.push(
|
|
14759
|
+
candidates.push(path24.join(home, ".config", "zed", "threads", "threads.db"));
|
|
14074
14760
|
}
|
|
14075
14761
|
return candidates;
|
|
14076
14762
|
}
|
|
14077
14763
|
function zedConfigDir(home, env) {
|
|
14078
14764
|
const platform2 = process.platform;
|
|
14079
14765
|
if (platform2 === "darwin") {
|
|
14080
|
-
return
|
|
14766
|
+
return path24.join(home, "Library", "Application Support", "Zed");
|
|
14081
14767
|
}
|
|
14082
14768
|
if (platform2 === "win32") {
|
|
14083
14769
|
const appdata = env?.APPDATA;
|
|
14084
14770
|
if (appdata && appdata.trim()) {
|
|
14085
|
-
return
|
|
14771
|
+
return path24.join(path24.resolve(appdata), "Zed");
|
|
14086
14772
|
}
|
|
14087
|
-
return
|
|
14773
|
+
return path24.join(home, "AppData", "Roaming", "Zed");
|
|
14088
14774
|
}
|
|
14089
14775
|
const xdgConfig = env?.XDG_CONFIG_HOME;
|
|
14090
14776
|
if (xdgConfig && xdgConfig.trim()) {
|
|
14091
|
-
return
|
|
14777
|
+
return path24.join(path24.resolve(xdgConfig), "zed");
|
|
14092
14778
|
}
|
|
14093
|
-
return
|
|
14779
|
+
return path24.join(home, ".config", "zed");
|
|
14094
14780
|
}
|
|
14095
14781
|
function baseZedEvent(event) {
|
|
14096
14782
|
return {
|
|
@@ -14154,7 +14840,7 @@ async function parseZedSessionFile(dbPath, options) {
|
|
|
14154
14840
|
const folderRaw = row.folder_paths || "";
|
|
14155
14841
|
const folder = folderRaw.split(/[\n,]/).map((s) => s.trim()).find(Boolean);
|
|
14156
14842
|
const cwd = folder || void 0;
|
|
14157
|
-
const project = cwd ?
|
|
14843
|
+
const project = cwd ? path24.basename(cwd) : row.summary ? row.summary.slice(0, 40) : void 0;
|
|
14158
14844
|
let json;
|
|
14159
14845
|
try {
|
|
14160
14846
|
const bytes = row.data_type === "zstd" ? decompress2(new Uint8Array(row.data)) : new Uint8Array(row.data);
|
|
@@ -14400,19 +15086,19 @@ async function parseZedSessionFile(dbPath, options) {
|
|
|
14400
15086
|
return events.filter((event) => matchesBackfillFilters(event, options));
|
|
14401
15087
|
}
|
|
14402
15088
|
async function zedBackfillFiles(sourceRoot, home = os13.homedir(), env) {
|
|
14403
|
-
const { stat:
|
|
15089
|
+
const { stat: stat19 } = await import("node:fs/promises");
|
|
14404
15090
|
if (sourceRoot) {
|
|
14405
15091
|
if (!sourceRoot.endsWith(".db")) {
|
|
14406
15092
|
return [];
|
|
14407
15093
|
}
|
|
14408
|
-
const info = await
|
|
15094
|
+
const info = await stat19(sourceRoot).catch(() => null);
|
|
14409
15095
|
if (!info) {
|
|
14410
15096
|
return [];
|
|
14411
15097
|
}
|
|
14412
15098
|
return [{ path: sourceRoot, modifiedAt: info.mtime.toISOString() }];
|
|
14413
15099
|
}
|
|
14414
15100
|
for (const candidatePath of zedThreadsCandidates(home, env)) {
|
|
14415
|
-
const info = await
|
|
15101
|
+
const info = await stat19(candidatePath).catch(() => null);
|
|
14416
15102
|
if (info) {
|
|
14417
15103
|
return [{ path: candidatePath, modifiedAt: info.mtime.toISOString() }];
|
|
14418
15104
|
}
|
|
@@ -14429,7 +15115,7 @@ function createZedAdapter() {
|
|
|
14429
15115
|
return zedConfigDir(home, env);
|
|
14430
15116
|
},
|
|
14431
15117
|
installedPath(home, env) {
|
|
14432
|
-
return
|
|
15118
|
+
return path24.join(zedConfigDir(home, env), "vibetime-marker");
|
|
14433
15119
|
},
|
|
14434
15120
|
async isInstalled() {
|
|
14435
15121
|
return false;
|
|
@@ -15244,19 +15930,19 @@ async function uninstallGeneratedFile(filePath, { dryRun, onWrite }) {
|
|
|
15244
15930
|
import { randomUUID } from "node:crypto";
|
|
15245
15931
|
import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, rmSync, writeFileSync } from "node:fs";
|
|
15246
15932
|
import { homedir, hostname } from "node:os";
|
|
15247
|
-
import
|
|
15933
|
+
import path25 from "node:path";
|
|
15248
15934
|
function disabledBackfillSourceSet(config) {
|
|
15249
15935
|
const list = Array.isArray(config.disabledSources) ? config.disabledSources : [];
|
|
15250
15936
|
return new Set(list.map((id) => String(id).trim()).filter(Boolean));
|
|
15251
15937
|
}
|
|
15252
15938
|
function configDir(home = homedir()) {
|
|
15253
|
-
return
|
|
15939
|
+
return path25.join(home, ".vibetime");
|
|
15254
15940
|
}
|
|
15255
15941
|
function configPath(home = homedir()) {
|
|
15256
|
-
return
|
|
15942
|
+
return path25.join(configDir(home), "config.json");
|
|
15257
15943
|
}
|
|
15258
15944
|
function machineIdPath(home = homedir()) {
|
|
15259
|
-
return
|
|
15945
|
+
return path25.join(configDir(home), "machine-id");
|
|
15260
15946
|
}
|
|
15261
15947
|
function readConfig(home = homedir()) {
|
|
15262
15948
|
const file = configPath(home);
|
|
@@ -15303,15 +15989,15 @@ function defaultMachineName() {
|
|
|
15303
15989
|
init_fs();
|
|
15304
15990
|
|
|
15305
15991
|
// src/lib/logger.ts
|
|
15306
|
-
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";
|
|
15307
15993
|
import { homedir as homedir2 } from "node:os";
|
|
15308
|
-
import
|
|
15994
|
+
import path26 from "node:path";
|
|
15309
15995
|
var MAX_BYTES = 1 * 1024 * 1024;
|
|
15310
15996
|
function logDir(home = homedir2()) {
|
|
15311
|
-
return
|
|
15997
|
+
return path26.join(home, ".vibetime", "logs");
|
|
15312
15998
|
}
|
|
15313
15999
|
function logPath(home = homedir2(), name = "cli.log") {
|
|
15314
|
-
return
|
|
16000
|
+
return path26.join(logDir(home), name);
|
|
15315
16001
|
}
|
|
15316
16002
|
function serializeError(error) {
|
|
15317
16003
|
if (error instanceof Error) {
|
|
@@ -15321,7 +16007,7 @@ function serializeError(error) {
|
|
|
15321
16007
|
}
|
|
15322
16008
|
async function rotateIfNeeded(file) {
|
|
15323
16009
|
try {
|
|
15324
|
-
const info = await
|
|
16010
|
+
const info = await stat17(file);
|
|
15325
16011
|
if (info.size > MAX_BYTES) {
|
|
15326
16012
|
await rename2(file, `${file}.1`).catch(() => {
|
|
15327
16013
|
});
|
|
@@ -15486,8 +16172,8 @@ function buildHeaders(token, machine) {
|
|
|
15486
16172
|
...machine?.platform ? { "x-machine-platform": machine.platform } : {}
|
|
15487
16173
|
};
|
|
15488
16174
|
}
|
|
15489
|
-
function joinUrl(base,
|
|
15490
|
-
return new URL(
|
|
16175
|
+
function joinUrl(base, path28) {
|
|
16176
|
+
return new URL(path28, base.endsWith("/") ? base : `${base}/`).toString();
|
|
15491
16177
|
}
|
|
15492
16178
|
async function postRollupBatch(remote, rollups, options = {}) {
|
|
15493
16179
|
const response = await remote.fetchImpl(joinUrl(remote.baseUrl, "/v3/agent/ingest"), {
|
|
@@ -15579,6 +16265,7 @@ function createRegistry() {
|
|
|
15579
16265
|
registry.register(createKimiCodeAdapter());
|
|
15580
16266
|
registry.register(createCursorAdapter());
|
|
15581
16267
|
registry.register(createGrokBotAdapter());
|
|
16268
|
+
registry.register(createHermesAdapter());
|
|
15582
16269
|
return registry;
|
|
15583
16270
|
}
|
|
15584
16271
|
var defaultContext = {
|
|
@@ -16143,6 +16830,9 @@ async function listBackfillSourceFiles(source, options, ctx) {
|
|
|
16143
16830
|
if (source.id === "grok-bot") {
|
|
16144
16831
|
return grokBotBackfillFiles(stringOption(options["source-root"]), resolveHome3(options, ctx), ctx.env, options);
|
|
16145
16832
|
}
|
|
16833
|
+
if (source.id === "hermes") {
|
|
16834
|
+
return hermesBackfillFiles(stringOption(options["source-root"]), resolveHome3(options, ctx), ctx.env);
|
|
16835
|
+
}
|
|
16146
16836
|
if (source.id === "pi") {
|
|
16147
16837
|
return piBackfillFiles(stringOption(options["source-root"]), resolveHome3(options, ctx), ctx.env);
|
|
16148
16838
|
}
|
|
@@ -16150,7 +16840,7 @@ async function listBackfillSourceFiles(source, options, ctx) {
|
|
|
16150
16840
|
const fileLists = await Promise.all(roots.map((r) => listJsonlFiles(r)));
|
|
16151
16841
|
const files = fileLists.flat().sort().slice(0, numberOption(options.limit) || void 0);
|
|
16152
16842
|
return Promise.all(files.map(async (filePath) => {
|
|
16153
|
-
const info = await
|
|
16843
|
+
const info = await stat18(filePath);
|
|
16154
16844
|
return { path: filePath, modifiedAt: info.mtime.toISOString() };
|
|
16155
16845
|
}));
|
|
16156
16846
|
}
|
|
@@ -16482,13 +17172,13 @@ function selectBackfillFilesForImport(files, watermarkTs) {
|
|
|
16482
17172
|
return picked;
|
|
16483
17173
|
}
|
|
16484
17174
|
function backfillIncrementalStatePath(home) {
|
|
16485
|
-
return
|
|
17175
|
+
return path27.join(home, ".vibetime", "backfill-state.json");
|
|
16486
17176
|
}
|
|
16487
17177
|
function syncLocalTriggerStatePath(home) {
|
|
16488
|
-
return
|
|
17178
|
+
return path27.join(home, ".vibetime", "sync-local-trigger.json");
|
|
16489
17179
|
}
|
|
16490
17180
|
function syncLocalTriggerLockPath(home) {
|
|
16491
|
-
return
|
|
17181
|
+
return path27.join(home, ".vibetime", "sync-local-trigger.lock");
|
|
16492
17182
|
}
|
|
16493
17183
|
function backfillRemoteKey(baseUrl) {
|
|
16494
17184
|
try {
|
|
@@ -16550,7 +17240,7 @@ async function readBackfillIncrementalStateFile(home, ctx) {
|
|
|
16550
17240
|
}
|
|
16551
17241
|
async function writeBackfillIncrementalStateFile(home, file) {
|
|
16552
17242
|
const statePath = backfillIncrementalStatePath(home);
|
|
16553
|
-
await mkdir6(
|
|
17243
|
+
await mkdir6(path27.dirname(statePath), { recursive: true });
|
|
16554
17244
|
await writeFile5(statePath, `${JSON.stringify(file, null, 2)}
|
|
16555
17245
|
`, "utf8");
|
|
16556
17246
|
}
|
|
@@ -16599,7 +17289,7 @@ async function readSyncLocalTriggerState(statePath) {
|
|
|
16599
17289
|
return nextState;
|
|
16600
17290
|
}
|
|
16601
17291
|
async function writeSyncLocalTriggerState(statePath, state) {
|
|
16602
|
-
await mkdir6(
|
|
17292
|
+
await mkdir6(path27.dirname(statePath), { recursive: true });
|
|
16603
17293
|
await writeFile5(statePath, `${JSON.stringify(state, null, 2)}
|
|
16604
17294
|
`, "utf8");
|
|
16605
17295
|
}
|
|
@@ -16614,12 +17304,12 @@ async function readSyncLocalLock(lockPath) {
|
|
|
16614
17304
|
return { pid: lock.pid, startedAt: lock.startedAt };
|
|
16615
17305
|
}
|
|
16616
17306
|
async function writeSyncLocalLock(lockPath, lock) {
|
|
16617
|
-
await mkdir6(
|
|
17307
|
+
await mkdir6(path27.dirname(lockPath), { recursive: true });
|
|
16618
17308
|
await writeFile5(lockPath, `${JSON.stringify(lock, null, 2)}
|
|
16619
17309
|
`, "utf8");
|
|
16620
17310
|
}
|
|
16621
17311
|
async function acquireSyncLocalLock(lockPath, lock) {
|
|
16622
|
-
await mkdir6(
|
|
17312
|
+
await mkdir6(path27.dirname(lockPath), { recursive: true });
|
|
16623
17313
|
try {
|
|
16624
17314
|
const handle = await open(lockPath, "wx");
|
|
16625
17315
|
try {
|
|
@@ -16699,10 +17389,10 @@ function syncLocalRunnerEntryArgs(cliPath) {
|
|
|
16699
17389
|
if (cliPath.endsWith(".ts")) {
|
|
16700
17390
|
return ["--import", "tsx", cliPath];
|
|
16701
17391
|
}
|
|
16702
|
-
return [
|
|
17392
|
+
return [path27.resolve(path27.dirname(cliPath), "../bin/vibetime.mjs")];
|
|
16703
17393
|
}
|
|
16704
17394
|
function resolveHome3(options, ctx) {
|
|
16705
|
-
return
|
|
17395
|
+
return path27.resolve(stringOption(options.home) || ctx.env.HOME || os14.homedir());
|
|
16706
17396
|
}
|
|
16707
17397
|
function requestedTargets(options) {
|
|
16708
17398
|
const value = options.target || options.targets;
|