overlord-cli 0.2606090710.0 → 0.2606091312.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/_cli/protocol.mjs +85 -37
- package/package.json +1 -1
package/bin/_cli/protocol.mjs
CHANGED
|
@@ -703,6 +703,19 @@ function resolveGitRepoRoot(workspacePath) {
|
|
|
703
703
|
}
|
|
704
704
|
}
|
|
705
705
|
|
|
706
|
+
// The server caps snapshot.diffStat at 20,000 chars (snapshotContextSchema in
|
|
707
|
+
// lib/overlord/validation.ts). A `git diff --stat` over a large change set can
|
|
708
|
+
// blow past that and make the update POST fail validation. diffstat is purely
|
|
709
|
+
// informational provenance, so truncate it to a safe size before sending.
|
|
710
|
+
const MAX_DIFFSTAT_CHARS = 16_000;
|
|
711
|
+
|
|
712
|
+
function clampDiffStat(diffStat) {
|
|
713
|
+
if (typeof diffStat !== 'string' || diffStat.length <= MAX_DIFFSTAT_CHARS) {
|
|
714
|
+
return diffStat || null;
|
|
715
|
+
}
|
|
716
|
+
return `${diffStat.slice(0, MAX_DIFFSTAT_CHARS)}\n… (diffstat truncated; ${diffStat.length} chars total)`;
|
|
717
|
+
}
|
|
718
|
+
|
|
706
719
|
/**
|
|
707
720
|
* Snapshot the working tree to a hidden ref refs/overlord/checkpoints/<objectiveId>.
|
|
708
721
|
* Captures tracked + untracked + staged + unstaged in one commit-tree object.
|
|
@@ -727,9 +740,11 @@ function createLocalCheckpoint({ flags, kind = 'objective', objectiveId, snapsho
|
|
|
727
740
|
const gitCommitId = runLocalCommand('git', ['-C', repoRoot, 'rev-parse', 'HEAD'], {
|
|
728
741
|
cwd: repoRoot
|
|
729
742
|
}).trim();
|
|
730
|
-
const diffStat =
|
|
731
|
-
|
|
732
|
-
|
|
743
|
+
const diffStat = clampDiffStat(
|
|
744
|
+
runLocalCommand('git', ['-C', repoRoot, 'diff', '--stat', 'HEAD'], {
|
|
745
|
+
cwd: repoRoot
|
|
746
|
+
}).trim()
|
|
747
|
+
);
|
|
733
748
|
return {
|
|
734
749
|
checkpoint: { diffStat: diffStat || null, kind },
|
|
735
750
|
snapshot: {
|
|
@@ -761,9 +776,11 @@ function createLocalCheckpoint({ flags, kind = 'objective', objectiveId, snapsho
|
|
|
761
776
|
if (existingSha) {
|
|
762
777
|
let diffStat = '';
|
|
763
778
|
try {
|
|
764
|
-
diffStat =
|
|
765
|
-
|
|
766
|
-
|
|
779
|
+
diffStat = clampDiffStat(
|
|
780
|
+
runLocalCommand('git', ['-C', repoRoot, 'diff', '--stat', `${existingSha}^!`], {
|
|
781
|
+
cwd: repoRoot
|
|
782
|
+
}).trim()
|
|
783
|
+
);
|
|
767
784
|
} catch {
|
|
768
785
|
/* ignore */
|
|
769
786
|
}
|
|
@@ -812,9 +829,11 @@ function createLocalCheckpoint({ flags, kind = 'objective', objectiveId, snapsho
|
|
|
812
829
|
});
|
|
813
830
|
let diffStat = '';
|
|
814
831
|
try {
|
|
815
|
-
diffStat =
|
|
816
|
-
|
|
817
|
-
|
|
832
|
+
diffStat = clampDiffStat(
|
|
833
|
+
runLocalCommand('git', ['-C', repoRoot, 'diff', '--stat', `${commit}^!`], {
|
|
834
|
+
cwd: repoRoot
|
|
835
|
+
}).trim()
|
|
836
|
+
);
|
|
818
837
|
} catch {
|
|
819
838
|
/* ignore */
|
|
820
839
|
}
|
|
@@ -947,22 +966,31 @@ async function createAndRecordPendingCheckpoints({
|
|
|
947
966
|
continue;
|
|
948
967
|
}
|
|
949
968
|
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
969
|
+
try {
|
|
970
|
+
await apiPost(
|
|
971
|
+
platformUrl,
|
|
972
|
+
bearerToken,
|
|
973
|
+
localSecret,
|
|
974
|
+
organizationId,
|
|
975
|
+
'/api/protocol/update',
|
|
976
|
+
{
|
|
977
|
+
sessionKey,
|
|
978
|
+
ticketId,
|
|
979
|
+
summary: `Created local git checkpoint for objective ${objectiveId}.`,
|
|
980
|
+
phase: 'execute',
|
|
981
|
+
snapshot: checkpointResult.snapshot
|
|
982
|
+
},
|
|
983
|
+
timeoutMs
|
|
984
|
+
);
|
|
985
|
+
recorded.push(objectiveId);
|
|
986
|
+
} catch (error) {
|
|
987
|
+
// A failed checkpoint update must not block the remaining objectives or
|
|
988
|
+
// the attach itself. The session key is already persisted by the caller.
|
|
989
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
990
|
+
process.stderr.write(
|
|
991
|
+
`[protocol] Failed to record checkpoint for objective ${objectiveId}: ${message}\n`
|
|
992
|
+
);
|
|
993
|
+
}
|
|
966
994
|
}
|
|
967
995
|
return recorded;
|
|
968
996
|
}
|
|
@@ -1275,25 +1303,45 @@ async function protocolAttach(args) {
|
|
|
1275
1303
|
timeoutMs
|
|
1276
1304
|
);
|
|
1277
1305
|
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1306
|
+
// Persist the new session key BEFORE any best-effort follow-up work. The
|
|
1307
|
+
// checkpoint step below posts a separate /update call whose payload can be
|
|
1308
|
+
// rejected by the server (e.g. a large diffstat exceeding the size cap). If
|
|
1309
|
+
// that throws, we must not lose the freshly minted session key — otherwise a
|
|
1310
|
+
// stale key from a previous ticket lingers in the persisted session file and
|
|
1311
|
+
// every later `ovld protocol` call in this directory resolves the wrong
|
|
1312
|
+
// session. Persisting first guarantees the new key survives a checkpoint
|
|
1313
|
+
// failure. See ticket 1:1430.
|
|
1314
|
+
const sessionKey = data.session?.sessionKey;
|
|
1315
|
+
if (sessionKey) {
|
|
1316
|
+
persistSession(sessionKey, ticketId);
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
// Best-effort: record local git checkpoints for any pending objectives. This
|
|
1320
|
+
// must never abort the attach or prevent the session key from being persisted
|
|
1321
|
+
// and emitted, so swallow any failure (size limits, network, no git repo).
|
|
1322
|
+
let recordedCheckpointObjectiveIds = [];
|
|
1323
|
+
try {
|
|
1324
|
+
recordedCheckpointObjectiveIds = await createAndRecordPendingCheckpoints({
|
|
1325
|
+
attachData: data,
|
|
1326
|
+
bearerToken,
|
|
1327
|
+
flags,
|
|
1328
|
+
localSecret,
|
|
1329
|
+
organizationId,
|
|
1330
|
+
platformUrl,
|
|
1331
|
+
ticketId,
|
|
1332
|
+
timeoutMs
|
|
1333
|
+
});
|
|
1334
|
+
} catch (error) {
|
|
1335
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1336
|
+
process.stderr.write(`[protocol] Checkpoint recording skipped (attach still succeeded): ${message}\n`);
|
|
1337
|
+
}
|
|
1288
1338
|
if (recordedCheckpointObjectiveIds.length > 0) {
|
|
1289
1339
|
data.recordedCheckpointObjectiveIds = recordedCheckpointObjectiveIds;
|
|
1290
1340
|
}
|
|
1291
1341
|
|
|
1292
|
-
const sessionKey = data.session?.sessionKey;
|
|
1293
1342
|
console.log(JSON.stringify(data, null, 2));
|
|
1294
1343
|
|
|
1295
1344
|
if (sessionKey) {
|
|
1296
|
-
persistSession(sessionKey, ticketId);
|
|
1297
1345
|
// Emit a machine-readable line for easy shell capture:
|
|
1298
1346
|
// SESSION_KEY=$(ovld protocol attach --ticket-id ... | grep ^SESSION_KEY= | cut -d= -f2)
|
|
1299
1347
|
process.stderr.write(`\nSESSION_KEY=${sessionKey}\n`);
|