@basou/cli 0.65.0 → 0.67.0
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/index.js +434 -332
- package/dist/index.js.map +1 -1
- package/dist/program.js +433 -333
- package/dist/program.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -138,7 +138,7 @@ import {
|
|
|
138
138
|
assertBasouRootSafe,
|
|
139
139
|
assertLockStoreSafe,
|
|
140
140
|
assertSessionDirSafe,
|
|
141
|
-
basouPaths,
|
|
141
|
+
basouPaths as basouPaths2,
|
|
142
142
|
EVENT_SCHEMA_VERSION,
|
|
143
143
|
enumerateApprovals,
|
|
144
144
|
findErrorCode,
|
|
@@ -152,9 +152,154 @@ import {
|
|
|
152
152
|
prefixedUlid,
|
|
153
153
|
readSessionYaml,
|
|
154
154
|
readYamlFile,
|
|
155
|
-
replayEvents
|
|
155
|
+
replayEvents
|
|
156
|
+
} from "@basou/core";
|
|
157
|
+
|
|
158
|
+
// src/lib/repo-root.ts
|
|
159
|
+
import { realpath, stat } from "fs/promises";
|
|
160
|
+
import { basename, resolve } from "path";
|
|
161
|
+
import {
|
|
162
|
+
basouPaths,
|
|
163
|
+
defaultPortfolioConfigPath,
|
|
164
|
+
loadPortfolioConfig,
|
|
165
|
+
readManifest,
|
|
166
|
+
resolveBasouRepositoryRoot,
|
|
156
167
|
resolveRepositoryRoot
|
|
157
168
|
} from "@basou/core";
|
|
169
|
+
async function resolveBasouRootForCommand(cwd, commandName, opts = {}) {
|
|
170
|
+
let root;
|
|
171
|
+
try {
|
|
172
|
+
root = await resolveBasouRepositoryRoot(cwd, {
|
|
173
|
+
onRedirect: ({ via, root: root2 }) => {
|
|
174
|
+
if (opts.quiet !== true) console.error(`Resolved workspace view to ${root2} (via ${via}).`);
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
} catch (error) {
|
|
178
|
+
if (error instanceof Error && error.message === "Not a git repository") {
|
|
179
|
+
throw new Error(
|
|
180
|
+
`Not a git repository. Run 'git init' first, then re-run 'basou ${commandName}'.`,
|
|
181
|
+
{ cause: error }
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
throw error;
|
|
185
|
+
}
|
|
186
|
+
if (!await hasBasouStore(root)) {
|
|
187
|
+
const master = await resolveMemberToMaster(
|
|
188
|
+
root,
|
|
189
|
+
opts.portfolioConfigPath ?? defaultPortfolioConfigPath()
|
|
190
|
+
);
|
|
191
|
+
if (master !== void 0) {
|
|
192
|
+
if (opts.quiet !== true) {
|
|
193
|
+
console.error(
|
|
194
|
+
`Resolved portfolio member to ${master.root} (via portfolio: ${master.label}).`
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
return master.root;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return root;
|
|
201
|
+
}
|
|
202
|
+
async function resolveRepositoryRootInPlace(cwd, commandName) {
|
|
203
|
+
try {
|
|
204
|
+
return await resolveRepositoryRoot(cwd);
|
|
205
|
+
} catch (error) {
|
|
206
|
+
if (!(error instanceof Error) || error.message !== "Not a git repository") throw error;
|
|
207
|
+
const links = await describeWorkspaceView(cwd);
|
|
208
|
+
if (links !== void 0) {
|
|
209
|
+
throw new Error(
|
|
210
|
+
`Not a git repository: this is a workspace view (it links ${links}). Run 'basou ${commandName}' inside a repository instead.`,
|
|
211
|
+
{ cause: error }
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
throw new Error(
|
|
215
|
+
`Not a git repository. Run 'git init' first, then re-run 'basou ${commandName}'.`,
|
|
216
|
+
{ cause: error }
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
async function describeWorkspaceView(dir) {
|
|
221
|
+
let via;
|
|
222
|
+
try {
|
|
223
|
+
await resolveBasouRepositoryRoot(dir, {
|
|
224
|
+
onRedirect: (info) => {
|
|
225
|
+
via = info.via;
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
} catch (error) {
|
|
229
|
+
if (error instanceof Error && error.message.startsWith("Ambiguous workspace view:")) {
|
|
230
|
+
return "more than one repository with a .basou store";
|
|
231
|
+
}
|
|
232
|
+
return void 0;
|
|
233
|
+
}
|
|
234
|
+
return via;
|
|
235
|
+
}
|
|
236
|
+
async function hasBasouStore(root) {
|
|
237
|
+
try {
|
|
238
|
+
return (await stat(basouPaths(root).root)).isDirectory();
|
|
239
|
+
} catch {
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
async function resolveMemberToMaster(repoRoot, configPath) {
|
|
244
|
+
let workspaces;
|
|
245
|
+
try {
|
|
246
|
+
workspaces = await loadPortfolioConfig(configPath);
|
|
247
|
+
} catch (error) {
|
|
248
|
+
if (!(error instanceof Error) || !error.message.startsWith("No portfolio config at")) {
|
|
249
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
250
|
+
console.error(`Ignoring ~/.basou/portfolio.yaml: ${detail}`);
|
|
251
|
+
}
|
|
252
|
+
return void 0;
|
|
253
|
+
}
|
|
254
|
+
const memberReal = await realpathOrNull(repoRoot);
|
|
255
|
+
if (memberReal === null) return void 0;
|
|
256
|
+
const claimants = /* @__PURE__ */ new Map();
|
|
257
|
+
const seenMaster = /* @__PURE__ */ new Set();
|
|
258
|
+
for (const ws of workspaces) {
|
|
259
|
+
const masterReal = await realpathOrNull(ws.path);
|
|
260
|
+
if (masterReal === null) continue;
|
|
261
|
+
if (masterReal === memberReal) continue;
|
|
262
|
+
if (seenMaster.has(masterReal)) continue;
|
|
263
|
+
seenMaster.add(masterReal);
|
|
264
|
+
let manifest;
|
|
265
|
+
try {
|
|
266
|
+
manifest = await readManifest(basouPaths(masterReal));
|
|
267
|
+
} catch (error) {
|
|
268
|
+
if (error instanceof Error && error.message !== "YAML file not found") {
|
|
269
|
+
console.error(
|
|
270
|
+
`Skipping portfolio workspace '${ws.label ?? basename(masterReal)}': could not read its manifest (${error.message}).`
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
const sourceRoots = manifest.import?.source_roots ?? ["."];
|
|
276
|
+
for (const sr of sourceRoots) {
|
|
277
|
+
const real = await realpathOrNull(resolve(masterReal, sr));
|
|
278
|
+
if (real !== null && real === memberReal) {
|
|
279
|
+
claimants.set(masterReal, { root: masterReal, label: ws.label ?? basename(masterReal) });
|
|
280
|
+
break;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
const matched = [...claimants.values()];
|
|
285
|
+
if (matched.length === 1) return matched[0];
|
|
286
|
+
if (matched.length > 1) {
|
|
287
|
+
const names = matched.map((c) => c.label).join(", ");
|
|
288
|
+
throw new Error(
|
|
289
|
+
`This repository is declared as a source root by ${matched.length} portfolio workspaces (${names}). Disambiguate in ~/.basou/portfolio.yaml so only one aggregates it.`
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
return void 0;
|
|
293
|
+
}
|
|
294
|
+
async function realpathOrNull(p) {
|
|
295
|
+
try {
|
|
296
|
+
return await realpath(p);
|
|
297
|
+
} catch {
|
|
298
|
+
return null;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// src/commands/approval.ts
|
|
158
303
|
var APPR_PREFIX = "appr_";
|
|
159
304
|
var SHORT_ID_BASE_LEN = 6;
|
|
160
305
|
var SHORT_ID_MAX_LEN = 26;
|
|
@@ -190,8 +335,8 @@ async function runApprovalList(options, ctx = {}) {
|
|
|
190
335
|
}
|
|
191
336
|
async function doRunApprovalList(options, ctx) {
|
|
192
337
|
const cwd = ctx.cwd ?? process.cwd();
|
|
193
|
-
const repositoryRoot = await
|
|
194
|
-
const paths =
|
|
338
|
+
const repositoryRoot = await resolveBasouRootForCommand(cwd, "approval list");
|
|
339
|
+
const paths = basouPaths2(repositoryRoot);
|
|
195
340
|
await assertWorkspaceInitialized(paths.root);
|
|
196
341
|
const ids = await enumerateApprovals(paths);
|
|
197
342
|
for (const entry of ids.unfollowed) {
|
|
@@ -263,8 +408,8 @@ async function runApprovalShow(idInput, options, ctx = {}) {
|
|
|
263
408
|
}
|
|
264
409
|
async function doRunApprovalShow(idInput, options, ctx) {
|
|
265
410
|
const cwd = ctx.cwd ?? process.cwd();
|
|
266
|
-
const repositoryRoot = await
|
|
267
|
-
const paths =
|
|
411
|
+
const repositoryRoot = await resolveBasouRootForCommand(cwd, "approval show");
|
|
412
|
+
const paths = basouPaths2(repositoryRoot);
|
|
268
413
|
await assertWorkspaceInitialized(paths.root);
|
|
269
414
|
const { id, unfollowed } = await resolveApprovalId(paths, idInput);
|
|
270
415
|
for (const entry2 of unfollowed) console.error(`Warning: ${describeUnfollowed(entry2)}`);
|
|
@@ -329,8 +474,8 @@ async function doRunApprovalResolve(idInput, options, ctx, decision) {
|
|
|
329
474
|
}
|
|
330
475
|
}
|
|
331
476
|
const cwd = ctx.cwd ?? process.cwd();
|
|
332
|
-
const repositoryRoot = await
|
|
333
|
-
const paths =
|
|
477
|
+
const repositoryRoot = await resolveBasouRootForCommand(cwd, `approval ${decision}`);
|
|
478
|
+
const paths = basouPaths2(repositoryRoot);
|
|
334
479
|
await assertWorkspaceInitialized(paths.root);
|
|
335
480
|
const { id, location } = await resolveApprovalId(paths, idInput);
|
|
336
481
|
if (location === "resolved") {
|
|
@@ -651,19 +796,6 @@ function truncate(value, maxLength) {
|
|
|
651
796
|
if (value.length <= maxLength) return value;
|
|
652
797
|
return `${value.slice(0, maxLength - 3)}...`;
|
|
653
798
|
}
|
|
654
|
-
async function resolveRepositoryRootForApproval(cwd, subcmd) {
|
|
655
|
-
try {
|
|
656
|
-
return await resolveRepositoryRoot(cwd);
|
|
657
|
-
} catch (error) {
|
|
658
|
-
if (error instanceof Error && error.message === "Not a git repository") {
|
|
659
|
-
throw new Error(
|
|
660
|
-
`Not a git repository. Run 'git init' first, then re-run 'basou approval ${subcmd}'.`,
|
|
661
|
-
{ cause: error }
|
|
662
|
-
);
|
|
663
|
-
}
|
|
664
|
-
throw error;
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
799
|
async function assertWorkspaceInitialized(basouRoot) {
|
|
668
800
|
try {
|
|
669
801
|
await assertBasouRootSafe(basouRoot);
|
|
@@ -710,6 +842,7 @@ import {
|
|
|
710
842
|
displayPath as displayPath3,
|
|
711
843
|
findErrorCode as findErrorCode3,
|
|
712
844
|
measureBoard,
|
|
845
|
+
measureBoardLive,
|
|
713
846
|
NO_PREVIOUS_RECORDS,
|
|
714
847
|
parseBoardDeclaration,
|
|
715
848
|
parseRecordInput,
|
|
@@ -733,16 +866,16 @@ import {
|
|
|
733
866
|
|
|
734
867
|
// src/commands/import.ts
|
|
735
868
|
import { createReadStream } from "fs";
|
|
736
|
-
import { readdir, readFile, rm, stat } from "fs/promises";
|
|
869
|
+
import { readdir, readFile, rm, stat as stat2 } from "fs/promises";
|
|
737
870
|
import { homedir } from "os";
|
|
738
|
-
import { basename, dirname as dirname2, join as join2, resolve } from "path";
|
|
871
|
+
import { basename as basename2, dirname as dirname2, join as join2, resolve as resolve2 } from "path";
|
|
739
872
|
import { createInterface } from "readline";
|
|
740
873
|
import {
|
|
741
874
|
AGENT_INFRA_DIRS,
|
|
742
875
|
assertBasouRootSafe as assertBasouRootSafe2,
|
|
743
876
|
assertLockStoreSafe as assertLockStoreSafe2,
|
|
744
877
|
assertSessionStoreSafe,
|
|
745
|
-
basouPaths as
|
|
878
|
+
basouPaths as basouPaths3,
|
|
746
879
|
CLAUDE_IMPORT_SOURCE,
|
|
747
880
|
CODEX_IMPORT_SOURCE,
|
|
748
881
|
classifyFilesBySourceRoot,
|
|
@@ -753,11 +886,10 @@ import {
|
|
|
753
886
|
findErrorCode as findErrorCode2,
|
|
754
887
|
importSessionFromJson,
|
|
755
888
|
observedFilesOf,
|
|
756
|
-
readManifest,
|
|
889
|
+
readManifest as readManifest2,
|
|
757
890
|
readSessionObservation,
|
|
758
891
|
readSessionYaml as readSessionYaml2,
|
|
759
892
|
reimportPreservingId,
|
|
760
|
-
resolveRepositoryRoot as resolveRepositoryRoot2,
|
|
761
893
|
SESSION_IMPORT_SCHEMA_VERSION,
|
|
762
894
|
SessionImportPayloadSchema
|
|
763
895
|
} from "@basou/core";
|
|
@@ -827,10 +959,10 @@ function resolveSourceRoots(args) {
|
|
|
827
959
|
const { projectFlags, manifest, repoRoot, cwd } = args;
|
|
828
960
|
let resolved;
|
|
829
961
|
if (projectFlags.length > 0) {
|
|
830
|
-
resolved = projectFlags.map((p) =>
|
|
962
|
+
resolved = projectFlags.map((p) => resolve2(cwd, p));
|
|
831
963
|
} else {
|
|
832
964
|
const roots = manifest.import?.source_roots;
|
|
833
|
-
resolved = roots !== void 0 && roots.length > 0 ? roots.map((r) =>
|
|
965
|
+
resolved = roots !== void 0 && roots.length > 0 ? roots.map((r) => resolve2(repoRoot, r)) : [repoRoot];
|
|
834
966
|
}
|
|
835
967
|
return [...new Set(resolved)];
|
|
836
968
|
}
|
|
@@ -848,7 +980,7 @@ async function doRunImportClaudeCode(options, ctx) {
|
|
|
848
980
|
const files = await selectTranscriptFiles(projectsRoot, projectPaths, options);
|
|
849
981
|
const projectSet = new Set(projectPaths);
|
|
850
982
|
const candidates = files.map((file) => {
|
|
851
|
-
const externalId =
|
|
983
|
+
const externalId = basename2(file, ".jsonl");
|
|
852
984
|
return {
|
|
853
985
|
externalId,
|
|
854
986
|
sourcePath: file,
|
|
@@ -923,10 +1055,10 @@ function assertSelector(options) {
|
|
|
923
1055
|
}
|
|
924
1056
|
async function resolveImportTarget(ctx) {
|
|
925
1057
|
const cwd = ctx.cwd ?? process.cwd();
|
|
926
|
-
const repositoryRoot = await
|
|
927
|
-
const paths =
|
|
1058
|
+
const repositoryRoot = await resolveBasouRootForCommand(cwd, "import");
|
|
1059
|
+
const paths = basouPaths3(repositoryRoot);
|
|
928
1060
|
await assertWorkspaceInitialized2(paths.root);
|
|
929
|
-
const manifest = await
|
|
1061
|
+
const manifest = await readManifest2(paths);
|
|
930
1062
|
return { repositoryRoot, paths, manifest };
|
|
931
1063
|
}
|
|
932
1064
|
async function importDerivedSessions(paths, manifest, options, sourceKind, candidates, projectPaths, boundaryDeclared) {
|
|
@@ -1173,7 +1305,7 @@ async function selectTranscriptFiles(projectsRoot, projectPaths, options) {
|
|
|
1173
1305
|
}
|
|
1174
1306
|
async function pathExists(file) {
|
|
1175
1307
|
try {
|
|
1176
|
-
await
|
|
1308
|
+
await stat2(file);
|
|
1177
1309
|
return true;
|
|
1178
1310
|
} catch (error) {
|
|
1179
1311
|
if (findErrorCode2(error, "ENOENT")) return false;
|
|
@@ -1182,7 +1314,7 @@ async function pathExists(file) {
|
|
|
1182
1314
|
}
|
|
1183
1315
|
async function statSize(file) {
|
|
1184
1316
|
try {
|
|
1185
|
-
return (await
|
|
1317
|
+
return (await stat2(file)).size;
|
|
1186
1318
|
} catch (error) {
|
|
1187
1319
|
if (findErrorCode2(error, "ENOENT")) return void 0;
|
|
1188
1320
|
throw error;
|
|
@@ -1374,18 +1506,6 @@ function shortId2(id) {
|
|
|
1374
1506
|
}
|
|
1375
1507
|
return id.slice(0, SHORT_ID_LEN2);
|
|
1376
1508
|
}
|
|
1377
|
-
async function resolveRepositoryRootForImport(cwd) {
|
|
1378
|
-
try {
|
|
1379
|
-
return await resolveRepositoryRoot2(cwd);
|
|
1380
|
-
} catch (error) {
|
|
1381
|
-
if (error instanceof Error && error.message === "Not a git repository") {
|
|
1382
|
-
throw new Error("Not a git repository. Run 'git init' first, then re-run 'basou import'.", {
|
|
1383
|
-
cause: error
|
|
1384
|
-
});
|
|
1385
|
-
}
|
|
1386
|
-
throw error;
|
|
1387
|
-
}
|
|
1388
|
-
}
|
|
1389
1509
|
async function assertWorkspaceInitialized2(basouRoot) {
|
|
1390
1510
|
try {
|
|
1391
1511
|
await assertBasouRootSafe2(basouRoot);
|
|
@@ -1398,7 +1518,13 @@ async function assertWorkspaceInitialized2(basouRoot) {
|
|
|
1398
1518
|
}
|
|
1399
1519
|
|
|
1400
1520
|
// src/lib/provenance-actions.ts
|
|
1401
|
-
|
|
1521
|
+
var capturing = Promise.resolve();
|
|
1522
|
+
function captureImportJson(fn) {
|
|
1523
|
+
const turn = capturing.then(() => captureNow(fn));
|
|
1524
|
+
capturing = turn.catch(() => void 0);
|
|
1525
|
+
return turn;
|
|
1526
|
+
}
|
|
1527
|
+
async function captureNow(fn) {
|
|
1402
1528
|
const stdout = [];
|
|
1403
1529
|
const originalLog = console.log;
|
|
1404
1530
|
const originalError = console.error;
|
|
@@ -1578,111 +1704,6 @@ async function probeStaleness(args) {
|
|
|
1578
1704
|
}
|
|
1579
1705
|
}
|
|
1580
1706
|
|
|
1581
|
-
// src/lib/repo-root.ts
|
|
1582
|
-
import { realpath, stat as stat2 } from "fs/promises";
|
|
1583
|
-
import { basename as basename2, resolve as resolve2 } from "path";
|
|
1584
|
-
import {
|
|
1585
|
-
basouPaths as basouPaths3,
|
|
1586
|
-
defaultPortfolioConfigPath,
|
|
1587
|
-
loadPortfolioConfig,
|
|
1588
|
-
readManifest as readManifest2,
|
|
1589
|
-
resolveBasouRepositoryRoot
|
|
1590
|
-
} from "@basou/core";
|
|
1591
|
-
async function resolveBasouRootForCommand(cwd, commandName, opts = {}) {
|
|
1592
|
-
let root;
|
|
1593
|
-
try {
|
|
1594
|
-
root = await resolveBasouRepositoryRoot(cwd, {
|
|
1595
|
-
onRedirect: ({ via, root: root2 }) => console.error(`Resolved workspace view to ${root2} (via ${via}).`)
|
|
1596
|
-
});
|
|
1597
|
-
} catch (error) {
|
|
1598
|
-
if (error instanceof Error && error.message === "Not a git repository") {
|
|
1599
|
-
throw new Error(
|
|
1600
|
-
`Not a git repository. Run 'git init' first, then re-run 'basou ${commandName}'.`,
|
|
1601
|
-
{ cause: error }
|
|
1602
|
-
);
|
|
1603
|
-
}
|
|
1604
|
-
throw error;
|
|
1605
|
-
}
|
|
1606
|
-
if (!await hasBasouStore(root)) {
|
|
1607
|
-
const master = await resolveMemberToMaster(
|
|
1608
|
-
root,
|
|
1609
|
-
opts.portfolioConfigPath ?? defaultPortfolioConfigPath()
|
|
1610
|
-
);
|
|
1611
|
-
if (master !== void 0) {
|
|
1612
|
-
console.error(
|
|
1613
|
-
`Resolved portfolio member to ${master.root} (via portfolio: ${master.label}).`
|
|
1614
|
-
);
|
|
1615
|
-
return master.root;
|
|
1616
|
-
}
|
|
1617
|
-
}
|
|
1618
|
-
return root;
|
|
1619
|
-
}
|
|
1620
|
-
async function hasBasouStore(root) {
|
|
1621
|
-
try {
|
|
1622
|
-
return (await stat2(basouPaths3(root).root)).isDirectory();
|
|
1623
|
-
} catch {
|
|
1624
|
-
return false;
|
|
1625
|
-
}
|
|
1626
|
-
}
|
|
1627
|
-
async function resolveMemberToMaster(repoRoot, configPath) {
|
|
1628
|
-
let workspaces;
|
|
1629
|
-
try {
|
|
1630
|
-
workspaces = await loadPortfolioConfig(configPath);
|
|
1631
|
-
} catch (error) {
|
|
1632
|
-
if (!(error instanceof Error) || !error.message.startsWith("No portfolio config at")) {
|
|
1633
|
-
const detail = error instanceof Error ? error.message : String(error);
|
|
1634
|
-
console.error(`Ignoring ~/.basou/portfolio.yaml: ${detail}`);
|
|
1635
|
-
}
|
|
1636
|
-
return void 0;
|
|
1637
|
-
}
|
|
1638
|
-
const memberReal = await realpathOrNull(repoRoot);
|
|
1639
|
-
if (memberReal === null) return void 0;
|
|
1640
|
-
const claimants = /* @__PURE__ */ new Map();
|
|
1641
|
-
const seenMaster = /* @__PURE__ */ new Set();
|
|
1642
|
-
for (const ws of workspaces) {
|
|
1643
|
-
const masterReal = await realpathOrNull(ws.path);
|
|
1644
|
-
if (masterReal === null) continue;
|
|
1645
|
-
if (masterReal === memberReal) continue;
|
|
1646
|
-
if (seenMaster.has(masterReal)) continue;
|
|
1647
|
-
seenMaster.add(masterReal);
|
|
1648
|
-
let manifest;
|
|
1649
|
-
try {
|
|
1650
|
-
manifest = await readManifest2(basouPaths3(masterReal));
|
|
1651
|
-
} catch (error) {
|
|
1652
|
-
if (error instanceof Error && error.message !== "YAML file not found") {
|
|
1653
|
-
console.error(
|
|
1654
|
-
`Skipping portfolio workspace '${ws.label ?? basename2(masterReal)}': could not read its manifest (${error.message}).`
|
|
1655
|
-
);
|
|
1656
|
-
}
|
|
1657
|
-
continue;
|
|
1658
|
-
}
|
|
1659
|
-
const sourceRoots = manifest.import?.source_roots ?? ["."];
|
|
1660
|
-
for (const sr of sourceRoots) {
|
|
1661
|
-
const real = await realpathOrNull(resolve2(masterReal, sr));
|
|
1662
|
-
if (real !== null && real === memberReal) {
|
|
1663
|
-
claimants.set(masterReal, { root: masterReal, label: ws.label ?? basename2(masterReal) });
|
|
1664
|
-
break;
|
|
1665
|
-
}
|
|
1666
|
-
}
|
|
1667
|
-
}
|
|
1668
|
-
const matched = [...claimants.values()];
|
|
1669
|
-
if (matched.length === 1) return matched[0];
|
|
1670
|
-
if (matched.length > 1) {
|
|
1671
|
-
const names = matched.map((c) => c.label).join(", ");
|
|
1672
|
-
throw new Error(
|
|
1673
|
-
`This repository is declared as a source root by ${matched.length} portfolio workspaces (${names}). Disambiguate in ~/.basou/portfolio.yaml so only one aggregates it.`
|
|
1674
|
-
);
|
|
1675
|
-
}
|
|
1676
|
-
return void 0;
|
|
1677
|
-
}
|
|
1678
|
-
async function realpathOrNull(p) {
|
|
1679
|
-
try {
|
|
1680
|
-
return await realpath(p);
|
|
1681
|
-
} catch {
|
|
1682
|
-
return null;
|
|
1683
|
-
}
|
|
1684
|
-
}
|
|
1685
|
-
|
|
1686
1707
|
// src/commands/board.ts
|
|
1687
1708
|
var DEFAULT_BOARD_PATH = "board/board.yaml";
|
|
1688
1709
|
function registerBoardCommand(program2) {
|
|
@@ -2012,6 +2033,41 @@ async function measureLoaded(loaded, ctx, model, previous) {
|
|
|
2012
2033
|
previous
|
|
2013
2034
|
});
|
|
2014
2035
|
}
|
|
2036
|
+
async function measureLiveBoard(root, ctx) {
|
|
2037
|
+
const paths = basouPaths4(root);
|
|
2038
|
+
let repos = ["."];
|
|
2039
|
+
let manifestUnread = false;
|
|
2040
|
+
try {
|
|
2041
|
+
const declared = ((await readManifest3(paths)).repos ?? []).map((repo) => repo.path);
|
|
2042
|
+
if (declared.length > 0) repos = declared;
|
|
2043
|
+
} catch {
|
|
2044
|
+
manifestUnread = true;
|
|
2045
|
+
}
|
|
2046
|
+
const now = ctx.nowProvider?.() ?? /* @__PURE__ */ new Date();
|
|
2047
|
+
const probeCtx = { cwd: root };
|
|
2048
|
+
if (ctx.claudeProjectsDir !== void 0) probeCtx.claudeProjectsDir = ctx.claudeProjectsDir;
|
|
2049
|
+
if (ctx.codexSessionsDir !== void 0) probeCtx.codexSessionsDir = ctx.codexSessionsDir;
|
|
2050
|
+
const measured = await measureBoardLive({
|
|
2051
|
+
root,
|
|
2052
|
+
repos,
|
|
2053
|
+
paths,
|
|
2054
|
+
now,
|
|
2055
|
+
measuredWith: { basou: BASOU_CLI_VERSION, build: BASOU_BUILD?.commit ?? null },
|
|
2056
|
+
probeImports: () => probeStaleness({ ctx: probeCtx, paths, nowIso: now.toISOString() })
|
|
2057
|
+
});
|
|
2058
|
+
if (!manifestUnread) return measured;
|
|
2059
|
+
return {
|
|
2060
|
+
...measured,
|
|
2061
|
+
complete: false,
|
|
2062
|
+
not_found: [
|
|
2063
|
+
{
|
|
2064
|
+
at: "repos",
|
|
2065
|
+
reason: "the manifest could not be read, so only the workspace's own repo was measured"
|
|
2066
|
+
},
|
|
2067
|
+
...measured.not_found
|
|
2068
|
+
]
|
|
2069
|
+
};
|
|
2070
|
+
}
|
|
2015
2071
|
function boardPath(options, cwd, root, manifest) {
|
|
2016
2072
|
if (options.board !== void 0)
|
|
2017
2073
|
return { path: resolve3(cwd, options.board), shown: options.board, given: true };
|
|
@@ -2479,7 +2535,6 @@ import {
|
|
|
2479
2535
|
prefixedUlid as prefixedUlid2,
|
|
2480
2536
|
readManifest as readManifest4,
|
|
2481
2537
|
replayEvents as replayEvents2,
|
|
2482
|
-
resolveRepositoryRoot as resolveRepositoryRoot3,
|
|
2483
2538
|
resolveSessionId,
|
|
2484
2539
|
sanitizePath
|
|
2485
2540
|
} from "@basou/core";
|
|
@@ -2762,7 +2817,7 @@ async function warnLinkedFilesOutsideRoots(input) {
|
|
|
2762
2817
|
}
|
|
2763
2818
|
async function doRunDecisionRecord(options, ctx) {
|
|
2764
2819
|
const cwd = ctx.cwd ?? process.cwd();
|
|
2765
|
-
const repositoryRoot = await
|
|
2820
|
+
const repositoryRoot = await resolveBasouRootForCommand(cwd, "decision record");
|
|
2766
2821
|
const paths = basouPaths6(repositoryRoot);
|
|
2767
2822
|
await assertWorkspaceInitialized4(paths.root);
|
|
2768
2823
|
const now = ctx.nowProvider !== void 0 ? ctx.nowProvider() : /* @__PURE__ */ new Date();
|
|
@@ -3409,19 +3464,6 @@ function printDecisionResult(options, result) {
|
|
|
3409
3464
|
);
|
|
3410
3465
|
}
|
|
3411
3466
|
}
|
|
3412
|
-
async function resolveRepositoryRootForDecision(cwd) {
|
|
3413
|
-
try {
|
|
3414
|
-
return await resolveRepositoryRoot3(cwd);
|
|
3415
|
-
} catch (error) {
|
|
3416
|
-
if (error instanceof Error && error.message === "Not a git repository") {
|
|
3417
|
-
throw new Error(
|
|
3418
|
-
"Not a git repository. Run 'git init' first, then re-run 'basou decision record'.",
|
|
3419
|
-
{ cause: error }
|
|
3420
|
-
);
|
|
3421
|
-
}
|
|
3422
|
-
throw error;
|
|
3423
|
-
}
|
|
3424
|
-
}
|
|
3425
3467
|
async function assertWorkspaceInitialized4(basouRoot) {
|
|
3426
3468
|
try {
|
|
3427
3469
|
await assertBasouRootSafe4(basouRoot);
|
|
@@ -3441,7 +3483,6 @@ import {
|
|
|
3441
3483
|
readMarkdownFile as readMarkdownFile3,
|
|
3442
3484
|
renderDecisions as renderDecisions2,
|
|
3443
3485
|
renderWithMarkers as renderWithMarkers2,
|
|
3444
|
-
resolveRepositoryRoot as resolveRepositoryRoot4,
|
|
3445
3486
|
writeMarkdownFile as writeMarkdownFile2
|
|
3446
3487
|
} from "@basou/core";
|
|
3447
3488
|
function registerDecisionsCommand(program2) {
|
|
@@ -3461,7 +3502,7 @@ async function runDecisionsGenerate(options, ctx = {}) {
|
|
|
3461
3502
|
async function doRunDecisionsGenerate(options, ctx) {
|
|
3462
3503
|
void options;
|
|
3463
3504
|
const cwd = ctx.cwd ?? process.cwd();
|
|
3464
|
-
const repositoryRoot = await
|
|
3505
|
+
const repositoryRoot = await resolveBasouRootForCommand(cwd, "decisions generate");
|
|
3465
3506
|
const paths = basouPaths7(repositoryRoot);
|
|
3466
3507
|
await assertWorkspaceInitialized5(paths.root);
|
|
3467
3508
|
const nowIso = (ctx.nowProvider?.() ?? /* @__PURE__ */ new Date()).toISOString();
|
|
@@ -3476,19 +3517,6 @@ async function doRunDecisionsGenerate(options, ctx) {
|
|
|
3476
3517
|
await writeMarkdownFile2(paths.files.decisions, finalBody);
|
|
3477
3518
|
console.log(`Generated .basou/decisions.md (decisions: ${result.decisionCount})`);
|
|
3478
3519
|
}
|
|
3479
|
-
async function resolveRepositoryRootForDecisions(cwd) {
|
|
3480
|
-
try {
|
|
3481
|
-
return await resolveRepositoryRoot4(cwd);
|
|
3482
|
-
} catch (error) {
|
|
3483
|
-
if (error instanceof Error && error.message === "Not a git repository") {
|
|
3484
|
-
throw new Error(
|
|
3485
|
-
"Not a git repository. Run 'git init' first, then re-run 'basou decisions generate'.",
|
|
3486
|
-
{ cause: error }
|
|
3487
|
-
);
|
|
3488
|
-
}
|
|
3489
|
-
throw error;
|
|
3490
|
-
}
|
|
3491
|
-
}
|
|
3492
3520
|
async function assertWorkspaceInitialized5(basouRoot) {
|
|
3493
3521
|
try {
|
|
3494
3522
|
await assertBasouRootSafe5(basouRoot);
|
|
@@ -3519,7 +3547,6 @@ import {
|
|
|
3519
3547
|
prefixedUlid as prefixedUlid3,
|
|
3520
3548
|
readManifest as readManifest5,
|
|
3521
3549
|
readYamlFile as readYamlFile2,
|
|
3522
|
-
resolveRepositoryRoot as resolveRepositoryRoot5,
|
|
3523
3550
|
SESSION_SCHEMA_VERSION,
|
|
3524
3551
|
SessionSchema,
|
|
3525
3552
|
sanitizeWorkingDirectory,
|
|
@@ -3542,7 +3569,7 @@ async function runExec(command, args, options, ctx = {}) {
|
|
|
3542
3569
|
const now = ctx.now ?? (() => /* @__PURE__ */ new Date());
|
|
3543
3570
|
const cwd = options.cwd ?? process.cwd();
|
|
3544
3571
|
const timeout_ms = options.timeout !== void 0 ? parseDuration(options.timeout) : void 0;
|
|
3545
|
-
const repoRoot = await
|
|
3572
|
+
const repoRoot = await resolveRepositoryRootInPlace(cwd, "exec");
|
|
3546
3573
|
const paths = basouPaths8(repoRoot);
|
|
3547
3574
|
await assertBasouRootSafe6(paths.root);
|
|
3548
3575
|
const manifest = await readManifest5(paths);
|
|
@@ -3840,18 +3867,6 @@ async function finalizeSessionAsFailed(paths, sessionDir, sessionId, appendEvent
|
|
|
3840
3867
|
s.session.invocation.exit_code = null;
|
|
3841
3868
|
});
|
|
3842
3869
|
}
|
|
3843
|
-
async function resolveRepositoryRootForExec(cwd) {
|
|
3844
|
-
try {
|
|
3845
|
-
return await resolveRepositoryRoot5(cwd);
|
|
3846
|
-
} catch (error) {
|
|
3847
|
-
if (error instanceof Error && error.message === "Not a git repository") {
|
|
3848
|
-
throw new Error("Not a git repository. Run 'git init' first, then re-run 'basou exec'.", {
|
|
3849
|
-
cause: error
|
|
3850
|
-
});
|
|
3851
|
-
}
|
|
3852
|
-
throw error;
|
|
3853
|
-
}
|
|
3854
|
-
}
|
|
3855
3870
|
|
|
3856
3871
|
// src/commands/handoff.ts
|
|
3857
3872
|
import {
|
|
@@ -5439,7 +5454,6 @@ import {
|
|
|
5439
5454
|
appendBasouGitignore,
|
|
5440
5455
|
createManifest,
|
|
5441
5456
|
ensureBasouDirectory,
|
|
5442
|
-
resolveRepositoryRoot as resolveRepositoryRoot6,
|
|
5443
5457
|
writeManifest
|
|
5444
5458
|
} from "@basou/core";
|
|
5445
5459
|
function collectValue(value, previous) {
|
|
@@ -5471,7 +5485,7 @@ async function runInit(options, ctx = {}) {
|
|
|
5471
5485
|
}
|
|
5472
5486
|
async function doRunInit(options, ctx) {
|
|
5473
5487
|
const cwd = ctx.cwd ?? process.cwd();
|
|
5474
|
-
const repositoryRoot = await
|
|
5488
|
+
const repositoryRoot = await resolveRepositoryRootInPlace(cwd, "init");
|
|
5475
5489
|
const workspaceName = options.name ?? basename6(repositoryRoot);
|
|
5476
5490
|
if (options.repoUrl !== void 0) {
|
|
5477
5491
|
console.error(
|
|
@@ -5507,18 +5521,6 @@ function renderGitignoreWarning(error, verbose) {
|
|
|
5507
5521
|
if (label !== void 0) console.error(`Caused by: ${label}`);
|
|
5508
5522
|
}
|
|
5509
5523
|
}
|
|
5510
|
-
async function resolveRepositoryRootForInit(cwd) {
|
|
5511
|
-
try {
|
|
5512
|
-
return await resolveRepositoryRoot6(cwd);
|
|
5513
|
-
} catch (error) {
|
|
5514
|
-
if (error instanceof Error && error.message === "Not a git repository") {
|
|
5515
|
-
throw new Error("Not a git repository. Run 'git init' first, then re-run 'basou init'.", {
|
|
5516
|
-
cause: error
|
|
5517
|
-
});
|
|
5518
|
-
}
|
|
5519
|
-
throw error;
|
|
5520
|
-
}
|
|
5521
|
-
}
|
|
5522
5524
|
|
|
5523
5525
|
// src/commands/note.ts
|
|
5524
5526
|
import { readFile as readFile5 } from "fs/promises";
|
|
@@ -5918,7 +5920,6 @@ import {
|
|
|
5918
5920
|
renderAnchorStarter,
|
|
5919
5921
|
renderViewPresetBlock,
|
|
5920
5922
|
renderWithMarkers as renderWithMarkers4,
|
|
5921
|
-
resolveRepositoryRoot as resolveRepositoryRoot7,
|
|
5922
5923
|
safeSimpleGit,
|
|
5923
5924
|
seedMarkers,
|
|
5924
5925
|
summarizePresetPlan,
|
|
@@ -8464,19 +8465,6 @@ async function runProjectNew(repos, options, ctx = {}) {
|
|
|
8464
8465
|
process.exitCode = 1;
|
|
8465
8466
|
}
|
|
8466
8467
|
}
|
|
8467
|
-
async function resolveRepositoryRootForNew(cwd) {
|
|
8468
|
-
try {
|
|
8469
|
-
return await resolveRepositoryRoot7(cwd);
|
|
8470
|
-
} catch (error) {
|
|
8471
|
-
if (error instanceof Error && error.message === "Not a git repository") {
|
|
8472
|
-
throw new Error(
|
|
8473
|
-
"Not a git repository. Run 'git init' first, then re-run 'basou project new'.",
|
|
8474
|
-
{ cause: error }
|
|
8475
|
-
);
|
|
8476
|
-
}
|
|
8477
|
-
throw error;
|
|
8478
|
-
}
|
|
8479
|
-
}
|
|
8480
8468
|
function validateProjectName(name) {
|
|
8481
8469
|
if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(name)) {
|
|
8482
8470
|
throw new Error(
|
|
@@ -8487,7 +8475,7 @@ function validateProjectName(name) {
|
|
|
8487
8475
|
}
|
|
8488
8476
|
async function doRunProjectNew(repos, options, ctx) {
|
|
8489
8477
|
const cwd = ctx.cwd ?? process.cwd();
|
|
8490
|
-
const repositoryRoot = await
|
|
8478
|
+
const repositoryRoot = await resolveRepositoryRootInPlace(cwd, "project new");
|
|
8491
8479
|
const workspaceName = basename7(repositoryRoot);
|
|
8492
8480
|
const productName = options.projectName !== void 0 ? validateProjectName(options.projectName) : void 0;
|
|
8493
8481
|
const viewStem = productName ?? workspaceName;
|
|
@@ -9694,7 +9682,6 @@ import {
|
|
|
9694
9682
|
basouPaths as basouPaths15,
|
|
9695
9683
|
findErrorCode as findErrorCode11,
|
|
9696
9684
|
renderReport,
|
|
9697
|
-
resolveRepositoryRoot as resolveRepositoryRoot8,
|
|
9698
9685
|
writeMarkdownFile as writeMarkdownFile6
|
|
9699
9686
|
} from "@basou/core";
|
|
9700
9687
|
function registerReportCommand(program2) {
|
|
@@ -9715,7 +9702,7 @@ async function runReportGenerate(options, ctx = {}) {
|
|
|
9715
9702
|
}
|
|
9716
9703
|
async function doRunReportGenerate(options, ctx) {
|
|
9717
9704
|
const cwd = ctx.cwd ?? process.cwd();
|
|
9718
|
-
const repositoryRoot = await
|
|
9705
|
+
const repositoryRoot = await resolveBasouRootForCommand(cwd, "report generate");
|
|
9719
9706
|
const paths = basouPaths15(repositoryRoot);
|
|
9720
9707
|
await assertWorkspaceInitialized10(paths.root);
|
|
9721
9708
|
const nowIso = (ctx.nowProvider?.() ?? /* @__PURE__ */ new Date()).toISOString();
|
|
@@ -9741,19 +9728,6 @@ async function doRunReportGenerate(options, ctx) {
|
|
|
9741
9728
|
console.log(result.body);
|
|
9742
9729
|
}
|
|
9743
9730
|
}
|
|
9744
|
-
async function resolveRepositoryRootForReport(cwd) {
|
|
9745
|
-
try {
|
|
9746
|
-
return await resolveRepositoryRoot8(cwd);
|
|
9747
|
-
} catch (error) {
|
|
9748
|
-
if (error instanceof Error && error.message === "Not a git repository") {
|
|
9749
|
-
throw new Error(
|
|
9750
|
-
"Not a git repository. Run 'git init' first, then re-run 'basou report generate'.",
|
|
9751
|
-
{ cause: error }
|
|
9752
|
-
);
|
|
9753
|
-
}
|
|
9754
|
-
throw error;
|
|
9755
|
-
}
|
|
9756
|
-
}
|
|
9757
9731
|
async function assertWorkspaceInitialized10(basouRoot) {
|
|
9758
9732
|
try {
|
|
9759
9733
|
await assertBasouRootSafe11(basouRoot);
|
|
@@ -10226,7 +10200,6 @@ import {
|
|
|
10226
10200
|
readYamlFile as readYamlFile5,
|
|
10227
10201
|
resolveClaudeCodeCommand,
|
|
10228
10202
|
resolveCodexCommand,
|
|
10229
|
-
resolveRepositoryRoot as resolveRepositoryRoot9,
|
|
10230
10203
|
SESSION_SCHEMA_VERSION as SESSION_SCHEMA_VERSION2,
|
|
10231
10204
|
SessionSchema as SessionSchema2,
|
|
10232
10205
|
sanitizeRelatedFiles,
|
|
@@ -10281,7 +10254,7 @@ async function runTrackedTool(args, options, ctx, adapter) {
|
|
|
10281
10254
|
const { command } = await adapter.resolveCommand();
|
|
10282
10255
|
const childArgs = adapter.transformArgs ? adapter.transformArgs(args) : args;
|
|
10283
10256
|
const cwd = options.cwd ?? process.cwd();
|
|
10284
|
-
const repoRoot = await
|
|
10257
|
+
const repoRoot = await resolveRepositoryRootInPlace(cwd, "run");
|
|
10285
10258
|
const paths = basouPaths18(repoRoot);
|
|
10286
10259
|
await assertBasouRootSafe13(paths.root);
|
|
10287
10260
|
const manifest = await readManifest11(paths);
|
|
@@ -10650,18 +10623,6 @@ async function finalizeSessionAsFailed2(paths, sessionDir, sessionId, appendEven
|
|
|
10650
10623
|
s.session.invocation.exit_code = null;
|
|
10651
10624
|
});
|
|
10652
10625
|
}
|
|
10653
|
-
async function resolveRepositoryRootForRun(cwd) {
|
|
10654
|
-
try {
|
|
10655
|
-
return await resolveRepositoryRoot9(cwd);
|
|
10656
|
-
} catch (error) {
|
|
10657
|
-
if (error instanceof Error && error.message === "Not a git repository") {
|
|
10658
|
-
throw new Error("Not a git repository. Run 'git init' first, then re-run 'basou run'.", {
|
|
10659
|
-
cause: error
|
|
10660
|
-
});
|
|
10661
|
-
}
|
|
10662
|
-
throw error;
|
|
10663
|
-
}
|
|
10664
|
-
}
|
|
10665
10626
|
async function noteCodexHookStatusPreSpawn(_cwd, ctx) {
|
|
10666
10627
|
const hooksPath = ctx.codexHooksPath ?? DEFAULT_CODEX_HOOKS_PATH;
|
|
10667
10628
|
let location;
|
|
@@ -11388,8 +11349,7 @@ import {
|
|
|
11388
11349
|
assertBasouRootSafe as assertBasouRootSafe15,
|
|
11389
11350
|
basouPaths as basouPaths20,
|
|
11390
11351
|
computeWorkStats,
|
|
11391
|
-
findErrorCode as findErrorCode14
|
|
11392
|
-
resolveRepositoryRoot as resolveRepositoryRoot10
|
|
11352
|
+
findErrorCode as findErrorCode14
|
|
11393
11353
|
} from "@basou/core";
|
|
11394
11354
|
function registerStatsCommand(program2) {
|
|
11395
11355
|
program2.command("stats").description("Report how much the AI worked (output volume + time proxies) across sessions").option("--by-source", "Break the totals down by session source kind").option("--by-day", "Break billable time and volume down by calendar day").option("--json", "Output the full stats as JSON").option("-v, --verbose", "Show error causes").action(async (options) => {
|
|
@@ -11406,7 +11366,7 @@ async function runStats(options, ctx = {}) {
|
|
|
11406
11366
|
}
|
|
11407
11367
|
async function doRunStats(options, ctx) {
|
|
11408
11368
|
const cwd = ctx.cwd ?? process.cwd();
|
|
11409
|
-
const repositoryRoot = await
|
|
11369
|
+
const repositoryRoot = await resolveBasouRootForCommand(cwd, "stats");
|
|
11410
11370
|
const paths = basouPaths20(repositoryRoot);
|
|
11411
11371
|
await assertWorkspaceInitialized13(paths.root);
|
|
11412
11372
|
const now = ctx.nowProvider?.() ?? /* @__PURE__ */ new Date();
|
|
@@ -11494,18 +11454,6 @@ function formatFloorMs(ms) {
|
|
|
11494
11454
|
function formatInt(n) {
|
|
11495
11455
|
return n.toLocaleString("en-US");
|
|
11496
11456
|
}
|
|
11497
|
-
async function resolveRepositoryRootForStats(cwd) {
|
|
11498
|
-
try {
|
|
11499
|
-
return await resolveRepositoryRoot10(cwd);
|
|
11500
|
-
} catch (error) {
|
|
11501
|
-
if (error instanceof Error && error.message === "Not a git repository") {
|
|
11502
|
-
throw new Error("Not a git repository. Run 'git init' first, then re-run 'basou stats'.", {
|
|
11503
|
-
cause: error
|
|
11504
|
-
});
|
|
11505
|
-
}
|
|
11506
|
-
throw error;
|
|
11507
|
-
}
|
|
11508
|
-
}
|
|
11509
11457
|
async function assertWorkspaceInitialized13(basouRoot) {
|
|
11510
11458
|
try {
|
|
11511
11459
|
await assertBasouRootSafe15(basouRoot);
|
|
@@ -11524,7 +11472,6 @@ import {
|
|
|
11524
11472
|
buildStatusSnapshot,
|
|
11525
11473
|
findErrorCode as findErrorCode15,
|
|
11526
11474
|
readManifest as readManifest13,
|
|
11527
|
-
resolveRepositoryRoot as resolveRepositoryRoot11,
|
|
11528
11475
|
writeStatus
|
|
11529
11476
|
} from "@basou/core";
|
|
11530
11477
|
function registerStatusCommand(program2) {
|
|
@@ -11542,7 +11489,7 @@ async function runStatus(options, ctx = {}) {
|
|
|
11542
11489
|
}
|
|
11543
11490
|
async function doRunStatus(options, ctx) {
|
|
11544
11491
|
const cwd = ctx.cwd ?? process.cwd();
|
|
11545
|
-
const repositoryRoot = await
|
|
11492
|
+
const repositoryRoot = await resolveBasouRootForCommand(cwd, "status");
|
|
11546
11493
|
const paths = basouPaths21(repositoryRoot);
|
|
11547
11494
|
try {
|
|
11548
11495
|
await assertBasouRootSafe16(paths.root);
|
|
@@ -11580,18 +11527,6 @@ function renderTextStatus(s) {
|
|
|
11580
11527
|
const present = Object.values(dp).filter((v) => v === true).length;
|
|
11581
11528
|
console.log(`Subdirectories present: ${present}/${total}`);
|
|
11582
11529
|
}
|
|
11583
|
-
async function resolveRepositoryRootForStatus(cwd) {
|
|
11584
|
-
try {
|
|
11585
|
-
return await resolveRepositoryRoot11(cwd);
|
|
11586
|
-
} catch (error) {
|
|
11587
|
-
if (error instanceof Error && error.message === "Not a git repository") {
|
|
11588
|
-
throw new Error("Not a git repository. Run 'git init' first, then re-run 'basou status'.", {
|
|
11589
|
-
cause: error
|
|
11590
|
-
});
|
|
11591
|
-
}
|
|
11592
|
-
throw error;
|
|
11593
|
-
}
|
|
11594
|
-
}
|
|
11595
11530
|
function formatVersionGateMessage(error) {
|
|
11596
11531
|
const issues = error.issues;
|
|
11597
11532
|
if (!Array.isArray(issues)) return void 0;
|
|
@@ -12733,7 +12668,6 @@ import {
|
|
|
12733
12668
|
basouPaths as basouPaths23,
|
|
12734
12669
|
enumerateSessionEntries as enumerateSessionEntries3,
|
|
12735
12670
|
findErrorCode as findErrorCode17,
|
|
12736
|
-
resolveRepositoryRoot as resolveRepositoryRoot12,
|
|
12737
12671
|
resolveSessionId as resolveSessionId5,
|
|
12738
12672
|
verifyEventsChain
|
|
12739
12673
|
} from "@basou/core";
|
|
@@ -12762,7 +12696,7 @@ async function doRunVerify(options, ctx) {
|
|
|
12762
12696
|
throw new Error("Specify either --session <id> or --all, not both");
|
|
12763
12697
|
}
|
|
12764
12698
|
const cwd = ctx.cwd ?? process.cwd();
|
|
12765
|
-
const repositoryRoot = await
|
|
12699
|
+
const repositoryRoot = await resolveBasouRootForCommand(cwd, "verify");
|
|
12766
12700
|
const paths = basouPaths23(repositoryRoot);
|
|
12767
12701
|
await assertWorkspaceInitialized15(paths.root);
|
|
12768
12702
|
const sessionIds = options.session !== void 0 ? [await resolveSessionId5(paths, options.session, { allowNotDirectory: true })] : await enumerateAllSessionNames2(paths);
|
|
@@ -12816,18 +12750,6 @@ async function enumerateAllSessionNames2(paths) {
|
|
|
12816
12750
|
const { dirs, notDirectories } = await enumerateSessionEntries3(paths);
|
|
12817
12751
|
return [...dirs, ...notDirectories].sort();
|
|
12818
12752
|
}
|
|
12819
|
-
async function resolveRepositoryRootForVerify(cwd) {
|
|
12820
|
-
try {
|
|
12821
|
-
return await resolveRepositoryRoot12(cwd);
|
|
12822
|
-
} catch (error) {
|
|
12823
|
-
if (error instanceof Error && error.message === "Not a git repository") {
|
|
12824
|
-
throw new Error("Not a git repository. Run 'git init' first, then re-run 'basou verify'.", {
|
|
12825
|
-
cause: error
|
|
12826
|
-
});
|
|
12827
|
-
}
|
|
12828
|
-
throw error;
|
|
12829
|
-
}
|
|
12830
|
-
}
|
|
12831
12753
|
async function assertWorkspaceInitialized15(basouRoot) {
|
|
12832
12754
|
try {
|
|
12833
12755
|
await assertBasouRootSafe18(basouRoot);
|
|
@@ -12848,8 +12770,7 @@ import {
|
|
|
12848
12770
|
basouPaths as basouPaths25,
|
|
12849
12771
|
findErrorCode as findErrorCode19,
|
|
12850
12772
|
loadPortfolioConfig as loadPortfolioConfig6,
|
|
12851
|
-
readManifest as readManifest18
|
|
12852
|
-
resolveRepositoryRoot as resolveRepositoryRoot14
|
|
12773
|
+
readManifest as readManifest18
|
|
12853
12774
|
} from "@basou/core";
|
|
12854
12775
|
import { InvalidArgumentError as InvalidArgumentError8 } from "commander";
|
|
12855
12776
|
|
|
@@ -12859,12 +12780,15 @@ import { readdir as readdir3, stat as stat7 } from "fs/promises";
|
|
|
12859
12780
|
import { homedir as homedir12 } from "os";
|
|
12860
12781
|
import { basename as basename9, dirname as dirname7, join as join16 } from "path";
|
|
12861
12782
|
import { createInterface as createInterface2 } from "readline";
|
|
12862
|
-
import { basouPaths as basouPaths24, readManifest as readManifest15
|
|
12783
|
+
import { basouPaths as basouPaths24, readManifest as readManifest15 } from "@basou/core";
|
|
12863
12784
|
function uncapturedTotal(result) {
|
|
12864
12785
|
return result.groups.reduce((sum, g) => sum + g.logs, 0) + result.unplaceable;
|
|
12865
12786
|
}
|
|
12866
12787
|
async function checkPortfolioCoverage(workspaces, ctx = {}) {
|
|
12867
|
-
const { roots, inertWorkspaces } = await collectDeclaredRoots(
|
|
12788
|
+
const { roots, inertWorkspaces } = await collectDeclaredRoots(
|
|
12789
|
+
workspaces,
|
|
12790
|
+
ctx.portfolioConfigPath
|
|
12791
|
+
);
|
|
12868
12792
|
const listedDirs = new Set([...roots].map((root) => encodeProjectDir(root)));
|
|
12869
12793
|
const claudeProjectsDir = ctx.claudeProjectsDir ?? join16(homedir12(), ".claude", "projects");
|
|
12870
12794
|
const codexSessionsDir = ctx.codexSessionsDir ?? join16(homedir12(), ".codex", "sessions");
|
|
@@ -12889,13 +12813,16 @@ async function checkPortfolioCoverage(workspaces, ctx = {}) {
|
|
|
12889
12813
|
}
|
|
12890
12814
|
return tally.finish(absentTrees, inertWorkspaces);
|
|
12891
12815
|
}
|
|
12892
|
-
async function collectDeclaredRoots(workspaces) {
|
|
12816
|
+
async function collectDeclaredRoots(workspaces, portfolioConfigPath) {
|
|
12893
12817
|
const roots = /* @__PURE__ */ new Set();
|
|
12894
12818
|
const inertWorkspaces = [];
|
|
12895
12819
|
for (const ws of workspaces) {
|
|
12896
12820
|
let importRoot;
|
|
12897
12821
|
try {
|
|
12898
|
-
importRoot = await
|
|
12822
|
+
importRoot = await resolveBasouRootForCommand(ws.repoRoot, "import", {
|
|
12823
|
+
quiet: true,
|
|
12824
|
+
...portfolioConfigPath !== void 0 ? { portfolioConfigPath } : {}
|
|
12825
|
+
});
|
|
12899
12826
|
} catch {
|
|
12900
12827
|
inertWorkspaces.push({ path: ws.repoRoot, reason: "not_a_git_repo" });
|
|
12901
12828
|
continue;
|
|
@@ -13351,6 +13278,7 @@ function formatSafetyReport(result) {
|
|
|
13351
13278
|
import { createServer } from "http";
|
|
13352
13279
|
import { basename as basename10, join as join18, resolve as resolve13 } from "path";
|
|
13353
13280
|
import {
|
|
13281
|
+
boardLivePage,
|
|
13354
13282
|
boardPage,
|
|
13355
13283
|
boardPageStrings,
|
|
13356
13284
|
boardPageUnavailable,
|
|
@@ -13492,6 +13420,7 @@ var BOARD_HTML = `<!doctype html>
|
|
|
13492
13420
|
if (k === 'text') node.textContent = attrs[k];
|
|
13493
13421
|
else if (k === 'class') node.className = attrs[k];
|
|
13494
13422
|
else if (k === 'onchange') node.addEventListener('change', attrs[k]);
|
|
13423
|
+
else if (k === 'onclick') node.addEventListener('click', attrs[k]);
|
|
13495
13424
|
else node.setAttribute(k, attrs[k]);
|
|
13496
13425
|
});
|
|
13497
13426
|
}
|
|
@@ -13585,7 +13514,11 @@ var BOARD_HTML = `<!doctype html>
|
|
|
13585
13514
|
clear(nav);
|
|
13586
13515
|
var page = d.page;
|
|
13587
13516
|
var list = page.records || [];
|
|
13588
|
-
if (list.length
|
|
13517
|
+
if (list.length > 0) recordLinks(nav, page, list);
|
|
13518
|
+
nav.appendChild(el('a', { href: '/board?live=1', text: S.live.measureNow }));
|
|
13519
|
+
}
|
|
13520
|
+
|
|
13521
|
+
function recordLinks(nav, page, list) {
|
|
13589
13522
|
var link = function (id, label) {
|
|
13590
13523
|
return el('a', { href: '/board?record=' + encodeURIComponent(id), text: label });
|
|
13591
13524
|
};
|
|
@@ -14066,8 +13999,12 @@ var BOARD_HTML = `<!doctype html>
|
|
|
14066
13999
|
not_found: S.unavailable.notFound, not_json: S.unavailable.notJson,
|
|
14067
14000
|
unknown_version: S.unavailable.unknownVersion, not_a_record: S.unavailable.notARecord
|
|
14068
14001
|
};
|
|
14069
|
-
|
|
14070
|
-
|
|
14002
|
+
// With no board or no record yet, draw what basou measures now instead.
|
|
14003
|
+
if (page.why === 'no_board' || page.why === 'no_records') {
|
|
14004
|
+
loadLive(page.why);
|
|
14005
|
+
return;
|
|
14006
|
+
}
|
|
14007
|
+
setStatus(fill(messages[page.why] || page.why, { record: page.id || '', version: page.version }), true);
|
|
14071
14008
|
return;
|
|
14072
14009
|
}
|
|
14073
14010
|
setStatus('', false);
|
|
@@ -14076,17 +14013,153 @@ var BOARD_HTML = `<!doctype html>
|
|
|
14076
14013
|
.forEach(function (node) { root.appendChild(node); });
|
|
14077
14014
|
}
|
|
14078
14015
|
|
|
14079
|
-
|
|
14080
|
-
|
|
14081
|
-
|
|
14082
|
-
|
|
14016
|
+
// The board measured now: the sections basou measures with nothing declared
|
|
14017
|
+
// or judged. why is the reason there was no record to draw, or null when
|
|
14018
|
+
// asked for with ?live=1.
|
|
14019
|
+
function liveTile(k, v, sub) {
|
|
14020
|
+
return el('div', { class: 'tile' }, [
|
|
14021
|
+
el('div', { class: 'k', text: k }), el('div', { class: 'v', text: v }),
|
|
14022
|
+
sub ? el('div', { class: 's', text: sub }) : null
|
|
14023
|
+
]);
|
|
14024
|
+
}
|
|
14025
|
+
function liveHeading(l, why) {
|
|
14026
|
+
var h = l.heading;
|
|
14027
|
+
var measured = h.complete ? S.heading.complete : fill(S.heading.incomplete, { n: h.not_found });
|
|
14028
|
+
var again = el('button', { type: 'button', text: S.live.remeasure, onclick: function () { loadLive(why); } });
|
|
14029
|
+
return el('header', null, [
|
|
14030
|
+
el('h1', { text: h.title }),
|
|
14031
|
+
el('div', { class: 'stamp' }, [fill(S.live.measuredAt, { at: when(h.measured_at) }) + ' / ' + measured + ' ', again])
|
|
14032
|
+
]);
|
|
14033
|
+
}
|
|
14034
|
+
// Whether the measurement says why the value at a place was not measured.
|
|
14035
|
+
function missingIn(l) {
|
|
14036
|
+
return function (at) { return l.footnotes.not_found.some(function (n) { return n.at === at; }); };
|
|
14037
|
+
}
|
|
14038
|
+
function liveRepos(l) {
|
|
14039
|
+
var missing = missingIn(l);
|
|
14040
|
+
var labels = [S.live.repo, S.live.branch, S.live.head, S.live.lastCommit, S.live.commits, S.live.uncommitted, S.live.behindMain];
|
|
14041
|
+
var head = el('tr', null, labels.map(function (label, i) { return el('th', { class: i >= 4 ? 'n' : '', text: label }); }));
|
|
14042
|
+
var rows = l.repos.map(function (r) {
|
|
14043
|
+
var at = 'repos[' + r.path + ']';
|
|
14044
|
+
// A null the measurement says it could not measure, or one that means
|
|
14045
|
+
// so (a detached HEAD, no commit yet, no origin/main), drawn as '-'.
|
|
14046
|
+
var value = function (field, v, show) {
|
|
14047
|
+
if (v !== null) return show(v);
|
|
14048
|
+
return missing(at) || missing(at + '.' + field) ? S.tiles.notMeasured : '-';
|
|
14049
|
+
};
|
|
14050
|
+
return el('tr', null, [
|
|
14051
|
+
el('td', { text: r.name === null ? r.path : r.name }),
|
|
14052
|
+
el('td', { text: value('branch', r.branch, String) }),
|
|
14053
|
+
el('td', { text: value('head', r.head, function (h) { return h.slice(0, 7); }) }),
|
|
14054
|
+
el('td', { text: value('last_commit', r.last_commit, when) }),
|
|
14055
|
+
el('td', { class: 'n', text: num(r.commits) }),
|
|
14056
|
+
el('td', { class: 'n', text: num(r.uncommitted) }),
|
|
14057
|
+
el('td', { class: 'n', text: value('behind_main', r.behind_main, num) })
|
|
14058
|
+
]);
|
|
14059
|
+
});
|
|
14060
|
+
return section(S.live.repos, false, [el('div', { class: 'scroll' }, [el('table', { class: 'grid' }, [head].concat(rows))])]);
|
|
14061
|
+
}
|
|
14062
|
+
function liveTrail(l) {
|
|
14063
|
+
var t = l.trail;
|
|
14064
|
+
var i = l.integrity;
|
|
14065
|
+
var f = l.freshness;
|
|
14066
|
+
var missing = missingIn(l);
|
|
14067
|
+
var newest = f.newest_session_at !== null ? when(f.newest_session_at)
|
|
14068
|
+
: missing('freshness.newest_session_at') ? S.tiles.notMeasured : S.live.noSession;
|
|
14069
|
+
var unimported = f.unimported === null ? S.live.unimportedNotMeasured : fill(S.live.unimported, {
|
|
14070
|
+
new: f.unimported.new, updated: f.unimported.updated, unverifiable: f.unimported.unverifiable
|
|
14071
|
+
});
|
|
14072
|
+
var counts = function (byKey) {
|
|
14073
|
+
if (byKey === null) return S.tiles.notMeasured;
|
|
14074
|
+
return Object.keys(byKey).map(function (k) { return k + ' ' + num(byKey[k]); }).join(' / ');
|
|
14075
|
+
};
|
|
14076
|
+
var tiles = el('div', { class: 'tiles' }, [
|
|
14077
|
+
liveTile(S.live.decisions, num(t.decisions_live), t.decisions_all === null ? null : fill(S.live.decisionsAll, { n: num(t.decisions_all) })),
|
|
14078
|
+
liveTile(S.tiles.openTracks, t.tracks_open === null ? S.tiles.notMeasured : num(t.tracks_open.length), null),
|
|
14079
|
+
liveTile(S.tiles.sessions, num(i.sessions), i.not_verified === null ? null : fill(S.tiles.sessionsNotVerified, { n: num(i.not_verified) })),
|
|
14080
|
+
liveTile(S.live.reviewGaps, num(l.review_gaps.gaps), null),
|
|
14081
|
+
liveTile(S.live.newestSession, newest, unimported)
|
|
14082
|
+
]);
|
|
14083
|
+
var tracks = t.tracks_open === null ? el('p', { class: 'muted', text: S.tiles.notMeasured })
|
|
14084
|
+
: t.tracks_open.length === 0 ? el('p', { class: 'muted', text: S.live.noTracks })
|
|
14085
|
+
: el('ul', null, t.tracks_open.map(function (tr) {
|
|
14086
|
+
return el('li', null, [el('span', { class: 'muted', text: tr.id + ' ' }), tr.title]);
|
|
14087
|
+
}));
|
|
14088
|
+
var breakdown = el('div', { class: 'muted' }, [
|
|
14089
|
+
el('div', { text: fill(S.live.byStatus, { list: counts(i.by_status) }) }),
|
|
14090
|
+
el('div', { text: fill(S.live.byVerdict, { list: counts(l.review_gaps.by_verdict) }) })
|
|
14091
|
+
]);
|
|
14092
|
+
return section(S.live.trail, false, [tiles, breakdown, el('h3', { text: S.live.tracks }), tracks]);
|
|
14093
|
+
}
|
|
14094
|
+
function liveComponents(l) {
|
|
14095
|
+
var c = l.components;
|
|
14096
|
+
var body = c === null ? el('p', { class: 'muted', text: S.tiles.notMeasured })
|
|
14097
|
+
: c.length === 0 ? el('p', { class: 'muted', text: S.live.noComponents })
|
|
14098
|
+
: el('ul', null, c.map(function (x) {
|
|
14099
|
+
return el('li', null, [el('code', { text: x.key }), el('span', { class: 'muted', text: ' ' + x.kinds.join(', ') })]);
|
|
14100
|
+
}));
|
|
14101
|
+
return section(S.live.components, false, [body]);
|
|
14102
|
+
}
|
|
14103
|
+
function liveFootnotes(l, why) {
|
|
14104
|
+
var f = l.footnotes;
|
|
14105
|
+
var items = [el('li', { text: S.live.note }), el('li', { text: S.live.judged })];
|
|
14106
|
+
if (why === 'no_board') items.push(el('li', { text: S.unavailable.noBoard }));
|
|
14107
|
+
if (f.not_found.length > 0) {
|
|
14108
|
+
items.push(el('li', null, [el('b', { text: S.footnotes.notMeasured }), el('ul', null, f.not_found.map(function (n) {
|
|
14109
|
+
return el('li', { text: n.at + ': ' + n.reason });
|
|
14110
|
+
}))]));
|
|
14111
|
+
}
|
|
14112
|
+
var build = f.measured_with.build === null ? '' : ' (' + f.measured_with.build + ')';
|
|
14113
|
+
items.push(el('li', { text: fill(S.footnotes.measuredWith, { basou: f.measured_with.basou, build: build }) }));
|
|
14114
|
+
return section(S.sections.footnotes, false, [el('ul', { class: 'foot' }, items)]);
|
|
14115
|
+
}
|
|
14116
|
+
var liveDrawn = 0;
|
|
14117
|
+
function drawLive(d, why) {
|
|
14118
|
+
S = d.strings;
|
|
14119
|
+
lang = d.language;
|
|
14120
|
+
document.documentElement.lang = lang;
|
|
14121
|
+
document.title = S.pageTitle;
|
|
14122
|
+
var drawn = ++liveDrawn;
|
|
14123
|
+
var nav = $('records');
|
|
14124
|
+
clear(nav);
|
|
14125
|
+
// Asked for with ?live=1: lead back to the records, when there are any.
|
|
14126
|
+
if (why === null) {
|
|
14127
|
+
getJson('/api/board').then(function (b) {
|
|
14128
|
+
var list = b && b.page && b.page.records ? b.page.records : [];
|
|
14129
|
+
if (drawn === liveDrawn && list.length > 0) nav.appendChild(el('a', { href: '/board', text: S.live.toRecords }));
|
|
14130
|
+
}).catch(function () {});
|
|
14131
|
+
}
|
|
14132
|
+
var root = $('board');
|
|
14133
|
+
clear(root);
|
|
14134
|
+
setStatus('', false);
|
|
14135
|
+
var l = d.live;
|
|
14136
|
+
[liveHeading(l, why), effort(l), liveRepos(l), liveTrail(l), liveComponents(l), liveFootnotes(l, why)]
|
|
14137
|
+
.forEach(function (node) { root.appendChild(node); });
|
|
14138
|
+
}
|
|
14139
|
+
|
|
14140
|
+
function getJson(url) {
|
|
14141
|
+
return fetch(url).then(function (res) {
|
|
14083
14142
|
return res.json().then(function (body) {
|
|
14084
14143
|
if (!res.ok) throw new Error(body && body.error ? body.error : String(res.status));
|
|
14085
14144
|
return body;
|
|
14086
14145
|
});
|
|
14087
|
-
})
|
|
14088
|
-
|
|
14089
|
-
|
|
14146
|
+
});
|
|
14147
|
+
}
|
|
14148
|
+
function failed(err) { setStatus(S ? fill(S.loadFailed, { message: err.message }) : String(err.message), true); }
|
|
14149
|
+
// Measuring takes seconds, so the page says so until it is done.
|
|
14150
|
+
function loadLive(why) {
|
|
14151
|
+
setStatus(S ? S.live.measuring : '...', false);
|
|
14152
|
+
getJson('/api/board/live').then(function (d) { drawLive(d, why); }).catch(failed);
|
|
14153
|
+
}
|
|
14154
|
+
|
|
14155
|
+
var params = new URLSearchParams(location.search);
|
|
14156
|
+
var record = params.get('record');
|
|
14157
|
+
if (params.get('live') !== null) {
|
|
14158
|
+
loadLive(null);
|
|
14159
|
+
} else {
|
|
14160
|
+
setStatus('...', false);
|
|
14161
|
+
getJson('/api/board' + (record ? '/' + encodeURIComponent(record) : '')).then(draw).catch(failed);
|
|
14162
|
+
}
|
|
14090
14163
|
})();
|
|
14091
14164
|
</script>
|
|
14092
14165
|
</body>
|
|
@@ -14907,7 +14980,8 @@ async function handleGet(res, pathname, deps) {
|
|
|
14907
14980
|
ws,
|
|
14908
14981
|
deps.nowProvider,
|
|
14909
14982
|
remoteUrlOf(deps),
|
|
14910
|
-
boardOf(deps)
|
|
14983
|
+
boardOf(deps),
|
|
14984
|
+
boardLiveOf(deps)
|
|
14911
14985
|
)) {
|
|
14912
14986
|
sendError(res, 404, "Not found");
|
|
14913
14987
|
}
|
|
@@ -14921,7 +14995,8 @@ async function handleGet(res, pathname, deps) {
|
|
|
14921
14995
|
primaryWorkspace(deps),
|
|
14922
14996
|
deps.nowProvider,
|
|
14923
14997
|
remoteUrlOf(deps),
|
|
14924
|
-
boardOf(deps)
|
|
14998
|
+
boardOf(deps),
|
|
14999
|
+
boardLiveOf(deps)
|
|
14925
15000
|
)) {
|
|
14926
15001
|
sendError(res, 404, "Not found");
|
|
14927
15002
|
}
|
|
@@ -14932,6 +15007,9 @@ async function handleGet(res, pathname, deps) {
|
|
|
14932
15007
|
function boardOf(deps) {
|
|
14933
15008
|
return deps.mode === "single" ? deps.board : void 0;
|
|
14934
15009
|
}
|
|
15010
|
+
function boardLiveOf(deps) {
|
|
15011
|
+
return deps.mode === "single" ? deps.boardLive : void 0;
|
|
15012
|
+
}
|
|
14935
15013
|
function remoteUrlOf(deps) {
|
|
14936
15014
|
return deps.remoteUrlOf ?? tryRemoteUrl;
|
|
14937
15015
|
}
|
|
@@ -14957,7 +15035,11 @@ async function handlePost(res, pathname, body, deps, runExclusive) {
|
|
|
14957
15035
|
}
|
|
14958
15036
|
sendError(res, 404, "Not found");
|
|
14959
15037
|
}
|
|
14960
|
-
async function handleWorkspaceGet(res, sub, ws, nowProvider, resolveRemoteUrl, board) {
|
|
15038
|
+
async function handleWorkspaceGet(res, sub, ws, nowProvider, resolveRemoteUrl, board, live) {
|
|
15039
|
+
if (live !== void 0 && sub === "board/live") {
|
|
15040
|
+
sendJson(res, 200, await boardLiveView(ws, live));
|
|
15041
|
+
return true;
|
|
15042
|
+
}
|
|
14961
15043
|
if (board !== void 0) {
|
|
14962
15044
|
if (sub === "board") {
|
|
14963
15045
|
sendJson(res, 200, await boardView(ws, board, void 0));
|
|
@@ -15009,9 +15091,13 @@ async function handleWorkspaceGet(res, sub, ws, nowProvider, resolveRemoteUrl, b
|
|
|
15009
15091
|
}
|
|
15010
15092
|
return false;
|
|
15011
15093
|
}
|
|
15094
|
+
var IMPORT_SUBS = /* @__PURE__ */ new Set(["import/claude-code", "import/codex"]);
|
|
15012
15095
|
async function handleWorkspacePost(res, sub, ws, body, deps, runExclusive) {
|
|
15013
15096
|
const nowIso = deps.nowProvider().toISOString();
|
|
15014
15097
|
const actionOptions = readActionOptions(body);
|
|
15098
|
+
if (!ws.initialized && (sub === "refresh" || IMPORT_SUBS.has(sub))) {
|
|
15099
|
+
throw new Error("Workspace not initialized. Run 'basou init' first.");
|
|
15100
|
+
}
|
|
15015
15101
|
if (sub === "refresh") {
|
|
15016
15102
|
const result = await runExclusive(
|
|
15017
15103
|
() => refreshAll({ options: actionOptions, ctx: ws.importCtx, paths: ws.paths, nowIso })
|
|
@@ -15069,6 +15155,14 @@ async function boardView(ws, board, recordId) {
|
|
|
15069
15155
|
const page = "why" in board ? boardPageUnavailable(board.why) : await boardPage(board.recordsDir, recordId);
|
|
15070
15156
|
return { language, strings: boardPageStrings(language), page };
|
|
15071
15157
|
}
|
|
15158
|
+
async function boardLiveView(ws, live) {
|
|
15159
|
+
const language = await resolveViewLanguageFromPaths(ws.paths);
|
|
15160
|
+
return {
|
|
15161
|
+
language,
|
|
15162
|
+
strings: boardPageStrings(language),
|
|
15163
|
+
live: boardLivePage(ws.label, await live())
|
|
15164
|
+
};
|
|
15165
|
+
}
|
|
15072
15166
|
async function portfolio(deps) {
|
|
15073
15167
|
const nowIso = deps.nowProvider().toISOString();
|
|
15074
15168
|
const workspaces = await Promise.all(deps.workspaces.map((ws) => portfolioCard(ws, nowIso)));
|
|
@@ -15388,7 +15482,8 @@ async function doRunView(options, ctx) {
|
|
|
15388
15482
|
if (isWholeRegistry) {
|
|
15389
15483
|
const coverage = await checkPortfolioCoverage(deps.workspaces, {
|
|
15390
15484
|
...ctx.claudeProjectsDir !== void 0 ? { claudeProjectsDir: ctx.claudeProjectsDir } : {},
|
|
15391
|
-
...ctx.codexSessionsDir !== void 0 ? { codexSessionsDir: ctx.codexSessionsDir } : {}
|
|
15485
|
+
...ctx.codexSessionsDir !== void 0 ? { codexSessionsDir: ctx.codexSessionsDir } : {},
|
|
15486
|
+
...ctx.portfolioConfigPath !== void 0 ? { portfolioConfigPath: ctx.portfolioConfigPath } : {}
|
|
15392
15487
|
});
|
|
15393
15488
|
console.log("");
|
|
15394
15489
|
for (const line of formatCoverageReport(coverage)) console.log(line);
|
|
@@ -15431,7 +15526,7 @@ async function doRunView(options, ctx) {
|
|
|
15431
15526
|
}
|
|
15432
15527
|
}
|
|
15433
15528
|
async function buildSingleDeps(ctx, cwd) {
|
|
15434
|
-
const repositoryRoot = await
|
|
15529
|
+
const repositoryRoot = await resolveBasouRootForCommand(cwd, "view");
|
|
15435
15530
|
const paths = basouPaths25(repositoryRoot);
|
|
15436
15531
|
await assertWorkspaceInitialized16(paths.root);
|
|
15437
15532
|
const entry = await buildWorkspaceEntry(repositoryRoot, ctx);
|
|
@@ -15440,7 +15535,26 @@ async function buildSingleDeps(ctx, cwd) {
|
|
|
15440
15535
|
mode: "single",
|
|
15441
15536
|
nowProvider: nowProviderOf(ctx),
|
|
15442
15537
|
...ctx.remoteUrlOf !== void 0 ? { remoteUrlOf: ctx.remoteUrlOf } : {},
|
|
15443
|
-
board: await viewBoardOf(repositoryRoot, paths)
|
|
15538
|
+
board: await viewBoardOf(repositoryRoot, paths),
|
|
15539
|
+
boardLive: liveBoardOf(repositoryRoot, ctx)
|
|
15540
|
+
};
|
|
15541
|
+
}
|
|
15542
|
+
function liveBoardOf(root, ctx) {
|
|
15543
|
+
return sharedWhileRunning(
|
|
15544
|
+
() => measureLiveBoard(root, {
|
|
15545
|
+
...ctx.nowProvider !== void 0 ? { nowProvider: ctx.nowProvider } : {},
|
|
15546
|
+
...ctx.claudeProjectsDir !== void 0 ? { claudeProjectsDir: ctx.claudeProjectsDir } : {},
|
|
15547
|
+
...ctx.codexSessionsDir !== void 0 ? { codexSessionsDir: ctx.codexSessionsDir } : {}
|
|
15548
|
+
})
|
|
15549
|
+
);
|
|
15550
|
+
}
|
|
15551
|
+
function sharedWhileRunning(run) {
|
|
15552
|
+
let running = null;
|
|
15553
|
+
return () => {
|
|
15554
|
+
running ??= run().finally(() => {
|
|
15555
|
+
running = null;
|
|
15556
|
+
});
|
|
15557
|
+
return running;
|
|
15444
15558
|
};
|
|
15445
15559
|
}
|
|
15446
15560
|
async function viewBoardOf(root, paths) {
|
|
@@ -15562,18 +15676,6 @@ function waitForShutdown(signal) {
|
|
|
15562
15676
|
}
|
|
15563
15677
|
});
|
|
15564
15678
|
}
|
|
15565
|
-
async function resolveRepositoryRootForView(cwd) {
|
|
15566
|
-
try {
|
|
15567
|
-
return await resolveRepositoryRoot14(cwd);
|
|
15568
|
-
} catch (error) {
|
|
15569
|
-
if (error instanceof Error && error.message === "Not a git repository") {
|
|
15570
|
-
throw new Error("Not a git repository. Run 'git init' first, then re-run 'basou view'.", {
|
|
15571
|
-
cause: error
|
|
15572
|
-
});
|
|
15573
|
-
}
|
|
15574
|
-
throw error;
|
|
15575
|
-
}
|
|
15576
|
-
}
|
|
15577
15679
|
async function assertWorkspaceInitialized16(basouRoot) {
|
|
15578
15680
|
try {
|
|
15579
15681
|
await assertBasouRootSafe19(basouRoot);
|
|
@@ -15617,7 +15719,7 @@ function installExperimentalNotice(program2, names = EXPERIMENTAL_COMMANDS, writ
|
|
|
15617
15719
|
function readBuildStamp() {
|
|
15618
15720
|
if (false) return void 0;
|
|
15619
15721
|
try {
|
|
15620
|
-
return JSON.parse('{"version":"0.
|
|
15722
|
+
return JSON.parse('{"version":"0.67.0","commit":"c4c4ebb","committedAt":"2026-10-08T23:33:17+09:00"}');
|
|
15621
15723
|
} catch {
|
|
15622
15724
|
return void 0;
|
|
15623
15725
|
}
|