hillclimb 0.1.4 → 0.1.6
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/dist/cli.js +103 -162
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -174,11 +174,10 @@ function pacificParts(date) {
|
|
|
174
174
|
hour: "2-digit",
|
|
175
175
|
minute: "2-digit",
|
|
176
176
|
second: "2-digit",
|
|
177
|
-
|
|
177
|
+
hourCycle: "h23"
|
|
178
178
|
}).formatToParts(date);
|
|
179
179
|
const lookup = {};
|
|
180
180
|
for (const p7 of parts) if (p7.type !== "literal") lookup[p7.type] = p7.value;
|
|
181
|
-
if (lookup.hour === "24") lookup.hour = "00";
|
|
182
181
|
return {
|
|
183
182
|
year: lookup.year ?? "0000",
|
|
184
183
|
month: lookup.month ?? "00",
|
|
@@ -382,7 +381,6 @@ var PlatformClient = class {
|
|
|
382
381
|
if (!data?.session?.user || !data.session.session) return null;
|
|
383
382
|
return {
|
|
384
383
|
session: {
|
|
385
|
-
activeOrganizationId: data.session.session.activeOrganizationId ?? null,
|
|
386
384
|
userId: data.session.user.id ?? "",
|
|
387
385
|
email: data.session.user.email ?? "",
|
|
388
386
|
role: data.session.user.role ?? null
|
|
@@ -391,24 +389,18 @@ var PlatformClient = class {
|
|
|
391
389
|
id: o.id,
|
|
392
390
|
name: o.name,
|
|
393
391
|
slug: o.slug
|
|
392
|
+
})),
|
|
393
|
+
projects: (data.projects ?? []).map((p7) => ({
|
|
394
|
+
id: p7.id,
|
|
395
|
+
name: p7.name,
|
|
396
|
+
slug: p7.slug
|
|
394
397
|
}))
|
|
395
398
|
};
|
|
396
399
|
}
|
|
397
|
-
async
|
|
398
|
-
await this.request("POST", "/api/auth/organization/set-active", {
|
|
399
|
-
organizationId
|
|
400
|
-
});
|
|
401
|
-
}
|
|
402
|
-
async setActiveOrganizationAsAdmin(organizationId) {
|
|
403
|
-
await this.request(
|
|
404
|
-
"POST",
|
|
405
|
-
`/api/v1/admin/organizations/${organizationId}/set-active`
|
|
406
|
-
);
|
|
407
|
-
}
|
|
408
|
-
async listWorkspaces(organizationId) {
|
|
400
|
+
async listProjects() {
|
|
409
401
|
const data = await this.request(
|
|
410
402
|
"GET",
|
|
411
|
-
|
|
403
|
+
"/api/v1/projects"
|
|
412
404
|
);
|
|
413
405
|
return data.workspaces ?? [];
|
|
414
406
|
}
|
|
@@ -507,8 +499,8 @@ var PlatformClient = class {
|
|
|
507
499
|
import fs4 from "fs";
|
|
508
500
|
import os2 from "os";
|
|
509
501
|
import path5 from "path";
|
|
510
|
-
var HOOK_CMD = (sub) => `npx hillclimb ${sub}`;
|
|
511
|
-
var GIT_TRACES_CMD = (tool) => `npx hillclimb git-traces --tool=${tool}`;
|
|
502
|
+
var HOOK_CMD = (sub) => `npx hillclimb@latest ${sub}`;
|
|
503
|
+
var GIT_TRACES_CMD = (tool) => `npx hillclimb@latest git-traces --tool=${tool}`;
|
|
512
504
|
var TOOLS = [
|
|
513
505
|
{
|
|
514
506
|
tool: "claude",
|
|
@@ -542,7 +534,7 @@ var TOOLS = [
|
|
|
542
534
|
// a plugin file at .opencode/plugins/hillclimb.js — auto-discovered by
|
|
543
535
|
// opencode with no registration. The plugin subscribes to session.created
|
|
544
536
|
// (SessionStart), session.idle (Stop, per-turn), and
|
|
545
|
-
// server.instance.disposed (SessionEnd) and shells out to `npx hillclimb`.
|
|
537
|
+
// server.instance.disposed (SessionEnd) and shells out to `npx hillclimb@latest`.
|
|
546
538
|
tool: "opencode",
|
|
547
539
|
label: "opencode",
|
|
548
540
|
settingsFile: ".opencode/plugins/hillclimb.js",
|
|
@@ -737,7 +729,7 @@ function copilotUninstall(settings, eventName, command) {
|
|
|
737
729
|
}
|
|
738
730
|
return true;
|
|
739
731
|
}
|
|
740
|
-
var OPENCODE_PLUGIN_VERSION =
|
|
732
|
+
var OPENCODE_PLUGIN_VERSION = 3;
|
|
741
733
|
var OPENCODE_PLUGIN_MARKER = `// HILLCLIMB_OPENCODE_PLUGIN_VERSION=${OPENCODE_PLUGIN_VERSION}`;
|
|
742
734
|
var OPENCODE_PLUGIN_CONTENT = `${OPENCODE_PLUGIN_MARKER}
|
|
743
735
|
// Auto-installed by \`npx hillclimb\`. Do not edit manually \u2014 re-running
|
|
@@ -785,7 +777,7 @@ function writeTranscript(sessionID) {
|
|
|
785
777
|
function spawnHillclimb(subcommand, payload) {
|
|
786
778
|
try {
|
|
787
779
|
const args = subcommand.split(" ").filter(Boolean);
|
|
788
|
-
const child = spawn("npx", ["hillclimb"].concat(args), {
|
|
780
|
+
const child = spawn("npx", ["hillclimb@latest"].concat(args), {
|
|
789
781
|
detached: true,
|
|
790
782
|
stdio: ["pipe", "ignore", "ignore"],
|
|
791
783
|
});
|
|
@@ -936,10 +928,11 @@ function uninstall(settings, format, eventName, command) {
|
|
|
936
928
|
}
|
|
937
929
|
}
|
|
938
930
|
function legacyCommandsFor(command) {
|
|
939
|
-
const prefix = "npx hillclimb ";
|
|
931
|
+
const prefix = "npx hillclimb@latest ";
|
|
940
932
|
if (!command.startsWith(prefix)) return [];
|
|
941
933
|
const sub = command.slice(prefix.length);
|
|
942
934
|
const legacy = [
|
|
935
|
+
`npx hillclimb ${sub}`,
|
|
943
936
|
`hillclimb-extract ${sub}`,
|
|
944
937
|
`npx hillclimb-extract ${sub}`,
|
|
945
938
|
`npx @hillclimb/extract ${sub}`
|
|
@@ -947,6 +940,7 @@ function legacyCommandsFor(command) {
|
|
|
947
940
|
const toolMatch = sub.match(/^(\S+)\s+--tool=\S+$/);
|
|
948
941
|
if (toolMatch) {
|
|
949
942
|
const bareSub = toolMatch[1];
|
|
943
|
+
legacy.push(`npx hillclimb@latest ${bareSub}`);
|
|
950
944
|
legacy.push(`npx hillclimb ${bareSub}`);
|
|
951
945
|
}
|
|
952
946
|
return legacy;
|
|
@@ -1039,20 +1033,45 @@ async function ensureCodexHooksEnabled() {
|
|
|
1039
1033
|
});
|
|
1040
1034
|
await fs4.promises.writeFile(
|
|
1041
1035
|
CODEX_CONFIG_PATH,
|
|
1042
|
-
"[features]\
|
|
1036
|
+
"[features]\nhooks = true\n"
|
|
1043
1037
|
);
|
|
1044
1038
|
return true;
|
|
1045
1039
|
}
|
|
1046
1040
|
throw err;
|
|
1047
1041
|
}
|
|
1048
|
-
|
|
1042
|
+
const original = content;
|
|
1043
|
+
content = content.replace(
|
|
1044
|
+
/^\s*codex_hooks\s*=\s*(true|false)\s*(?:#.*)?\r?\n?/gim,
|
|
1045
|
+
""
|
|
1046
|
+
);
|
|
1049
1047
|
const featuresMatch = content.match(/^\[features\]\s*$/m);
|
|
1050
1048
|
if (featuresMatch) {
|
|
1051
|
-
const
|
|
1052
|
-
|
|
1049
|
+
const matchIndex = featuresMatch.index;
|
|
1050
|
+
if (matchIndex === void 0) {
|
|
1051
|
+
throw new Error("Could not locate [features] section.");
|
|
1052
|
+
}
|
|
1053
|
+
const bodyStart = matchIndex + featuresMatch[0].length;
|
|
1054
|
+
const nextSectionOffset = content.slice(bodyStart).search(/\n\[[^\n]+\]\s*(?:\r?\n|$)/);
|
|
1055
|
+
const bodyEnd = nextSectionOffset === -1 ? content.length : bodyStart + nextSectionOffset;
|
|
1056
|
+
const body = content.slice(bodyStart, bodyEnd);
|
|
1057
|
+
const hooksMatch = body.match(/^(\s*)hooks\s*=\s*(true|false)(.*)$/im);
|
|
1058
|
+
if (hooksMatch?.[2]?.toLowerCase() === "true") {
|
|
1059
|
+
} else if (hooksMatch?.index !== void 0) {
|
|
1060
|
+
const lineStart = bodyStart + hooksMatch.index;
|
|
1061
|
+
const lineEnd = lineStart + hooksMatch[0].length;
|
|
1062
|
+
content = content.slice(0, lineStart) + `${hooksMatch[1]}hooks = true${hooksMatch[3]}` + content.slice(lineEnd);
|
|
1063
|
+
} else {
|
|
1064
|
+
content = `${content.slice(0, bodyStart)}
|
|
1065
|
+
hooks = true${content.slice(bodyStart)}`;
|
|
1066
|
+
}
|
|
1053
1067
|
} else {
|
|
1054
|
-
content = content.trimEnd()
|
|
1068
|
+
content = `${content.trimEnd()}
|
|
1069
|
+
|
|
1070
|
+
[features]
|
|
1071
|
+
hooks = true
|
|
1072
|
+
`;
|
|
1055
1073
|
}
|
|
1074
|
+
if (content === original) return false;
|
|
1056
1075
|
await fs4.promises.writeFile(CODEX_CONFIG_PATH, content);
|
|
1057
1076
|
return true;
|
|
1058
1077
|
}
|
|
@@ -1312,130 +1331,61 @@ async function runInit(args = []) {
|
|
|
1312
1331
|
);
|
|
1313
1332
|
}
|
|
1314
1333
|
}
|
|
1315
|
-
let activeOrgId = bootstrap.session.activeOrganizationId;
|
|
1316
|
-
const orgs = bootstrap.organizations;
|
|
1317
|
-
const isAdmin = bootstrap.session.role === "admin";
|
|
1318
|
-
if (orgs.length === 0 && !isAdmin) {
|
|
1319
|
-
p3.log.error(
|
|
1320
|
-
"You do not belong to any organization. Ask a platform admin to add you."
|
|
1321
|
-
);
|
|
1322
|
-
p3.outro("Aborted.");
|
|
1323
|
-
process.exit(1);
|
|
1324
|
-
}
|
|
1325
|
-
let pickedId;
|
|
1326
1334
|
let workspace;
|
|
1327
1335
|
if (workspaceSlugFlag) {
|
|
1328
1336
|
const resolved = await withSpinner(
|
|
1329
|
-
`Looking up
|
|
1330
|
-
(w) => `Found
|
|
1331
|
-
`Could not find
|
|
1337
|
+
`Looking up project "${workspaceSlugFlag}"...`,
|
|
1338
|
+
(w) => `Found project: ${w.name}`,
|
|
1339
|
+
`Could not find project "${workspaceSlugFlag}".`,
|
|
1332
1340
|
() => client.getWorkspaceBySlug(workspaceSlugFlag)
|
|
1333
1341
|
);
|
|
1334
1342
|
if (resolved.status !== "active") {
|
|
1335
1343
|
p3.log.error(
|
|
1336
|
-
`
|
|
1344
|
+
`Project "${resolved.name}" is ${resolved.status}. Only active projects can be initialized.`
|
|
1337
1345
|
);
|
|
1338
1346
|
p3.outro("Aborted.");
|
|
1339
1347
|
process.exit(1);
|
|
1340
1348
|
}
|
|
1341
|
-
pickedId = resolved.organizationId;
|
|
1342
1349
|
workspace = resolved;
|
|
1343
1350
|
appendLog(
|
|
1344
1351
|
"info",
|
|
1345
|
-
`init:
|
|
1352
|
+
`init: project pre-scoped (slug=${workspaceSlugFlag}, id=${resolved.id})`
|
|
1346
1353
|
);
|
|
1347
|
-
const belongs = orgs.some((o) => o.id === pickedId);
|
|
1348
|
-
if (!belongs && !isAdmin) {
|
|
1349
|
-
p3.log.error(
|
|
1350
|
-
"You do not have access to this workspace's organization."
|
|
1351
|
-
);
|
|
1352
|
-
p3.outro("Aborted.");
|
|
1353
|
-
process.exit(1);
|
|
1354
|
-
}
|
|
1355
|
-
if (pickedId !== activeOrgId) {
|
|
1356
|
-
try {
|
|
1357
|
-
if (isAdmin) {
|
|
1358
|
-
await client.setActiveOrganizationAsAdmin(pickedId);
|
|
1359
|
-
} else {
|
|
1360
|
-
await client.setActiveOrganization(pickedId);
|
|
1361
|
-
}
|
|
1362
|
-
} catch (err) {
|
|
1363
|
-
appendLog("error", `init: setActiveOrganization failed: ${formatError(err)}`);
|
|
1364
|
-
p3.log.error(err instanceof Error ? err.message : String(err));
|
|
1365
|
-
p3.outro("Aborted.");
|
|
1366
|
-
process.exit(1);
|
|
1367
|
-
}
|
|
1368
|
-
}
|
|
1369
|
-
activeOrgId = pickedId;
|
|
1370
1354
|
} else {
|
|
1371
|
-
if (orgs.length === 1) {
|
|
1372
|
-
const only = orgs[0];
|
|
1373
|
-
if (!only) {
|
|
1374
|
-
p3.log.error("Unexpected empty organization list.");
|
|
1375
|
-
p3.outro("Aborted.");
|
|
1376
|
-
process.exit(1);
|
|
1377
|
-
}
|
|
1378
|
-
pickedId = only.id;
|
|
1379
|
-
p3.log.info(`Using organization: ${only.name}`);
|
|
1380
|
-
} else {
|
|
1381
|
-
const selected = await p3.select({
|
|
1382
|
-
message: "Select an organization",
|
|
1383
|
-
options: orgs.map((o) => ({
|
|
1384
|
-
value: o.id,
|
|
1385
|
-
label: o.name,
|
|
1386
|
-
hint: o.id === activeOrgId ? `${o.slug ?? ""} (active)` : o.slug ?? ""
|
|
1387
|
-
})),
|
|
1388
|
-
initialValue: activeOrgId ?? orgs[0]?.id
|
|
1389
|
-
});
|
|
1390
|
-
if (p3.isCancel(selected)) {
|
|
1391
|
-
p3.cancel("Cancelled.");
|
|
1392
|
-
process.exit(0);
|
|
1393
|
-
}
|
|
1394
|
-
pickedId = selected;
|
|
1395
|
-
}
|
|
1396
|
-
if (pickedId !== activeOrgId) {
|
|
1397
|
-
try {
|
|
1398
|
-
if (isAdmin) {
|
|
1399
|
-
await client.setActiveOrganizationAsAdmin(pickedId);
|
|
1400
|
-
} else {
|
|
1401
|
-
await client.setActiveOrganization(pickedId);
|
|
1402
|
-
}
|
|
1403
|
-
} catch (err) {
|
|
1404
|
-
appendLog("error", `init: setActiveOrganization failed: ${formatError(err)}`);
|
|
1405
|
-
p3.log.error(err instanceof Error ? err.message : String(err));
|
|
1406
|
-
p3.outro("Aborted.");
|
|
1407
|
-
process.exit(1);
|
|
1408
|
-
}
|
|
1409
|
-
}
|
|
1410
|
-
activeOrgId = pickedId;
|
|
1411
1355
|
const workspaces = await withSpinner(
|
|
1412
|
-
"Loading
|
|
1413
|
-
(ws) => `Found ${ws.length}
|
|
1414
|
-
"Could not list
|
|
1415
|
-
() => client.
|
|
1356
|
+
"Loading projects...",
|
|
1357
|
+
(ws) => `Found ${ws.length} project(s).`,
|
|
1358
|
+
"Could not list projects.",
|
|
1359
|
+
() => client.listProjects()
|
|
1416
1360
|
);
|
|
1417
1361
|
const activeWorkspaces = workspaces.filter((w) => w.status === "active");
|
|
1418
1362
|
const workspaceChoices = activeWorkspaces.length > 0 ? activeWorkspaces : workspaces;
|
|
1419
1363
|
if (workspaceChoices.length === 0) {
|
|
1420
1364
|
p3.log.error(
|
|
1421
|
-
"
|
|
1365
|
+
"You do not have access to any projects. Create one in the web UI first."
|
|
1422
1366
|
);
|
|
1423
1367
|
p3.outro("Aborted.");
|
|
1424
1368
|
process.exit(1);
|
|
1425
1369
|
}
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1370
|
+
let picked;
|
|
1371
|
+
if (workspaceChoices.length === 1) {
|
|
1372
|
+
picked = workspaceChoices[0];
|
|
1373
|
+
p3.log.info(`Using project: ${picked.name}`);
|
|
1374
|
+
} else {
|
|
1375
|
+
const selectedWorkspaceId = await p3.select({
|
|
1376
|
+
message: "Select a project",
|
|
1377
|
+
options: workspaceChoices.map((w) => ({
|
|
1378
|
+
value: w.id,
|
|
1379
|
+
label: w.name,
|
|
1380
|
+
hint: `${w.slug} (${w.status})`
|
|
1381
|
+
}))
|
|
1382
|
+
});
|
|
1383
|
+
if (p3.isCancel(selectedWorkspaceId)) {
|
|
1384
|
+
p3.cancel("Cancelled.");
|
|
1385
|
+
process.exit(0);
|
|
1386
|
+
}
|
|
1387
|
+
picked = workspaceChoices.find((w) => w.id === selectedWorkspaceId);
|
|
1437
1388
|
}
|
|
1438
|
-
const picked = workspaceChoices.find((w) => w.id === selectedWorkspaceId);
|
|
1439
1389
|
if (!picked) {
|
|
1440
1390
|
p3.log.error("Invalid workspace selection.");
|
|
1441
1391
|
p3.outro("Aborted.");
|
|
@@ -1444,7 +1394,7 @@ async function runInit(args = []) {
|
|
|
1444
1394
|
workspace = picked;
|
|
1445
1395
|
appendLog(
|
|
1446
1396
|
"info",
|
|
1447
|
-
`init:
|
|
1397
|
+
`init: project selected (slug=${workspace.slug}, id=${workspace.id})`
|
|
1448
1398
|
);
|
|
1449
1399
|
}
|
|
1450
1400
|
const types = await withSpinner(
|
|
@@ -1455,7 +1405,7 @@ async function runInit(args = []) {
|
|
|
1455
1405
|
);
|
|
1456
1406
|
if (types.length === 0) {
|
|
1457
1407
|
p3.log.error(
|
|
1458
|
-
`
|
|
1408
|
+
`Project "${workspace.name}" has no contribution types. Create one in the web UI first.`
|
|
1459
1409
|
);
|
|
1460
1410
|
p3.outro("Aborted.");
|
|
1461
1411
|
process.exit(1);
|
|
@@ -1468,7 +1418,7 @@ async function runInit(args = []) {
|
|
|
1468
1418
|
p3.log.info(`Using contribution type: ${type.name}`);
|
|
1469
1419
|
} else {
|
|
1470
1420
|
p3.log.warn(
|
|
1471
|
-
'Could not find the default "Agent Traces" contribution type in this
|
|
1421
|
+
'Could not find the default "Agent Traces" contribution type in this project. Please contact the project maintainer.'
|
|
1472
1422
|
);
|
|
1473
1423
|
const selectedTypeId = await p3.select({
|
|
1474
1424
|
message: "Select a contribution type",
|
|
@@ -1500,11 +1450,9 @@ async function runInit(args = []) {
|
|
|
1500
1450
|
"info",
|
|
1501
1451
|
`init: contribution type selected (slug=${type.slug}, name=${type.name})`
|
|
1502
1452
|
);
|
|
1503
|
-
const pickedOrg = orgs.find((o) => o.id === activeOrgId);
|
|
1504
1453
|
await upsertProject(repoRoot, {
|
|
1505
1454
|
apiBaseUrl,
|
|
1506
|
-
organizationId:
|
|
1507
|
-
organizationName: pickedOrg?.name,
|
|
1455
|
+
organizationId: workspace.organizationId,
|
|
1508
1456
|
workspaceId: workspace.id,
|
|
1509
1457
|
workspaceSlug: workspace.slug,
|
|
1510
1458
|
workspaceName: workspace.name,
|
|
@@ -1548,19 +1496,16 @@ async function runInit(args = []) {
|
|
|
1548
1496
|
try {
|
|
1549
1497
|
const changed = await ensureCodexHooksEnabled();
|
|
1550
1498
|
if (changed) {
|
|
1551
|
-
appendLog(
|
|
1552
|
-
|
|
1553
|
-
"init: enabled codex_hooks in ~/.codex/config.toml"
|
|
1554
|
-
);
|
|
1555
|
-
p3.log.success("Enabled codex_hooks in ~/.codex/config.toml");
|
|
1499
|
+
appendLog("info", "init: enabled hooks in ~/.codex/config.toml");
|
|
1500
|
+
p3.log.success("Enabled hooks in ~/.codex/config.toml");
|
|
1556
1501
|
}
|
|
1557
1502
|
} catch (err) {
|
|
1558
1503
|
appendLog(
|
|
1559
1504
|
"warn",
|
|
1560
|
-
`init: could not enable
|
|
1505
|
+
`init: could not enable Codex hooks: ${formatError(err)}`
|
|
1561
1506
|
);
|
|
1562
1507
|
p3.log.warn(
|
|
1563
|
-
`Could not enable
|
|
1508
|
+
`Could not enable hooks in config.toml: ${err instanceof Error ? err.message : String(err)}`
|
|
1564
1509
|
);
|
|
1565
1510
|
}
|
|
1566
1511
|
}
|
|
@@ -1575,7 +1520,7 @@ async function runInit(args = []) {
|
|
|
1575
1520
|
}
|
|
1576
1521
|
appendLog(
|
|
1577
1522
|
"info",
|
|
1578
|
-
`init: completed (
|
|
1523
|
+
`init: completed (project=${workspace.slug}, contributionType=${type.slug})`
|
|
1579
1524
|
);
|
|
1580
1525
|
p3.outro(
|
|
1581
1526
|
`Done. Your next coding session in this repo will upload automatically to ${workspace.name}.`
|
|
@@ -1827,18 +1772,19 @@ async function runStatus(args = []) {
|
|
|
1827
1772
|
const identity = await loadIdentity(config.apiBaseUrl);
|
|
1828
1773
|
let signedInEmail = null;
|
|
1829
1774
|
let loginError = null;
|
|
1830
|
-
let orgNameFromBootstrap = null;
|
|
1831
1775
|
if (!identity) {
|
|
1832
1776
|
loginError = "expired";
|
|
1833
1777
|
} else {
|
|
1834
|
-
const client = new PlatformClient(
|
|
1778
|
+
const client = new PlatformClient(
|
|
1779
|
+
config.apiBaseUrl,
|
|
1780
|
+
identity.sessionCookie
|
|
1781
|
+
);
|
|
1835
1782
|
try {
|
|
1836
1783
|
const bootstrap = await client.getBootstrap();
|
|
1837
1784
|
if (!bootstrap) {
|
|
1838
1785
|
loginError = "expired";
|
|
1839
1786
|
} else {
|
|
1840
1787
|
signedInEmail = bootstrap.session.email;
|
|
1841
|
-
orgNameFromBootstrap = bootstrap.organizations.find((o) => o.id === config.organizationId)?.name ?? null;
|
|
1842
1788
|
}
|
|
1843
1789
|
} catch (err) {
|
|
1844
1790
|
if (err instanceof PlatformError && err.status === 401) {
|
|
@@ -1858,9 +1804,7 @@ async function runStatus(args = []) {
|
|
|
1858
1804
|
} else {
|
|
1859
1805
|
row(CROSS, "Login", dim(`couldn't reach ${config.apiBaseUrl}`));
|
|
1860
1806
|
}
|
|
1861
|
-
|
|
1862
|
-
row(CHECK, "Organization", bold(orgDisplay));
|
|
1863
|
-
row(CHECK, "Workspace", bold(config.workspaceName));
|
|
1807
|
+
row(CHECK, "Project", bold(config.workspaceName));
|
|
1864
1808
|
row(CHECK, "Contribution", bold(config.contributionTypeName));
|
|
1865
1809
|
row(CHECK, "Repo", bold(repoName));
|
|
1866
1810
|
let anyHookInstalled = false;
|
|
@@ -1898,9 +1842,11 @@ async function runStatus(args = []) {
|
|
|
1898
1842
|
debugRow("Configured repos:", String(Object.keys(projects.projects).length));
|
|
1899
1843
|
debugRow("Repo root:", repoRoot);
|
|
1900
1844
|
debugRow("API URL:", config.apiBaseUrl);
|
|
1901
|
-
|
|
1845
|
+
if (config.organizationId) {
|
|
1846
|
+
debugRow("Legacy org ID:", config.organizationId);
|
|
1847
|
+
}
|
|
1902
1848
|
const wsIdent = config.workspaceSlug === config.workspaceId ? config.workspaceId : `${config.workspaceSlug} / ${config.workspaceId}`;
|
|
1903
|
-
debugRow("
|
|
1849
|
+
debugRow("Project:", `${config.workspaceName} (${wsIdent})`);
|
|
1904
1850
|
debugRow(
|
|
1905
1851
|
"Contribution type:",
|
|
1906
1852
|
`${config.contributionTypeName} (${config.contributionTypeSlug})`
|
|
@@ -11717,13 +11663,8 @@ async function readStdin() {
|
|
|
11717
11663
|
function sanitize(value) {
|
|
11718
11664
|
return value.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
11719
11665
|
}
|
|
11720
|
-
function
|
|
11721
|
-
|
|
11722
|
-
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}-${pad(date.getHours())}${pad(date.getMinutes())}${pad(date.getSeconds())}`;
|
|
11723
|
-
}
|
|
11724
|
-
function formatTitleTimestamp(date) {
|
|
11725
|
-
const pad = (n) => String(n).padStart(2, "0");
|
|
11726
|
-
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}`;
|
|
11666
|
+
function formatEpochSeconds(date) {
|
|
11667
|
+
return String(Math.floor(date.getTime() / 1e3));
|
|
11727
11668
|
}
|
|
11728
11669
|
function lineHasAssistant(line) {
|
|
11729
11670
|
return line.includes('"type":"assistant"') || line.includes('"role":"assistant"') || line.includes('"type":"assistant.');
|
|
@@ -11871,12 +11812,13 @@ async function uploadSession(args) {
|
|
|
11871
11812
|
opencode: "opencode"
|
|
11872
11813
|
};
|
|
11873
11814
|
const toolLabel = toolLabels[sourceTool] ?? "Claude";
|
|
11874
|
-
const
|
|
11815
|
+
const epochSeconds = formatEpochSeconds(now);
|
|
11816
|
+
const title = `${toolLabel} session ${shortId} \u2014 ${epochSeconds}`;
|
|
11875
11817
|
const body = `Session ID: ${sessionId}
|
|
11876
11818
|
Tool: ${toolLabel}
|
|
11877
11819
|
Repo: ${repoRoot}
|
|
11878
11820
|
Uploaded: ${now.toISOString()}`;
|
|
11879
|
-
const zipFilename = `${sourceTool}-${sanitize(shortId)}-${
|
|
11821
|
+
const zipFilename = `${sourceTool}-${sanitize(shortId)}-${epochSeconds}.zip`;
|
|
11880
11822
|
const output = new PlatformUploadOutput({
|
|
11881
11823
|
client,
|
|
11882
11824
|
workspaceId: config.workspaceId,
|
|
@@ -12519,9 +12461,8 @@ async function releaseLock(repoRoot, tool) {
|
|
|
12519
12461
|
var CLI_VERSION = "0.1.0";
|
|
12520
12462
|
var GIT_TRACES_SLUG = "git-traces";
|
|
12521
12463
|
var MAX_UPLOAD_BYTES = 500 * 1024 * 1024;
|
|
12522
|
-
function
|
|
12523
|
-
|
|
12524
|
-
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}`;
|
|
12464
|
+
function formatEpochSeconds2(date) {
|
|
12465
|
+
return String(Math.floor(date.getTime() / 1e3));
|
|
12525
12466
|
}
|
|
12526
12467
|
var TOOL_LABELS = {
|
|
12527
12468
|
cursor: "Cursor",
|
|
@@ -12768,12 +12709,13 @@ async function handleStop(payload, tool) {
|
|
|
12768
12709
|
if (!artifacts) return;
|
|
12769
12710
|
const toolLabel = TOOL_LABELS[tool] ?? "Claude";
|
|
12770
12711
|
const now = /* @__PURE__ */ new Date();
|
|
12712
|
+
const epochSeconds = formatEpochSeconds2(now);
|
|
12771
12713
|
const shortId = state.sessionId.slice(0, 12);
|
|
12772
12714
|
const contribution = await client.createContribution(
|
|
12773
12715
|
project.config.workspaceId,
|
|
12774
12716
|
{
|
|
12775
12717
|
contributionTypeSlug: GIT_TRACES_SLUG,
|
|
12776
|
-
title: `${toolLabel} session ${shortId} \u2014 ${
|
|
12718
|
+
title: `${toolLabel} session ${shortId} \u2014 ${epochSeconds}`,
|
|
12777
12719
|
body: `Session ID: ${state.sessionId}
|
|
12778
12720
|
Tool: ${toolLabel}
|
|
12779
12721
|
Repo: ${cwd}
|
|
@@ -13130,9 +13072,8 @@ var ZipOutput = class {
|
|
|
13130
13072
|
const repoName = sanitizeFilename(path15.basename(group.repoPath));
|
|
13131
13073
|
const timeRange = options.timeRange;
|
|
13132
13074
|
const rangePart = timeRange?.label ?? "all";
|
|
13133
|
-
const
|
|
13134
|
-
const
|
|
13135
|
-
const baseName = `logs-${repoName}-${rangePart}-${timestamp}`;
|
|
13075
|
+
const epochSeconds = Math.floor(Date.now() / 1e3);
|
|
13076
|
+
const baseName = `logs-${repoName}-${rangePart}-${epochSeconds}`;
|
|
13136
13077
|
const outputPath = getUniqueFilename(downloadsDir, baseName, ".zip");
|
|
13137
13078
|
const output = fs12.createWriteStream(outputPath);
|
|
13138
13079
|
const archive = archiver2("zip", { zlib: { level: 6 } });
|