codebyplan 1.13.58 → 1.13.60
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js
CHANGED
|
@@ -48,7 +48,7 @@ var VERSION, PACKAGE_NAME;
|
|
|
48
48
|
var init_version = __esm({
|
|
49
49
|
"src/lib/version.ts"() {
|
|
50
50
|
"use strict";
|
|
51
|
-
VERSION = "1.13.
|
|
51
|
+
VERSION = "1.13.60";
|
|
52
52
|
PACKAGE_NAME = "codebyplan";
|
|
53
53
|
}
|
|
54
54
|
});
|
|
@@ -186,6 +186,17 @@ var init_local_config = __esm({
|
|
|
186
186
|
});
|
|
187
187
|
|
|
188
188
|
// src/lib/flags.ts
|
|
189
|
+
var flags_exports = {};
|
|
190
|
+
__export(flags_exports, {
|
|
191
|
+
coerceFieldValues: () => coerceFieldValues,
|
|
192
|
+
deriveRepoRoot: () => deriveRepoRoot,
|
|
193
|
+
findCodebyplanConfig: () => findCodebyplanConfig,
|
|
194
|
+
hasFlag: () => hasFlag,
|
|
195
|
+
kebabToSnakeKeys: () => kebabToSnakeKeys,
|
|
196
|
+
parseFlags: () => parseFlags,
|
|
197
|
+
parseFlagsFromArgs: () => parseFlagsFromArgs,
|
|
198
|
+
resolveConfig: () => resolveConfig
|
|
199
|
+
});
|
|
189
200
|
import { readFile as readFile2 } from "node:fs/promises";
|
|
190
201
|
import { join as join2, resolve } from "node:path";
|
|
191
202
|
async function findCodebyplanConfig(startDir, maxDepth = 20) {
|
|
@@ -869,29 +880,42 @@ async function deleteFallback(filename) {
|
|
|
869
880
|
} catch {
|
|
870
881
|
}
|
|
871
882
|
}
|
|
883
|
+
function useKeychain() {
|
|
884
|
+
const v = process.env.CODEBYPLAN_USE_KEYCHAIN;
|
|
885
|
+
return v === "1" || v === "true";
|
|
886
|
+
}
|
|
872
887
|
async function saveTokens(tokens) {
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
888
|
+
if (useKeychain()) {
|
|
889
|
+
const Keyring = await loadKeyring();
|
|
890
|
+
if (Keyring) {
|
|
891
|
+
try {
|
|
892
|
+
new Keyring(SERVICE, TOKEN_ACCOUNT).setPassword(JSON.stringify(tokens));
|
|
893
|
+
return;
|
|
894
|
+
} catch {
|
|
895
|
+
}
|
|
879
896
|
}
|
|
880
897
|
}
|
|
881
898
|
await writeFallback("credentials.json", tokens);
|
|
882
899
|
}
|
|
883
900
|
async function loadTokens() {
|
|
901
|
+
const fromFile = await readFallback("credentials.json");
|
|
902
|
+
if (fromFile) return fromFile;
|
|
884
903
|
const Keyring = await loadKeyring();
|
|
885
904
|
if (Keyring) {
|
|
886
905
|
try {
|
|
887
906
|
const raw = new Keyring(SERVICE, TOKEN_ACCOUNT).getPassword();
|
|
888
|
-
if (raw)
|
|
907
|
+
if (raw) {
|
|
908
|
+
const tokens = JSON.parse(raw);
|
|
909
|
+
if (!useKeychain()) await writeFallback("credentials.json", tokens);
|
|
910
|
+
return tokens;
|
|
911
|
+
}
|
|
889
912
|
} catch {
|
|
890
913
|
}
|
|
891
914
|
}
|
|
892
|
-
return
|
|
915
|
+
return null;
|
|
893
916
|
}
|
|
894
917
|
async function clearTokens() {
|
|
918
|
+
await deleteFallback("credentials.json");
|
|
895
919
|
const Keyring = await loadKeyring();
|
|
896
920
|
if (Keyring) {
|
|
897
921
|
try {
|
|
@@ -899,31 +923,39 @@ async function clearTokens() {
|
|
|
899
923
|
} catch {
|
|
900
924
|
}
|
|
901
925
|
}
|
|
902
|
-
await deleteFallback("credentials.json");
|
|
903
926
|
}
|
|
904
927
|
async function saveClientRegistration(reg) {
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
928
|
+
if (useKeychain()) {
|
|
929
|
+
const Keyring = await loadKeyring();
|
|
930
|
+
if (Keyring) {
|
|
931
|
+
try {
|
|
932
|
+
new Keyring(SERVICE, CLIENT_ACCOUNT).setPassword(JSON.stringify(reg));
|
|
933
|
+
return;
|
|
934
|
+
} catch {
|
|
935
|
+
}
|
|
911
936
|
}
|
|
912
937
|
}
|
|
913
938
|
await writeFallback("client.json", reg);
|
|
914
939
|
}
|
|
915
940
|
async function loadClientRegistration() {
|
|
941
|
+
const fromFile = await readFallback("client.json");
|
|
942
|
+
if (fromFile) return fromFile;
|
|
916
943
|
const Keyring = await loadKeyring();
|
|
917
944
|
if (Keyring) {
|
|
918
945
|
try {
|
|
919
946
|
const raw = new Keyring(SERVICE, CLIENT_ACCOUNT).getPassword();
|
|
920
|
-
if (raw)
|
|
947
|
+
if (raw) {
|
|
948
|
+
const reg = JSON.parse(raw);
|
|
949
|
+
if (!useKeychain()) await writeFallback("client.json", reg);
|
|
950
|
+
return reg;
|
|
951
|
+
}
|
|
921
952
|
} catch {
|
|
922
953
|
}
|
|
923
954
|
}
|
|
924
|
-
return
|
|
955
|
+
return null;
|
|
925
956
|
}
|
|
926
957
|
async function clearClientRegistration() {
|
|
958
|
+
await deleteFallback("client.json");
|
|
927
959
|
const Keyring = await loadKeyring();
|
|
928
960
|
if (Keyring) {
|
|
929
961
|
try {
|
|
@@ -931,7 +963,6 @@ async function clearClientRegistration() {
|
|
|
931
963
|
} catch {
|
|
932
964
|
}
|
|
933
965
|
}
|
|
934
|
-
await deleteFallback("client.json");
|
|
935
966
|
}
|
|
936
967
|
var SERVICE, TOKEN_ACCOUNT, CLIENT_ACCOUNT, keyringOverride;
|
|
937
968
|
var init_keychain = __esm({
|
|
@@ -4809,9 +4840,9 @@ async function eslintInit(repoId, projectPath) {
|
|
|
4809
4840
|
Install ${missingPkgs.length} missing packages? [Y/n] `
|
|
4810
4841
|
);
|
|
4811
4842
|
if (confirmed) {
|
|
4812
|
-
const { execSync:
|
|
4843
|
+
const { execSync: execSync12 } = await import("node:child_process");
|
|
4813
4844
|
try {
|
|
4814
|
-
|
|
4845
|
+
execSync12(installCmd, { cwd: projectPath, stdio: "inherit" });
|
|
4815
4846
|
console.log(" Packages installed.\n");
|
|
4816
4847
|
} catch (err) {
|
|
4817
4848
|
console.error(
|
|
@@ -4989,6 +5020,7 @@ __export(state_store_exports, {
|
|
|
4989
5020
|
deleteEntityFile: () => deleteEntityFile,
|
|
4990
5021
|
hashEntity: () => hashEntity,
|
|
4991
5022
|
listEntityFiles: () => listEntityFiles,
|
|
5023
|
+
pendingDir: () => pendingDir,
|
|
4992
5024
|
pendingMarkerPath: () => pendingMarkerPath,
|
|
4993
5025
|
pruneEntityTree: () => pruneEntityTree,
|
|
4994
5026
|
readCursor: () => readCursor,
|
|
@@ -5054,6 +5086,9 @@ function todosPath(repoRoot) {
|
|
|
5054
5086
|
function worktreesPath(repoRoot) {
|
|
5055
5087
|
return join19(stateDir(repoRoot), "worktrees.json");
|
|
5056
5088
|
}
|
|
5089
|
+
function pendingDir(repoRoot) {
|
|
5090
|
+
return join19(stateDir(repoRoot), "_pending");
|
|
5091
|
+
}
|
|
5057
5092
|
function pendingMarkerPath(repoRoot, entityId) {
|
|
5058
5093
|
return join19(stateDir(repoRoot), "_pending", `${entityId}.json`);
|
|
5059
5094
|
}
|
|
@@ -5251,6 +5286,126 @@ var state_sync_exports = {};
|
|
|
5251
5286
|
__export(state_sync_exports, {
|
|
5252
5287
|
runSync: () => runSync
|
|
5253
5288
|
});
|
|
5289
|
+
async function replayOutbox(repoRoot, authHeaders) {
|
|
5290
|
+
const markerPaths = await listEntityFiles(pendingDir(repoRoot));
|
|
5291
|
+
for (const markerPath of markerPaths) {
|
|
5292
|
+
try {
|
|
5293
|
+
const marker = await readEntityFile(markerPath);
|
|
5294
|
+
if (!marker) {
|
|
5295
|
+
await deleteEntityFile(markerPath);
|
|
5296
|
+
continue;
|
|
5297
|
+
}
|
|
5298
|
+
if (marker.operation === "complete") {
|
|
5299
|
+
process.stderr.write(
|
|
5300
|
+
`state-sync: replayOutbox: skipping "complete" marker for ${marker.entity} ${marker.id} (deferred; different endpoint \u2014 see CHK-222 TASK-4 follow-up)
|
|
5301
|
+
`
|
|
5302
|
+
);
|
|
5303
|
+
continue;
|
|
5304
|
+
}
|
|
5305
|
+
if (marker.operation !== "update" && marker.operation !== "update-log") {
|
|
5306
|
+
process.stderr.write(
|
|
5307
|
+
`state-sync: replayOutbox: discarding unknown operation "${marker.operation}" for ${marker.entity} ${marker.id}
|
|
5308
|
+
`
|
|
5309
|
+
);
|
|
5310
|
+
await deleteEntityFile(markerPath);
|
|
5311
|
+
continue;
|
|
5312
|
+
}
|
|
5313
|
+
let entityPath = null;
|
|
5314
|
+
let patchEndpoint = null;
|
|
5315
|
+
switch (marker.entity) {
|
|
5316
|
+
case "checkpoint":
|
|
5317
|
+
entityPath = checkpointPath(repoRoot, marker.id);
|
|
5318
|
+
patchEndpoint = `${backendCheckpointsEndpoint()}/${marker.id}`;
|
|
5319
|
+
break;
|
|
5320
|
+
case "task":
|
|
5321
|
+
if (marker.checkpoint_id) {
|
|
5322
|
+
entityPath = taskPath(repoRoot, marker.checkpoint_id, marker.id);
|
|
5323
|
+
}
|
|
5324
|
+
patchEndpoint = `${backendTasksEndpoint()}/${marker.id}`;
|
|
5325
|
+
break;
|
|
5326
|
+
case "round":
|
|
5327
|
+
if (marker.checkpoint_id && marker.task_id) {
|
|
5328
|
+
entityPath = roundPath(
|
|
5329
|
+
repoRoot,
|
|
5330
|
+
marker.checkpoint_id,
|
|
5331
|
+
marker.task_id,
|
|
5332
|
+
marker.id
|
|
5333
|
+
);
|
|
5334
|
+
}
|
|
5335
|
+
patchEndpoint = `${backendRoundsEndpoint()}/${marker.id}`;
|
|
5336
|
+
break;
|
|
5337
|
+
case "session_log":
|
|
5338
|
+
entityPath = sessionLogPath(repoRoot);
|
|
5339
|
+
patchEndpoint = `${backendSessionLogsEndpoint()}/${marker.id}`;
|
|
5340
|
+
break;
|
|
5341
|
+
default:
|
|
5342
|
+
process.stderr.write(
|
|
5343
|
+
`state-sync: replayOutbox: discarding unknown entity type "${marker.entity}" ${marker.id}
|
|
5344
|
+
`
|
|
5345
|
+
);
|
|
5346
|
+
await deleteEntityFile(markerPath);
|
|
5347
|
+
continue;
|
|
5348
|
+
}
|
|
5349
|
+
if (!entityPath) {
|
|
5350
|
+
process.stderr.write(
|
|
5351
|
+
`state-sync: replayOutbox: missing FK for ${marker.entity} ${marker.id} \u2014 discarding marker
|
|
5352
|
+
`
|
|
5353
|
+
);
|
|
5354
|
+
await deleteEntityFile(markerPath);
|
|
5355
|
+
continue;
|
|
5356
|
+
}
|
|
5357
|
+
const entityData = await readEntityFile(entityPath);
|
|
5358
|
+
if (!entityData) {
|
|
5359
|
+
await deleteEntityFile(markerPath);
|
|
5360
|
+
continue;
|
|
5361
|
+
}
|
|
5362
|
+
try {
|
|
5363
|
+
const res = await fetch(patchEndpoint, {
|
|
5364
|
+
method: "PATCH",
|
|
5365
|
+
headers: { ...authHeaders, "Content-Type": "application/json" },
|
|
5366
|
+
body: JSON.stringify({
|
|
5367
|
+
...entityData,
|
|
5368
|
+
expected_sync_seq: entityData["sync_seq"]
|
|
5369
|
+
}),
|
|
5370
|
+
signal: AbortSignal.timeout(3e4)
|
|
5371
|
+
});
|
|
5372
|
+
if (res.ok || res.status >= 400 && res.status < 500) {
|
|
5373
|
+
await deleteEntityFile(markerPath);
|
|
5374
|
+
}
|
|
5375
|
+
} catch {
|
|
5376
|
+
}
|
|
5377
|
+
} catch (err) {
|
|
5378
|
+
process.stderr.write(
|
|
5379
|
+
`state-sync: replayOutbox: unexpected error for marker ${markerPath} (non-fatal): ${err instanceof Error ? err.message : String(err)}
|
|
5380
|
+
`
|
|
5381
|
+
);
|
|
5382
|
+
}
|
|
5383
|
+
}
|
|
5384
|
+
}
|
|
5385
|
+
function resolveTombstoneEntityPath(repoRoot, tomb) {
|
|
5386
|
+
switch (tomb.entity_table) {
|
|
5387
|
+
case "checkpoints":
|
|
5388
|
+
return checkpointPath(repoRoot, tomb.entity_id);
|
|
5389
|
+
case "tasks": {
|
|
5390
|
+
const checkpointId = tomb.parent_ids?.checkpoint_id;
|
|
5391
|
+
if (!checkpointId) return null;
|
|
5392
|
+
return taskPath(repoRoot, checkpointId, tomb.entity_id);
|
|
5393
|
+
}
|
|
5394
|
+
case "rounds": {
|
|
5395
|
+
const checkpointId = tomb.parent_ids?.checkpoint_id;
|
|
5396
|
+
const taskId = tomb.parent_ids?.task_id;
|
|
5397
|
+
if (!checkpointId || !taskId) return null;
|
|
5398
|
+
return roundPath(repoRoot, checkpointId, taskId, tomb.entity_id);
|
|
5399
|
+
}
|
|
5400
|
+
// Single-slot caches: no per-id file — reconcile on next full hydrate.
|
|
5401
|
+
// session_logs → session/current.json (deleting it would kill active session data)
|
|
5402
|
+
// todos → todos.json
|
|
5403
|
+
// worktrees → worktrees.json
|
|
5404
|
+
// Port allocations are intentionally not mirrored to state/.
|
|
5405
|
+
default:
|
|
5406
|
+
return null;
|
|
5407
|
+
}
|
|
5408
|
+
}
|
|
5254
5409
|
async function runSync(repoRoot, repoId, worktreeId, opts = {}) {
|
|
5255
5410
|
const { full = false, dryRun = false } = opts;
|
|
5256
5411
|
try {
|
|
@@ -5273,6 +5428,9 @@ async function runSync(repoRoot, repoId, worktreeId, opts = {}) {
|
|
|
5273
5428
|
error: `auth: ${err instanceof Error ? err.message : String(err)}`
|
|
5274
5429
|
};
|
|
5275
5430
|
}
|
|
5431
|
+
if (!dryRun) {
|
|
5432
|
+
await replayOutbox(repoRoot, authHeaders);
|
|
5433
|
+
}
|
|
5276
5434
|
let result;
|
|
5277
5435
|
try {
|
|
5278
5436
|
const res = await fetch(url.toString(), {
|
|
@@ -5299,6 +5457,7 @@ async function runSync(repoRoot, repoId, worktreeId, opts = {}) {
|
|
|
5299
5457
|
ok: true,
|
|
5300
5458
|
written: 0,
|
|
5301
5459
|
pruned: 0,
|
|
5460
|
+
tombstoned: 0,
|
|
5302
5461
|
mode: isFull ? "full" : "delta",
|
|
5303
5462
|
max_seq: result.max_seq
|
|
5304
5463
|
};
|
|
@@ -5352,6 +5511,15 @@ async function runSync(repoRoot, repoId, worktreeId, opts = {}) {
|
|
|
5352
5511
|
await writeEntityFile(worktreesPath(repoRoot), result.worktrees);
|
|
5353
5512
|
written++;
|
|
5354
5513
|
}
|
|
5514
|
+
let tombstoned = 0;
|
|
5515
|
+
for (const tomb of result.deleted ?? []) {
|
|
5516
|
+
const filePath = resolveTombstoneEntityPath(repoRoot, tomb);
|
|
5517
|
+
if (filePath) {
|
|
5518
|
+
await deleteEntityFile(filePath);
|
|
5519
|
+
delete entityHashes[tomb.entity_id];
|
|
5520
|
+
tombstoned++;
|
|
5521
|
+
}
|
|
5522
|
+
}
|
|
5355
5523
|
let pruned = 0;
|
|
5356
5524
|
if (isFull) {
|
|
5357
5525
|
const knownIdsByTable = {
|
|
@@ -5378,6 +5546,7 @@ async function runSync(repoRoot, repoId, worktreeId, opts = {}) {
|
|
|
5378
5546
|
ok: true,
|
|
5379
5547
|
written,
|
|
5380
5548
|
pruned,
|
|
5549
|
+
tombstoned,
|
|
5381
5550
|
mode: isFull ? "full" : "delta",
|
|
5382
5551
|
max_seq: result.max_seq
|
|
5383
5552
|
};
|
|
@@ -14535,8 +14704,8 @@ var require_RealtimeChannel = __commonJS({
|
|
|
14535
14704
|
}
|
|
14536
14705
|
/** @internal */
|
|
14537
14706
|
_notThisChannelEvent(event, ref) {
|
|
14538
|
-
const { close, error, leave, join:
|
|
14539
|
-
const events = [close, error, leave,
|
|
14707
|
+
const { close, error, leave, join: join60 } = constants_1.CHANNEL_EVENTS;
|
|
14708
|
+
const events = [close, error, leave, join60];
|
|
14540
14709
|
return ref && events.includes(event) && ref !== this.joinPush.ref;
|
|
14541
14710
|
}
|
|
14542
14711
|
/** @internal */
|
|
@@ -27986,6 +28155,9 @@ var init_watch = __esm({
|
|
|
27986
28155
|
});
|
|
27987
28156
|
|
|
27988
28157
|
// src/lib/state-client.ts
|
|
28158
|
+
function isConflict(err) {
|
|
28159
|
+
return err instanceof BackendError && err.status === 409;
|
|
28160
|
+
}
|
|
27989
28161
|
async function backendRequest(method, path22, body) {
|
|
27990
28162
|
const url = `${getBackendBase()}${path22}`;
|
|
27991
28163
|
const auth = await getAuthHeaders();
|
|
@@ -28037,11 +28209,316 @@ var init_state_client = __esm({
|
|
|
28037
28209
|
}
|
|
28038
28210
|
});
|
|
28039
28211
|
|
|
28212
|
+
// src/lib/mcp-client.ts
|
|
28213
|
+
async function mcpCall(toolName, args) {
|
|
28214
|
+
let accessToken;
|
|
28215
|
+
try {
|
|
28216
|
+
accessToken = await getAccessToken();
|
|
28217
|
+
} catch (err) {
|
|
28218
|
+
if (err instanceof NoTokenError) {
|
|
28219
|
+
throw new McpError(
|
|
28220
|
+
"Not logged in. Run `codebyplan login` to authenticate."
|
|
28221
|
+
);
|
|
28222
|
+
}
|
|
28223
|
+
throw err;
|
|
28224
|
+
}
|
|
28225
|
+
const body = {
|
|
28226
|
+
jsonrpc: "2.0",
|
|
28227
|
+
id: 1,
|
|
28228
|
+
method: "tools/call",
|
|
28229
|
+
params: { name: toolName, arguments: args }
|
|
28230
|
+
};
|
|
28231
|
+
let res;
|
|
28232
|
+
try {
|
|
28233
|
+
res = await fetch(mcpEndpoint(), {
|
|
28234
|
+
method: "POST",
|
|
28235
|
+
headers: {
|
|
28236
|
+
"Content-Type": "application/json",
|
|
28237
|
+
Accept: "application/json, text/event-stream",
|
|
28238
|
+
Authorization: `Bearer ${accessToken}`
|
|
28239
|
+
},
|
|
28240
|
+
body: JSON.stringify(body),
|
|
28241
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS3)
|
|
28242
|
+
});
|
|
28243
|
+
} catch (err) {
|
|
28244
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
28245
|
+
throw new McpError(`mcp ${toolName} network error: ${message}`);
|
|
28246
|
+
}
|
|
28247
|
+
if (res.status === 401) {
|
|
28248
|
+
throw new McpError(
|
|
28249
|
+
"Authentication failed. Run `codebyplan login` to refresh your session.",
|
|
28250
|
+
401
|
|
28251
|
+
);
|
|
28252
|
+
}
|
|
28253
|
+
if (!res.ok) {
|
|
28254
|
+
throw new McpError(
|
|
28255
|
+
`mcp ${toolName} failed with status ${res.status}`,
|
|
28256
|
+
res.status
|
|
28257
|
+
);
|
|
28258
|
+
}
|
|
28259
|
+
const contentType = res.headers.get("content-type") ?? "";
|
|
28260
|
+
let envelope;
|
|
28261
|
+
if (contentType.includes("text/event-stream")) {
|
|
28262
|
+
const text = await res.text();
|
|
28263
|
+
envelope = parseSseEnvelope(text, toolName);
|
|
28264
|
+
} else {
|
|
28265
|
+
envelope = await res.json();
|
|
28266
|
+
}
|
|
28267
|
+
if (envelope.error) {
|
|
28268
|
+
throw new McpError(
|
|
28269
|
+
envelope.error.message ?? `mcp ${toolName} protocol error`,
|
|
28270
|
+
void 0,
|
|
28271
|
+
envelope.error.code !== void 0 ? String(envelope.error.code) : void 0
|
|
28272
|
+
);
|
|
28273
|
+
}
|
|
28274
|
+
const result = envelope.result;
|
|
28275
|
+
if (!result) {
|
|
28276
|
+
throw new McpError(`mcp ${toolName} returned no result`);
|
|
28277
|
+
}
|
|
28278
|
+
const textContent = result.content?.find((c) => c.type === "text")?.text;
|
|
28279
|
+
if (textContent === void 0) {
|
|
28280
|
+
throw new McpError(`mcp ${toolName} returned no text content`);
|
|
28281
|
+
}
|
|
28282
|
+
if (result.isError === true) {
|
|
28283
|
+
throw new McpError(textContent);
|
|
28284
|
+
}
|
|
28285
|
+
try {
|
|
28286
|
+
return JSON.parse(textContent);
|
|
28287
|
+
} catch {
|
|
28288
|
+
throw new McpError(
|
|
28289
|
+
`mcp ${toolName} returned non-JSON payload: ${textContent.slice(0, 200)}`
|
|
28290
|
+
);
|
|
28291
|
+
}
|
|
28292
|
+
}
|
|
28293
|
+
function parseSseEnvelope(text, toolName) {
|
|
28294
|
+
const frames = text.split("\n\n");
|
|
28295
|
+
for (let i = frames.length - 1; i >= 0; i--) {
|
|
28296
|
+
const frame = frames[i];
|
|
28297
|
+
const dataLines = frame.split("\n").filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trim());
|
|
28298
|
+
if (dataLines.length === 0) continue;
|
|
28299
|
+
const dataText = dataLines.join("\n");
|
|
28300
|
+
try {
|
|
28301
|
+
return JSON.parse(dataText);
|
|
28302
|
+
} catch {
|
|
28303
|
+
continue;
|
|
28304
|
+
}
|
|
28305
|
+
}
|
|
28306
|
+
throw new McpError(`mcp ${toolName} returned unparseable SSE body`);
|
|
28307
|
+
}
|
|
28308
|
+
var REQUEST_TIMEOUT_MS3, McpError;
|
|
28309
|
+
var init_mcp_client = __esm({
|
|
28310
|
+
"src/lib/mcp-client.ts"() {
|
|
28311
|
+
"use strict";
|
|
28312
|
+
init_token_refresh();
|
|
28313
|
+
init_urls();
|
|
28314
|
+
REQUEST_TIMEOUT_MS3 = 12e4;
|
|
28315
|
+
McpError = class extends Error {
|
|
28316
|
+
status;
|
|
28317
|
+
code;
|
|
28318
|
+
constructor(message, status, code) {
|
|
28319
|
+
super(message);
|
|
28320
|
+
this.name = "McpError";
|
|
28321
|
+
this.status = status;
|
|
28322
|
+
this.code = code;
|
|
28323
|
+
}
|
|
28324
|
+
};
|
|
28325
|
+
}
|
|
28326
|
+
});
|
|
28327
|
+
|
|
28328
|
+
// src/cli/export-writer.ts
|
|
28329
|
+
import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync3 } from "node:fs";
|
|
28330
|
+
import { join as join21 } from "node:path";
|
|
28331
|
+
async function buildCheckpointExport(checkpointId) {
|
|
28332
|
+
const checkpointResponse = await apiGet(
|
|
28333
|
+
`/checkpoints/${checkpointId}`
|
|
28334
|
+
);
|
|
28335
|
+
const checkpoint = checkpointResponse.data;
|
|
28336
|
+
if (!checkpoint) {
|
|
28337
|
+
throw new Error(
|
|
28338
|
+
`buildCheckpointExport: checkpoint ${checkpointId} not found`
|
|
28339
|
+
);
|
|
28340
|
+
}
|
|
28341
|
+
const tasksResponse = await apiGet(
|
|
28342
|
+
"/tasks",
|
|
28343
|
+
{ checkpoint_id: checkpointId }
|
|
28344
|
+
);
|
|
28345
|
+
const rawTasks = tasksResponse.data ?? [];
|
|
28346
|
+
const tasks = await Promise.all(
|
|
28347
|
+
rawTasks.map(async (task) => {
|
|
28348
|
+
const rawRounds = await fetchRoundsForTask(task.id);
|
|
28349
|
+
const rounds = rawRounds.map((r) => ({
|
|
28350
|
+
id: r.id,
|
|
28351
|
+
number: r.number,
|
|
28352
|
+
status: r.status,
|
|
28353
|
+
files_changed: r.files_changed ?? [],
|
|
28354
|
+
context: r.context ?? null
|
|
28355
|
+
}));
|
|
28356
|
+
return {
|
|
28357
|
+
id: task.id,
|
|
28358
|
+
number: task.number,
|
|
28359
|
+
title: task.title ?? null,
|
|
28360
|
+
status: task.status,
|
|
28361
|
+
completed_at: task.completed_at ?? null,
|
|
28362
|
+
files_changed: task.files_changed ?? [],
|
|
28363
|
+
qa: task.qa ?? null,
|
|
28364
|
+
rounds
|
|
28365
|
+
};
|
|
28366
|
+
})
|
|
28367
|
+
);
|
|
28368
|
+
return {
|
|
28369
|
+
schema_version: EXPORT_SCHEMA_VERSION,
|
|
28370
|
+
exported_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
28371
|
+
checkpoint_id: checkpointId,
|
|
28372
|
+
number: checkpoint.number,
|
|
28373
|
+
sync_seq: checkpoint.sync_seq,
|
|
28374
|
+
title: checkpoint.title ?? null,
|
|
28375
|
+
status: checkpoint.status,
|
|
28376
|
+
completed_at: checkpoint.completed_at ?? null,
|
|
28377
|
+
context: checkpoint.context ?? null,
|
|
28378
|
+
files_changed: checkpoint.files_changed ?? [],
|
|
28379
|
+
qa: checkpoint.qa ?? null,
|
|
28380
|
+
tasks
|
|
28381
|
+
};
|
|
28382
|
+
}
|
|
28383
|
+
async function buildStandaloneExport(taskId, repoRoot, repoIdHint) {
|
|
28384
|
+
let repoId = repoIdHint;
|
|
28385
|
+
if (!repoId) {
|
|
28386
|
+
const { findCodebyplanConfig: findCodebyplanConfig2 } = await Promise.resolve().then(() => (init_flags(), flags_exports));
|
|
28387
|
+
const found = await findCodebyplanConfig2(repoRoot);
|
|
28388
|
+
repoId = found?.contents.repo_id;
|
|
28389
|
+
}
|
|
28390
|
+
if (!repoId) {
|
|
28391
|
+
throw new Error(
|
|
28392
|
+
"buildStandaloneExport: could not resolve repo_id from .codebyplan/repo.json"
|
|
28393
|
+
);
|
|
28394
|
+
}
|
|
28395
|
+
const allTasks = await mcpCall("get_standalone_tasks", {
|
|
28396
|
+
repo_id: repoId
|
|
28397
|
+
});
|
|
28398
|
+
const task = allTasks.find((t) => t.id === taskId);
|
|
28399
|
+
if (!task) {
|
|
28400
|
+
throw new Error(
|
|
28401
|
+
`buildStandaloneExport: standalone task ${taskId} not found`
|
|
28402
|
+
);
|
|
28403
|
+
}
|
|
28404
|
+
const rawRounds = await mcpCall("get_standalone_rounds", {
|
|
28405
|
+
standalone_task_id: taskId
|
|
28406
|
+
});
|
|
28407
|
+
const rounds = rawRounds.map((r) => ({
|
|
28408
|
+
id: r.id,
|
|
28409
|
+
number: r.number,
|
|
28410
|
+
status: r.status,
|
|
28411
|
+
files_changed: r.files_changed ?? [],
|
|
28412
|
+
context: r.context ?? null
|
|
28413
|
+
}));
|
|
28414
|
+
const taskEntry = {
|
|
28415
|
+
id: task.id,
|
|
28416
|
+
number: task.number,
|
|
28417
|
+
title: task.title,
|
|
28418
|
+
status: task.status,
|
|
28419
|
+
completed_at: task.completed_at ?? null,
|
|
28420
|
+
files_changed: task.files_changed ?? [],
|
|
28421
|
+
qa: task.qa ?? null,
|
|
28422
|
+
rounds
|
|
28423
|
+
};
|
|
28424
|
+
return {
|
|
28425
|
+
schema_version: EXPORT_SCHEMA_VERSION,
|
|
28426
|
+
exported_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
28427
|
+
standalone_task_id: taskId,
|
|
28428
|
+
number: task.number,
|
|
28429
|
+
title: task.title,
|
|
28430
|
+
status: task.status,
|
|
28431
|
+
completed_at: task.completed_at ?? null,
|
|
28432
|
+
context: task.context ?? null,
|
|
28433
|
+
files_changed: task.files_changed ?? [],
|
|
28434
|
+
qa: task.qa ?? null,
|
|
28435
|
+
tasks: [taskEntry]
|
|
28436
|
+
};
|
|
28437
|
+
}
|
|
28438
|
+
function renderSummaryMd(data) {
|
|
28439
|
+
const isCheckpoint = "checkpoint_id" in data;
|
|
28440
|
+
const entityLabel = isCheckpoint ? "Checkpoint" : "Standalone Task";
|
|
28441
|
+
const entityId = isCheckpoint ? data.checkpoint_id : data.standalone_task_id;
|
|
28442
|
+
const completedLine = data.completed_at ? `**Completed**: ${data.completed_at}` : `**Status**: ${data.status}`;
|
|
28443
|
+
const ctx = data.context;
|
|
28444
|
+
const decisions = Array.isArray(ctx?.decisions) ? ctx.decisions : [];
|
|
28445
|
+
const decisionsBlock = decisions.length > 0 ? `
|
|
28446
|
+
## Decisions
|
|
28447
|
+
|
|
28448
|
+
${decisions.map(
|
|
28449
|
+
(d, i) => `${i + 1}. ${typeof d === "string" ? d : JSON.stringify(d)}`
|
|
28450
|
+
).join("\n")}
|
|
28451
|
+
` : "";
|
|
28452
|
+
const taskRows = data.tasks.map((t) => {
|
|
28453
|
+
const roundCount = t.rounds.length;
|
|
28454
|
+
const fileCount = Array.isArray(t.files_changed) ? t.files_changed.length : 0;
|
|
28455
|
+
return `| ${t.number} | ${t.title ?? "(untitled)"} | ${t.status} | ${roundCount} | ${fileCount} |`;
|
|
28456
|
+
}).join("\n");
|
|
28457
|
+
const tasksBlock = data.tasks.length > 0 ? `
|
|
28458
|
+
## Tasks
|
|
28459
|
+
|
|
28460
|
+
| # | Title | Status | Rounds | Files |
|
|
28461
|
+
|---|-------|--------|--------|-------|
|
|
28462
|
+
${taskRows}
|
|
28463
|
+
` : "";
|
|
28464
|
+
const allFiles = /* @__PURE__ */ new Set();
|
|
28465
|
+
for (const task of data.tasks) {
|
|
28466
|
+
if (Array.isArray(task.files_changed)) {
|
|
28467
|
+
for (const f of task.files_changed) {
|
|
28468
|
+
const path22 = typeof f === "string" ? f : f?.path;
|
|
28469
|
+
if (path22) allFiles.add(path22);
|
|
28470
|
+
}
|
|
28471
|
+
}
|
|
28472
|
+
}
|
|
28473
|
+
const filesBlock = allFiles.size > 0 ? `
|
|
28474
|
+
## Files Changed (${allFiles.size})
|
|
28475
|
+
|
|
28476
|
+
${[...allFiles].sort().map((f) => `- \`${f}\``).join("\n")}
|
|
28477
|
+
` : "";
|
|
28478
|
+
return `# ${entityLabel} Export
|
|
28479
|
+
|
|
28480
|
+
**${entityLabel} ID**: \`${entityId}\`
|
|
28481
|
+
**Number**: ${data.number}
|
|
28482
|
+
**Title**: ${data.title ?? "(untitled)"}
|
|
28483
|
+
${completedLine}
|
|
28484
|
+
**Exported**: ${data.exported_at}
|
|
28485
|
+
` + decisionsBlock + tasksBlock + filesBlock;
|
|
28486
|
+
}
|
|
28487
|
+
function writeExportArtifacts(outDir, exportData, summaryMd) {
|
|
28488
|
+
mkdirSync3(outDir, { recursive: true });
|
|
28489
|
+
const exportJsonPath = join21(outDir, "export.json");
|
|
28490
|
+
const summaryMdPath = join21(outDir, "summary.md");
|
|
28491
|
+
writeFileSync3(
|
|
28492
|
+
exportJsonPath,
|
|
28493
|
+
JSON.stringify(exportData, null, 2) + "\n",
|
|
28494
|
+
"utf-8"
|
|
28495
|
+
);
|
|
28496
|
+
writeFileSync3(summaryMdPath, summaryMd, "utf-8");
|
|
28497
|
+
return { exportJsonPath, summaryMdPath };
|
|
28498
|
+
}
|
|
28499
|
+
async function fetchRoundsForTask(taskId) {
|
|
28500
|
+
try {
|
|
28501
|
+
return await mcpCall("get_rounds", { task_id: taskId });
|
|
28502
|
+
} catch {
|
|
28503
|
+
return [];
|
|
28504
|
+
}
|
|
28505
|
+
}
|
|
28506
|
+
var EXPORT_SCHEMA_VERSION;
|
|
28507
|
+
var init_export_writer = __esm({
|
|
28508
|
+
"src/cli/export-writer.ts"() {
|
|
28509
|
+
"use strict";
|
|
28510
|
+
init_api();
|
|
28511
|
+
init_mcp_client();
|
|
28512
|
+
EXPORT_SCHEMA_VERSION = 1;
|
|
28513
|
+
}
|
|
28514
|
+
});
|
|
28515
|
+
|
|
28040
28516
|
// src/cli/checkpoint.ts
|
|
28041
28517
|
var checkpoint_exports = {};
|
|
28042
28518
|
__export(checkpoint_exports, {
|
|
28043
28519
|
runCheckpointCommand: () => runCheckpointCommand
|
|
28044
28520
|
});
|
|
28521
|
+
import { join as join22 } from "node:path";
|
|
28045
28522
|
async function resolveRepoRoot() {
|
|
28046
28523
|
const found = await findCodebyplanConfig(process.cwd());
|
|
28047
28524
|
if (!found?.contents.repo_id) return null;
|
|
@@ -28127,41 +28604,91 @@ async function runCheckpointUpdate(args) {
|
|
|
28127
28604
|
const snakePatch = coerceFieldValues(kebabToSnakeKeys(patchBody));
|
|
28128
28605
|
const optimistic = { ...snapshot ?? {}, ...snakePatch, id };
|
|
28129
28606
|
await writeEntityFile(filePath, optimistic);
|
|
28130
|
-
|
|
28131
|
-
|
|
28132
|
-
|
|
28133
|
-
|
|
28134
|
-
|
|
28135
|
-
|
|
28136
|
-
|
|
28137
|
-
process.stdout.write(JSON.stringify(updated) + "\n");
|
|
28138
|
-
} catch (err) {
|
|
28139
|
-
if (err instanceof BackendError && err.status < 500) {
|
|
28140
|
-
if (snapshot !== null) {
|
|
28141
|
-
await writeEntityFile(filePath, snapshot);
|
|
28142
|
-
} else {
|
|
28143
|
-
await deleteEntityFile(filePath);
|
|
28144
|
-
}
|
|
28145
|
-
process.stderr.write(
|
|
28146
|
-
`checkpoint update: backend rejected (${err.status}): ${err.message}
|
|
28147
|
-
`
|
|
28607
|
+
let freshRow = snapshot;
|
|
28608
|
+
let lastErr;
|
|
28609
|
+
let successRow = null;
|
|
28610
|
+
if (freshRow === null) {
|
|
28611
|
+
try {
|
|
28612
|
+
const bootstrapResponse = await apiGet(
|
|
28613
|
+
`/checkpoints/${id}`
|
|
28148
28614
|
);
|
|
28615
|
+
freshRow = bootstrapResponse.data;
|
|
28616
|
+
await writeEntityFile(filePath, freshRow);
|
|
28617
|
+
} catch {
|
|
28618
|
+
}
|
|
28619
|
+
}
|
|
28620
|
+
for (let attempt = 0; attempt <= MAX_OCC_RETRIES; attempt++) {
|
|
28621
|
+
const currentSeq = freshRow !== null && typeof freshRow.sync_seq === "number" ? freshRow.sync_seq : void 0;
|
|
28622
|
+
const patchWithSeq = currentSeq !== void 0 ? { ...snakePatch, expected_sync_seq: currentSeq } : { ...snakePatch };
|
|
28623
|
+
try {
|
|
28624
|
+
const updated = await apiBackendPatch(
|
|
28625
|
+
`${new URL(backendCheckpointsEndpoint()).pathname}/${id}`,
|
|
28626
|
+
patchWithSeq
|
|
28627
|
+
);
|
|
28628
|
+
await writeEntityFile(filePath, updated);
|
|
28629
|
+
await updateCursorHash(repoRoot, id, updated);
|
|
28630
|
+
successRow = updated;
|
|
28631
|
+
break;
|
|
28632
|
+
} catch (err2) {
|
|
28633
|
+
if (isConflict(err2) && attempt < MAX_OCC_RETRIES) {
|
|
28634
|
+
try {
|
|
28635
|
+
const freshResponse = await apiGet(
|
|
28636
|
+
`/checkpoints/${id}`
|
|
28637
|
+
);
|
|
28638
|
+
freshRow = freshResponse.data;
|
|
28639
|
+
await writeEntityFile(filePath, freshRow);
|
|
28640
|
+
} catch {
|
|
28641
|
+
lastErr = err2;
|
|
28642
|
+
break;
|
|
28643
|
+
}
|
|
28644
|
+
lastErr = err2;
|
|
28645
|
+
continue;
|
|
28646
|
+
}
|
|
28647
|
+
lastErr = err2;
|
|
28648
|
+
break;
|
|
28649
|
+
}
|
|
28650
|
+
}
|
|
28651
|
+
if (successRow !== null) {
|
|
28652
|
+
process.stdout.write(JSON.stringify(successRow) + "\n");
|
|
28653
|
+
process.exit(0);
|
|
28654
|
+
}
|
|
28655
|
+
const err = lastErr;
|
|
28656
|
+
if (isConflict(err)) {
|
|
28657
|
+
if (freshRow !== null) {
|
|
28658
|
+
await writeEntityFile(filePath, freshRow);
|
|
28659
|
+
} else if (snapshot !== null) {
|
|
28660
|
+
await writeEntityFile(filePath, snapshot);
|
|
28149
28661
|
} else {
|
|
28150
|
-
await
|
|
28151
|
-
|
|
28152
|
-
|
|
28153
|
-
|
|
28154
|
-
attempted_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
28155
|
-
error: err instanceof Error ? err.message : String(err)
|
|
28156
|
-
});
|
|
28157
|
-
process.stderr.write(
|
|
28158
|
-
`checkpoint update: backend unavailable \u2014 local write kept, pending marker written. Error: ${err instanceof Error ? err.message : String(err)}
|
|
28662
|
+
await deleteEntityFile(filePath);
|
|
28663
|
+
}
|
|
28664
|
+
process.stderr.write(
|
|
28665
|
+
`checkpoint update: conflict \u2014 another writer updated checkpoint ${id} concurrently. Re-read the checkpoint and retry.
|
|
28159
28666
|
`
|
|
28160
|
-
|
|
28667
|
+
);
|
|
28668
|
+
} else if (err instanceof BackendError && err.status < 500) {
|
|
28669
|
+
if (snapshot !== null) {
|
|
28670
|
+
await writeEntityFile(filePath, snapshot);
|
|
28671
|
+
} else {
|
|
28672
|
+
await deleteEntityFile(filePath);
|
|
28161
28673
|
}
|
|
28162
|
-
process.
|
|
28674
|
+
process.stderr.write(
|
|
28675
|
+
`checkpoint update: backend rejected (${err.status}): ${err.message}
|
|
28676
|
+
`
|
|
28677
|
+
);
|
|
28678
|
+
} else {
|
|
28679
|
+
await writeEntityFile(pendingMarkerPath(repoRoot, id), {
|
|
28680
|
+
entity: "checkpoint",
|
|
28681
|
+
id,
|
|
28682
|
+
operation: "update",
|
|
28683
|
+
attempted_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
28684
|
+
error: err instanceof Error ? err.message : String(err)
|
|
28685
|
+
});
|
|
28686
|
+
process.stderr.write(
|
|
28687
|
+
`checkpoint update: backend unavailable \u2014 local write kept, pending marker written. Error: ${err instanceof Error ? err.message : String(err)}
|
|
28688
|
+
`
|
|
28689
|
+
);
|
|
28163
28690
|
}
|
|
28164
|
-
process.exit(
|
|
28691
|
+
process.exit(1);
|
|
28165
28692
|
}
|
|
28166
28693
|
async function runCheckpointComplete(args) {
|
|
28167
28694
|
const { flags } = parseFlagsFromArgs(args);
|
|
@@ -28184,45 +28711,145 @@ async function runCheckpointComplete(args) {
|
|
|
28184
28711
|
const snapshot = await readEntityFile(filePath);
|
|
28185
28712
|
const optimistic = { ...snapshot ?? {}, id, status: "completed" };
|
|
28186
28713
|
await writeEntityFile(filePath, optimistic);
|
|
28187
|
-
|
|
28188
|
-
|
|
28189
|
-
|
|
28190
|
-
|
|
28191
|
-
|
|
28192
|
-
|
|
28193
|
-
|
|
28194
|
-
|
|
28195
|
-
|
|
28196
|
-
|
|
28197
|
-
|
|
28198
|
-
|
|
28199
|
-
|
|
28200
|
-
|
|
28714
|
+
let freshRow = snapshot;
|
|
28715
|
+
let lastErr;
|
|
28716
|
+
let successRow = null;
|
|
28717
|
+
for (let attempt = 0; attempt <= MAX_OCC_RETRIES; attempt++) {
|
|
28718
|
+
try {
|
|
28719
|
+
const completed = await apiBackendPost(
|
|
28720
|
+
`${new URL(backendCheckpointsEndpoint()).pathname}/${id}/complete`,
|
|
28721
|
+
{}
|
|
28722
|
+
);
|
|
28723
|
+
await writeEntityFile(filePath, completed);
|
|
28724
|
+
await updateCursorHash(repoRoot, id, completed);
|
|
28725
|
+
successRow = completed;
|
|
28726
|
+
break;
|
|
28727
|
+
} catch (err2) {
|
|
28728
|
+
if (isConflict(err2) && attempt < MAX_OCC_RETRIES) {
|
|
28729
|
+
try {
|
|
28730
|
+
const freshResponse = await apiGet(
|
|
28731
|
+
`/checkpoints/${id}`
|
|
28732
|
+
);
|
|
28733
|
+
freshRow = freshResponse.data;
|
|
28734
|
+
await writeEntityFile(filePath, freshRow);
|
|
28735
|
+
} catch {
|
|
28736
|
+
lastErr = err2;
|
|
28737
|
+
break;
|
|
28738
|
+
}
|
|
28739
|
+
lastErr = err2;
|
|
28740
|
+
continue;
|
|
28201
28741
|
}
|
|
28202
|
-
|
|
28203
|
-
|
|
28742
|
+
lastErr = err2;
|
|
28743
|
+
break;
|
|
28744
|
+
}
|
|
28745
|
+
}
|
|
28746
|
+
if (successRow !== null) {
|
|
28747
|
+
process.stdout.write(JSON.stringify(successRow) + "\n");
|
|
28748
|
+
process.exit(0);
|
|
28749
|
+
}
|
|
28750
|
+
const err = lastErr;
|
|
28751
|
+
if (isConflict(err)) {
|
|
28752
|
+
if (freshRow !== null) {
|
|
28753
|
+
await writeEntityFile(filePath, freshRow);
|
|
28754
|
+
} else if (snapshot !== null) {
|
|
28755
|
+
await writeEntityFile(filePath, snapshot);
|
|
28756
|
+
} else {
|
|
28757
|
+
await deleteEntityFile(filePath);
|
|
28758
|
+
}
|
|
28759
|
+
process.stderr.write(
|
|
28760
|
+
`checkpoint complete: conflict \u2014 another writer updated checkpoint ${id} concurrently. Re-read the checkpoint and retry.
|
|
28204
28761
|
`
|
|
28205
|
-
|
|
28762
|
+
);
|
|
28763
|
+
} else if (err instanceof BackendError && err.status < 500) {
|
|
28764
|
+
if (snapshot !== null) {
|
|
28765
|
+
await writeEntityFile(filePath, snapshot);
|
|
28206
28766
|
} else {
|
|
28207
|
-
await
|
|
28208
|
-
|
|
28209
|
-
|
|
28210
|
-
|
|
28211
|
-
|
|
28212
|
-
|
|
28213
|
-
|
|
28767
|
+
await deleteEntityFile(filePath);
|
|
28768
|
+
}
|
|
28769
|
+
process.stderr.write(
|
|
28770
|
+
`checkpoint complete: backend rejected (${err.status}): ${err.message}
|
|
28771
|
+
`
|
|
28772
|
+
);
|
|
28773
|
+
} else {
|
|
28774
|
+
await writeEntityFile(pendingMarkerPath(repoRoot, id), {
|
|
28775
|
+
entity: "checkpoint",
|
|
28776
|
+
id,
|
|
28777
|
+
operation: "complete",
|
|
28778
|
+
attempted_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
28779
|
+
error: err instanceof Error ? err.message : String(err)
|
|
28780
|
+
});
|
|
28781
|
+
process.stderr.write(
|
|
28782
|
+
`checkpoint complete: backend unavailable \u2014 local write kept, pending marker written. Error: ${err instanceof Error ? err.message : String(err)}
|
|
28783
|
+
`
|
|
28784
|
+
);
|
|
28785
|
+
}
|
|
28786
|
+
process.exit(1);
|
|
28787
|
+
}
|
|
28788
|
+
async function runCheckpointExport(args) {
|
|
28789
|
+
const { flags } = parseFlagsFromArgs(args);
|
|
28790
|
+
const id = flags.id ?? flags["checkpoint-id"];
|
|
28791
|
+
if (!id) {
|
|
28792
|
+
process.stderr.write(
|
|
28793
|
+
"checkpoint export: --id <checkpoint-id> is required\n"
|
|
28794
|
+
);
|
|
28795
|
+
process.exit(1);
|
|
28796
|
+
}
|
|
28797
|
+
const repoInfo = await resolveRepoRoot();
|
|
28798
|
+
if (!repoInfo) {
|
|
28799
|
+
process.stderr.write(
|
|
28800
|
+
"checkpoint export: no .codebyplan/repo.json found. Run `codebyplan setup`.\n"
|
|
28801
|
+
);
|
|
28802
|
+
process.exit(1);
|
|
28803
|
+
}
|
|
28804
|
+
const { repoRoot } = repoInfo;
|
|
28805
|
+
try {
|
|
28806
|
+
const exportData = await buildCheckpointExport(id);
|
|
28807
|
+
const outDir = join22(
|
|
28808
|
+
repoRoot,
|
|
28809
|
+
".codebyplan",
|
|
28810
|
+
"exports",
|
|
28811
|
+
String(exportData.number)
|
|
28812
|
+
);
|
|
28813
|
+
const summaryMd = renderSummaryMd(exportData);
|
|
28814
|
+
const { exportJsonPath, summaryMdPath } = writeExportArtifacts(
|
|
28815
|
+
outDir,
|
|
28816
|
+
exportData,
|
|
28817
|
+
summaryMd
|
|
28818
|
+
);
|
|
28819
|
+
const last_exported_at = exportData.exported_at;
|
|
28820
|
+
try {
|
|
28821
|
+
await apiBackendPatch(
|
|
28822
|
+
`${new URL(backendCheckpointsEndpoint()).pathname}/${id}`,
|
|
28823
|
+
{ last_exported_at, expected_sync_seq: exportData.sync_seq }
|
|
28824
|
+
);
|
|
28825
|
+
} catch (err) {
|
|
28826
|
+
const detail = err instanceof BackendError ? `(${err.status}): ${err.message}` : err instanceof Error ? err.message : String(err);
|
|
28214
28827
|
process.stderr.write(
|
|
28215
|
-
`checkpoint
|
|
28828
|
+
`checkpoint export: warning \u2014 could not stamp last_exported_at ${detail}
|
|
28216
28829
|
`
|
|
28217
28830
|
);
|
|
28218
28831
|
}
|
|
28832
|
+
process.stdout.write(
|
|
28833
|
+
JSON.stringify({
|
|
28834
|
+
exported: true,
|
|
28835
|
+
path: outDir,
|
|
28836
|
+
export_json: exportJsonPath,
|
|
28837
|
+
summary_md: summaryMdPath,
|
|
28838
|
+
last_exported_at
|
|
28839
|
+
}) + "\n"
|
|
28840
|
+
);
|
|
28841
|
+
} catch (err) {
|
|
28842
|
+
process.stderr.write(
|
|
28843
|
+
`checkpoint export: ${err instanceof Error ? err.message : String(err)}
|
|
28844
|
+
`
|
|
28845
|
+
);
|
|
28219
28846
|
process.exit(1);
|
|
28220
28847
|
}
|
|
28221
28848
|
process.exit(0);
|
|
28222
28849
|
}
|
|
28223
28850
|
function printCheckpointHelp() {
|
|
28224
28851
|
process.stdout.write(
|
|
28225
|
-
"\n codebyplan checkpoint <subcommand>\n\n Subcommands:\n create Create a checkpoint (--repo-id auto-resolved, pass extra fields as --key value)\n update Update a checkpoint (--id <uuid> required, then --key value pairs)\n complete Complete a checkpoint (--id <uuid> required)\n\n"
|
|
28852
|
+
"\n codebyplan checkpoint <subcommand>\n\n Subcommands:\n create Create a checkpoint (--repo-id auto-resolved, pass extra fields as --key value)\n update Update a checkpoint (--id <uuid> required, then --key value pairs)\n complete Complete a checkpoint (--id <uuid> required)\n export Export checkpoint data to .codebyplan/exports/{N}/ (--id <uuid> required)\n\n"
|
|
28226
28853
|
);
|
|
28227
28854
|
}
|
|
28228
28855
|
async function runCheckpointCommand(args) {
|
|
@@ -28239,6 +28866,10 @@ async function runCheckpointCommand(args) {
|
|
|
28239
28866
|
await runCheckpointComplete(args.slice(1));
|
|
28240
28867
|
return;
|
|
28241
28868
|
}
|
|
28869
|
+
if (subcommand === "export") {
|
|
28870
|
+
await runCheckpointExport(args.slice(1));
|
|
28871
|
+
return;
|
|
28872
|
+
}
|
|
28242
28873
|
if (subcommand === "help" || subcommand === "--help" || subcommand === "-h") {
|
|
28243
28874
|
printCheckpointHelp();
|
|
28244
28875
|
process.exit(0);
|
|
@@ -28254,13 +28885,17 @@ Run 'codebyplan checkpoint help' for usage.
|
|
|
28254
28885
|
}
|
|
28255
28886
|
process.exit(1);
|
|
28256
28887
|
}
|
|
28888
|
+
var MAX_OCC_RETRIES;
|
|
28257
28889
|
var init_checkpoint = __esm({
|
|
28258
28890
|
"src/cli/checkpoint.ts"() {
|
|
28259
28891
|
"use strict";
|
|
28892
|
+
init_api();
|
|
28260
28893
|
init_flags();
|
|
28261
28894
|
init_state_store();
|
|
28262
28895
|
init_state_client();
|
|
28263
28896
|
init_urls();
|
|
28897
|
+
init_export_writer();
|
|
28898
|
+
MAX_OCC_RETRIES = 3;
|
|
28264
28899
|
}
|
|
28265
28900
|
});
|
|
28266
28901
|
|
|
@@ -28364,42 +28999,88 @@ async function runTaskUpdate(args) {
|
|
|
28364
28999
|
const snakePatch = coerceFieldValues(kebabToSnakeKeys(patchBody));
|
|
28365
29000
|
const optimistic = { ...snapshot ?? {}, ...snakePatch, id };
|
|
28366
29001
|
await writeEntityFile(filePath, optimistic);
|
|
28367
|
-
|
|
28368
|
-
|
|
28369
|
-
|
|
28370
|
-
|
|
28371
|
-
|
|
28372
|
-
|
|
28373
|
-
|
|
28374
|
-
|
|
28375
|
-
|
|
28376
|
-
|
|
28377
|
-
|
|
28378
|
-
|
|
28379
|
-
|
|
28380
|
-
|
|
28381
|
-
|
|
28382
|
-
|
|
28383
|
-
|
|
28384
|
-
|
|
29002
|
+
let freshRow = snapshot;
|
|
29003
|
+
let lastErr;
|
|
29004
|
+
let successRow = null;
|
|
29005
|
+
if (freshRow === null) {
|
|
29006
|
+
try {
|
|
29007
|
+
const bootstrapResponse = await apiGet(`/tasks/${id}`);
|
|
29008
|
+
freshRow = bootstrapResponse.data;
|
|
29009
|
+
await writeEntityFile(filePath, freshRow);
|
|
29010
|
+
} catch {
|
|
29011
|
+
}
|
|
29012
|
+
}
|
|
29013
|
+
for (let attempt = 0; attempt <= MAX_OCC_RETRIES2; attempt++) {
|
|
29014
|
+
const currentSeq = freshRow !== null && typeof freshRow.sync_seq === "number" ? freshRow.sync_seq : void 0;
|
|
29015
|
+
const patchWithSeq = currentSeq !== void 0 ? { ...snakePatch, expected_sync_seq: currentSeq } : { ...snakePatch };
|
|
29016
|
+
try {
|
|
29017
|
+
const updated = await apiBackendPatch(
|
|
29018
|
+
`${new URL(backendTasksEndpoint()).pathname}/${id}`,
|
|
29019
|
+
patchWithSeq
|
|
28385
29020
|
);
|
|
29021
|
+
await writeEntityFile(filePath, updated);
|
|
29022
|
+
await updateCursorHash2(repoRoot, id, updated);
|
|
29023
|
+
successRow = updated;
|
|
29024
|
+
break;
|
|
29025
|
+
} catch (err2) {
|
|
29026
|
+
if (isConflict(err2) && attempt < MAX_OCC_RETRIES2) {
|
|
29027
|
+
try {
|
|
29028
|
+
const freshResponse = await apiGet(`/tasks/${id}`);
|
|
29029
|
+
freshRow = freshResponse.data;
|
|
29030
|
+
await writeEntityFile(filePath, freshRow);
|
|
29031
|
+
} catch {
|
|
29032
|
+
lastErr = err2;
|
|
29033
|
+
break;
|
|
29034
|
+
}
|
|
29035
|
+
lastErr = err2;
|
|
29036
|
+
continue;
|
|
29037
|
+
}
|
|
29038
|
+
lastErr = err2;
|
|
29039
|
+
break;
|
|
29040
|
+
}
|
|
29041
|
+
}
|
|
29042
|
+
if (successRow !== null) {
|
|
29043
|
+
process.stdout.write(JSON.stringify(successRow) + "\n");
|
|
29044
|
+
process.exit(0);
|
|
29045
|
+
}
|
|
29046
|
+
const err = lastErr;
|
|
29047
|
+
if (isConflict(err)) {
|
|
29048
|
+
if (freshRow !== null) {
|
|
29049
|
+
await writeEntityFile(filePath, freshRow);
|
|
29050
|
+
} else if (snapshot !== null) {
|
|
29051
|
+
await writeEntityFile(filePath, snapshot);
|
|
28386
29052
|
} else {
|
|
28387
|
-
await
|
|
28388
|
-
|
|
28389
|
-
|
|
28390
|
-
|
|
28391
|
-
operation: "update",
|
|
28392
|
-
attempted_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
28393
|
-
error: err instanceof Error ? err.message : String(err)
|
|
28394
|
-
});
|
|
28395
|
-
process.stderr.write(
|
|
28396
|
-
`task update: backend unavailable \u2014 local write kept, pending marker written. Error: ${err instanceof Error ? err.message : String(err)}
|
|
29053
|
+
await deleteEntityFile(filePath);
|
|
29054
|
+
}
|
|
29055
|
+
process.stderr.write(
|
|
29056
|
+
`task update: conflict \u2014 another writer updated task ${id} concurrently. Re-read the task and retry.
|
|
28397
29057
|
`
|
|
28398
|
-
|
|
29058
|
+
);
|
|
29059
|
+
} else if (err instanceof BackendError && err.status < 500) {
|
|
29060
|
+
if (snapshot !== null) {
|
|
29061
|
+
await writeEntityFile(filePath, snapshot);
|
|
29062
|
+
} else {
|
|
29063
|
+
await deleteEntityFile(filePath);
|
|
28399
29064
|
}
|
|
28400
|
-
process.
|
|
29065
|
+
process.stderr.write(
|
|
29066
|
+
`task update: backend rejected (${err.status}): ${err.message}
|
|
29067
|
+
`
|
|
29068
|
+
);
|
|
29069
|
+
} else {
|
|
29070
|
+
await writeEntityFile(pendingMarkerPath(repoRoot, id), {
|
|
29071
|
+
entity: "task",
|
|
29072
|
+
id,
|
|
29073
|
+
checkpoint_id: checkpointId,
|
|
29074
|
+
operation: "update",
|
|
29075
|
+
attempted_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
29076
|
+
error: err instanceof Error ? err.message : String(err)
|
|
29077
|
+
});
|
|
29078
|
+
process.stderr.write(
|
|
29079
|
+
`task update: backend unavailable \u2014 local write kept, pending marker written. Error: ${err instanceof Error ? err.message : String(err)}
|
|
29080
|
+
`
|
|
29081
|
+
);
|
|
28401
29082
|
}
|
|
28402
|
-
process.exit(
|
|
29083
|
+
process.exit(1);
|
|
28403
29084
|
}
|
|
28404
29085
|
async function runTaskComplete(args) {
|
|
28405
29086
|
const { flags } = parseFlagsFromArgs(args);
|
|
@@ -28427,42 +29108,78 @@ async function runTaskComplete(args) {
|
|
|
28427
29108
|
const snapshot = await readEntityFile(filePath);
|
|
28428
29109
|
const optimistic = { ...snapshot ?? {}, id, status: "completed" };
|
|
28429
29110
|
await writeEntityFile(filePath, optimistic);
|
|
28430
|
-
|
|
28431
|
-
|
|
28432
|
-
|
|
28433
|
-
|
|
28434
|
-
|
|
28435
|
-
|
|
28436
|
-
|
|
28437
|
-
|
|
28438
|
-
} catch (err) {
|
|
28439
|
-
if (err instanceof BackendError && err.status < 500) {
|
|
28440
|
-
if (snapshot !== null) {
|
|
28441
|
-
await writeEntityFile(filePath, snapshot);
|
|
28442
|
-
} else {
|
|
28443
|
-
await deleteEntityFile(filePath);
|
|
28444
|
-
}
|
|
28445
|
-
process.stderr.write(
|
|
28446
|
-
`task complete: backend rejected (${err.status}): ${err.message}
|
|
28447
|
-
`
|
|
29111
|
+
let freshRow = snapshot;
|
|
29112
|
+
let lastErr;
|
|
29113
|
+
let successRow = null;
|
|
29114
|
+
for (let attempt = 0; attempt <= MAX_OCC_RETRIES2; attempt++) {
|
|
29115
|
+
try {
|
|
29116
|
+
const completed = await apiBackendPost(
|
|
29117
|
+
`${new URL(backendTasksEndpoint()).pathname}/${id}/complete`,
|
|
29118
|
+
{}
|
|
28448
29119
|
);
|
|
29120
|
+
await writeEntityFile(filePath, completed);
|
|
29121
|
+
await updateCursorHash2(repoRoot, id, completed);
|
|
29122
|
+
successRow = completed;
|
|
29123
|
+
break;
|
|
29124
|
+
} catch (err2) {
|
|
29125
|
+
if (isConflict(err2) && attempt < MAX_OCC_RETRIES2) {
|
|
29126
|
+
try {
|
|
29127
|
+
const freshResponse = await apiGet(`/tasks/${id}`);
|
|
29128
|
+
freshRow = freshResponse.data;
|
|
29129
|
+
await writeEntityFile(filePath, freshRow);
|
|
29130
|
+
} catch {
|
|
29131
|
+
lastErr = err2;
|
|
29132
|
+
break;
|
|
29133
|
+
}
|
|
29134
|
+
lastErr = err2;
|
|
29135
|
+
continue;
|
|
29136
|
+
}
|
|
29137
|
+
lastErr = err2;
|
|
29138
|
+
break;
|
|
29139
|
+
}
|
|
29140
|
+
}
|
|
29141
|
+
if (successRow !== null) {
|
|
29142
|
+
process.stdout.write(JSON.stringify(successRow) + "\n");
|
|
29143
|
+
process.exit(0);
|
|
29144
|
+
}
|
|
29145
|
+
const err = lastErr;
|
|
29146
|
+
if (isConflict(err)) {
|
|
29147
|
+
if (freshRow !== null) {
|
|
29148
|
+
await writeEntityFile(filePath, freshRow);
|
|
29149
|
+
} else if (snapshot !== null) {
|
|
29150
|
+
await writeEntityFile(filePath, snapshot);
|
|
28449
29151
|
} else {
|
|
28450
|
-
await
|
|
28451
|
-
|
|
28452
|
-
|
|
28453
|
-
|
|
28454
|
-
operation: "complete",
|
|
28455
|
-
attempted_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
28456
|
-
error: err instanceof Error ? err.message : String(err)
|
|
28457
|
-
});
|
|
28458
|
-
process.stderr.write(
|
|
28459
|
-
`task complete: backend unavailable \u2014 local write kept, pending marker written. Error: ${err instanceof Error ? err.message : String(err)}
|
|
29152
|
+
await deleteEntityFile(filePath);
|
|
29153
|
+
}
|
|
29154
|
+
process.stderr.write(
|
|
29155
|
+
`task complete: conflict \u2014 another writer updated task ${id} concurrently. Re-read the task and retry.
|
|
28460
29156
|
`
|
|
28461
|
-
|
|
29157
|
+
);
|
|
29158
|
+
} else if (err instanceof BackendError && err.status < 500) {
|
|
29159
|
+
if (snapshot !== null) {
|
|
29160
|
+
await writeEntityFile(filePath, snapshot);
|
|
29161
|
+
} else {
|
|
29162
|
+
await deleteEntityFile(filePath);
|
|
28462
29163
|
}
|
|
28463
|
-
process.
|
|
29164
|
+
process.stderr.write(
|
|
29165
|
+
`task complete: backend rejected (${err.status}): ${err.message}
|
|
29166
|
+
`
|
|
29167
|
+
);
|
|
29168
|
+
} else {
|
|
29169
|
+
await writeEntityFile(pendingMarkerPath(repoRoot, id), {
|
|
29170
|
+
entity: "task",
|
|
29171
|
+
id,
|
|
29172
|
+
checkpoint_id: checkpointId,
|
|
29173
|
+
operation: "complete",
|
|
29174
|
+
attempted_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
29175
|
+
error: err instanceof Error ? err.message : String(err)
|
|
29176
|
+
});
|
|
29177
|
+
process.stderr.write(
|
|
29178
|
+
`task complete: backend unavailable \u2014 local write kept, pending marker written. Error: ${err instanceof Error ? err.message : String(err)}
|
|
29179
|
+
`
|
|
29180
|
+
);
|
|
28464
29181
|
}
|
|
28465
|
-
process.exit(
|
|
29182
|
+
process.exit(1);
|
|
28466
29183
|
}
|
|
28467
29184
|
function printTaskHelp() {
|
|
28468
29185
|
process.stdout.write(
|
|
@@ -28498,129 +29215,16 @@ Run 'codebyplan task help' for usage.
|
|
|
28498
29215
|
}
|
|
28499
29216
|
process.exit(1);
|
|
28500
29217
|
}
|
|
29218
|
+
var MAX_OCC_RETRIES2;
|
|
28501
29219
|
var init_task = __esm({
|
|
28502
29220
|
"src/cli/task.ts"() {
|
|
28503
29221
|
"use strict";
|
|
29222
|
+
init_api();
|
|
28504
29223
|
init_flags();
|
|
28505
29224
|
init_state_store();
|
|
28506
29225
|
init_state_client();
|
|
28507
29226
|
init_urls();
|
|
28508
|
-
|
|
28509
|
-
});
|
|
28510
|
-
|
|
28511
|
-
// src/lib/mcp-client.ts
|
|
28512
|
-
async function mcpCall(toolName, args) {
|
|
28513
|
-
let accessToken;
|
|
28514
|
-
try {
|
|
28515
|
-
accessToken = await getAccessToken();
|
|
28516
|
-
} catch (err) {
|
|
28517
|
-
if (err instanceof NoTokenError) {
|
|
28518
|
-
throw new McpError(
|
|
28519
|
-
"Not logged in. Run `codebyplan login` to authenticate."
|
|
28520
|
-
);
|
|
28521
|
-
}
|
|
28522
|
-
throw err;
|
|
28523
|
-
}
|
|
28524
|
-
const body = {
|
|
28525
|
-
jsonrpc: "2.0",
|
|
28526
|
-
id: 1,
|
|
28527
|
-
method: "tools/call",
|
|
28528
|
-
params: { name: toolName, arguments: args }
|
|
28529
|
-
};
|
|
28530
|
-
let res;
|
|
28531
|
-
try {
|
|
28532
|
-
res = await fetch(mcpEndpoint(), {
|
|
28533
|
-
method: "POST",
|
|
28534
|
-
headers: {
|
|
28535
|
-
"Content-Type": "application/json",
|
|
28536
|
-
Accept: "application/json, text/event-stream",
|
|
28537
|
-
Authorization: `Bearer ${accessToken}`
|
|
28538
|
-
},
|
|
28539
|
-
body: JSON.stringify(body),
|
|
28540
|
-
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS3)
|
|
28541
|
-
});
|
|
28542
|
-
} catch (err) {
|
|
28543
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
28544
|
-
throw new McpError(`mcp ${toolName} network error: ${message}`);
|
|
28545
|
-
}
|
|
28546
|
-
if (res.status === 401) {
|
|
28547
|
-
throw new McpError(
|
|
28548
|
-
"Authentication failed. Run `codebyplan login` to refresh your session.",
|
|
28549
|
-
401
|
|
28550
|
-
);
|
|
28551
|
-
}
|
|
28552
|
-
if (!res.ok) {
|
|
28553
|
-
throw new McpError(
|
|
28554
|
-
`mcp ${toolName} failed with status ${res.status}`,
|
|
28555
|
-
res.status
|
|
28556
|
-
);
|
|
28557
|
-
}
|
|
28558
|
-
const contentType = res.headers.get("content-type") ?? "";
|
|
28559
|
-
let envelope;
|
|
28560
|
-
if (contentType.includes("text/event-stream")) {
|
|
28561
|
-
const text = await res.text();
|
|
28562
|
-
envelope = parseSseEnvelope(text, toolName);
|
|
28563
|
-
} else {
|
|
28564
|
-
envelope = await res.json();
|
|
28565
|
-
}
|
|
28566
|
-
if (envelope.error) {
|
|
28567
|
-
throw new McpError(
|
|
28568
|
-
envelope.error.message ?? `mcp ${toolName} protocol error`,
|
|
28569
|
-
void 0,
|
|
28570
|
-
envelope.error.code !== void 0 ? String(envelope.error.code) : void 0
|
|
28571
|
-
);
|
|
28572
|
-
}
|
|
28573
|
-
const result = envelope.result;
|
|
28574
|
-
if (!result) {
|
|
28575
|
-
throw new McpError(`mcp ${toolName} returned no result`);
|
|
28576
|
-
}
|
|
28577
|
-
const textContent = result.content?.find((c) => c.type === "text")?.text;
|
|
28578
|
-
if (textContent === void 0) {
|
|
28579
|
-
throw new McpError(`mcp ${toolName} returned no text content`);
|
|
28580
|
-
}
|
|
28581
|
-
if (result.isError === true) {
|
|
28582
|
-
throw new McpError(textContent);
|
|
28583
|
-
}
|
|
28584
|
-
try {
|
|
28585
|
-
return JSON.parse(textContent);
|
|
28586
|
-
} catch {
|
|
28587
|
-
throw new McpError(
|
|
28588
|
-
`mcp ${toolName} returned non-JSON payload: ${textContent.slice(0, 200)}`
|
|
28589
|
-
);
|
|
28590
|
-
}
|
|
28591
|
-
}
|
|
28592
|
-
function parseSseEnvelope(text, toolName) {
|
|
28593
|
-
const frames = text.split("\n\n");
|
|
28594
|
-
for (let i = frames.length - 1; i >= 0; i--) {
|
|
28595
|
-
const frame = frames[i];
|
|
28596
|
-
const dataLines = frame.split("\n").filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trim());
|
|
28597
|
-
if (dataLines.length === 0) continue;
|
|
28598
|
-
const dataText = dataLines.join("\n");
|
|
28599
|
-
try {
|
|
28600
|
-
return JSON.parse(dataText);
|
|
28601
|
-
} catch {
|
|
28602
|
-
continue;
|
|
28603
|
-
}
|
|
28604
|
-
}
|
|
28605
|
-
throw new McpError(`mcp ${toolName} returned unparseable SSE body`);
|
|
28606
|
-
}
|
|
28607
|
-
var REQUEST_TIMEOUT_MS3, McpError;
|
|
28608
|
-
var init_mcp_client = __esm({
|
|
28609
|
-
"src/lib/mcp-client.ts"() {
|
|
28610
|
-
"use strict";
|
|
28611
|
-
init_token_refresh();
|
|
28612
|
-
init_urls();
|
|
28613
|
-
REQUEST_TIMEOUT_MS3 = 12e4;
|
|
28614
|
-
McpError = class extends Error {
|
|
28615
|
-
status;
|
|
28616
|
-
code;
|
|
28617
|
-
constructor(message, status, code) {
|
|
28618
|
-
super(message);
|
|
28619
|
-
this.name = "McpError";
|
|
28620
|
-
this.status = status;
|
|
28621
|
-
this.code = code;
|
|
28622
|
-
}
|
|
28623
|
-
};
|
|
29227
|
+
MAX_OCC_RETRIES2 = 3;
|
|
28624
29228
|
}
|
|
28625
29229
|
});
|
|
28626
29230
|
|
|
@@ -28766,6 +29370,7 @@ var init_sync_approvals = __esm({
|
|
|
28766
29370
|
var round_exports = {};
|
|
28767
29371
|
__export(round_exports, {
|
|
28768
29372
|
GIT_STATUS_CMD: () => GIT_STATUS_CMD,
|
|
29373
|
+
MAX_OCC_RETRIES: () => MAX_OCC_RETRIES3,
|
|
28769
29374
|
RETRY_DELAY_MS: () => RETRY_DELAY_MS,
|
|
28770
29375
|
fetchRoundsWithRetry: () => fetchRoundsWithRetry,
|
|
28771
29376
|
isTransientMcpError: () => isTransientMcpError,
|
|
@@ -28777,7 +29382,7 @@ __export(round_exports, {
|
|
|
28777
29382
|
setRetryDelayMs: () => setRetryDelayMs
|
|
28778
29383
|
});
|
|
28779
29384
|
import { access as access4 } from "node:fs/promises";
|
|
28780
|
-
import { join as
|
|
29385
|
+
import { join as join23 } from "node:path";
|
|
28781
29386
|
import { execSync as execSync3 } from "node:child_process";
|
|
28782
29387
|
function setRetryDelayMs(ms) {
|
|
28783
29388
|
RETRY_DELAY_MS = ms;
|
|
@@ -28953,43 +29558,89 @@ async function runRoundUpdate(args) {
|
|
|
28953
29558
|
const snakePatch = coerceFieldValues(kebabToSnakeKeys(patchBody));
|
|
28954
29559
|
const optimistic = { ...snapshot ?? {}, ...snakePatch, id };
|
|
28955
29560
|
await writeEntityFile(filePath, optimistic);
|
|
28956
|
-
|
|
28957
|
-
|
|
28958
|
-
|
|
28959
|
-
|
|
28960
|
-
|
|
28961
|
-
|
|
28962
|
-
|
|
28963
|
-
|
|
28964
|
-
|
|
28965
|
-
|
|
28966
|
-
|
|
28967
|
-
|
|
28968
|
-
|
|
28969
|
-
|
|
28970
|
-
|
|
28971
|
-
|
|
28972
|
-
|
|
28973
|
-
|
|
29561
|
+
let freshRow = snapshot;
|
|
29562
|
+
let lastErr;
|
|
29563
|
+
let successRow = null;
|
|
29564
|
+
if (freshRow === null) {
|
|
29565
|
+
try {
|
|
29566
|
+
const bootstrapResponse = await apiGet(`/rounds/${id}`);
|
|
29567
|
+
freshRow = bootstrapResponse.data;
|
|
29568
|
+
await writeEntityFile(filePath, freshRow);
|
|
29569
|
+
} catch {
|
|
29570
|
+
}
|
|
29571
|
+
}
|
|
29572
|
+
for (let attempt = 0; attempt <= MAX_OCC_RETRIES3; attempt++) {
|
|
29573
|
+
const currentSeq = freshRow !== null && typeof freshRow.sync_seq === "number" ? freshRow.sync_seq : void 0;
|
|
29574
|
+
const patchWithSeq = currentSeq !== void 0 ? { ...snakePatch, expected_sync_seq: currentSeq } : { ...snakePatch };
|
|
29575
|
+
try {
|
|
29576
|
+
const updated = await apiBackendPatch(
|
|
29577
|
+
`${new URL(backendRoundsEndpoint()).pathname}/${id}`,
|
|
29578
|
+
patchWithSeq
|
|
28974
29579
|
);
|
|
29580
|
+
await writeEntityFile(filePath, updated);
|
|
29581
|
+
await updateRoundCursorHash(repoRoot, id, updated);
|
|
29582
|
+
successRow = updated;
|
|
29583
|
+
break;
|
|
29584
|
+
} catch (err2) {
|
|
29585
|
+
if (isConflict(err2) && attempt < MAX_OCC_RETRIES3) {
|
|
29586
|
+
try {
|
|
29587
|
+
const freshResponse = await apiGet(`/rounds/${id}`);
|
|
29588
|
+
freshRow = freshResponse.data;
|
|
29589
|
+
await writeEntityFile(filePath, freshRow);
|
|
29590
|
+
} catch {
|
|
29591
|
+
lastErr = err2;
|
|
29592
|
+
break;
|
|
29593
|
+
}
|
|
29594
|
+
lastErr = err2;
|
|
29595
|
+
continue;
|
|
29596
|
+
}
|
|
29597
|
+
lastErr = err2;
|
|
29598
|
+
break;
|
|
29599
|
+
}
|
|
29600
|
+
}
|
|
29601
|
+
if (successRow !== null) {
|
|
29602
|
+
process.stdout.write(JSON.stringify(successRow) + "\n");
|
|
29603
|
+
process.exit(0);
|
|
29604
|
+
}
|
|
29605
|
+
const err = lastErr;
|
|
29606
|
+
if (isConflict(err)) {
|
|
29607
|
+
if (freshRow !== null) {
|
|
29608
|
+
await writeEntityFile(filePath, freshRow);
|
|
29609
|
+
} else if (snapshot !== null) {
|
|
29610
|
+
await writeEntityFile(filePath, snapshot);
|
|
28975
29611
|
} else {
|
|
28976
|
-
await
|
|
28977
|
-
|
|
28978
|
-
|
|
28979
|
-
|
|
28980
|
-
task_id: taskId,
|
|
28981
|
-
operation: "update",
|
|
28982
|
-
attempted_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
28983
|
-
error: err instanceof Error ? err.message : String(err)
|
|
28984
|
-
});
|
|
28985
|
-
process.stderr.write(
|
|
28986
|
-
`round update: backend unavailable \u2014 local write kept, pending marker written. Error: ${err instanceof Error ? err.message : String(err)}
|
|
29612
|
+
await deleteEntityFile(filePath);
|
|
29613
|
+
}
|
|
29614
|
+
process.stderr.write(
|
|
29615
|
+
`round update: conflict \u2014 another writer updated round ${id} concurrently. Re-read the round and retry.
|
|
28987
29616
|
`
|
|
28988
|
-
|
|
29617
|
+
);
|
|
29618
|
+
} else if (err instanceof BackendError && err.status < 500) {
|
|
29619
|
+
if (snapshot !== null) {
|
|
29620
|
+
await writeEntityFile(filePath, snapshot);
|
|
29621
|
+
} else {
|
|
29622
|
+
await deleteEntityFile(filePath);
|
|
28989
29623
|
}
|
|
28990
|
-
process.
|
|
29624
|
+
process.stderr.write(
|
|
29625
|
+
`round update: backend rejected (${err.status}): ${err.message}
|
|
29626
|
+
`
|
|
29627
|
+
);
|
|
29628
|
+
} else {
|
|
29629
|
+
await writeEntityFile(pendingMarkerPath(repoRoot, id), {
|
|
29630
|
+
entity: "round",
|
|
29631
|
+
id,
|
|
29632
|
+
checkpoint_id: checkpointId,
|
|
29633
|
+
task_id: taskId,
|
|
29634
|
+
operation: "update",
|
|
29635
|
+
attempted_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
29636
|
+
error: err instanceof Error ? err.message : String(err)
|
|
29637
|
+
});
|
|
29638
|
+
process.stderr.write(
|
|
29639
|
+
`round update: backend unavailable \u2014 local write kept, pending marker written. Error: ${err instanceof Error ? err.message : String(err)}
|
|
29640
|
+
`
|
|
29641
|
+
);
|
|
28991
29642
|
}
|
|
28992
|
-
process.exit(
|
|
29643
|
+
process.exit(1);
|
|
28993
29644
|
}
|
|
28994
29645
|
async function runRoundComplete(args) {
|
|
28995
29646
|
const { flags } = parseFlagsFromArgs(args);
|
|
@@ -29022,43 +29673,79 @@ async function runRoundComplete(args) {
|
|
|
29022
29673
|
const snapshot = await readEntityFile(filePath);
|
|
29023
29674
|
const optimistic = { ...snapshot ?? {}, id, status: "completed" };
|
|
29024
29675
|
await writeEntityFile(filePath, optimistic);
|
|
29025
|
-
|
|
29026
|
-
|
|
29027
|
-
|
|
29028
|
-
|
|
29029
|
-
|
|
29030
|
-
|
|
29031
|
-
|
|
29032
|
-
|
|
29033
|
-
} catch (err) {
|
|
29034
|
-
if (err instanceof BackendError && err.status < 500) {
|
|
29035
|
-
if (snapshot !== null) {
|
|
29036
|
-
await writeEntityFile(filePath, snapshot);
|
|
29037
|
-
} else {
|
|
29038
|
-
await deleteEntityFile(filePath);
|
|
29039
|
-
}
|
|
29040
|
-
process.stderr.write(
|
|
29041
|
-
`round complete: backend rejected (${err.status}): ${err.message}
|
|
29042
|
-
`
|
|
29676
|
+
let freshRow = snapshot;
|
|
29677
|
+
let lastErr;
|
|
29678
|
+
let successRow = null;
|
|
29679
|
+
for (let attempt = 0; attempt <= MAX_OCC_RETRIES3; attempt++) {
|
|
29680
|
+
try {
|
|
29681
|
+
const completed = await apiBackendPost(
|
|
29682
|
+
`${new URL(backendRoundsEndpoint()).pathname}/${id}/complete`,
|
|
29683
|
+
{}
|
|
29043
29684
|
);
|
|
29685
|
+
await writeEntityFile(filePath, completed);
|
|
29686
|
+
await updateRoundCursorHash(repoRoot, id, completed);
|
|
29687
|
+
successRow = completed;
|
|
29688
|
+
break;
|
|
29689
|
+
} catch (err2) {
|
|
29690
|
+
if (isConflict(err2) && attempt < MAX_OCC_RETRIES3) {
|
|
29691
|
+
try {
|
|
29692
|
+
const freshResponse = await apiGet(`/rounds/${id}`);
|
|
29693
|
+
freshRow = freshResponse.data;
|
|
29694
|
+
await writeEntityFile(filePath, freshRow);
|
|
29695
|
+
} catch {
|
|
29696
|
+
lastErr = err2;
|
|
29697
|
+
break;
|
|
29698
|
+
}
|
|
29699
|
+
lastErr = err2;
|
|
29700
|
+
continue;
|
|
29701
|
+
}
|
|
29702
|
+
lastErr = err2;
|
|
29703
|
+
break;
|
|
29704
|
+
}
|
|
29705
|
+
}
|
|
29706
|
+
if (successRow !== null) {
|
|
29707
|
+
process.stdout.write(JSON.stringify(successRow) + "\n");
|
|
29708
|
+
process.exit(0);
|
|
29709
|
+
}
|
|
29710
|
+
const err = lastErr;
|
|
29711
|
+
if (isConflict(err)) {
|
|
29712
|
+
if (freshRow !== null) {
|
|
29713
|
+
await writeEntityFile(filePath, freshRow);
|
|
29714
|
+
} else if (snapshot !== null) {
|
|
29715
|
+
await writeEntityFile(filePath, snapshot);
|
|
29044
29716
|
} else {
|
|
29045
|
-
await
|
|
29046
|
-
|
|
29047
|
-
|
|
29048
|
-
|
|
29049
|
-
task_id: taskId,
|
|
29050
|
-
operation: "complete",
|
|
29051
|
-
attempted_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
29052
|
-
error: err instanceof Error ? err.message : String(err)
|
|
29053
|
-
});
|
|
29054
|
-
process.stderr.write(
|
|
29055
|
-
`round complete: backend unavailable \u2014 local write kept, pending marker written. Error: ${err instanceof Error ? err.message : String(err)}
|
|
29717
|
+
await deleteEntityFile(filePath);
|
|
29718
|
+
}
|
|
29719
|
+
process.stderr.write(
|
|
29720
|
+
`round complete: conflict \u2014 another writer updated round ${id} concurrently. Re-read the round and retry.
|
|
29056
29721
|
`
|
|
29057
|
-
|
|
29722
|
+
);
|
|
29723
|
+
} else if (err instanceof BackendError && err.status < 500) {
|
|
29724
|
+
if (snapshot !== null) {
|
|
29725
|
+
await writeEntityFile(filePath, snapshot);
|
|
29726
|
+
} else {
|
|
29727
|
+
await deleteEntityFile(filePath);
|
|
29058
29728
|
}
|
|
29059
|
-
process.
|
|
29729
|
+
process.stderr.write(
|
|
29730
|
+
`round complete: backend rejected (${err.status}): ${err.message}
|
|
29731
|
+
`
|
|
29732
|
+
);
|
|
29733
|
+
} else {
|
|
29734
|
+
await writeEntityFile(pendingMarkerPath(repoRoot, id), {
|
|
29735
|
+
entity: "round",
|
|
29736
|
+
id,
|
|
29737
|
+
checkpoint_id: checkpointId,
|
|
29738
|
+
task_id: taskId,
|
|
29739
|
+
operation: "complete",
|
|
29740
|
+
attempted_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
29741
|
+
error: err instanceof Error ? err.message : String(err)
|
|
29742
|
+
});
|
|
29743
|
+
process.stderr.write(
|
|
29744
|
+
`round complete: backend unavailable \u2014 local write kept, pending marker written. Error: ${err instanceof Error ? err.message : String(err)}
|
|
29745
|
+
`
|
|
29746
|
+
);
|
|
29060
29747
|
}
|
|
29061
|
-
process.exit(
|
|
29748
|
+
process.exit(1);
|
|
29062
29749
|
}
|
|
29063
29750
|
async function resolveCallerWorktreeId(repoRoot, currentBranch, repoId, overrideId) {
|
|
29064
29751
|
if (overrideId) {
|
|
@@ -29157,7 +29844,7 @@ async function runRoundSyncApprovals(args) {
|
|
|
29157
29844
|
"sync-approvals: git status failed; proceeding with empty diff\n"
|
|
29158
29845
|
);
|
|
29159
29846
|
}
|
|
29160
|
-
const hookPath =
|
|
29847
|
+
const hookPath = join23(
|
|
29161
29848
|
repoRoot,
|
|
29162
29849
|
".claude",
|
|
29163
29850
|
"hooks",
|
|
@@ -29234,7 +29921,7 @@ async function runRoundSyncApprovals(args) {
|
|
|
29234
29921
|
process.stdout.write(stdoutPayload + "\n");
|
|
29235
29922
|
process.exit(0);
|
|
29236
29923
|
}
|
|
29237
|
-
var RETRY_DELAY_MS, GIT_STATUS_CMD;
|
|
29924
|
+
var RETRY_DELAY_MS, MAX_OCC_RETRIES3, GIT_STATUS_CMD;
|
|
29238
29925
|
var init_round = __esm({
|
|
29239
29926
|
"src/cli/round.ts"() {
|
|
29240
29927
|
"use strict";
|
|
@@ -29250,6 +29937,7 @@ var init_round = __esm({
|
|
|
29250
29937
|
init_state_client();
|
|
29251
29938
|
init_urls();
|
|
29252
29939
|
RETRY_DELAY_MS = 1e3;
|
|
29940
|
+
MAX_OCC_RETRIES3 = 3;
|
|
29253
29941
|
GIT_STATUS_CMD = "git status --short --porcelain --untracked-files=all -z";
|
|
29254
29942
|
}
|
|
29255
29943
|
});
|
|
@@ -29259,6 +29947,7 @@ var standalone_task_exports = {};
|
|
|
29259
29947
|
__export(standalone_task_exports, {
|
|
29260
29948
|
runStandaloneTaskCommand: () => runStandaloneTaskCommand
|
|
29261
29949
|
});
|
|
29950
|
+
import { join as join24 } from "node:path";
|
|
29262
29951
|
async function resolveRepoRoot3() {
|
|
29263
29952
|
const found = await findCodebyplanConfig(process.cwd());
|
|
29264
29953
|
if (!found?.contents.repo_id) return null;
|
|
@@ -29520,9 +30209,62 @@ async function runStandaloneTaskComplete(args) {
|
|
|
29520
30209
|
}
|
|
29521
30210
|
process.exit(0);
|
|
29522
30211
|
}
|
|
30212
|
+
async function runStandaloneTaskExport(args) {
|
|
30213
|
+
const { flags } = parseFlagsFromArgs(args);
|
|
30214
|
+
const id = flags.id ?? flags["standalone-task-id"];
|
|
30215
|
+
if (!id) {
|
|
30216
|
+
process.stderr.write(
|
|
30217
|
+
"standalone-task export: --id <standalone-task-id> is required\n"
|
|
30218
|
+
);
|
|
30219
|
+
process.exit(1);
|
|
30220
|
+
}
|
|
30221
|
+
const repoInfo = await resolveRepoRoot3();
|
|
30222
|
+
if (!repoInfo) {
|
|
30223
|
+
process.stderr.write(
|
|
30224
|
+
"standalone-task export: no .codebyplan/repo.json found. Run `codebyplan setup`.\n"
|
|
30225
|
+
);
|
|
30226
|
+
process.exit(1);
|
|
30227
|
+
}
|
|
30228
|
+
const { repoRoot, repoId } = repoInfo;
|
|
30229
|
+
try {
|
|
30230
|
+
const exportData = await buildStandaloneExport(id, repoRoot, repoId);
|
|
30231
|
+
const outDir = join24(
|
|
30232
|
+
repoRoot,
|
|
30233
|
+
".codebyplan",
|
|
30234
|
+
"exports",
|
|
30235
|
+
"standalone",
|
|
30236
|
+
String(exportData.number)
|
|
30237
|
+
);
|
|
30238
|
+
const summaryMd = renderSummaryMd(exportData);
|
|
30239
|
+
const { exportJsonPath, summaryMdPath } = writeExportArtifacts(
|
|
30240
|
+
outDir,
|
|
30241
|
+
exportData,
|
|
30242
|
+
summaryMd
|
|
30243
|
+
);
|
|
30244
|
+
process.stderr.write(
|
|
30245
|
+
"standalone-task export: note \u2014 standalone_tasks does not have a last_exported_at column; stamp skipped.\n"
|
|
30246
|
+
);
|
|
30247
|
+
process.stdout.write(
|
|
30248
|
+
JSON.stringify({
|
|
30249
|
+
exported: true,
|
|
30250
|
+
path: outDir,
|
|
30251
|
+
export_json: exportJsonPath,
|
|
30252
|
+
summary_md: summaryMdPath,
|
|
30253
|
+
last_exported_at: null
|
|
30254
|
+
}) + "\n"
|
|
30255
|
+
);
|
|
30256
|
+
} catch (err) {
|
|
30257
|
+
process.stderr.write(
|
|
30258
|
+
`standalone-task export: ${err instanceof Error ? err.message : String(err)}
|
|
30259
|
+
`
|
|
30260
|
+
);
|
|
30261
|
+
process.exit(1);
|
|
30262
|
+
}
|
|
30263
|
+
process.exit(0);
|
|
30264
|
+
}
|
|
29523
30265
|
function printStandaloneTaskHelp() {
|
|
29524
30266
|
process.stdout.write(
|
|
29525
|
-
"\n codebyplan standalone-task <subcommand>\n\n Standalone tasks are independent work items (no checkpoint parent).\n Writes go through the standalone MCP tools \u2014 no --checkpoint-id flag.\n\n Subcommands:\n create Create a standalone task (--title required, pass extra fields as --key value)\n update Update a standalone task (--id required, then --key value pairs)\n complete Complete a standalone task (--id required; caller worktree must resolve)\n\n"
|
|
30267
|
+
"\n codebyplan standalone-task <subcommand>\n\n Standalone tasks are independent work items (no checkpoint parent).\n Writes go through the standalone MCP tools \u2014 no --checkpoint-id flag.\n\n Subcommands:\n create Create a standalone task (--title required, pass extra fields as --key value)\n update Update a standalone task (--id required, then --key value pairs)\n complete Complete a standalone task (--id required; caller worktree must resolve)\n export Export task data to .codebyplan/exports/standalone/{N}/ (--id required)\n\n"
|
|
29526
30268
|
);
|
|
29527
30269
|
}
|
|
29528
30270
|
async function runStandaloneTaskCommand(args) {
|
|
@@ -29539,6 +30281,10 @@ async function runStandaloneTaskCommand(args) {
|
|
|
29539
30281
|
await runStandaloneTaskComplete(args.slice(1));
|
|
29540
30282
|
return;
|
|
29541
30283
|
}
|
|
30284
|
+
if (subcommand === "export") {
|
|
30285
|
+
await runStandaloneTaskExport(args.slice(1));
|
|
30286
|
+
return;
|
|
30287
|
+
}
|
|
29542
30288
|
if (subcommand === "help" || subcommand === "--help" || subcommand === "-h") {
|
|
29543
30289
|
printStandaloneTaskHelp();
|
|
29544
30290
|
process.exit(0);
|
|
@@ -29561,6 +30307,7 @@ var init_standalone_task = __esm({
|
|
|
29561
30307
|
init_mcp_client();
|
|
29562
30308
|
init_round();
|
|
29563
30309
|
init_flags();
|
|
30310
|
+
init_export_writer();
|
|
29564
30311
|
init_git_utils();
|
|
29565
30312
|
init_worktree_cache();
|
|
29566
30313
|
init_resolve_worktree();
|
|
@@ -31101,7 +31848,7 @@ var init_session2 = __esm({
|
|
|
31101
31848
|
|
|
31102
31849
|
// src/lib/migrate-branch-model.ts
|
|
31103
31850
|
import { readFile as readFile18, writeFile as writeFile15 } from "node:fs/promises";
|
|
31104
|
-
import { join as
|
|
31851
|
+
import { join as join27 } from "node:path";
|
|
31105
31852
|
import { execSync as execSync4 } from "node:child_process";
|
|
31106
31853
|
function assertValidBranchName(branch) {
|
|
31107
31854
|
if (!/^[a-zA-Z0-9/_.-]+$/.test(branch)) {
|
|
@@ -31180,12 +31927,12 @@ async function runBranchMigration(opts) {
|
|
|
31180
31927
|
if (found) {
|
|
31181
31928
|
if (found.path.endsWith("/repo.json")) {
|
|
31182
31929
|
const dir = found.path.slice(0, found.path.lastIndexOf("/"));
|
|
31183
|
-
configPath =
|
|
31930
|
+
configPath = join27(dir, "git.json");
|
|
31184
31931
|
} else {
|
|
31185
31932
|
configPath = found.path;
|
|
31186
31933
|
}
|
|
31187
31934
|
} else {
|
|
31188
|
-
configPath =
|
|
31935
|
+
configPath = join27(cwd, ".codebyplan", "git.json");
|
|
31189
31936
|
}
|
|
31190
31937
|
let fileRaw;
|
|
31191
31938
|
let fileParsed;
|
|
@@ -31532,7 +32279,7 @@ var init_branch = __esm({
|
|
|
31532
32279
|
|
|
31533
32280
|
// src/lib/bump.ts
|
|
31534
32281
|
import { readFile as readFile19, writeFile as writeFile16, access as access5, readdir as readdir4 } from "node:fs/promises";
|
|
31535
|
-
import { join as
|
|
32282
|
+
import { join as join28, relative as relative5, resolve as resolve3 } from "node:path";
|
|
31536
32283
|
import { spawnSync as spawnSync10 } from "node:child_process";
|
|
31537
32284
|
function parsePnpmWorkspaceGlobs(raw) {
|
|
31538
32285
|
const lines = raw.split("\n");
|
|
@@ -31562,18 +32309,18 @@ async function expandGlob(cwd, glob) {
|
|
|
31562
32309
|
if (parts.length !== 2 || parts[1] !== "*") {
|
|
31563
32310
|
return [];
|
|
31564
32311
|
}
|
|
31565
|
-
const parentDir =
|
|
32312
|
+
const parentDir = join28(cwd, parts[0]);
|
|
31566
32313
|
let dirs;
|
|
31567
32314
|
try {
|
|
31568
32315
|
const entries = await readdir4(parentDir, { withFileTypes: true });
|
|
31569
|
-
dirs = entries.filter((e) => e.isDirectory()).map((e) =>
|
|
32316
|
+
dirs = entries.filter((e) => e.isDirectory()).map((e) => join28(parentDir, e.name));
|
|
31570
32317
|
} catch {
|
|
31571
32318
|
return [];
|
|
31572
32319
|
}
|
|
31573
32320
|
const results = [];
|
|
31574
32321
|
for (const dir of dirs) {
|
|
31575
32322
|
try {
|
|
31576
|
-
await access5(
|
|
32323
|
+
await access5(join28(dir, "package.json"));
|
|
31577
32324
|
results.push(dir);
|
|
31578
32325
|
} catch {
|
|
31579
32326
|
}
|
|
@@ -31584,7 +32331,7 @@ async function buildPackageMap(cwd) {
|
|
|
31584
32331
|
const map = /* @__PURE__ */ new Map();
|
|
31585
32332
|
let globs = [];
|
|
31586
32333
|
try {
|
|
31587
|
-
const raw = await readFile19(
|
|
32334
|
+
const raw = await readFile19(join28(cwd, "pnpm-workspace.yaml"), "utf-8");
|
|
31588
32335
|
globs = parsePnpmWorkspaceGlobs(raw);
|
|
31589
32336
|
} catch {
|
|
31590
32337
|
}
|
|
@@ -31592,7 +32339,7 @@ async function buildPackageMap(cwd) {
|
|
|
31592
32339
|
const dirs = await expandGlob(cwd, glob);
|
|
31593
32340
|
for (const dir of dirs) {
|
|
31594
32341
|
try {
|
|
31595
|
-
const pkgRaw = await readFile19(
|
|
32342
|
+
const pkgRaw = await readFile19(join28(dir, "package.json"), "utf-8");
|
|
31596
32343
|
const pkg = JSON.parse(pkgRaw);
|
|
31597
32344
|
const name = pkg.name ?? relative5(cwd, dir);
|
|
31598
32345
|
map.set(dir, { name, dir });
|
|
@@ -31751,7 +32498,7 @@ async function runBump(opts) {
|
|
|
31751
32498
|
const changedFiles = (diffResult.stdout ?? "").trim().split("\n").filter(Boolean).map((f) => resolve3(cwd, f));
|
|
31752
32499
|
const packageMap = await buildPackageMap(cwd);
|
|
31753
32500
|
const packageDirs = Array.from(packageMap.keys());
|
|
31754
|
-
const rootPkgPath =
|
|
32501
|
+
const rootPkgPath = join28(cwd, "package.json");
|
|
31755
32502
|
const changedPackageDirs = /* @__PURE__ */ new Set();
|
|
31756
32503
|
for (const absFile of changedFiles) {
|
|
31757
32504
|
const owner = findOwningPackage(absFile, packageDirs);
|
|
@@ -31762,19 +32509,19 @@ async function runBump(opts) {
|
|
|
31762
32509
|
const entries = [];
|
|
31763
32510
|
for (const pkgDir of changedPackageDirs) {
|
|
31764
32511
|
const pkgInfo = packageMap.get(pkgDir);
|
|
31765
|
-
const pkgJsonPath =
|
|
32512
|
+
const pkgJsonPath = join28(pkgDir, "package.json");
|
|
31766
32513
|
if (pkgJsonPath === rootPkgPath) continue;
|
|
31767
32514
|
const versionFileCandidates = [
|
|
31768
32515
|
{ abs: pkgJsonPath, rel: relative5(cwd, pkgJsonPath).replace(/\\/g, "/") }
|
|
31769
32516
|
];
|
|
31770
|
-
const tauriConfPath =
|
|
32517
|
+
const tauriConfPath = join28(pkgDir, "src-tauri", "tauri.conf.json");
|
|
31771
32518
|
const tauriRelPath = relative5(cwd, tauriConfPath).replace(/\\/g, "/");
|
|
31772
32519
|
try {
|
|
31773
32520
|
await access5(tauriConfPath);
|
|
31774
32521
|
versionFileCandidates.push({ abs: tauriConfPath, rel: tauriRelPath });
|
|
31775
32522
|
} catch {
|
|
31776
32523
|
}
|
|
31777
|
-
const appJsonPath =
|
|
32524
|
+
const appJsonPath = join28(pkgDir, "app.json");
|
|
31778
32525
|
const appJsonRelPath = relative5(cwd, appJsonPath).replace(/\\/g, "/");
|
|
31779
32526
|
try {
|
|
31780
32527
|
await access5(appJsonPath);
|
|
@@ -31846,7 +32593,7 @@ async function runBump(opts) {
|
|
|
31846
32593
|
}
|
|
31847
32594
|
updatedVersionFiles.push(rel);
|
|
31848
32595
|
}
|
|
31849
|
-
const changelogPath =
|
|
32596
|
+
const changelogPath = join28(pkgDir, "CHANGELOG.md");
|
|
31850
32597
|
const changelogUpdated = await prependChangelog(
|
|
31851
32598
|
changelogPath,
|
|
31852
32599
|
pkgInfo.name,
|
|
@@ -34314,7 +35061,7 @@ __export(version_status_exports, {
|
|
|
34314
35061
|
});
|
|
34315
35062
|
import { execFileSync, execSync as execSync7 } from "node:child_process";
|
|
34316
35063
|
import { existsSync as existsSync10, readFileSync as readFileSync11 } from "node:fs";
|
|
34317
|
-
import { dirname as dirname13, join as
|
|
35064
|
+
import { dirname as dirname13, join as join35 } from "node:path";
|
|
34318
35065
|
function fetchLatestVersion() {
|
|
34319
35066
|
try {
|
|
34320
35067
|
return execFileSync("npm", ["view", "codebyplan", "version"], {
|
|
@@ -34338,9 +35085,9 @@ function detectPackageManager2(gitRoot) {
|
|
|
34338
35085
|
let dir = process.cwd();
|
|
34339
35086
|
const stopAt = gitRoot ?? null;
|
|
34340
35087
|
while (true) {
|
|
34341
|
-
if (existsSync10(
|
|
34342
|
-
if (existsSync10(
|
|
34343
|
-
if (existsSync10(
|
|
35088
|
+
if (existsSync10(join35(dir, "pnpm-lock.yaml"))) return "pnpm";
|
|
35089
|
+
if (existsSync10(join35(dir, "yarn.lock"))) return "yarn";
|
|
35090
|
+
if (existsSync10(join35(dir, "package-lock.json"))) return "npm";
|
|
34344
35091
|
if (stopAt !== null && dir === stopAt) break;
|
|
34345
35092
|
const parent = dirname13(dir);
|
|
34346
35093
|
if (parent === dir) break;
|
|
@@ -34360,7 +35107,7 @@ function buildInstallCommand2(pm) {
|
|
|
34360
35107
|
}
|
|
34361
35108
|
async function resolveGuard(gitRoot, currentBranch) {
|
|
34362
35109
|
if (gitRoot !== null) {
|
|
34363
|
-
const canonicalPkgPath =
|
|
35110
|
+
const canonicalPkgPath = join35(
|
|
34364
35111
|
gitRoot,
|
|
34365
35112
|
"packages",
|
|
34366
35113
|
"codebyplan-package",
|
|
@@ -34384,10 +35131,10 @@ async function resolveGuard(gitRoot, currentBranch) {
|
|
|
34384
35131
|
let gitJsonPath;
|
|
34385
35132
|
if (found.path.endsWith("/repo.json")) {
|
|
34386
35133
|
const dir = found.path.slice(0, found.path.lastIndexOf("/"));
|
|
34387
|
-
gitJsonPath =
|
|
35134
|
+
gitJsonPath = join35(dir, "git.json");
|
|
34388
35135
|
} else {
|
|
34389
35136
|
const legacyDir = found.path.slice(0, found.path.lastIndexOf("/"));
|
|
34390
|
-
gitJsonPath =
|
|
35137
|
+
gitJsonPath = join35(legacyDir, ".codebyplan", "git.json");
|
|
34391
35138
|
}
|
|
34392
35139
|
const raw = readFileSync11(gitJsonPath, "utf-8");
|
|
34393
35140
|
const parsed = JSON.parse(raw);
|
|
@@ -34472,7 +35219,7 @@ __export(upload_e2e_images_exports, {
|
|
|
34472
35219
|
runUploadE2eImagesCommand: () => runUploadE2eImagesCommand
|
|
34473
35220
|
});
|
|
34474
35221
|
import { readFile as readFile20 } from "node:fs/promises";
|
|
34475
|
-
import { join as
|
|
35222
|
+
import { join as join36, basename as basename2, resolve as resolve10 } from "node:path";
|
|
34476
35223
|
import { execSync as execSync8 } from "node:child_process";
|
|
34477
35224
|
function baseUrl2() {
|
|
34478
35225
|
return (process.env.CODEBYPLAN_API_URL ?? "https://www.codebyplan.com").replace(/\/$/, "");
|
|
@@ -34507,7 +35254,7 @@ function parseArgs(args) {
|
|
|
34507
35254
|
async function readE2eConfig(projectPath) {
|
|
34508
35255
|
try {
|
|
34509
35256
|
const raw = await readFile20(
|
|
34510
|
-
|
|
35257
|
+
join36(projectPath, ".codebyplan", "e2e.json"),
|
|
34511
35258
|
"utf-8"
|
|
34512
35259
|
);
|
|
34513
35260
|
return JSON.parse(raw);
|
|
@@ -34548,7 +35295,7 @@ function collectPngsFromGitDiff(projectPath, frameworkName, frameworkConfig, bas
|
|
|
34548
35295
|
continue;
|
|
34549
35296
|
const isNew = status === "A";
|
|
34550
35297
|
results.push({
|
|
34551
|
-
absolutePath:
|
|
35298
|
+
absolutePath: join36(projectPath, filePath),
|
|
34552
35299
|
filename: basename2(filePath),
|
|
34553
35300
|
framework: frameworkName,
|
|
34554
35301
|
is_new: isNew
|
|
@@ -34724,7 +35471,7 @@ __export(arch_map_exports, {
|
|
|
34724
35471
|
});
|
|
34725
35472
|
import { readFile as readFile21, writeFile as writeFile17 } from "node:fs/promises";
|
|
34726
35473
|
import { existsSync as existsSync11, readdirSync as readdirSync4 } from "node:fs";
|
|
34727
|
-
import { join as
|
|
35474
|
+
import { join as join37 } from "node:path";
|
|
34728
35475
|
import { spawnSync as spawnSync12 } from "node:child_process";
|
|
34729
35476
|
function normalizeModulePath(modulePath) {
|
|
34730
35477
|
return modulePath.replace(/\/+$/, "");
|
|
@@ -34749,7 +35496,7 @@ async function resolveCodebyplanDir(startDir) {
|
|
|
34749
35496
|
}
|
|
34750
35497
|
}
|
|
34751
35498
|
async function readArchitectureConfig(codebyplanDir) {
|
|
34752
|
-
const filePath =
|
|
35499
|
+
const filePath = join37(codebyplanDir, "architecture.json");
|
|
34753
35500
|
try {
|
|
34754
35501
|
const raw = await readFile21(filePath, "utf-8");
|
|
34755
35502
|
const parsed = JSON.parse(raw);
|
|
@@ -34762,7 +35509,7 @@ async function readArchitectureConfig(codebyplanDir) {
|
|
|
34762
35509
|
}
|
|
34763
35510
|
}
|
|
34764
35511
|
async function writeArchitectureConfig(codebyplanDir, config) {
|
|
34765
|
-
const filePath =
|
|
35512
|
+
const filePath = join37(codebyplanDir, "architecture.json");
|
|
34766
35513
|
await writeFile17(filePath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
34767
35514
|
}
|
|
34768
35515
|
function resolveGitSha(modulePath, cwd) {
|
|
@@ -34781,7 +35528,7 @@ function resolveGitSha(modulePath, cwd) {
|
|
|
34781
35528
|
}
|
|
34782
35529
|
async function discoverModulePaths(projectRoot) {
|
|
34783
35530
|
const paths = [];
|
|
34784
|
-
const workspacePath =
|
|
35531
|
+
const workspacePath = join37(projectRoot, "pnpm-workspace.yaml");
|
|
34785
35532
|
let patterns = [];
|
|
34786
35533
|
try {
|
|
34787
35534
|
const raw = await readFile21(workspacePath, "utf-8");
|
|
@@ -34808,7 +35555,7 @@ async function discoverModulePaths(projectRoot) {
|
|
|
34808
35555
|
for (const pattern of patterns) {
|
|
34809
35556
|
if (pattern.endsWith("/*")) {
|
|
34810
35557
|
const dir = pattern.slice(0, -2);
|
|
34811
|
-
const absDir =
|
|
35558
|
+
const absDir = join37(projectRoot, dir);
|
|
34812
35559
|
try {
|
|
34813
35560
|
if (existsSync11(absDir)) {
|
|
34814
35561
|
const entries = readdirSync4(absDir, { withFileTypes: true });
|
|
@@ -34821,7 +35568,7 @@ async function discoverModulePaths(projectRoot) {
|
|
|
34821
35568
|
} catch {
|
|
34822
35569
|
}
|
|
34823
35570
|
} else if (!pattern.includes("*")) {
|
|
34824
|
-
const absPath =
|
|
35571
|
+
const absPath = join37(projectRoot, pattern);
|
|
34825
35572
|
if (existsSync11(absPath)) {
|
|
34826
35573
|
paths.push(pattern);
|
|
34827
35574
|
}
|
|
@@ -34829,7 +35576,7 @@ async function discoverModulePaths(projectRoot) {
|
|
|
34829
35576
|
}
|
|
34830
35577
|
const crossCutting = ["supabase", ".github", "scripts"];
|
|
34831
35578
|
for (const dir of crossCutting) {
|
|
34832
|
-
const absPath =
|
|
35579
|
+
const absPath = join37(projectRoot, dir);
|
|
34833
35580
|
try {
|
|
34834
35581
|
if (existsSync11(absPath)) {
|
|
34835
35582
|
paths.push(dir);
|
|
@@ -35015,7 +35762,7 @@ async function runStamp(modulePath, sha, depthArg, projectRoot) {
|
|
|
35015
35762
|
}
|
|
35016
35763
|
await writeArchitectureConfig(codebyplanDir, config);
|
|
35017
35764
|
const stampedEntry = existingIndex >= 0 ? config.modules[existingIndex] : config.modules[config.modules.length - 1];
|
|
35018
|
-
const mapAbsPath =
|
|
35765
|
+
const mapAbsPath = join37(repoRoot, stampedEntry.map_file);
|
|
35019
35766
|
let mapContent = null;
|
|
35020
35767
|
try {
|
|
35021
35768
|
mapContent = await readFile21(mapAbsPath, "utf-8");
|
|
@@ -35221,18 +35968,18 @@ var init_worktree_port_resolver = __esm({
|
|
|
35221
35968
|
|
|
35222
35969
|
// src/lib/migrate-local-config.ts
|
|
35223
35970
|
import { mkdir as mkdir9, readFile as readFile22, unlink as unlink5, writeFile as writeFile18 } from "node:fs/promises";
|
|
35224
|
-
import { join as
|
|
35971
|
+
import { join as join38 } from "node:path";
|
|
35225
35972
|
function legacySharedPath(projectPath) {
|
|
35226
|
-
return
|
|
35973
|
+
return join38(projectPath, ".codebyplan.json");
|
|
35227
35974
|
}
|
|
35228
35975
|
function legacyLocalPath(projectPath) {
|
|
35229
|
-
return
|
|
35976
|
+
return join38(projectPath, ".codebyplan.local.json");
|
|
35230
35977
|
}
|
|
35231
35978
|
function newDirPath(projectPath) {
|
|
35232
|
-
return
|
|
35979
|
+
return join38(projectPath, ".codebyplan");
|
|
35233
35980
|
}
|
|
35234
35981
|
function sentinelPath(projectPath) {
|
|
35235
|
-
return
|
|
35982
|
+
return join38(projectPath, ".codebyplan", "repo.json");
|
|
35236
35983
|
}
|
|
35237
35984
|
async function statSafe(p) {
|
|
35238
35985
|
const { stat: stat3 } = await import("node:fs/promises");
|
|
@@ -35326,7 +36073,7 @@ async function runLocalMigration(projectPath) {
|
|
|
35326
36073
|
if ("organization_id" in cfg) repoJson.organization_id = cfg.organization_id;
|
|
35327
36074
|
if ("project_id" in cfg) repoJson.project_id = cfg.project_id;
|
|
35328
36075
|
await writeFile18(
|
|
35329
|
-
|
|
36076
|
+
join38(projectPath, ".codebyplan", "repo.json"),
|
|
35330
36077
|
JSON.stringify(repoJson, null, 2) + "\n",
|
|
35331
36078
|
"utf-8"
|
|
35332
36079
|
);
|
|
@@ -35339,7 +36086,7 @@ async function runLocalMigration(projectPath) {
|
|
|
35339
36086
|
if ("port_allocations" in cfg)
|
|
35340
36087
|
serverJson.port_allocations = cfg.port_allocations;
|
|
35341
36088
|
await writeFile18(
|
|
35342
|
-
|
|
36089
|
+
join38(projectPath, ".codebyplan", "server.json"),
|
|
35343
36090
|
JSON.stringify(serverJson, null, 2) + "\n",
|
|
35344
36091
|
"utf-8"
|
|
35345
36092
|
);
|
|
@@ -35348,7 +36095,7 @@ async function runLocalMigration(projectPath) {
|
|
|
35348
36095
|
if ("git_branch" in cfg) gitJson.git_branch = cfg.git_branch;
|
|
35349
36096
|
if ("branch_config" in cfg) gitJson.branch_config = cfg.branch_config;
|
|
35350
36097
|
await writeFile18(
|
|
35351
|
-
|
|
36098
|
+
join38(projectPath, ".codebyplan", "git.json"),
|
|
35352
36099
|
JSON.stringify(gitJson, null, 2) + "\n",
|
|
35353
36100
|
"utf-8"
|
|
35354
36101
|
);
|
|
@@ -35356,35 +36103,35 @@ async function runLocalMigration(projectPath) {
|
|
|
35356
36103
|
const shipmentJson = {};
|
|
35357
36104
|
if ("shipment" in cfg) shipmentJson.shipment = cfg.shipment;
|
|
35358
36105
|
await writeFile18(
|
|
35359
|
-
|
|
36106
|
+
join38(projectPath, ".codebyplan", "shipment.json"),
|
|
35360
36107
|
JSON.stringify(shipmentJson, null, 2) + "\n",
|
|
35361
36108
|
"utf-8"
|
|
35362
36109
|
);
|
|
35363
36110
|
filesChanged.push(".codebyplan/shipment.json");
|
|
35364
36111
|
const vendorJson = {};
|
|
35365
36112
|
await writeFile18(
|
|
35366
|
-
|
|
36113
|
+
join38(projectPath, ".codebyplan", "vendor.json"),
|
|
35367
36114
|
JSON.stringify(vendorJson, null, 2) + "\n",
|
|
35368
36115
|
"utf-8"
|
|
35369
36116
|
);
|
|
35370
36117
|
filesChanged.push(".codebyplan/vendor.json");
|
|
35371
36118
|
const e2eJson = {};
|
|
35372
36119
|
await writeFile18(
|
|
35373
|
-
|
|
36120
|
+
join38(projectPath, ".codebyplan", "e2e.json"),
|
|
35374
36121
|
JSON.stringify(e2eJson, null, 2) + "\n",
|
|
35375
36122
|
"utf-8"
|
|
35376
36123
|
);
|
|
35377
36124
|
filesChanged.push(".codebyplan/e2e.json");
|
|
35378
36125
|
const eslintJson = {};
|
|
35379
36126
|
await writeFile18(
|
|
35380
|
-
|
|
36127
|
+
join38(projectPath, ".codebyplan", "eslint.json"),
|
|
35381
36128
|
JSON.stringify(eslintJson, null, 2) + "\n",
|
|
35382
36129
|
"utf-8"
|
|
35383
36130
|
);
|
|
35384
36131
|
filesChanged.push(".codebyplan/eslint.json");
|
|
35385
36132
|
if (!deviceWrittenByHelper) {
|
|
35386
36133
|
await writeFile18(
|
|
35387
|
-
|
|
36134
|
+
join38(projectPath, ".codebyplan", "device.local.json"),
|
|
35388
36135
|
JSON.stringify({ device_id: deviceId }, null, 2) + "\n",
|
|
35389
36136
|
"utf-8"
|
|
35390
36137
|
);
|
|
@@ -35396,7 +36143,7 @@ async function runLocalMigration(projectPath) {
|
|
|
35396
36143
|
"Migration write incomplete: .codebyplan/repo.json was not persisted. Re-run migration to retry from a clean state."
|
|
35397
36144
|
);
|
|
35398
36145
|
}
|
|
35399
|
-
const gitignorePath =
|
|
36146
|
+
const gitignorePath = join38(projectPath, ".gitignore");
|
|
35400
36147
|
try {
|
|
35401
36148
|
const gitignoreContent = await readFile22(gitignorePath, "utf-8");
|
|
35402
36149
|
const legacyLine = ".codebyplan.local.json";
|
|
@@ -35460,7 +36207,7 @@ __export(config_exports, {
|
|
|
35460
36207
|
runConfigMigrate: () => runConfigMigrate
|
|
35461
36208
|
});
|
|
35462
36209
|
import { mkdir as mkdir10, readFile as readFile23, writeFile as writeFile19 } from "node:fs/promises";
|
|
35463
|
-
import { join as
|
|
36210
|
+
import { join as join39 } from "node:path";
|
|
35464
36211
|
async function runConfig() {
|
|
35465
36212
|
const flags = parseFlags(3);
|
|
35466
36213
|
const dryRun = hasFlag("dry-run", 3);
|
|
@@ -35493,7 +36240,7 @@ async function runConfig() {
|
|
|
35493
36240
|
console.log("\n Config complete.\n");
|
|
35494
36241
|
}
|
|
35495
36242
|
async function syncConfigToFile(repoId, projectPath, dryRun) {
|
|
35496
|
-
const codebyplanDir =
|
|
36243
|
+
const codebyplanDir = join39(projectPath, ".codebyplan");
|
|
35497
36244
|
const {
|
|
35498
36245
|
resolvedWorktreeId,
|
|
35499
36246
|
portAllocations,
|
|
@@ -35586,7 +36333,7 @@ async function syncConfigToFile(repoId, projectPath, dryRun) {
|
|
|
35586
36333
|
];
|
|
35587
36334
|
let anyUpdated = false;
|
|
35588
36335
|
for (const { name, payload, createOnly } of files) {
|
|
35589
|
-
const filePath =
|
|
36336
|
+
const filePath = join39(codebyplanDir, name);
|
|
35590
36337
|
const newJson = JSON.stringify(payload, null, 2) + "\n";
|
|
35591
36338
|
let currentJson = "";
|
|
35592
36339
|
try {
|
|
@@ -35606,7 +36353,7 @@ async function syncConfigToFile(repoId, projectPath, dryRun) {
|
|
|
35606
36353
|
async function readRepoConfig(projectPath) {
|
|
35607
36354
|
try {
|
|
35608
36355
|
const raw = await readFile23(
|
|
35609
|
-
|
|
36356
|
+
join39(projectPath, ".codebyplan", "repo.json"),
|
|
35610
36357
|
"utf-8"
|
|
35611
36358
|
);
|
|
35612
36359
|
return JSON.parse(raw);
|
|
@@ -35617,7 +36364,7 @@ async function readRepoConfig(projectPath) {
|
|
|
35617
36364
|
async function readServerConfig(projectPath) {
|
|
35618
36365
|
try {
|
|
35619
36366
|
const raw = await readFile23(
|
|
35620
|
-
|
|
36367
|
+
join39(projectPath, ".codebyplan", "server.json"),
|
|
35621
36368
|
"utf-8"
|
|
35622
36369
|
);
|
|
35623
36370
|
return JSON.parse(raw);
|
|
@@ -35628,7 +36375,7 @@ async function readServerConfig(projectPath) {
|
|
|
35628
36375
|
async function readGitConfig2(projectPath) {
|
|
35629
36376
|
try {
|
|
35630
36377
|
const raw = await readFile23(
|
|
35631
|
-
|
|
36378
|
+
join39(projectPath, ".codebyplan", "git.json"),
|
|
35632
36379
|
"utf-8"
|
|
35633
36380
|
);
|
|
35634
36381
|
return JSON.parse(raw);
|
|
@@ -35639,7 +36386,7 @@ async function readGitConfig2(projectPath) {
|
|
|
35639
36386
|
async function readShipmentConfig2(projectPath) {
|
|
35640
36387
|
try {
|
|
35641
36388
|
const raw = await readFile23(
|
|
35642
|
-
|
|
36389
|
+
join39(projectPath, ".codebyplan", "shipment.json"),
|
|
35643
36390
|
"utf-8"
|
|
35644
36391
|
);
|
|
35645
36392
|
return JSON.parse(raw);
|
|
@@ -35650,7 +36397,7 @@ async function readShipmentConfig2(projectPath) {
|
|
|
35650
36397
|
async function readVendorConfig(projectPath) {
|
|
35651
36398
|
try {
|
|
35652
36399
|
const raw = await readFile23(
|
|
35653
|
-
|
|
36400
|
+
join39(projectPath, ".codebyplan", "vendor.json"),
|
|
35654
36401
|
"utf-8"
|
|
35655
36402
|
);
|
|
35656
36403
|
return JSON.parse(raw);
|
|
@@ -35661,7 +36408,7 @@ async function readVendorConfig(projectPath) {
|
|
|
35661
36408
|
async function readE2eConfig2(projectPath) {
|
|
35662
36409
|
try {
|
|
35663
36410
|
const raw = await readFile23(
|
|
35664
|
-
|
|
36411
|
+
join39(projectPath, ".codebyplan", "e2e.json"),
|
|
35665
36412
|
"utf-8"
|
|
35666
36413
|
);
|
|
35667
36414
|
return JSON.parse(raw);
|
|
@@ -35672,7 +36419,7 @@ async function readE2eConfig2(projectPath) {
|
|
|
35672
36419
|
async function readServerLocalConfig(projectPath) {
|
|
35673
36420
|
try {
|
|
35674
36421
|
const raw = await readFile23(
|
|
35675
|
-
|
|
36422
|
+
join39(projectPath, ".codebyplan", "server.local.json"),
|
|
35676
36423
|
"utf-8"
|
|
35677
36424
|
);
|
|
35678
36425
|
return JSON.parse(raw);
|
|
@@ -35745,7 +36492,7 @@ var init_config = __esm({
|
|
|
35745
36492
|
|
|
35746
36493
|
// src/lib/server-detect.ts
|
|
35747
36494
|
import { readFile as readFile24, readdir as readdir5, access as access6 } from "node:fs/promises";
|
|
35748
|
-
import { join as
|
|
36495
|
+
import { join as join40 } from "node:path";
|
|
35749
36496
|
async function fileExists4(filePath) {
|
|
35750
36497
|
try {
|
|
35751
36498
|
await access6(filePath);
|
|
@@ -35756,8 +36503,8 @@ async function fileExists4(filePath) {
|
|
|
35756
36503
|
}
|
|
35757
36504
|
function detectPackageManager3(dir) {
|
|
35758
36505
|
return (async () => {
|
|
35759
|
-
if (await fileExists4(
|
|
35760
|
-
if (await fileExists4(
|
|
36506
|
+
if (await fileExists4(join40(dir, "pnpm-lock.yaml"))) return "pnpm";
|
|
36507
|
+
if (await fileExists4(join40(dir, "yarn.lock"))) return "yarn";
|
|
35761
36508
|
return "npm";
|
|
35762
36509
|
})();
|
|
35763
36510
|
}
|
|
@@ -35789,12 +36536,12 @@ function detectPortFromScripts(pkg) {
|
|
|
35789
36536
|
return null;
|
|
35790
36537
|
}
|
|
35791
36538
|
async function isMonorepo(dir) {
|
|
35792
|
-
return await fileExists4(
|
|
36539
|
+
return await fileExists4(join40(dir, "turbo.json")) || await fileExists4(join40(dir, "pnpm-workspace.yaml"));
|
|
35793
36540
|
}
|
|
35794
36541
|
async function detectServers(projectPath) {
|
|
35795
36542
|
let pkg;
|
|
35796
36543
|
try {
|
|
35797
|
-
const raw = await readFile24(
|
|
36544
|
+
const raw = await readFile24(join40(projectPath, "package.json"), "utf-8");
|
|
35798
36545
|
pkg = JSON.parse(raw);
|
|
35799
36546
|
} catch {
|
|
35800
36547
|
return {
|
|
@@ -35810,13 +36557,13 @@ async function detectServers(projectPath) {
|
|
|
35810
36557
|
const mono = await isMonorepo(projectPath);
|
|
35811
36558
|
const servers = [];
|
|
35812
36559
|
if (mono) {
|
|
35813
|
-
const appsDir =
|
|
36560
|
+
const appsDir = join40(projectPath, "apps");
|
|
35814
36561
|
try {
|
|
35815
36562
|
const entries = await readdir5(appsDir, { withFileTypes: true });
|
|
35816
36563
|
const sorted = [...entries].sort((a, b) => a.name.localeCompare(b.name));
|
|
35817
36564
|
for (const entry of sorted) {
|
|
35818
36565
|
if (!entry.isDirectory()) continue;
|
|
35819
|
-
const appPkgPath =
|
|
36566
|
+
const appPkgPath = join40(appsDir, entry.name, "package.json");
|
|
35820
36567
|
try {
|
|
35821
36568
|
const appRaw = await readFile24(appPkgPath, "utf-8");
|
|
35822
36569
|
const appPkg = JSON.parse(appRaw);
|
|
@@ -35982,7 +36729,7 @@ __export(ports_exports, {
|
|
|
35982
36729
|
runPorts: () => runPorts
|
|
35983
36730
|
});
|
|
35984
36731
|
import { mkdir as mkdir11, readFile as readFile26, writeFile as writeFile20 } from "node:fs/promises";
|
|
35985
|
-
import { join as
|
|
36732
|
+
import { join as join41 } from "node:path";
|
|
35986
36733
|
function printDetectionResult(result, projectPath) {
|
|
35987
36734
|
console.log(`
|
|
35988
36735
|
CodeByPlan Ports - List`);
|
|
@@ -36138,8 +36885,8 @@ async function writeServerLocalConfig(repoId, projectPath, dryRun) {
|
|
|
36138
36885
|
// and ServerLocalConfig.port_allocations is typed the same — honest end-to-end.
|
|
36139
36886
|
port_allocations: portAllocations
|
|
36140
36887
|
};
|
|
36141
|
-
const codebyplanDir =
|
|
36142
|
-
const filePath =
|
|
36888
|
+
const codebyplanDir = join41(projectPath, ".codebyplan");
|
|
36889
|
+
const filePath = join41(codebyplanDir, "server.local.json");
|
|
36143
36890
|
const newJson = JSON.stringify(payload, null, 2) + "\n";
|
|
36144
36891
|
let currentJson = "";
|
|
36145
36892
|
try {
|
|
@@ -36161,8 +36908,8 @@ async function writeServerLocalConfig(repoId, projectPath, dryRun) {
|
|
|
36161
36908
|
);
|
|
36162
36909
|
}
|
|
36163
36910
|
async function provisionE2eEnv(projectPath, dryRun) {
|
|
36164
|
-
const relSource =
|
|
36165
|
-
const sourcePath =
|
|
36911
|
+
const relSource = join41("apps", "web", ".env.local");
|
|
36912
|
+
const sourcePath = join41(projectPath, relSource);
|
|
36166
36913
|
let sourceRaw;
|
|
36167
36914
|
try {
|
|
36168
36915
|
sourceRaw = await readFile26(sourcePath, "utf-8");
|
|
@@ -36194,8 +36941,8 @@ async function provisionE2eEnv(projectPath, dryRun) {
|
|
|
36194
36941
|
);
|
|
36195
36942
|
return;
|
|
36196
36943
|
}
|
|
36197
|
-
const codebyplanDir =
|
|
36198
|
-
const filePath =
|
|
36944
|
+
const codebyplanDir = join41(projectPath, ".codebyplan");
|
|
36945
|
+
const filePath = join41(codebyplanDir, "e2e.env");
|
|
36199
36946
|
const newContent = lines.join("\n") + "\n";
|
|
36200
36947
|
let currentContent = "";
|
|
36201
36948
|
try {
|
|
@@ -36480,7 +37227,7 @@ __export(docs_exports, {
|
|
|
36480
37227
|
});
|
|
36481
37228
|
import { existsSync as existsSync13 } from "node:fs";
|
|
36482
37229
|
import { mkdir as mkdir12, readFile as readFile27, readdir as readdir6, rm as rm2, writeFile as writeFile21 } from "node:fs/promises";
|
|
36483
|
-
import { dirname as dirname14, isAbsolute as isAbsolute2, join as
|
|
37230
|
+
import { dirname as dirname14, isAbsolute as isAbsolute2, join as join42, relative as relative7, sep as sep2 } from "node:path";
|
|
36484
37231
|
function selectDependencies(deps) {
|
|
36485
37232
|
const byName = /* @__PURE__ */ new Map();
|
|
36486
37233
|
for (const dep of deps) {
|
|
@@ -36534,12 +37281,12 @@ async function mapWithConcurrency(items, limit, fn) {
|
|
|
36534
37281
|
}
|
|
36535
37282
|
async function resolveExactVersion(projectPath, dep) {
|
|
36536
37283
|
const candidateDirs = [projectPath];
|
|
36537
|
-
const sourceDir =
|
|
37284
|
+
const sourceDir = join42(projectPath, dirname14(dep.sourcePath));
|
|
36538
37285
|
if (sourceDir !== projectPath) candidateDirs.push(sourceDir);
|
|
36539
37286
|
for (const base of candidateDirs) {
|
|
36540
37287
|
try {
|
|
36541
37288
|
const raw = await readFile27(
|
|
36542
|
-
|
|
37289
|
+
join42(base, "node_modules", dep.name, "package.json"),
|
|
36543
37290
|
"utf-8"
|
|
36544
37291
|
);
|
|
36545
37292
|
const pkg = JSON.parse(raw);
|
|
@@ -36554,7 +37301,7 @@ async function resolveExactVersion(projectPath, dep) {
|
|
|
36554
37301
|
async function readVendorDocsPath(projectPath) {
|
|
36555
37302
|
try {
|
|
36556
37303
|
const raw = await readFile27(
|
|
36557
|
-
|
|
37304
|
+
join42(projectPath, ".codebyplan", "vendor.json"),
|
|
36558
37305
|
"utf-8"
|
|
36559
37306
|
);
|
|
36560
37307
|
const parsed = JSON.parse(raw);
|
|
@@ -36567,7 +37314,7 @@ async function readVendorDocsPath(projectPath) {
|
|
|
36567
37314
|
}
|
|
36568
37315
|
async function resolveDocsDir(projectPath, flags) {
|
|
36569
37316
|
const configured = flags["dir"] ?? await readVendorDocsPath(projectPath) ?? DEFAULT_DOCS_DIR;
|
|
36570
|
-
const absDir = isAbsolute2(configured) ? configured :
|
|
37317
|
+
const absDir = isAbsolute2(configured) ? configured : join42(projectPath, configured);
|
|
36571
37318
|
const rel = relative7(projectPath, absDir);
|
|
36572
37319
|
const relDir = rel === "" || rel.startsWith("..") ? null : rel.split(sep2).join("/");
|
|
36573
37320
|
return { absDir, relDir };
|
|
@@ -36576,7 +37323,7 @@ async function readDocsLock(absDir) {
|
|
|
36576
37323
|
const empty = { generated_at: "", libraries: {} };
|
|
36577
37324
|
let raw;
|
|
36578
37325
|
try {
|
|
36579
|
-
raw = await readFile27(
|
|
37326
|
+
raw = await readFile27(join42(absDir, LOCK_FILE), "utf-8");
|
|
36580
37327
|
} catch {
|
|
36581
37328
|
return empty;
|
|
36582
37329
|
}
|
|
@@ -36672,7 +37419,7 @@ function buildTopIndex(outcomes) {
|
|
|
36672
37419
|
}
|
|
36673
37420
|
async function ensureDocsGitignoreEntry(projectPath, relDir, dryRun) {
|
|
36674
37421
|
const entry = `/${relDir}/`;
|
|
36675
|
-
const gitignorePath =
|
|
37422
|
+
const gitignorePath = join42(projectPath, ".gitignore");
|
|
36676
37423
|
let existing = "";
|
|
36677
37424
|
try {
|
|
36678
37425
|
existing = await readFile27(gitignorePath, "utf-8");
|
|
@@ -36695,7 +37442,7 @@ async function markUncovered(dep, exactVersion, ctx) {
|
|
|
36695
37442
|
console.log(
|
|
36696
37443
|
` uncovered ${dep.name}@${exactVersion || "?"} \u2014 no docs in the library mirror`
|
|
36697
37444
|
);
|
|
36698
|
-
const libPath =
|
|
37445
|
+
const libPath = join42(ctx.absDir, libDirName(dep.name));
|
|
36699
37446
|
if (existsSync13(libPath)) {
|
|
36700
37447
|
if (ctx.dryRun) {
|
|
36701
37448
|
console.log(` would remove stale mirror dir ${libPath}`);
|
|
@@ -36748,14 +37495,14 @@ async function syncOneLibrary(dep, ctx) {
|
|
|
36748
37495
|
}
|
|
36749
37496
|
}
|
|
36750
37497
|
const lockEntry = ctx.lock.libraries[dep.name];
|
|
36751
|
-
const libPath =
|
|
36752
|
-
const versionPath =
|
|
37498
|
+
const libPath = join42(ctx.absDir, libDirName(dep.name));
|
|
37499
|
+
const versionPath = join42(libPath, manifest.resolved_version);
|
|
36753
37500
|
if (manifestMatchesLock(manifest, lockEntry)) {
|
|
36754
37501
|
console.log(` unchanged ${dep.name}@${manifest.resolved_version}`);
|
|
36755
|
-
if (!ctx.dryRun && !existsSync13(
|
|
37502
|
+
if (!ctx.dryRun && !existsSync13(join42(libPath, "INDEX.md"))) {
|
|
36756
37503
|
await mkdir12(libPath, { recursive: true });
|
|
36757
37504
|
await writeFile21(
|
|
36758
|
-
|
|
37505
|
+
join42(libPath, "INDEX.md"),
|
|
36759
37506
|
buildLibIndex(dep.name, manifest),
|
|
36760
37507
|
"utf-8"
|
|
36761
37508
|
);
|
|
@@ -36777,7 +37524,7 @@ async function syncOneLibrary(dep, ctx) {
|
|
|
36777
37524
|
);
|
|
36778
37525
|
continue;
|
|
36779
37526
|
}
|
|
36780
|
-
const target =
|
|
37527
|
+
const target = join42(versionPath, rel);
|
|
36781
37528
|
if (sameVersionLockFiles[file.path] === file.content_hash && existsSync13(target)) {
|
|
36782
37529
|
continue;
|
|
36783
37530
|
}
|
|
@@ -36795,7 +37542,7 @@ async function syncOneLibrary(dep, ctx) {
|
|
|
36795
37542
|
const rel = sanitizeDocPath(lockedPath);
|
|
36796
37543
|
if (rel === null) continue;
|
|
36797
37544
|
removedFiles++;
|
|
36798
|
-
if (!ctx.dryRun) await rm2(
|
|
37545
|
+
if (!ctx.dryRun) await rm2(join42(versionPath, rel), { force: true });
|
|
36799
37546
|
}
|
|
36800
37547
|
}
|
|
36801
37548
|
let removedVersionDirs = 0;
|
|
@@ -36810,13 +37557,13 @@ async function syncOneLibrary(dep, ctx) {
|
|
|
36810
37557
|
}
|
|
36811
37558
|
removedVersionDirs++;
|
|
36812
37559
|
if (!ctx.dryRun) {
|
|
36813
|
-
await rm2(
|
|
37560
|
+
await rm2(join42(libPath, entry.name), { recursive: true, force: true });
|
|
36814
37561
|
}
|
|
36815
37562
|
}
|
|
36816
37563
|
if (!ctx.dryRun) {
|
|
36817
37564
|
await mkdir12(libPath, { recursive: true });
|
|
36818
37565
|
await writeFile21(
|
|
36819
|
-
|
|
37566
|
+
join42(libPath, "INDEX.md"),
|
|
36820
37567
|
buildLibIndex(dep.name, manifest),
|
|
36821
37568
|
"utf-8"
|
|
36822
37569
|
);
|
|
@@ -36870,7 +37617,7 @@ async function runDocsSync() {
|
|
|
36870
37617
|
);
|
|
36871
37618
|
if (!dryRun) {
|
|
36872
37619
|
await mkdir12(absDir, { recursive: true });
|
|
36873
|
-
await writeFile21(
|
|
37620
|
+
await writeFile21(join42(absDir, "INDEX.md"), buildTopIndex(outcomes), "utf-8");
|
|
36874
37621
|
const libraries = {};
|
|
36875
37622
|
for (const o of outcomes) {
|
|
36876
37623
|
if (o.kind === "synced" || o.kind === "unchanged") {
|
|
@@ -36896,7 +37643,7 @@ async function runDocsSync() {
|
|
|
36896
37643
|
libraries: sortedLibraries
|
|
36897
37644
|
};
|
|
36898
37645
|
await writeFile21(
|
|
36899
|
-
|
|
37646
|
+
join42(absDir, LOCK_FILE),
|
|
36900
37647
|
JSON.stringify(newLock, null, 2) + "\n",
|
|
36901
37648
|
"utf-8"
|
|
36902
37649
|
);
|
|
@@ -36938,7 +37685,7 @@ async function countFilesRecursively(dirPath) {
|
|
|
36938
37685
|
let count = 0;
|
|
36939
37686
|
for (const entry of entries) {
|
|
36940
37687
|
if (entry.isDirectory()) {
|
|
36941
|
-
count += await countFilesRecursively(
|
|
37688
|
+
count += await countFilesRecursively(join42(dirPath, entry.name));
|
|
36942
37689
|
} else if (entry.isFile()) {
|
|
36943
37690
|
count++;
|
|
36944
37691
|
}
|
|
@@ -36955,7 +37702,7 @@ async function runDocsStatus() {
|
|
|
36955
37702
|
`);
|
|
36956
37703
|
let raw;
|
|
36957
37704
|
try {
|
|
36958
|
-
raw = await readFile27(
|
|
37705
|
+
raw = await readFile27(join42(absDir, LOCK_FILE), "utf-8");
|
|
36959
37706
|
} catch {
|
|
36960
37707
|
console.log(
|
|
36961
37708
|
` No ${LOCK_FILE} found \u2014 run \`codebyplan docs sync\` first.
|
|
@@ -36984,7 +37731,7 @@ async function runDocsStatus() {
|
|
|
36984
37731
|
let outOfSync = 0;
|
|
36985
37732
|
for (const name of names) {
|
|
36986
37733
|
const entry = lock.libraries[name];
|
|
36987
|
-
const versionPath =
|
|
37734
|
+
const versionPath = join42(absDir, libDirName(name), entry.resolved_version);
|
|
36988
37735
|
const expected = Object.keys(entry.files).length;
|
|
36989
37736
|
if (!existsSync13(versionPath)) {
|
|
36990
37737
|
outOfSync++;
|
|
@@ -37071,8 +37818,8 @@ var init_docs = __esm({
|
|
|
37071
37818
|
});
|
|
37072
37819
|
|
|
37073
37820
|
// src/lib/check-baseline.ts
|
|
37074
|
-
import { readFileSync as readFileSync12, writeFileSync as
|
|
37075
|
-
import { join as
|
|
37821
|
+
import { readFileSync as readFileSync12, writeFileSync as writeFileSync8 } from "node:fs";
|
|
37822
|
+
import { join as join43 } from "node:path";
|
|
37076
37823
|
function emptyBaseline() {
|
|
37077
37824
|
return {
|
|
37078
37825
|
lint: { known_failing: [] },
|
|
@@ -37082,7 +37829,7 @@ function emptyBaseline() {
|
|
|
37082
37829
|
};
|
|
37083
37830
|
}
|
|
37084
37831
|
function loadBaseline(projectRoot) {
|
|
37085
|
-
const filePath =
|
|
37832
|
+
const filePath = join43(projectRoot, BASELINE_FILENAME);
|
|
37086
37833
|
try {
|
|
37087
37834
|
const raw = readFileSync12(filePath, "utf-8");
|
|
37088
37835
|
const parsed = JSON.parse(raw);
|
|
@@ -37106,8 +37853,8 @@ function loadBaseline(projectRoot) {
|
|
|
37106
37853
|
}
|
|
37107
37854
|
}
|
|
37108
37855
|
function saveBaseline(projectRoot, baseline) {
|
|
37109
|
-
const filePath =
|
|
37110
|
-
|
|
37856
|
+
const filePath = join43(projectRoot, BASELINE_FILENAME);
|
|
37857
|
+
writeFileSync8(filePath, JSON.stringify(baseline, null, 2) + "\n", "utf-8");
|
|
37111
37858
|
}
|
|
37112
37859
|
function diffBaseline(check, currentFailingPackages, baseline) {
|
|
37113
37860
|
const knownFailing = new Set(baseline[check].known_failing);
|
|
@@ -37156,7 +37903,7 @@ var init_check_baseline = __esm({
|
|
|
37156
37903
|
|
|
37157
37904
|
// src/lib/check.ts
|
|
37158
37905
|
import { readFileSync as readFileSync13, existsSync as existsSync14 } from "node:fs";
|
|
37159
|
-
import { join as
|
|
37906
|
+
import { join as join44 } from "node:path";
|
|
37160
37907
|
import { spawnSync as spawnSync13 } from "node:child_process";
|
|
37161
37908
|
function hasSentinelValue(arrays) {
|
|
37162
37909
|
const SENTINELS = /* @__PURE__ */ new Set([
|
|
@@ -37224,9 +37971,9 @@ function parseFailingPackagesFromSummary(summaryPath) {
|
|
|
37224
37971
|
return Array.from(failing).sort();
|
|
37225
37972
|
}
|
|
37226
37973
|
function resolveTurboBin(projectRoot) {
|
|
37227
|
-
const localBin =
|
|
37974
|
+
const localBin = join44(projectRoot, "node_modules", ".bin", "turbo");
|
|
37228
37975
|
if (existsSync14(localBin)) return localBin;
|
|
37229
|
-
const workspaceRootBin =
|
|
37976
|
+
const workspaceRootBin = join44(
|
|
37230
37977
|
projectRoot,
|
|
37231
37978
|
"..",
|
|
37232
37979
|
"..",
|
|
@@ -39365,7 +40112,7 @@ __export(generate_exports, {
|
|
|
39365
40112
|
runGenerate: () => runGenerate
|
|
39366
40113
|
});
|
|
39367
40114
|
import { readFile as readFile28, mkdir as mkdir13, writeFile as writeFile22 } from "node:fs/promises";
|
|
39368
|
-
import { join as
|
|
40115
|
+
import { join as join51, resolve as resolve11 } from "node:path";
|
|
39369
40116
|
async function readJsonFile4(filePath) {
|
|
39370
40117
|
try {
|
|
39371
40118
|
const raw = await readFile28(filePath, "utf-8");
|
|
@@ -39376,7 +40123,7 @@ async function readJsonFile4(filePath) {
|
|
|
39376
40123
|
}
|
|
39377
40124
|
async function readPkgName(absPath) {
|
|
39378
40125
|
try {
|
|
39379
|
-
const raw = await readFile28(
|
|
40126
|
+
const raw = await readFile28(join51(absPath, "package.json"), "utf-8");
|
|
39380
40127
|
const pkg = JSON.parse(raw);
|
|
39381
40128
|
return typeof pkg.name === "string" ? pkg.name : null;
|
|
39382
40129
|
} catch {
|
|
@@ -39390,7 +40137,7 @@ async function runGenerate(opts) {
|
|
|
39390
40137
|
const rootDir = resolve11(projectDir);
|
|
39391
40138
|
let packageManager;
|
|
39392
40139
|
try {
|
|
39393
|
-
const raw = await readFile28(
|
|
40140
|
+
const raw = await readFile28(join51(rootDir, "package.json"), "utf-8");
|
|
39394
40141
|
const pkg = JSON.parse(raw);
|
|
39395
40142
|
if (typeof pkg.packageManager === "string") {
|
|
39396
40143
|
packageManager = pkg.packageManager;
|
|
@@ -39398,7 +40145,7 @@ async function runGenerate(opts) {
|
|
|
39398
40145
|
} catch {
|
|
39399
40146
|
}
|
|
39400
40147
|
const serverJson = await readJsonFile4(
|
|
39401
|
-
|
|
40148
|
+
join51(rootDir, ".codebyplan", "server.json")
|
|
39402
40149
|
);
|
|
39403
40150
|
const ports = [];
|
|
39404
40151
|
for (const alloc of serverJson?.port_allocations ?? []) {
|
|
@@ -39411,7 +40158,7 @@ async function runGenerate(opts) {
|
|
|
39411
40158
|
}
|
|
39412
40159
|
}
|
|
39413
40160
|
const gitJson = await readJsonFile4(
|
|
39414
|
-
|
|
40161
|
+
join51(rootDir, ".codebyplan", "git.json")
|
|
39415
40162
|
);
|
|
39416
40163
|
const branchModel = gitJson?.branch_config?.production ? {
|
|
39417
40164
|
production: gitJson.branch_config.production,
|
|
@@ -39420,7 +40167,7 @@ async function runGenerate(opts) {
|
|
|
39420
40167
|
)
|
|
39421
40168
|
} : void 0;
|
|
39422
40169
|
const shipmentJson = await readJsonFile4(
|
|
39423
|
-
|
|
40170
|
+
join51(rootDir, ".codebyplan", "shipment.json")
|
|
39424
40171
|
);
|
|
39425
40172
|
const shipmentSurfaces = [];
|
|
39426
40173
|
const rawSurfaces = shipmentJson?.shipment?.surfaces ?? shipmentJson?.surfaces ?? {};
|
|
@@ -39491,7 +40238,7 @@ async function runGenerate(opts) {
|
|
|
39491
40238
|
const structureMdContent = generateStructureMd(config);
|
|
39492
40239
|
const agentsContent = generateAgentsMd(structureMdContent);
|
|
39493
40240
|
if (check) {
|
|
39494
|
-
const agentsMdPath2 =
|
|
40241
|
+
const agentsMdPath2 = join51(rootDir, "AGENTS.md");
|
|
39495
40242
|
let existingAgents = null;
|
|
39496
40243
|
try {
|
|
39497
40244
|
existingAgents = await readFile28(agentsMdPath2, "utf-8");
|
|
@@ -39530,13 +40277,13 @@ async function runGenerate(opts) {
|
|
|
39530
40277
|
process.stdout.write(agentsContent);
|
|
39531
40278
|
return;
|
|
39532
40279
|
}
|
|
39533
|
-
const outputDir =
|
|
40280
|
+
const outputDir = join51(rootDir, ".claude", "generated");
|
|
39534
40281
|
await mkdir13(outputDir, { recursive: true });
|
|
39535
|
-
const outputPath =
|
|
40282
|
+
const outputPath = join51(outputDir, "structure.md");
|
|
39536
40283
|
await writeFile22(outputPath, structureMdContent, "utf-8");
|
|
39537
40284
|
process.stdout.write(`Wrote: .claude/generated/structure.md
|
|
39538
40285
|
`);
|
|
39539
|
-
const agentsMdPath =
|
|
40286
|
+
const agentsMdPath = join51(rootDir, "AGENTS.md");
|
|
39540
40287
|
let existingAgentsContent = null;
|
|
39541
40288
|
try {
|
|
39542
40289
|
existingAgentsContent = await readFile28(agentsMdPath, "utf-8");
|
|
@@ -39568,7 +40315,7 @@ __export(readme_exports, {
|
|
|
39568
40315
|
runReadmeCommand: () => runReadmeCommand
|
|
39569
40316
|
});
|
|
39570
40317
|
import { readFile as readFile29, writeFile as writeFile23 } from "node:fs/promises";
|
|
39571
|
-
import { join as
|
|
40318
|
+
import { join as join52, resolve as resolve12, relative as relative9 } from "node:path";
|
|
39572
40319
|
async function readJsonFile5(filePath) {
|
|
39573
40320
|
try {
|
|
39574
40321
|
const raw = await readFile29(filePath, "utf-8");
|
|
@@ -39640,7 +40387,7 @@ async function discoverUnits(rootDir, rootPkgJson) {
|
|
|
39640
40387
|
const discovered = await discoverMonorepoApps(rootDir);
|
|
39641
40388
|
for (const app of discovered) {
|
|
39642
40389
|
const pkgJson = await readJsonFile5(
|
|
39643
|
-
|
|
40390
|
+
join52(app.absPath, "package.json")
|
|
39644
40391
|
);
|
|
39645
40392
|
pkgJsonByPath.set(app.absPath, pkgJson);
|
|
39646
40393
|
allPackages.push({
|
|
@@ -39666,7 +40413,7 @@ async function runReadme(opts) {
|
|
|
39666
40413
|
const init = opts.init ?? opts["init"] ?? false;
|
|
39667
40414
|
const rootDir = resolve12(projectDir);
|
|
39668
40415
|
const rootPkgJson = await readJsonFile5(
|
|
39669
|
-
|
|
40416
|
+
join52(rootDir, "package.json")
|
|
39670
40417
|
);
|
|
39671
40418
|
const { units, allPackages, pkgJsonByPath } = await discoverUnits(
|
|
39672
40419
|
rootDir,
|
|
@@ -39675,8 +40422,8 @@ async function runReadme(opts) {
|
|
|
39675
40422
|
const driftUnits = [];
|
|
39676
40423
|
const missingUnits = [];
|
|
39677
40424
|
for (const unit of units) {
|
|
39678
|
-
const readmePath =
|
|
39679
|
-
const relPath = unit.isRoot ? "README.md" :
|
|
40425
|
+
const readmePath = join52(unit.absPath, "README.md");
|
|
40426
|
+
const relPath = unit.isRoot ? "README.md" : join52(relative9(rootDir, unit.absPath), "README.md");
|
|
39680
40427
|
let existingContent = null;
|
|
39681
40428
|
try {
|
|
39682
40429
|
existingContent = await readFile29(readmePath, "utf-8");
|
|
@@ -39867,7 +40614,7 @@ import {
|
|
|
39867
40614
|
readdir as readdir7
|
|
39868
40615
|
} from "node:fs/promises";
|
|
39869
40616
|
import { existsSync as existsSync21 } from "node:fs";
|
|
39870
|
-
import { join as
|
|
40617
|
+
import { join as join53, resolve as resolve13, dirname as dirname16, sep as sep4 } from "node:path";
|
|
39871
40618
|
import { homedir as homedir8 } from "node:os";
|
|
39872
40619
|
function encodeProjectPath(absPath) {
|
|
39873
40620
|
return resolve13(absPath).replace(/[/\\]/g, "-");
|
|
@@ -39878,7 +40625,7 @@ function resolveAutoMemoryDir(opts) {
|
|
|
39878
40625
|
}
|
|
39879
40626
|
const projectDir = opts.projectDir ?? process.cwd();
|
|
39880
40627
|
const encoded = encodeProjectPath(projectDir);
|
|
39881
|
-
return
|
|
40628
|
+
return join53(homedir8(), ".claude", "projects", encoded, "memory");
|
|
39882
40629
|
}
|
|
39883
40630
|
function parseFrontmatter(content) {
|
|
39884
40631
|
content = content.replace(/\r\n/g, "\n");
|
|
@@ -39944,7 +40691,7 @@ async function inventoryFiles(dir) {
|
|
|
39944
40691
|
}
|
|
39945
40692
|
const results = [];
|
|
39946
40693
|
for (const filename of filenames) {
|
|
39947
|
-
const sourcePath =
|
|
40694
|
+
const sourcePath = join53(dir, filename);
|
|
39948
40695
|
let raw;
|
|
39949
40696
|
try {
|
|
39950
40697
|
raw = await readFile30(sourcePath, "utf-8");
|
|
@@ -40033,8 +40780,8 @@ async function applyPlan(plan, opts) {
|
|
|
40033
40780
|
if (entry.suggested_action !== "keep") continue;
|
|
40034
40781
|
if (!entry.suggested_target?.startsWith("nested:")) continue;
|
|
40035
40782
|
const relPath = entry.suggested_target.slice("nested:".length);
|
|
40036
|
-
const targetDir = resolve13(
|
|
40037
|
-
const targetFile =
|
|
40783
|
+
const targetDir = resolve13(join53(projectDir, relPath));
|
|
40784
|
+
const targetFile = join53(targetDir, "CLAUDE.md");
|
|
40038
40785
|
if (!targetDir.startsWith(resolve13(projectDir) + sep4)) {
|
|
40039
40786
|
process.stderr.write(
|
|
40040
40787
|
`migrate-memory: skipping unsafe suggested_target "${entry.suggested_target}" \u2014 resolves outside projectDir
|
|
@@ -40084,7 +40831,7 @@ ${anchor}
|
|
|
40084
40831
|
);
|
|
40085
40832
|
}
|
|
40086
40833
|
}
|
|
40087
|
-
const rootClaudeMd =
|
|
40834
|
+
const rootClaudeMd = join53(projectDir, ".claude", "CLAUDE.md");
|
|
40088
40835
|
if (dryRun) {
|
|
40089
40836
|
process.stdout.write(
|
|
40090
40837
|
`[dry-run] Would ensure ${rootClaudeMd} contains: ${IMPORT_LINE}
|
|
@@ -40128,8 +40875,8 @@ ${IMPORT_LINE}
|
|
|
40128
40875
|
} catch {
|
|
40129
40876
|
}
|
|
40130
40877
|
}
|
|
40131
|
-
const memoryMd =
|
|
40132
|
-
const safeRmdirBase =
|
|
40878
|
+
const memoryMd = join53(plan.auto_memory_dir, "MEMORY.md");
|
|
40879
|
+
const safeRmdirBase = join53(homedir8(), ".claude", "projects");
|
|
40133
40880
|
if (dryRun) {
|
|
40134
40881
|
process.stdout.write(`[dry-run] Would delete MEMORY.md: ${memoryMd}
|
|
40135
40882
|
`);
|
|
@@ -40253,7 +41000,7 @@ var init_migrate_memory = __esm({
|
|
|
40253
41000
|
|
|
40254
41001
|
// src/lib/claude-mode-audit.ts
|
|
40255
41002
|
import { readdirSync as readdirSync7, readFileSync as readFileSync19, existsSync as existsSync22 } from "node:fs";
|
|
40256
|
-
import { join as
|
|
41003
|
+
import { join as join54, basename as basename3 } from "node:path";
|
|
40257
41004
|
function parseFrontmatter2(content) {
|
|
40258
41005
|
const match = /^---\r?\n([\s\S]*?)\r?\n---/.exec(content);
|
|
40259
41006
|
if (!match) return {};
|
|
@@ -40330,19 +41077,19 @@ function auditSkill(filePath) {
|
|
|
40330
41077
|
}
|
|
40331
41078
|
function auditMode(templatesDir) {
|
|
40332
41079
|
const entries = [];
|
|
40333
|
-
const agentsDir =
|
|
41080
|
+
const agentsDir = join54(templatesDir, "agents");
|
|
40334
41081
|
if (existsSync22(agentsDir)) {
|
|
40335
41082
|
const agentFiles = readdirSync7(agentsDir).filter((f) => f.endsWith(".md")).sort();
|
|
40336
41083
|
for (const f of agentFiles) {
|
|
40337
|
-
entries.push(auditAgent(
|
|
41084
|
+
entries.push(auditAgent(join54(agentsDir, f)));
|
|
40338
41085
|
}
|
|
40339
41086
|
}
|
|
40340
|
-
const skillsDir =
|
|
41087
|
+
const skillsDir = join54(templatesDir, "skills");
|
|
40341
41088
|
if (existsSync22(skillsDir)) {
|
|
40342
41089
|
const skillDirs = readdirSync7(skillsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name).sort();
|
|
40343
41090
|
for (const dir of skillDirs) {
|
|
40344
|
-
if (existsSync22(
|
|
40345
|
-
const skillMd =
|
|
41091
|
+
if (existsSync22(join54(skillsDir, dir, "PROVENANCE.md"))) continue;
|
|
41092
|
+
const skillMd = join54(skillsDir, dir, "SKILL.md");
|
|
40346
41093
|
if (existsSync22(skillMd)) {
|
|
40347
41094
|
entries.push(auditSkill(skillMd));
|
|
40348
41095
|
}
|
|
@@ -40608,8 +41355,8 @@ function slugify(name) {
|
|
|
40608
41355
|
function newMigration(args, deps = {}) {
|
|
40609
41356
|
const cwd = deps.cwd ?? process.cwd();
|
|
40610
41357
|
const genTimestamp = deps.generateTimestamp ?? generateMonotonicTimestamp;
|
|
40611
|
-
const
|
|
40612
|
-
const
|
|
41358
|
+
const mkdirSync12 = deps.mkdirSyncFn ?? ((dir, opts) => fs19.mkdirSync(dir, opts));
|
|
41359
|
+
const writeFileSync13 = deps.writeFileSyncFn ?? ((filePath2, content) => fs19.writeFileSync(filePath2, content));
|
|
40613
41360
|
const rawName = args[0];
|
|
40614
41361
|
if (!rawName) {
|
|
40615
41362
|
process.stderr.write(
|
|
@@ -40625,8 +41372,8 @@ function newMigration(args, deps = {}) {
|
|
|
40625
41372
|
const migrationsDir = path21.join(cwd, "supabase", "migrations");
|
|
40626
41373
|
const filename = `${stamp}_${slug}.sql`;
|
|
40627
41374
|
const filePath = path21.join(migrationsDir, filename);
|
|
40628
|
-
|
|
40629
|
-
|
|
41375
|
+
mkdirSync12(migrationsDir, { recursive: true });
|
|
41376
|
+
writeFileSync13(filePath, "");
|
|
40630
41377
|
process.stdout.write(JSON.stringify({ path: filePath }) + "\n");
|
|
40631
41378
|
return 0;
|
|
40632
41379
|
}
|
|
@@ -41189,12 +41936,12 @@ var init_validate_waves2 = __esm({
|
|
|
41189
41936
|
});
|
|
41190
41937
|
|
|
41191
41938
|
// src/cli/worktree/path.ts
|
|
41192
|
-
import { dirname as dirname17, basename as basename4, join as
|
|
41939
|
+
import { dirname as dirname17, basename as basename4, join as join56 } from "node:path";
|
|
41193
41940
|
function computeWorktreePath(cwd, checkpointNumber) {
|
|
41194
41941
|
const parent = dirname17(cwd);
|
|
41195
41942
|
const base = basename4(cwd);
|
|
41196
41943
|
const nnn = String(checkpointNumber).padStart(3, "0");
|
|
41197
|
-
return
|
|
41944
|
+
return join56(parent, `${base}-CHK-${nnn}`);
|
|
41198
41945
|
}
|
|
41199
41946
|
var init_path = __esm({
|
|
41200
41947
|
"src/cli/worktree/path.ts"() {
|
|
@@ -41203,7 +41950,7 @@ var init_path = __esm({
|
|
|
41203
41950
|
});
|
|
41204
41951
|
|
|
41205
41952
|
// src/cli/worktree/add.ts
|
|
41206
|
-
import { join as
|
|
41953
|
+
import { join as join57, basename as basename5 } from "node:path";
|
|
41207
41954
|
import { mkdir as mkdir15, readFile as readFile32, writeFile as writeFile25 } from "node:fs/promises";
|
|
41208
41955
|
import { spawnSync as spawnSync18 } from "node:child_process";
|
|
41209
41956
|
async function defaultGetRepoId(cwd) {
|
|
@@ -41253,11 +42000,11 @@ async function copyClaudeSettings(srcCwd, destPath, deps = {}) {
|
|
|
41253
42000
|
(fsp) => fsp.access(p).then(() => true).catch(() => false)
|
|
41254
42001
|
));
|
|
41255
42002
|
const mkdirFn = deps.mkdirFn ?? ((p, opts) => mkdir15(p, opts));
|
|
41256
|
-
await mkdirFn(
|
|
42003
|
+
await mkdirFn(join57(destPath, ".claude"), { recursive: true });
|
|
41257
42004
|
const claudeStubs = ["settings.json", "settings.local.json"];
|
|
41258
42005
|
for (const stub of claudeStubs) {
|
|
41259
|
-
const srcFile =
|
|
41260
|
-
const destFile =
|
|
42006
|
+
const srcFile = join57(srcCwd, ".claude", stub);
|
|
42007
|
+
const destFile = join57(destPath, ".claude", stub);
|
|
41261
42008
|
try {
|
|
41262
42009
|
const destExists = await existsFn(destFile);
|
|
41263
42010
|
if (destExists) continue;
|
|
@@ -41268,22 +42015,22 @@ async function copyClaudeSettings(srcCwd, destPath, deps = {}) {
|
|
|
41268
42015
|
}
|
|
41269
42016
|
}
|
|
41270
42017
|
async function defaultCopyConfigStubs(srcCwd, destPath) {
|
|
41271
|
-
await mkdir15(
|
|
42018
|
+
await mkdir15(join57(destPath, ".codebyplan"), { recursive: true });
|
|
41272
42019
|
const topLevelStubs = [".mcp.json", ".env.local"];
|
|
41273
42020
|
for (const stub of topLevelStubs) {
|
|
41274
42021
|
try {
|
|
41275
|
-
const content = await readFile32(
|
|
41276
|
-
await writeFile25(
|
|
42022
|
+
const content = await readFile32(join57(srcCwd, stub), "utf-8");
|
|
42023
|
+
await writeFile25(join57(destPath, stub), content, "utf-8");
|
|
41277
42024
|
} catch {
|
|
41278
42025
|
}
|
|
41279
42026
|
}
|
|
41280
42027
|
try {
|
|
41281
42028
|
const content = await readFile32(
|
|
41282
|
-
|
|
42029
|
+
join57(srcCwd, ".codebyplan", "repo.json"),
|
|
41283
42030
|
"utf-8"
|
|
41284
42031
|
);
|
|
41285
42032
|
await writeFile25(
|
|
41286
|
-
|
|
42033
|
+
join57(destPath, ".codebyplan", "repo.json"),
|
|
41287
42034
|
content,
|
|
41288
42035
|
"utf-8"
|
|
41289
42036
|
);
|
|
@@ -41448,7 +42195,7 @@ var init_add = __esm({
|
|
|
41448
42195
|
});
|
|
41449
42196
|
|
|
41450
42197
|
// src/cli/worktree/create.ts
|
|
41451
|
-
import { join as
|
|
42198
|
+
import { join as join58 } from "node:path";
|
|
41452
42199
|
async function defaultGetRepoIdentity(cwd) {
|
|
41453
42200
|
const found = await findCodebyplanConfig(cwd);
|
|
41454
42201
|
const contents = found?.contents ?? null;
|
|
@@ -41504,7 +42251,7 @@ async function runWorktreeCreate(args, deps = {}) {
|
|
|
41504
42251
|
);
|
|
41505
42252
|
return 1;
|
|
41506
42253
|
}
|
|
41507
|
-
const worktreePath = explicitPath ??
|
|
42254
|
+
const worktreePath = explicitPath ?? join58(cwd, "..", name);
|
|
41508
42255
|
const deviceId = await getDeviceId(cwd);
|
|
41509
42256
|
let filesWritten = false;
|
|
41510
42257
|
try {
|
|
@@ -42143,14 +42890,55 @@ var init_e2e2 = __esm({
|
|
|
42143
42890
|
}
|
|
42144
42891
|
});
|
|
42145
42892
|
|
|
42893
|
+
// src/cli/cleanup-plan-folders.ts
|
|
42894
|
+
var cleanup_plan_folders_exports = {};
|
|
42895
|
+
__export(cleanup_plan_folders_exports, {
|
|
42896
|
+
runCleanupPlanFolders: () => runCleanupPlanFolders
|
|
42897
|
+
});
|
|
42898
|
+
import { execSync as execSync10 } from "node:child_process";
|
|
42899
|
+
async function runCleanupPlanFolders(args) {
|
|
42900
|
+
void args;
|
|
42901
|
+
const found = await findCodebyplanConfig(process.cwd());
|
|
42902
|
+
if (!found) {
|
|
42903
|
+
process.stderr.write(
|
|
42904
|
+
"cleanup-plan-folders: no .codebyplan/repo.json found. Run `codebyplan setup`.\n"
|
|
42905
|
+
);
|
|
42906
|
+
process.exit(1);
|
|
42907
|
+
}
|
|
42908
|
+
const repoRoot = deriveRepoRoot(found.path);
|
|
42909
|
+
const targets = [".codebyplan/checkpoint", ".codebyplan/standalone"];
|
|
42910
|
+
let stdout7 = "";
|
|
42911
|
+
try {
|
|
42912
|
+
const result = execSync10(
|
|
42913
|
+
`git rm -r --ignore-unmatch -- ${targets.map((t) => `"${t}"`).join(" ")}`,
|
|
42914
|
+
{ cwd: repoRoot, stdio: "pipe" }
|
|
42915
|
+
);
|
|
42916
|
+
stdout7 = result.toString("utf-8");
|
|
42917
|
+
} catch (err) {
|
|
42918
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
42919
|
+
process.stderr.write(`cleanup-plan-folders: git rm failed: ${msg}
|
|
42920
|
+
`);
|
|
42921
|
+
process.exit(1);
|
|
42922
|
+
}
|
|
42923
|
+
const removed = stdout7.split("\n").map((line) => line.trim()).filter((line) => line.startsWith("rm '") && line.endsWith("'")).map((line) => line.slice(4, -1));
|
|
42924
|
+
process.stdout.write(JSON.stringify({ removed, skipped: [] }) + "\n");
|
|
42925
|
+
process.exit(0);
|
|
42926
|
+
}
|
|
42927
|
+
var init_cleanup_plan_folders = __esm({
|
|
42928
|
+
"src/cli/cleanup-plan-folders.ts"() {
|
|
42929
|
+
"use strict";
|
|
42930
|
+
init_flags();
|
|
42931
|
+
}
|
|
42932
|
+
});
|
|
42933
|
+
|
|
42146
42934
|
// src/cli/doctor.ts
|
|
42147
42935
|
var doctor_exports = {};
|
|
42148
42936
|
__export(doctor_exports, {
|
|
42149
42937
|
runDoctor: () => runDoctor
|
|
42150
42938
|
});
|
|
42151
42939
|
import { existsSync as existsSync23 } from "node:fs";
|
|
42152
|
-
import { join as
|
|
42153
|
-
import { execSync as
|
|
42940
|
+
import { join as join59 } from "node:path";
|
|
42941
|
+
import { execSync as execSync11 } from "node:child_process";
|
|
42154
42942
|
async function checkAuth() {
|
|
42155
42943
|
try {
|
|
42156
42944
|
await validateAuth();
|
|
@@ -42171,7 +42959,7 @@ async function checkVersion() {
|
|
|
42171
42959
|
const installed = VERSION;
|
|
42172
42960
|
let gitRoot = null;
|
|
42173
42961
|
try {
|
|
42174
|
-
gitRoot =
|
|
42962
|
+
gitRoot = execSync11("git rev-parse --show-toplevel", {
|
|
42175
42963
|
encoding: "utf-8"
|
|
42176
42964
|
}).trim();
|
|
42177
42965
|
} catch {
|
|
@@ -42260,7 +43048,7 @@ function checkSettings() {
|
|
|
42260
43048
|
try {
|
|
42261
43049
|
let projectDir;
|
|
42262
43050
|
try {
|
|
42263
|
-
projectDir =
|
|
43051
|
+
projectDir = execSync11("git rev-parse --show-toplevel", {
|
|
42264
43052
|
encoding: "utf-8"
|
|
42265
43053
|
}).trim();
|
|
42266
43054
|
} catch {
|
|
@@ -42273,7 +43061,7 @@ function checkSettings() {
|
|
|
42273
43061
|
detail: "codebyplan not installed (no .cbp.manifest.json)"
|
|
42274
43062
|
};
|
|
42275
43063
|
}
|
|
42276
|
-
if (!existsSync23(
|
|
43064
|
+
if (!existsSync23(join59(projectDir, ".claude", "settings.json"))) {
|
|
42277
43065
|
return {
|
|
42278
43066
|
name: "settings",
|
|
42279
43067
|
status: "warn",
|
|
@@ -42819,6 +43607,12 @@ void (async () => {
|
|
|
42819
43607
|
const rest = process.argv.slice(3);
|
|
42820
43608
|
process.exit(await runE2eCommand2(rest));
|
|
42821
43609
|
}
|
|
43610
|
+
if (arg === "cleanup-plan-folders") {
|
|
43611
|
+
const { runCleanupPlanFolders: runCleanupPlanFolders2 } = await Promise.resolve().then(() => (init_cleanup_plan_folders(), cleanup_plan_folders_exports));
|
|
43612
|
+
const rest = process.argv.slice(3);
|
|
43613
|
+
await runCleanupPlanFolders2(rest);
|
|
43614
|
+
process.exit(0);
|
|
43615
|
+
}
|
|
42822
43616
|
if (arg === "doctor") {
|
|
42823
43617
|
const { runDoctor: runDoctor2 } = await Promise.resolve().then(() => (init_doctor(), doctor_exports));
|
|
42824
43618
|
const rest = process.argv.slice(3);
|