@basou/cli 0.53.0 → 0.55.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 +194 -96
- package/dist/index.js.map +1 -1
- package/dist/program.js +194 -96
- package/dist/program.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -139,6 +139,7 @@ import {
|
|
|
139
139
|
LOCAL_CLI_EVENT_SOURCE,
|
|
140
140
|
linkYamlFile,
|
|
141
141
|
loadApproval,
|
|
142
|
+
normalizeApprovalTimestamps,
|
|
142
143
|
prefixedUlid,
|
|
143
144
|
readSessionYaml,
|
|
144
145
|
readYamlFile,
|
|
@@ -226,7 +227,7 @@ async function readApprovalListRecord(paths, id, location, now) {
|
|
|
226
227
|
console.error(`Skipped ${shortId(id)}: ${describeReadError(error)}`);
|
|
227
228
|
return null;
|
|
228
229
|
}
|
|
229
|
-
const parse = ApprovalSchema.safeParse(raw);
|
|
230
|
+
const parse = ApprovalSchema.safeParse(normalizeApprovalTimestamps(raw));
|
|
230
231
|
if (!parse.success) {
|
|
231
232
|
console.error(`Skipped ${shortId(id)}: invalid approval schema`);
|
|
232
233
|
return null;
|
|
@@ -323,7 +324,7 @@ async function doRunApprovalResolve(idInput, options, ctx, decision) {
|
|
|
323
324
|
}
|
|
324
325
|
throw new Error("Failed to read approval", { cause: error });
|
|
325
326
|
}
|
|
326
|
-
const approvalParse = ApprovalSchema.safeParse(pendingRaw);
|
|
327
|
+
const approvalParse = ApprovalSchema.safeParse(normalizeApprovalTimestamps(pendingRaw));
|
|
327
328
|
if (!approvalParse.success) {
|
|
328
329
|
throw new Error("Failed to read approval", { cause: approvalParse.error });
|
|
329
330
|
}
|
|
@@ -4876,6 +4877,9 @@ async function resolveRepositoryRootForInit(cwd) {
|
|
|
4876
4877
|
}
|
|
4877
4878
|
|
|
4878
4879
|
// src/commands/note.ts
|
|
4880
|
+
import { readFile as readFile4 } from "fs/promises";
|
|
4881
|
+
import { homedir as homedir9 } from "os";
|
|
4882
|
+
import { resolve as resolve8 } from "path";
|
|
4879
4883
|
import {
|
|
4880
4884
|
acquireLock as acquireLock4,
|
|
4881
4885
|
appendEventToExistingSession as appendEventToExistingSession2,
|
|
@@ -4886,7 +4890,8 @@ import {
|
|
|
4886
4890
|
findErrorCode as findErrorCode7,
|
|
4887
4891
|
LOCAL_CLI_EVENT_SOURCE as LOCAL_CLI_EVENT_SOURCE3,
|
|
4888
4892
|
readManifest as readManifest6,
|
|
4889
|
-
resolveSessionId as resolveSessionId2
|
|
4893
|
+
resolveSessionId as resolveSessionId2,
|
|
4894
|
+
sanitizePath as sanitizePath2
|
|
4890
4895
|
} from "@basou/core";
|
|
4891
4896
|
import { InvalidArgumentError as InvalidArgumentError3 } from "commander";
|
|
4892
4897
|
var NOTE_SUBCOMMAND_LOOKALIKES = /* @__PURE__ */ new Set([
|
|
@@ -4904,11 +4909,33 @@ var NOTE_SUBCOMMAND_LOOKALIKES = /* @__PURE__ */ new Set([
|
|
|
4904
4909
|
]);
|
|
4905
4910
|
var LABEL_BODY_MAX = 80;
|
|
4906
4911
|
var LABEL_TRUNCATE_HEAD2 = LABEL_BODY_MAX - 3;
|
|
4912
|
+
var NOTE_HELP = `
|
|
4913
|
+
Text that contains backticks, $(...), $VAR or ! is safest on stdin through a
|
|
4914
|
+
heredoc whose delimiter is QUOTED: the shell then passes the text through
|
|
4915
|
+
untouched. Inside double quotes the shell runs backticks and $(...) as commands
|
|
4916
|
+
and records their output in place of the text, without any error.
|
|
4917
|
+
|
|
4918
|
+
Example (heredoc on stdin):
|
|
4919
|
+
basou note <<'EOF'
|
|
4920
|
+
Next: rebase \`topic\` onto main, then rerun the $CI job.
|
|
4921
|
+
EOF
|
|
4922
|
+
|
|
4923
|
+
Keep the text on its own lines: words on the same line as <<'EOF' are ordinary
|
|
4924
|
+
shell words, not part of the quoted text. 'basou note -' does not read stdin;
|
|
4925
|
+
omit the argument instead.
|
|
4926
|
+
|
|
4927
|
+
Trailing newlines in text read from stdin or --file are dropped (a heredoc
|
|
4928
|
+
always ends with one); everything else is recorded exactly as read.
|
|
4929
|
+
`;
|
|
4930
|
+
var HEREDOC_EXAMPLE = [" basou note <<'EOF'", " <your note>", " EOF"].join("\n");
|
|
4931
|
+
var NO_INPUT_HINT2 = `No note text. Pass it on stdin through a quoted heredoc, with the text on its own lines:
|
|
4932
|
+
${HEREDOC_EXAMPLE}
|
|
4933
|
+
or pass it as an argument, or with --file <path>.`;
|
|
4907
4934
|
function registerNoteCommand(program2) {
|
|
4908
|
-
program2.command("note").description("Record a free-text note (orientation surfaces the latest as the next step)").argument("
|
|
4935
|
+
program2.command("note").description("Record a free-text note (orientation surfaces the latest as the next step)").argument("[body]", "Note text (omit it to read the text from stdin or --file)", parseBody).option("--file <path>", "Read the note text from a file instead of the argument or stdin").option(
|
|
4909
4936
|
"--session <session_id>",
|
|
4910
4937
|
"Attach to an existing session; otherwise an ad-hoc session is created"
|
|
4911
|
-
).option("--json", "Output the result as JSON").option("-v, --verbose", "Show error causes").action(async (body, options) => {
|
|
4938
|
+
).option("--json", "Output the result as JSON").option("-v, --verbose", "Show error causes").addHelpText("after", NOTE_HELP).action(async (body, options) => {
|
|
4912
4939
|
await runNote(body, options);
|
|
4913
4940
|
});
|
|
4914
4941
|
}
|
|
@@ -4923,17 +4950,29 @@ async function runNote(body, options, ctx = {}) {
|
|
|
4923
4950
|
process.exitCode = 1;
|
|
4924
4951
|
}
|
|
4925
4952
|
}
|
|
4926
|
-
async function doRunNote(
|
|
4953
|
+
async function doRunNote(bodyArgument, options, ctx) {
|
|
4954
|
+
const cwd = ctx.cwd ?? process.cwd();
|
|
4955
|
+
const { body, source } = await readNoteBody(bodyArgument, options, ctx, cwd);
|
|
4956
|
+
if (source === "stdin" && body.trim().length === 0) {
|
|
4957
|
+
throw new Error(NO_INPUT_HINT2);
|
|
4958
|
+
}
|
|
4927
4959
|
if (body.trim().length === 0) {
|
|
4928
4960
|
throw new Error("Note body must not be empty");
|
|
4929
4961
|
}
|
|
4930
4962
|
const reserved = body.trim().toLowerCase();
|
|
4931
4963
|
if (NOTE_SUBCOMMAND_LOOKALIKES.has(reserved)) {
|
|
4932
4964
|
throw new Error(
|
|
4933
|
-
`'basou note' records a free-text note and has no '${body.trim()}' subcommand. To record a note, pass its full text
|
|
4965
|
+
`'basou note' records a free-text note and has no '${body.trim()}' subcommand. To record a note, pass its full text, e.g. on stdin through a quoted heredoc, with the text on its own lines:
|
|
4966
|
+
${HEREDOC_EXAMPLE}`
|
|
4967
|
+
);
|
|
4968
|
+
}
|
|
4969
|
+
if (reserved === "-") {
|
|
4970
|
+
throw new Error(
|
|
4971
|
+
source === "argument" ? `'basou note -' does not read stdin; it would record '-' as the note. To pass the note on stdin, omit the argument:
|
|
4972
|
+
${HEREDOC_EXAMPLE}` : `The note text is just '-', which would be recorded as the next step. Write the note itself, e.g.:
|
|
4973
|
+
${HEREDOC_EXAMPLE}`
|
|
4934
4974
|
);
|
|
4935
4975
|
}
|
|
4936
|
-
const cwd = ctx.cwd ?? process.cwd();
|
|
4937
4976
|
const repositoryRoot = await resolveBasouRootForCommand(cwd, "note");
|
|
4938
4977
|
const paths = basouPaths11(repositoryRoot);
|
|
4939
4978
|
await assertWorkspaceInitialized7(paths.root);
|
|
@@ -4972,7 +5011,7 @@ async function doRunNote(body, options, ctx) {
|
|
|
4972
5011
|
workingDirectory: repositoryRoot,
|
|
4973
5012
|
invocation: {
|
|
4974
5013
|
command: "basou note",
|
|
4975
|
-
args:
|
|
5014
|
+
args: noteInvocationArgs({ body, source, file: options.file, cwd, repositoryRoot })
|
|
4976
5015
|
},
|
|
4977
5016
|
targetEventBuilders: [
|
|
4978
5017
|
(sessionId, eventId) => buildNoteEvent({ eventId, sessionId, occurredAt, body })
|
|
@@ -5005,6 +5044,64 @@ function buildAdHocLabel2(body) {
|
|
|
5005
5044
|
const truncated = oneLine3.length > LABEL_BODY_MAX ? `${oneLine3.slice(0, LABEL_TRUNCATE_HEAD2)}...` : oneLine3;
|
|
5006
5045
|
return `Ad-hoc note: ${truncated}`;
|
|
5007
5046
|
}
|
|
5047
|
+
async function readNoteBody(bodyArgument, options, ctx, cwd) {
|
|
5048
|
+
if (bodyArgument !== void 0 && options.file !== void 0) {
|
|
5049
|
+
throw new Error("Pass the note text either as an argument or with --file, not both.");
|
|
5050
|
+
}
|
|
5051
|
+
if (bodyArgument !== void 0) {
|
|
5052
|
+
return { body: bodyArgument, source: "argument" };
|
|
5053
|
+
}
|
|
5054
|
+
if (options.file !== void 0) {
|
|
5055
|
+
let raw;
|
|
5056
|
+
try {
|
|
5057
|
+
raw = await readFile4(resolve8(cwd, options.file), "utf8");
|
|
5058
|
+
} catch (error) {
|
|
5059
|
+
if (findErrorCode7(error, "ENOENT")) {
|
|
5060
|
+
throw new Error("--file names a file that does not exist", { cause: error });
|
|
5061
|
+
}
|
|
5062
|
+
if (findErrorCode7(error, "EISDIR")) {
|
|
5063
|
+
throw new Error("--file names a directory, not a file", { cause: error });
|
|
5064
|
+
}
|
|
5065
|
+
throw new Error("Could not read the file --file names", { cause: error });
|
|
5066
|
+
}
|
|
5067
|
+
return { body: dropTrailingNewlines(raw), source: "file" };
|
|
5068
|
+
}
|
|
5069
|
+
if (ctx.readInput !== void 0) {
|
|
5070
|
+
return { body: dropTrailingNewlines(await ctx.readInput()), source: "stdin" };
|
|
5071
|
+
}
|
|
5072
|
+
if (process.stdin.isTTY === true) {
|
|
5073
|
+
throw new Error(NO_INPUT_HINT2);
|
|
5074
|
+
}
|
|
5075
|
+
return { body: dropTrailingNewlines(await readStdinToEnd2()), source: "stdin" };
|
|
5076
|
+
}
|
|
5077
|
+
function dropTrailingNewlines(text) {
|
|
5078
|
+
let end = text.length;
|
|
5079
|
+
while (end > 0 && text[end - 1] === "\n") {
|
|
5080
|
+
end -= 1;
|
|
5081
|
+
if (end > 0 && text[end - 1] === "\r") end -= 1;
|
|
5082
|
+
}
|
|
5083
|
+
return text.slice(0, end);
|
|
5084
|
+
}
|
|
5085
|
+
async function readStdinToEnd2() {
|
|
5086
|
+
const chunks = [];
|
|
5087
|
+
for await (const chunk of process.stdin) {
|
|
5088
|
+
chunks.push(Buffer.from(chunk));
|
|
5089
|
+
}
|
|
5090
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
5091
|
+
}
|
|
5092
|
+
function noteInvocationArgs(input) {
|
|
5093
|
+
if (input.source === "argument") return [input.body];
|
|
5094
|
+
if (input.source === "file" && input.file !== void 0) {
|
|
5095
|
+
return [
|
|
5096
|
+
"--file",
|
|
5097
|
+
sanitizePath2(resolve8(input.cwd, input.file), {
|
|
5098
|
+
workingDirectory: input.repositoryRoot,
|
|
5099
|
+
homedir: homedir9()
|
|
5100
|
+
})
|
|
5101
|
+
];
|
|
5102
|
+
}
|
|
5103
|
+
return [];
|
|
5104
|
+
}
|
|
5008
5105
|
function parseBody(raw) {
|
|
5009
5106
|
if (raw.trim().length === 0) {
|
|
5010
5107
|
throw new InvalidArgumentError3("Note body must not be empty");
|
|
@@ -5155,7 +5252,7 @@ import {
|
|
|
5155
5252
|
writeFileSync,
|
|
5156
5253
|
writeSync
|
|
5157
5254
|
} from "fs";
|
|
5158
|
-
import { basename as basename6, dirname as dirname4, isAbsolute as isAbsolute4, join as join12, relative as relative2, resolve as
|
|
5255
|
+
import { basename as basename6, dirname as dirname4, isAbsolute as isAbsolute4, join as join12, relative as relative2, resolve as resolve9 } from "path";
|
|
5159
5256
|
import {
|
|
5160
5257
|
appendBasouGitignore as appendBasouGitignore2,
|
|
5161
5258
|
basouPaths as basouPaths12,
|
|
@@ -5530,7 +5627,7 @@ async function runProjectAdopt(options, ctx = {}) {
|
|
|
5530
5627
|
}
|
|
5531
5628
|
}
|
|
5532
5629
|
function classifySourceRoot(repositoryRoot, declaredPath) {
|
|
5533
|
-
const absolute =
|
|
5630
|
+
const absolute = resolve9(repositoryRoot, declaredPath);
|
|
5534
5631
|
let real;
|
|
5535
5632
|
try {
|
|
5536
5633
|
real = realpathSync(absolute);
|
|
@@ -5637,7 +5734,7 @@ async function gatherRepoWiring(repositoryRoot, entry) {
|
|
|
5637
5734
|
};
|
|
5638
5735
|
let real;
|
|
5639
5736
|
try {
|
|
5640
|
-
real = realpathSync(
|
|
5737
|
+
real = realpathSync(resolve9(repositoryRoot, entry.path));
|
|
5641
5738
|
} catch {
|
|
5642
5739
|
return { ...base, reachable: false, instructionFiles: [] };
|
|
5643
5740
|
}
|
|
@@ -5756,7 +5853,7 @@ function gatherRepoGitignore(repositoryRoot, entry) {
|
|
|
5756
5853
|
};
|
|
5757
5854
|
let real;
|
|
5758
5855
|
try {
|
|
5759
|
-
real = realpathSync(
|
|
5856
|
+
real = realpathSync(resolve9(repositoryRoot, entry.path));
|
|
5760
5857
|
} catch {
|
|
5761
5858
|
return { ...base, reachable: false, currentLines: [] };
|
|
5762
5859
|
}
|
|
@@ -5777,7 +5874,7 @@ function readGitignoreLines(file) {
|
|
|
5777
5874
|
}
|
|
5778
5875
|
}
|
|
5779
5876
|
function applyGitignorePlan(repositoryRoot, plan) {
|
|
5780
|
-
const file = join12(realpathSync(
|
|
5877
|
+
const file = join12(realpathSync(resolve9(repositoryRoot, plan.path)), ".gitignore");
|
|
5781
5878
|
let existing = "";
|
|
5782
5879
|
try {
|
|
5783
5880
|
existing = readFileSync(file, "utf8");
|
|
@@ -5912,7 +6009,7 @@ function gatherRepoSymlinks(repositoryRoot, anchorReal, entry) {
|
|
|
5912
6009
|
const base = { path: entry.path, ...isSelf ? { self: true } : {} };
|
|
5913
6010
|
let real;
|
|
5914
6011
|
try {
|
|
5915
|
-
real = realpathSync(
|
|
6012
|
+
real = realpathSync(resolve9(repositoryRoot, entry.path));
|
|
5916
6013
|
} catch {
|
|
5917
6014
|
return { ...base, isAnchor: false, reachable: false, canonicalPresent: false, files: [] };
|
|
5918
6015
|
}
|
|
@@ -5984,7 +6081,7 @@ function gatherRepoSymlinks(repositoryRoot, anchorReal, entry) {
|
|
|
5984
6081
|
function applySymlinkPlan(repositoryRoot, plan) {
|
|
5985
6082
|
let real;
|
|
5986
6083
|
try {
|
|
5987
|
-
real = realpathSync(
|
|
6084
|
+
real = realpathSync(resolve9(repositoryRoot, plan.path));
|
|
5988
6085
|
} catch (error) {
|
|
5989
6086
|
const message = failureReason(error);
|
|
5990
6087
|
return { created: [], failed: plan.toCreate.map((c) => ({ file: c.name, message })) };
|
|
@@ -6010,9 +6107,9 @@ function viewCanonicalCollision(repositoryRoot, roster, viewName) {
|
|
|
6010
6107
|
for (const entry of roster) {
|
|
6011
6108
|
let name;
|
|
6012
6109
|
try {
|
|
6013
|
-
name = basename6(realpathSync(
|
|
6110
|
+
name = basename6(realpathSync(resolve9(repositoryRoot, entry.path)));
|
|
6014
6111
|
} catch {
|
|
6015
|
-
name = basename6(
|
|
6112
|
+
name = basename6(resolve9(repositoryRoot, entry.path));
|
|
6016
6113
|
}
|
|
6017
6114
|
if (name === viewName) return entry.path;
|
|
6018
6115
|
}
|
|
@@ -6259,7 +6356,7 @@ async function runProjectWorkspace(options, ctx = {}) {
|
|
|
6259
6356
|
}
|
|
6260
6357
|
}
|
|
6261
6358
|
function resolveViewDir(repositoryRoot, viewPath) {
|
|
6262
|
-
const abs =
|
|
6359
|
+
const abs = resolve9(repositoryRoot, viewPath);
|
|
6263
6360
|
try {
|
|
6264
6361
|
return realpathSync(abs);
|
|
6265
6362
|
} catch {
|
|
@@ -6273,7 +6370,7 @@ function resolveViewDir(repositoryRoot, viewPath) {
|
|
|
6273
6370
|
function gatherViewRepo(repositoryRoot, viewDir, entry) {
|
|
6274
6371
|
let repoReal;
|
|
6275
6372
|
try {
|
|
6276
|
-
repoReal = realpathSync(
|
|
6373
|
+
repoReal = realpathSync(resolve9(repositoryRoot, entry.path));
|
|
6277
6374
|
} catch {
|
|
6278
6375
|
return { path: entry.path, reachable: false };
|
|
6279
6376
|
}
|
|
@@ -6325,7 +6422,7 @@ function classifyViewLink(viewDir, name, rosterRealpaths) {
|
|
|
6325
6422
|
} catch {
|
|
6326
6423
|
return null;
|
|
6327
6424
|
}
|
|
6328
|
-
const resolved = isAbsolute4(target) ? target :
|
|
6425
|
+
const resolved = isAbsolute4(target) ? target : resolve9(viewDir, target);
|
|
6329
6426
|
try {
|
|
6330
6427
|
if (rosterRealpaths.has(realpathSync(resolved))) return null;
|
|
6331
6428
|
} catch {
|
|
@@ -6411,11 +6508,11 @@ async function doRunProjectWorkspace(options, ctx) {
|
|
|
6411
6508
|
} else {
|
|
6412
6509
|
const viewDir = resolveViewDir(repositoryRoot, viewPath);
|
|
6413
6510
|
const facts = roster.map((entry) => gatherViewRepo(repositoryRoot, viewDir, entry));
|
|
6414
|
-
const rosterNames = roster.map((entry) => basename6(
|
|
6511
|
+
const rosterNames = roster.map((entry) => basename6(resolve9(repositoryRoot, entry.path)));
|
|
6415
6512
|
const rosterRealpaths = /* @__PURE__ */ new Set();
|
|
6416
6513
|
for (const entry of roster) {
|
|
6417
6514
|
try {
|
|
6418
|
-
rosterRealpaths.add(realpathSync(
|
|
6515
|
+
rosterRealpaths.add(realpathSync(resolve9(repositoryRoot, entry.path)));
|
|
6419
6516
|
} catch {
|
|
6420
6517
|
}
|
|
6421
6518
|
}
|
|
@@ -6595,7 +6692,7 @@ async function gatherRepoPreset(repositoryRoot, anchorReal, entry) {
|
|
|
6595
6692
|
}
|
|
6596
6693
|
let real;
|
|
6597
6694
|
try {
|
|
6598
|
-
real = realpathSync(
|
|
6695
|
+
real = realpathSync(resolve9(repositoryRoot, entry.path));
|
|
6599
6696
|
} catch {
|
|
6600
6697
|
return { ...declared, isAnchor: false, reachable: false, canonicalPresent: false };
|
|
6601
6698
|
}
|
|
@@ -6651,7 +6748,7 @@ function viewPresetReposFor(repositoryRoot, roster) {
|
|
|
6651
6748
|
anchorReal = void 0;
|
|
6652
6749
|
}
|
|
6653
6750
|
return roster.map((entry) => {
|
|
6654
|
-
const abs =
|
|
6751
|
+
const abs = resolve9(repositoryRoot, entry.path);
|
|
6655
6752
|
let real;
|
|
6656
6753
|
try {
|
|
6657
6754
|
real = realpathSync(abs);
|
|
@@ -6975,7 +7072,7 @@ function gatherArchiveTeardown(repositoryRoot, manifest, target) {
|
|
|
6975
7072
|
};
|
|
6976
7073
|
let real;
|
|
6977
7074
|
try {
|
|
6978
|
-
real = realpathSync(
|
|
7075
|
+
real = realpathSync(resolve9(repositoryRoot, target));
|
|
6979
7076
|
} catch {
|
|
6980
7077
|
return empty;
|
|
6981
7078
|
}
|
|
@@ -7024,7 +7121,7 @@ function viewLinkPointsAt(viewDir, name, repoReal) {
|
|
|
7024
7121
|
if (!lstatSync(filePath).isSymbolicLink()) return false;
|
|
7025
7122
|
const target = readlinkSync(filePath);
|
|
7026
7123
|
if (isAbsolute4(target)) return false;
|
|
7027
|
-
return realpathSync(
|
|
7124
|
+
return realpathSync(resolve9(viewDir, target)) === repoReal;
|
|
7028
7125
|
} catch {
|
|
7029
7126
|
return false;
|
|
7030
7127
|
}
|
|
@@ -7035,7 +7132,7 @@ function viewLinkPointsAtPath(viewDir, name, expectedRepoPath) {
|
|
|
7035
7132
|
if (!lstatSync(filePath).isSymbolicLink()) return false;
|
|
7036
7133
|
const target = readlinkSync(filePath);
|
|
7037
7134
|
if (isAbsolute4(target)) return false;
|
|
7038
|
-
return
|
|
7135
|
+
return resolve9(viewDir, target) === expectedRepoPath;
|
|
7039
7136
|
} catch {
|
|
7040
7137
|
return false;
|
|
7041
7138
|
}
|
|
@@ -7044,19 +7141,19 @@ function gatherRepoTeardown(repositoryRoot, manifest, target) {
|
|
|
7044
7141
|
const anchorReal = realpathSync(repositoryRoot);
|
|
7045
7142
|
let repoReal;
|
|
7046
7143
|
try {
|
|
7047
|
-
repoReal = realpathSync(
|
|
7144
|
+
repoReal = realpathSync(resolve9(repositoryRoot, target));
|
|
7048
7145
|
} catch {
|
|
7049
7146
|
repoReal = void 0;
|
|
7050
7147
|
}
|
|
7051
7148
|
const isAnchor = repoReal !== void 0 && repoReal === anchorReal;
|
|
7052
|
-
const targetAbs =
|
|
7149
|
+
const targetAbs = resolve9(repositoryRoot, target);
|
|
7053
7150
|
const canonicalName = basename6(repoReal ?? targetAbs);
|
|
7054
7151
|
const roster = manifest.repos ?? [];
|
|
7055
7152
|
const declaredEntry = roster.find((r) => {
|
|
7056
7153
|
try {
|
|
7057
|
-
return realpathSync(
|
|
7154
|
+
return realpathSync(resolve9(repositoryRoot, r.path)) === (repoReal ?? "\0");
|
|
7058
7155
|
} catch {
|
|
7059
|
-
return
|
|
7156
|
+
return resolve9(repositoryRoot, r.path) === targetAbs;
|
|
7060
7157
|
}
|
|
7061
7158
|
});
|
|
7062
7159
|
const inRoster = declaredEntry !== void 0;
|
|
@@ -7065,7 +7162,7 @@ function gatherRepoTeardown(repositoryRoot, manifest, target) {
|
|
|
7065
7162
|
const canonicalShared = roster.some((r) => {
|
|
7066
7163
|
let rReal = null;
|
|
7067
7164
|
try {
|
|
7068
|
-
rReal = realpathSync(
|
|
7165
|
+
rReal = realpathSync(resolve9(repositoryRoot, r.path));
|
|
7069
7166
|
} catch {
|
|
7070
7167
|
rReal = null;
|
|
7071
7168
|
}
|
|
@@ -7073,8 +7170,8 @@ function gatherRepoTeardown(repositoryRoot, manifest, target) {
|
|
|
7073
7170
|
if (repoReal !== void 0 && rReal === repoReal) return false;
|
|
7074
7171
|
return basename6(rReal).toLowerCase() === cnFold;
|
|
7075
7172
|
}
|
|
7076
|
-
if (
|
|
7077
|
-
return basename6(
|
|
7173
|
+
if (resolve9(repositoryRoot, r.path) === targetAbs) return false;
|
|
7174
|
+
return basename6(resolve9(repositoryRoot, r.path)).toLowerCase() === cnFold;
|
|
7078
7175
|
});
|
|
7079
7176
|
const collisionNote = "shared with another repo of the same basename, so it cannot be removed (check manually)";
|
|
7080
7177
|
const items = [];
|
|
@@ -7255,7 +7352,7 @@ function applyRepoTeardown(repositoryRoot, manifest, plan) {
|
|
|
7255
7352
|
const changed = (label) => failed.push({ label, message: "the state changed since the scan (re-run)" });
|
|
7256
7353
|
let currentRepoReal = null;
|
|
7257
7354
|
try {
|
|
7258
|
-
currentRepoReal = realpathSync(
|
|
7355
|
+
currentRepoReal = realpathSync(resolve9(repositoryRoot, plan.target));
|
|
7259
7356
|
} catch {
|
|
7260
7357
|
currentRepoReal = null;
|
|
7261
7358
|
}
|
|
@@ -7290,7 +7387,7 @@ function applyRepoTeardown(repositoryRoot, manifest, plan) {
|
|
|
7290
7387
|
continue;
|
|
7291
7388
|
}
|
|
7292
7389
|
const viewDir = resolveViewDir(repositoryRoot, viewPath);
|
|
7293
|
-
const owned = repoReal !== null ? viewLinkPointsAt(viewDir, item.label, repoReal) : viewLinkPointsAtPath(viewDir, item.label,
|
|
7390
|
+
const owned = repoReal !== null ? viewLinkPointsAt(viewDir, item.label, repoReal) : viewLinkPointsAtPath(viewDir, item.label, resolve9(repositoryRoot, plan.target));
|
|
7294
7391
|
if (!owned) {
|
|
7295
7392
|
changed(item.label);
|
|
7296
7393
|
continue;
|
|
@@ -7452,7 +7549,7 @@ async function doRunProjectArchive(target, options, ctx) {
|
|
|
7452
7549
|
const roster = manifest.repos ?? [];
|
|
7453
7550
|
let targetIsAnchor = false;
|
|
7454
7551
|
try {
|
|
7455
|
-
targetIsAnchor = realpathSync(
|
|
7552
|
+
targetIsAnchor = realpathSync(resolve9(repositoryRoot, target)) === realpathSync(repositoryRoot);
|
|
7456
7553
|
} catch {
|
|
7457
7554
|
targetIsAnchor = false;
|
|
7458
7555
|
}
|
|
@@ -7609,7 +7706,7 @@ async function doRunProjectRename(oldPath, newPath, options, ctx) {
|
|
|
7609
7706
|
const roster = manifest.repos ?? [];
|
|
7610
7707
|
let oldIsAnchor = false;
|
|
7611
7708
|
try {
|
|
7612
|
-
oldIsAnchor = realpathSync(
|
|
7709
|
+
oldIsAnchor = realpathSync(resolve9(repositoryRoot, oldPath)) === realpathSync(repositoryRoot);
|
|
7613
7710
|
} catch {
|
|
7614
7711
|
oldIsAnchor = false;
|
|
7615
7712
|
}
|
|
@@ -7755,7 +7852,7 @@ async function doRunProjectNew(repos, options, ctx) {
|
|
|
7755
7852
|
const viewStem = productName ?? workspaceName;
|
|
7756
7853
|
const viewOverridesProjectName = productName !== void 0 && typeof options.view === "string";
|
|
7757
7854
|
const declared = repos.map((p) => {
|
|
7758
|
-
const abs =
|
|
7855
|
+
const abs = resolve9(cwd, p);
|
|
7759
7856
|
let real;
|
|
7760
7857
|
try {
|
|
7761
7858
|
real = realpathSync(abs);
|
|
@@ -8020,7 +8117,7 @@ function pathPresent(p) {
|
|
|
8020
8117
|
}
|
|
8021
8118
|
function gatherRetrofit(repositoryRoot, anchorReal, roster, argAbs, argReal, viewCanonicalName) {
|
|
8022
8119
|
const declaredEntry = roster.find((entry) => {
|
|
8023
|
-
const entryAbs =
|
|
8120
|
+
const entryAbs = resolve9(repositoryRoot, entry.path);
|
|
8024
8121
|
if (argReal !== void 0) {
|
|
8025
8122
|
try {
|
|
8026
8123
|
if (realpathSync(entryAbs) === argReal) return true;
|
|
@@ -8160,7 +8257,7 @@ async function doRunProjectRetrofit(repo, options, ctx) {
|
|
|
8160
8257
|
}
|
|
8161
8258
|
return result2;
|
|
8162
8259
|
}
|
|
8163
|
-
const argAbs =
|
|
8260
|
+
const argAbs = resolve9(repositoryRoot, repo);
|
|
8164
8261
|
let argReal;
|
|
8165
8262
|
try {
|
|
8166
8263
|
argReal = realpathSync(argAbs);
|
|
@@ -8381,7 +8478,7 @@ function renderProjectRetrofit(result) {
|
|
|
8381
8478
|
}
|
|
8382
8479
|
|
|
8383
8480
|
// src/commands/protocol.ts
|
|
8384
|
-
import { readFile as
|
|
8481
|
+
import { readFile as readFile5, stat as stat5 } from "fs/promises";
|
|
8385
8482
|
import {
|
|
8386
8483
|
carryForwardProtocolStamp,
|
|
8387
8484
|
PROTOCOL_END as PROTOCOL_END2,
|
|
@@ -8438,7 +8535,7 @@ async function readProtocolSources(entries) {
|
|
|
8438
8535
|
for (const entry of entries) {
|
|
8439
8536
|
let content;
|
|
8440
8537
|
try {
|
|
8441
|
-
content = await
|
|
8538
|
+
content = await readFile5(entry.source, "utf8");
|
|
8442
8539
|
} catch (error) {
|
|
8443
8540
|
if (error instanceof Error && error.code === "ENOENT") {
|
|
8444
8541
|
throw new Error(
|
|
@@ -8571,7 +8668,7 @@ import { InvalidArgumentError as InvalidArgumentError4 } from "commander";
|
|
|
8571
8668
|
|
|
8572
8669
|
// src/commands/refresh-watch.ts
|
|
8573
8670
|
import { readdir as readdir2, stat as stat6 } from "fs/promises";
|
|
8574
|
-
import { homedir as
|
|
8671
|
+
import { homedir as homedir10 } from "os";
|
|
8575
8672
|
import { join as join13 } from "path";
|
|
8576
8673
|
import { findErrorCode as findErrorCode8 } from "@basou/core";
|
|
8577
8674
|
var DEFAULT_WATCH_INTERVAL_SEC = 30;
|
|
@@ -8579,8 +8676,8 @@ var MIN_WATCH_INTERVAL_SEC = 5;
|
|
|
8579
8676
|
var MAX_WATCH_INTERVAL_SEC = 86400;
|
|
8580
8677
|
function watchedRoots(ctx) {
|
|
8581
8678
|
return [
|
|
8582
|
-
ctx.codexSessionsDir ?? join13(
|
|
8583
|
-
ctx.claudeProjectsDir ?? join13(
|
|
8679
|
+
ctx.codexSessionsDir ?? join13(homedir10(), ".codex", "sessions"),
|
|
8680
|
+
ctx.claudeProjectsDir ?? join13(homedir10(), ".claude", "projects")
|
|
8584
8681
|
];
|
|
8585
8682
|
}
|
|
8586
8683
|
async function scanSourceLogs(roots) {
|
|
@@ -8701,19 +8798,19 @@ function parseInterval(value) {
|
|
|
8701
8798
|
return seconds;
|
|
8702
8799
|
}
|
|
8703
8800
|
function abortableSleep(ms, signal) {
|
|
8704
|
-
return new Promise((
|
|
8801
|
+
return new Promise((resolve15) => {
|
|
8705
8802
|
if (signal.aborted) {
|
|
8706
|
-
|
|
8803
|
+
resolve15();
|
|
8707
8804
|
return;
|
|
8708
8805
|
}
|
|
8709
8806
|
let timer;
|
|
8710
8807
|
const onAbort = () => {
|
|
8711
8808
|
clearTimeout(timer);
|
|
8712
|
-
|
|
8809
|
+
resolve15();
|
|
8713
8810
|
};
|
|
8714
8811
|
timer = setTimeout(() => {
|
|
8715
8812
|
signal.removeEventListener("abort", onAbort);
|
|
8716
|
-
|
|
8813
|
+
resolve15();
|
|
8717
8814
|
}, ms);
|
|
8718
8815
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
8719
8816
|
});
|
|
@@ -8939,7 +9036,7 @@ async function assertWorkspaceInitialized8(basouRoot) {
|
|
|
8939
9036
|
}
|
|
8940
9037
|
|
|
8941
9038
|
// src/commands/report.ts
|
|
8942
|
-
import { isAbsolute as isAbsolute5, resolve as
|
|
9039
|
+
import { isAbsolute as isAbsolute5, resolve as resolve10 } from "path";
|
|
8943
9040
|
import {
|
|
8944
9041
|
assertBasouRootSafe as assertBasouRootSafe10,
|
|
8945
9042
|
basouPaths as basouPaths14,
|
|
@@ -8979,7 +9076,7 @@ async function doRunReportGenerate(options, ctx) {
|
|
|
8979
9076
|
onTaskSkip: (taskId, reason) => printTaskSkip(taskId, reason)
|
|
8980
9077
|
});
|
|
8981
9078
|
if (options.out !== void 0) {
|
|
8982
|
-
const outPath = isAbsolute5(options.out) ? options.out :
|
|
9079
|
+
const outPath = isAbsolute5(options.out) ? options.out : resolve10(cwd, options.out);
|
|
8983
9080
|
await writeMarkdownFile6(outPath, result.body);
|
|
8984
9081
|
const { sessions, decisions, tasks } = result.data;
|
|
8985
9082
|
console.error(
|
|
@@ -9017,9 +9114,9 @@ async function assertWorkspaceInitialized9(basouRoot) {
|
|
|
9017
9114
|
}
|
|
9018
9115
|
|
|
9019
9116
|
// src/commands/review.ts
|
|
9020
|
-
import { readFile as
|
|
9021
|
-
import { homedir as
|
|
9022
|
-
import { resolve as
|
|
9117
|
+
import { readFile as readFile6 } from "fs/promises";
|
|
9118
|
+
import { homedir as homedir11 } from "os";
|
|
9119
|
+
import { resolve as resolve11 } from "path";
|
|
9023
9120
|
import {
|
|
9024
9121
|
assertBasouRootSafe as assertBasouRootSafe11,
|
|
9025
9122
|
basouPaths as basouPaths15,
|
|
@@ -9031,7 +9128,7 @@ import {
|
|
|
9031
9128
|
parseReviewRecordInput,
|
|
9032
9129
|
readManifest as readManifest9,
|
|
9033
9130
|
resolveRepoRoot,
|
|
9034
|
-
sanitizePath as
|
|
9131
|
+
sanitizePath as sanitizePath3
|
|
9035
9132
|
} from "@basou/core";
|
|
9036
9133
|
function registerReviewCommand(program2) {
|
|
9037
9134
|
const review = program2.command("review").description("Record reviews that ran (the durable signal a review happened)");
|
|
@@ -9119,9 +9216,9 @@ async function doRunReviewRecord(options, ctx) {
|
|
|
9119
9216
|
const manifest = await readManifest9(paths);
|
|
9120
9217
|
const invocationArgs = options.file !== void 0 ? [
|
|
9121
9218
|
"--file",
|
|
9122
|
-
|
|
9219
|
+
sanitizePath3(resolve11(cwd, options.file), {
|
|
9123
9220
|
workingDirectory: repositoryRoot,
|
|
9124
|
-
homedir:
|
|
9221
|
+
homedir: homedir11()
|
|
9125
9222
|
})
|
|
9126
9223
|
] : [];
|
|
9127
9224
|
const adHoc = await createAdHocSessionWithEvent3({
|
|
@@ -9161,7 +9258,7 @@ ${detail}
|
|
|
9161
9258
|
async function readReviewInput(options, ctx) {
|
|
9162
9259
|
if (options.file !== void 0) {
|
|
9163
9260
|
try {
|
|
9164
|
-
return await
|
|
9261
|
+
return await readFile6(options.file, "utf8");
|
|
9165
9262
|
} catch (error) {
|
|
9166
9263
|
if (findErrorCode11(error, "ENOENT")) {
|
|
9167
9264
|
throw new Error(`Input file not found: ${options.file}`);
|
|
@@ -9173,18 +9270,18 @@ async function readReviewInput(options, ctx) {
|
|
|
9173
9270
|
return await ctx.readInput();
|
|
9174
9271
|
}
|
|
9175
9272
|
if (process.stdin.isTTY === true) {
|
|
9176
|
-
throw new Error(
|
|
9273
|
+
throw new Error(NO_INPUT_HINT3);
|
|
9177
9274
|
}
|
|
9178
|
-
return await
|
|
9275
|
+
return await readStdinToEnd3();
|
|
9179
9276
|
}
|
|
9180
|
-
async function
|
|
9277
|
+
async function readStdinToEnd3() {
|
|
9181
9278
|
const chunks = [];
|
|
9182
9279
|
for await (const chunk of process.stdin) {
|
|
9183
9280
|
chunks.push(Buffer.from(chunk));
|
|
9184
9281
|
}
|
|
9185
9282
|
return Buffer.concat(chunks).toString("utf8");
|
|
9186
9283
|
}
|
|
9187
|
-
var
|
|
9284
|
+
var NO_INPUT_HINT3 = "No input: pipe a JSON object describing the review to stdin or pass --file <path>.";
|
|
9188
9285
|
function reviewToPayload(review) {
|
|
9189
9286
|
const payload = {
|
|
9190
9287
|
reviewer: review.reviewer,
|
|
@@ -9454,8 +9551,8 @@ function unattachedLines(u) {
|
|
|
9454
9551
|
}
|
|
9455
9552
|
|
|
9456
9553
|
// src/commands/run.ts
|
|
9457
|
-
import { mkdir as mkdir2, readFile as
|
|
9458
|
-
import { homedir as
|
|
9554
|
+
import { mkdir as mkdir2, readFile as readFile7 } from "fs/promises";
|
|
9555
|
+
import { homedir as homedir12 } from "os";
|
|
9459
9556
|
import { join as join14 } from "path";
|
|
9460
9557
|
import {
|
|
9461
9558
|
acquireLock as acquireLock5,
|
|
@@ -9681,7 +9778,7 @@ async function runTrackedTool(args, options, ctx, adapter) {
|
|
|
9681
9778
|
const rawRelated = computeRelatedFiles(preSnapshot, postSnapshot, diff);
|
|
9682
9779
|
const relatedFiles = sanitizeRelatedFiles(rawRelated, {
|
|
9683
9780
|
workingDirectory: repoRoot,
|
|
9684
|
-
homedir:
|
|
9781
|
+
homedir: homedir12()
|
|
9685
9782
|
}).sanitized;
|
|
9686
9783
|
const finalStatus = decideFinalStatus2(result, signalReceived);
|
|
9687
9784
|
await appendEvent(sessionDir, {
|
|
@@ -9825,7 +9922,7 @@ function buildInitialSession2(input) {
|
|
|
9825
9922
|
source: { ...input.source },
|
|
9826
9923
|
started_at: input.startedAt,
|
|
9827
9924
|
status: "initialized",
|
|
9828
|
-
working_directory: sanitizeWorkingDirectory2(input.cwd, { homedir:
|
|
9925
|
+
working_directory: sanitizeWorkingDirectory2(input.cwd, { homedir: homedir12() }),
|
|
9829
9926
|
invocation: {
|
|
9830
9927
|
command: input.command,
|
|
9831
9928
|
args: [...input.args],
|
|
@@ -9901,7 +9998,7 @@ async function noteCodexHookStatusPreSpawn(_cwd, ctx) {
|
|
|
9901
9998
|
const hooksPath = ctx.codexHooksPath ?? DEFAULT_CODEX_HOOKS_PATH;
|
|
9902
9999
|
let location;
|
|
9903
10000
|
try {
|
|
9904
|
-
location = findBasouSessionStartHook2(JSON.parse(await
|
|
10001
|
+
location = findBasouSessionStartHook2(JSON.parse(await readFile7(hooksPath, "utf8")));
|
|
9905
10002
|
} catch (error) {
|
|
9906
10003
|
if (!(error instanceof Error && error.code === "ENOENT")) return null;
|
|
9907
10004
|
location = null;
|
|
@@ -9915,7 +10012,7 @@ async function noteCodexHookStatusPreSpawn(_cwd, ctx) {
|
|
|
9915
10012
|
}
|
|
9916
10013
|
|
|
9917
10014
|
// src/commands/session.ts
|
|
9918
|
-
import { readFile as
|
|
10015
|
+
import { readFile as readFile8 } from "fs/promises";
|
|
9919
10016
|
import { basename as basename7, isAbsolute as isAbsolute6, join as join15, relative as relative3, sep as sep2 } from "path";
|
|
9920
10017
|
import {
|
|
9921
10018
|
acquireLock as acquireLock6,
|
|
@@ -9929,6 +10026,7 @@ import {
|
|
|
9929
10026
|
importSessionFromJson as importSessionFromJson2,
|
|
9930
10027
|
LOCAL_CLI_EVENT_SOURCE as LOCAL_CLI_EVENT_SOURCE4,
|
|
9931
10028
|
loadSessionEntries as loadSessionEntries2,
|
|
10029
|
+
normalizeSessionTimestamps,
|
|
9932
10030
|
readAllEvents,
|
|
9933
10031
|
readManifest as readManifest11,
|
|
9934
10032
|
readObservedDuration,
|
|
@@ -10051,7 +10149,7 @@ async function doRunSessionShow(idInput, options, ctx) {
|
|
|
10051
10149
|
let session;
|
|
10052
10150
|
try {
|
|
10053
10151
|
const raw = await readYamlFile7(sessionYamlPath);
|
|
10054
|
-
session = SessionSchema3.parse(raw);
|
|
10152
|
+
session = SessionSchema3.parse(normalizeSessionTimestamps(raw));
|
|
10055
10153
|
} catch (error) {
|
|
10056
10154
|
if (findErrorCode12(error, "ENOENT")) {
|
|
10057
10155
|
throw new Error(`Session not found: ${idInput}`);
|
|
@@ -10386,7 +10484,7 @@ async function doRunSessionImport(options, ctx) {
|
|
|
10386
10484
|
}
|
|
10387
10485
|
async function readInputFile(path) {
|
|
10388
10486
|
try {
|
|
10389
|
-
return await
|
|
10487
|
+
return await readFile8(path, "utf8");
|
|
10390
10488
|
} catch (error) {
|
|
10391
10489
|
if (findErrorCode12(error, "ENOENT")) {
|
|
10392
10490
|
throw new Error("Import source not found", { cause: error });
|
|
@@ -10503,7 +10601,7 @@ async function doRunSessionNote(sessionIdInput, options, ctx) {
|
|
|
10503
10601
|
}
|
|
10504
10602
|
async function readNoteFile(path) {
|
|
10505
10603
|
try {
|
|
10506
|
-
return await
|
|
10604
|
+
return await readFile8(path, "utf8");
|
|
10507
10605
|
} catch (error) {
|
|
10508
10606
|
if (findErrorCode12(error, "ENOENT")) {
|
|
10509
10607
|
throw new Error("Note source not found", { cause: error });
|
|
@@ -10828,7 +10926,7 @@ function formatVersionGateMessage(error) {
|
|
|
10828
10926
|
}
|
|
10829
10927
|
|
|
10830
10928
|
// src/commands/task.ts
|
|
10831
|
-
import { readFile as
|
|
10929
|
+
import { readFile as readFile9 } from "fs/promises";
|
|
10832
10930
|
import { join as join16 } from "path";
|
|
10833
10931
|
import {
|
|
10834
10932
|
archiveTask,
|
|
@@ -11843,7 +11941,7 @@ function parsePositiveInt2(raw) {
|
|
|
11843
11941
|
}
|
|
11844
11942
|
async function readDescriptionFile(path) {
|
|
11845
11943
|
try {
|
|
11846
|
-
return await
|
|
11944
|
+
return await readFile9(path, "utf8");
|
|
11847
11945
|
} catch (error) {
|
|
11848
11946
|
if (findErrorCode15(error, "ENOENT")) {
|
|
11849
11947
|
throw new Error("Description source not found", { cause: error });
|
|
@@ -12048,7 +12146,7 @@ async function assertWorkspaceInitialized14(basouRoot) {
|
|
|
12048
12146
|
// src/commands/view.ts
|
|
12049
12147
|
import { spawn } from "child_process";
|
|
12050
12148
|
import { createHash as createHash2 } from "crypto";
|
|
12051
|
-
import { basename as basename10, resolve as
|
|
12149
|
+
import { basename as basename10, resolve as resolve14 } from "path";
|
|
12052
12150
|
import {
|
|
12053
12151
|
assertBasouRootSafe as assertBasouRootSafe18,
|
|
12054
12152
|
basouPaths as basouPaths24,
|
|
@@ -12061,7 +12159,7 @@ import { InvalidArgumentError as InvalidArgumentError8 } from "commander";
|
|
|
12061
12159
|
// src/lib/portfolio-coverage.ts
|
|
12062
12160
|
import { createReadStream as createReadStream2 } from "fs";
|
|
12063
12161
|
import { readdir as readdir3, stat as stat7 } from "fs/promises";
|
|
12064
|
-
import { homedir as
|
|
12162
|
+
import { homedir as homedir13 } from "os";
|
|
12065
12163
|
import { basename as basename8, dirname as dirname5, join as join17 } from "path";
|
|
12066
12164
|
import { createInterface as createInterface2 } from "readline";
|
|
12067
12165
|
import { basouPaths as basouPaths23, readManifest as readManifest14, resolveRepositoryRoot as resolveRepositoryRoot13 } from "@basou/core";
|
|
@@ -12071,8 +12169,8 @@ function uncapturedTotal(result) {
|
|
|
12071
12169
|
async function checkPortfolioCoverage(workspaces, ctx = {}) {
|
|
12072
12170
|
const { roots, inertWorkspaces } = await collectDeclaredRoots(workspaces);
|
|
12073
12171
|
const listedDirs = new Set([...roots].map((root) => encodeProjectDir(root)));
|
|
12074
|
-
const claudeProjectsDir = ctx.claudeProjectsDir ?? join17(
|
|
12075
|
-
const codexSessionsDir = ctx.codexSessionsDir ?? join17(
|
|
12172
|
+
const claudeProjectsDir = ctx.claudeProjectsDir ?? join17(homedir13(), ".claude", "projects");
|
|
12173
|
+
const codexSessionsDir = ctx.codexSessionsDir ?? join17(homedir13(), ".codex", "sessions");
|
|
12076
12174
|
const tally = new Tally(roots);
|
|
12077
12175
|
const absentTrees = [];
|
|
12078
12176
|
const claudeFiles = await listClaudeTranscripts(claudeProjectsDir);
|
|
@@ -12376,7 +12474,7 @@ function inertLines(result) {
|
|
|
12376
12474
|
// src/lib/portfolio-safety.ts
|
|
12377
12475
|
import { execFile as execFile2 } from "child_process";
|
|
12378
12476
|
import { lstat as lstat2, realpath as realpath4 } from "fs/promises";
|
|
12379
|
-
import { isAbsolute as isAbsolute7, join as join18, relative as relative4, resolve as
|
|
12477
|
+
import { isAbsolute as isAbsolute7, join as join18, relative as relative4, resolve as resolve12, sep as sep3 } from "path";
|
|
12380
12478
|
import { promisify as promisify2 } from "util";
|
|
12381
12479
|
import { readManifest as readManifest15 } from "@basou/core";
|
|
12382
12480
|
var execFileAsync2 = promisify2(execFile2);
|
|
@@ -12387,7 +12485,7 @@ async function canonical(p) {
|
|
|
12387
12485
|
try {
|
|
12388
12486
|
return await realpath4(p);
|
|
12389
12487
|
} catch {
|
|
12390
|
-
return
|
|
12488
|
+
return resolve12(p);
|
|
12391
12489
|
}
|
|
12392
12490
|
}
|
|
12393
12491
|
function isInside(child, parent) {
|
|
@@ -12455,13 +12553,13 @@ async function checkPortfolioSafety(workspaces) {
|
|
|
12455
12553
|
}
|
|
12456
12554
|
const monitored = /* @__PURE__ */ new Map();
|
|
12457
12555
|
for (const root of sourceRoots) {
|
|
12458
|
-
const display =
|
|
12556
|
+
const display = resolve12(ws.repoRoot, root);
|
|
12459
12557
|
const real = await canonical(display);
|
|
12460
12558
|
if (real !== wsReal) monitored.set(real, display);
|
|
12461
12559
|
}
|
|
12462
12560
|
const claimed = new Set(monitored.keys());
|
|
12463
12561
|
if (isMaster && viewPath !== void 0) {
|
|
12464
|
-
const viewReal = await canonical(
|
|
12562
|
+
const viewReal = await canonical(resolve12(ws.repoRoot, viewPath));
|
|
12465
12563
|
if (viewReal !== wsReal) claimed.add(viewReal);
|
|
12466
12564
|
}
|
|
12467
12565
|
records.push({ ws, real: wsReal, isMaster, claimed });
|
|
@@ -12554,7 +12652,7 @@ function formatSafetyReport(result) {
|
|
|
12554
12652
|
|
|
12555
12653
|
// src/lib/view-server.ts
|
|
12556
12654
|
import { createServer } from "http";
|
|
12557
|
-
import { basename as basename9, join as join19, resolve as
|
|
12655
|
+
import { basename as basename9, join as join19, resolve as resolve13 } from "path";
|
|
12558
12656
|
import {
|
|
12559
12657
|
computeWorkStats as computeWorkStats2,
|
|
12560
12658
|
enumerateApprovals as enumerateApprovals2,
|
|
@@ -13308,7 +13406,7 @@ function startViewServer(opts) {
|
|
|
13308
13406
|
};
|
|
13309
13407
|
let boundPort = port;
|
|
13310
13408
|
const getPort = () => boundPort;
|
|
13311
|
-
return new Promise((
|
|
13409
|
+
return new Promise((resolve15, reject) => {
|
|
13312
13410
|
const server = createServer((req, res) => {
|
|
13313
13411
|
handleRequest(req, res, deps, getPort, runExclusive).catch((error) => {
|
|
13314
13412
|
sendError(res, error instanceof HttpError ? error.status : 500, pathlessMessage(error));
|
|
@@ -13319,7 +13417,7 @@ function startViewServer(opts) {
|
|
|
13319
13417
|
const address = server.address();
|
|
13320
13418
|
boundPort = isAddressInfo(address) ? address.port : port;
|
|
13321
13419
|
server.off("error", reject);
|
|
13322
|
-
|
|
13420
|
+
resolve15({
|
|
13323
13421
|
url: `http://${host}:${boundPort}`,
|
|
13324
13422
|
port: boundPort,
|
|
13325
13423
|
close: () => closeServer(server)
|
|
@@ -13331,8 +13429,8 @@ function isAddressInfo(value) {
|
|
|
13331
13429
|
return value !== null && typeof value === "object";
|
|
13332
13430
|
}
|
|
13333
13431
|
function closeServer(server) {
|
|
13334
|
-
return new Promise((
|
|
13335
|
-
server.close(() =>
|
|
13432
|
+
return new Promise((resolve15) => {
|
|
13433
|
+
server.close(() => resolve15());
|
|
13336
13434
|
server.closeAllConnections();
|
|
13337
13435
|
});
|
|
13338
13436
|
}
|
|
@@ -13604,7 +13702,7 @@ async function rosterRepos(repoRoot, manifest, resolveRemoteUrl) {
|
|
|
13604
13702
|
const roster = manifest.repos ?? [];
|
|
13605
13703
|
return Promise.all(
|
|
13606
13704
|
roster.map(async (repo) => {
|
|
13607
|
-
const abs =
|
|
13705
|
+
const abs = resolve13(repoRoot, repo.path);
|
|
13608
13706
|
const remote = await resolveRemoteUrl(abs);
|
|
13609
13707
|
const url = remote !== void 0 ? toBrowserUrl(remote) : null;
|
|
13610
13708
|
return {
|
|
@@ -13880,12 +13978,12 @@ async function buildSingleDeps(ctx, cwd) {
|
|
|
13880
13978
|
};
|
|
13881
13979
|
}
|
|
13882
13980
|
async function buildPortfolioDeps(workspaceFlags, ctx, cwd) {
|
|
13883
|
-
const specs = workspaceFlags.length > 0 ? workspaceFlags.map((p) => ({ path:
|
|
13981
|
+
const specs = workspaceFlags.length > 0 ? workspaceFlags.map((p) => ({ path: resolve14(cwd, p) })) : await loadPortfolioConfig(ctx.portfolioConfigPath);
|
|
13884
13982
|
const entries = [];
|
|
13885
13983
|
const seenPath = /* @__PURE__ */ new Set();
|
|
13886
13984
|
const seenKey = /* @__PURE__ */ new Set();
|
|
13887
13985
|
for (const spec of specs) {
|
|
13888
|
-
const repoRoot =
|
|
13986
|
+
const repoRoot = resolve14(spec.path);
|
|
13889
13987
|
if (seenPath.has(repoRoot)) continue;
|
|
13890
13988
|
seenPath.add(repoRoot);
|
|
13891
13989
|
const entry = await buildWorkspaceEntry(repoRoot, ctx, spec.label);
|
|
@@ -13962,7 +14060,7 @@ function openInBrowser(url, override) {
|
|
|
13962
14060
|
}
|
|
13963
14061
|
}
|
|
13964
14062
|
function waitForShutdown(signal) {
|
|
13965
|
-
return new Promise((
|
|
14063
|
+
return new Promise((resolve15) => {
|
|
13966
14064
|
const cleanup = () => {
|
|
13967
14065
|
process.off("SIGINT", onSignal);
|
|
13968
14066
|
process.off("SIGTERM", onSignal);
|
|
@@ -13970,18 +14068,18 @@ function waitForShutdown(signal) {
|
|
|
13970
14068
|
};
|
|
13971
14069
|
const onSignal = () => {
|
|
13972
14070
|
cleanup();
|
|
13973
|
-
|
|
14071
|
+
resolve15();
|
|
13974
14072
|
};
|
|
13975
14073
|
const onAbort = () => {
|
|
13976
14074
|
cleanup();
|
|
13977
|
-
|
|
14075
|
+
resolve15();
|
|
13978
14076
|
};
|
|
13979
14077
|
process.on("SIGINT", onSignal);
|
|
13980
14078
|
process.on("SIGTERM", onSignal);
|
|
13981
14079
|
if (signal !== void 0) {
|
|
13982
14080
|
if (signal.aborted) {
|
|
13983
14081
|
cleanup();
|
|
13984
|
-
|
|
14082
|
+
resolve15();
|
|
13985
14083
|
return;
|
|
13986
14084
|
}
|
|
13987
14085
|
signal.addEventListener("abort", onAbort);
|
|
@@ -14015,7 +14113,7 @@ async function assertWorkspaceInitialized15(basouRoot) {
|
|
|
14015
14113
|
function readBuildStamp() {
|
|
14016
14114
|
if (false) return void 0;
|
|
14017
14115
|
try {
|
|
14018
|
-
return JSON.parse('{"version":"0.
|
|
14116
|
+
return JSON.parse('{"version":"0.55.0","commit":"c59daeb","committedAt":"2026-09-30T10:04:37+09:00"}');
|
|
14019
14117
|
} catch {
|
|
14020
14118
|
return void 0;
|
|
14021
14119
|
}
|