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