@mduan/paseo-cli 0.11.0-fork.1 → 0.11.0-fork.2
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/node_modules/@getpaseo/client/package.json +3 -3
- package/node_modules/@getpaseo/highlight/package.json +1 -1
- package/node_modules/@getpaseo/plugin/package.json +3 -3
- package/node_modules/@getpaseo/protocol/dist/agent-types.d.ts +2 -0
- package/node_modules/@getpaseo/protocol/dist/generated/validation/ws-outbound.aot.js +106 -1
- package/node_modules/@getpaseo/protocol/dist/messages.js +3 -0
- package/node_modules/@getpaseo/protocol/package.json +1 -1
- package/node_modules/@getpaseo/relay/package.json +1 -1
- package/node_modules/@getpaseo/server/dist/server/builtin-plugins/package.json +1 -1
- package/node_modules/@getpaseo/server/dist/server/server/agent/agent-manager.d.ts +2 -2
- package/node_modules/@getpaseo/server/dist/server/server/agent/agent-projections.js +3 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/agent-sdk-types.d.ts +3 -1
- package/node_modules/@getpaseo/server/dist/server/server/agent/agent-storage.d.ts +1 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/agent-storage.js +1 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/provider-subagents/subtitle-format.d.ts +5 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/provider-subagents/subtitle-format.js +16 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/appended-lines-reader.d.ts +20 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/appended-lines-reader.js +59 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/claude/agent.js +61 -2
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/claude/subagents/live-source.d.ts +2 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/claude/subagents/live-source.js +7 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/claude/subagents/presentation.d.ts +2 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/claude/subagents/presentation.js +3 -8
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/claude/subagents/transcript-cost.d.ts +18 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/claude/subagents/transcript-cost.js +50 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/codex/pricing.d.ts +15 -1
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/codex/pricing.js +32 -1
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/codex/rollout-cost.d.ts +4 -8
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/codex/rollout-cost.js +11 -51
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/codex-app-server-agent.d.ts +5 -1
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/codex-app-server-agent.js +82 -11
- package/node_modules/@getpaseo/server/dist/server/server/agent/turn-diffs/snapshot.d.ts +14 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/turn-diffs/snapshot.js +91 -4
- package/node_modules/@getpaseo/server/dist/server/server/agent/turn-diffs/store.d.ts +3 -3
- package/node_modules/@getpaseo/server/dist/server/server/agent/turn-diffs/store.js +24 -18
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/{index-9489c4e1587c4252f0bd3b6e4b1abab3.js → index-23bdbee37d31a9422c12f2a801979611.js} +21 -21
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/index-23bdbee37d31a9422c12f2a801979611.js.br +0 -0
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/{index-9489c4e1587c4252f0bd3b6e4b1abab3.js.gz → index-23bdbee37d31a9422c12f2a801979611.js.gz} +0 -0
- package/node_modules/@getpaseo/server/dist/server/web-ui/index.html +1 -1
- package/node_modules/@getpaseo/server/dist/server/web-ui/index.html.br +0 -0
- package/node_modules/@getpaseo/server/dist/server/web-ui/index.html.gz +0 -0
- package/node_modules/@getpaseo/server/package.json +6 -6
- package/package.json +7 -7
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/index-9489c4e1587c4252f0bd3b6e4b1abab3.js.br +0 -0
|
@@ -15,10 +15,14 @@ async function git(args, options) {
|
|
|
15
15
|
}
|
|
16
16
|
async function resolveRepo(cwd) {
|
|
17
17
|
try {
|
|
18
|
-
const [repoRoot, indexPath] = (await git(["rev-parse", "--show-toplevel", "--git-path", "index"], { cwd }))
|
|
18
|
+
const [repoRoot, indexPath, headLogPath] = (await git(["rev-parse", "--show-toplevel", "--git-path", "index", "--git-path", "logs/HEAD"], { cwd }))
|
|
19
19
|
.trim()
|
|
20
20
|
.split("\n");
|
|
21
|
-
return {
|
|
21
|
+
return {
|
|
22
|
+
repoRoot,
|
|
23
|
+
indexPath: path.resolve(cwd, indexPath),
|
|
24
|
+
headLogPath: path.resolve(cwd, headLogPath),
|
|
25
|
+
};
|
|
22
26
|
}
|
|
23
27
|
catch {
|
|
24
28
|
// Not a git repository (or git is missing): turn diffs are git-only.
|
|
@@ -43,6 +47,19 @@ export async function snapshotWorkingTree(cwd) {
|
|
|
43
47
|
const repo = await resolveRepo(cwd);
|
|
44
48
|
if (!repo)
|
|
45
49
|
return null;
|
|
50
|
+
return { repoRoot: repo.repoRoot, tree: await writeWorkingTree(repo) };
|
|
51
|
+
}
|
|
52
|
+
/** A working tree snapshot plus where HEAD and its reflog stood, to separate out branch moves. */
|
|
53
|
+
export async function snapshotTurnStart(cwd) {
|
|
54
|
+
const repo = await resolveRepo(cwd);
|
|
55
|
+
if (!repo)
|
|
56
|
+
return null;
|
|
57
|
+
const headLogSize = await fs.stat(repo.headLogPath).then((stat) => stat.size, () => 0);
|
|
58
|
+
const head = await readHead(repo.repoRoot);
|
|
59
|
+
const tree = await writeWorkingTree(repo);
|
|
60
|
+
return { repoRoot: repo.repoRoot, tree, head, headLogPath: repo.headLogPath, headLogSize };
|
|
61
|
+
}
|
|
62
|
+
async function writeWorkingTree(repo) {
|
|
46
63
|
const tempIndex = path.join(os.tmpdir(), `paseo-turn-index-${randomUUID()}`);
|
|
47
64
|
try {
|
|
48
65
|
const stat = await fs.stat(repo.indexPath).catch(() => null);
|
|
@@ -61,13 +78,83 @@ export async function snapshotWorkingTree(cwd) {
|
|
|
61
78
|
input: untracked.map((file) => `${file}\0`).join(""),
|
|
62
79
|
});
|
|
63
80
|
}
|
|
64
|
-
|
|
65
|
-
return { repoRoot: repo.repoRoot, tree };
|
|
81
|
+
return (await git(["write-tree"], { cwd: repo.repoRoot, env })).trim();
|
|
66
82
|
}
|
|
67
83
|
finally {
|
|
68
84
|
await fs.rm(tempIndex, { force: true });
|
|
69
85
|
}
|
|
70
86
|
}
|
|
87
|
+
async function readHead(repoRoot) {
|
|
88
|
+
try {
|
|
89
|
+
return (await git(["rev-parse", "--verify", "-q", "HEAD"], { cwd: repoRoot })).trim();
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
async function readFileFrom(filePath, offset) {
|
|
96
|
+
const handle = await fs.open(filePath, "r").catch(() => null);
|
|
97
|
+
if (!handle)
|
|
98
|
+
return undefined;
|
|
99
|
+
try {
|
|
100
|
+
const { size } = await handle.stat();
|
|
101
|
+
if (size < offset)
|
|
102
|
+
return undefined;
|
|
103
|
+
const buffer = Buffer.alloc(size - offset);
|
|
104
|
+
await handle.read(buffer, 0, buffer.length, offset);
|
|
105
|
+
return buffer.toString("utf8");
|
|
106
|
+
}
|
|
107
|
+
finally {
|
|
108
|
+
await handle.close();
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
const OWN_COMMIT_MESSAGE = /^commit( \((initial|amend)\))?: /;
|
|
112
|
+
/**
|
|
113
|
+
* The commit HEAD landed on after the turn's last branch move (checkout, reset, pull, merge,
|
|
114
|
+
* rebase, cherry-pick), read from the reflog lines the turn appended. Undefined when HEAD only
|
|
115
|
+
* moved by the agent's own commits; null when the reflog can't tell.
|
|
116
|
+
*/
|
|
117
|
+
async function findLastBranchMove(start) {
|
|
118
|
+
const appended = await readFileFrom(start.headLogPath, start.headLogSize);
|
|
119
|
+
if (appended === undefined)
|
|
120
|
+
return null;
|
|
121
|
+
let landing;
|
|
122
|
+
for (const line of appended.split("\n")) {
|
|
123
|
+
// <old> <new> <identity> <time> <tz>\t<message>
|
|
124
|
+
const [header, message = ""] = line.split("\t", 2);
|
|
125
|
+
const [oldHead, newHead] = header.split(" ");
|
|
126
|
+
if (!newHead || oldHead === newHead || OWN_COMMIT_MESSAGE.test(message))
|
|
127
|
+
continue;
|
|
128
|
+
landing = newHead;
|
|
129
|
+
}
|
|
130
|
+
return landing;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* The tree to diff a turn from. When the turn moved HEAD to another commit, the start snapshot's
|
|
134
|
+
* uncommitted changes are replayed onto where HEAD landed, so the diff holds the agent's edits and
|
|
135
|
+
* commits and none of the content the move brought in. Undefined when that can't be worked out
|
|
136
|
+
* (no reflog, unborn branch, replay conflict); the turn then gets no diff.
|
|
137
|
+
*/
|
|
138
|
+
export async function resolveTurnFromTree(start) {
|
|
139
|
+
const head = await readHead(start.repoRoot);
|
|
140
|
+
if (head === start.head)
|
|
141
|
+
return start.tree;
|
|
142
|
+
if (!head || !start.head)
|
|
143
|
+
return undefined;
|
|
144
|
+
const landing = await findLastBranchMove(start);
|
|
145
|
+
if (landing === null)
|
|
146
|
+
return undefined;
|
|
147
|
+
if (landing === undefined || landing === start.head)
|
|
148
|
+
return start.tree;
|
|
149
|
+
try {
|
|
150
|
+
const output = await git(["merge-tree", "--write-tree", `--merge-base=${start.head}`, landing, start.tree], { cwd: start.repoRoot });
|
|
151
|
+
return output.split("\n")[0];
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
// Exit code 1: the start's uncommitted changes conflict with where HEAD landed.
|
|
155
|
+
return undefined;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
71
158
|
export async function diffTreeStats(params) {
|
|
72
159
|
if (params.fromTree === params.toTree)
|
|
73
160
|
return [];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Logger } from "pino";
|
|
2
2
|
import { type AgentTurnDiffTarget, type TurnDiffSummary } from "../../messages.js";
|
|
3
|
-
import { type
|
|
3
|
+
import { type TurnStartSnapshot } from "./snapshot.js";
|
|
4
4
|
export interface TurnDiffRange {
|
|
5
5
|
repoRoot: string;
|
|
6
6
|
fromTree: string;
|
|
@@ -8,7 +8,7 @@ export interface TurnDiffRange {
|
|
|
8
8
|
}
|
|
9
9
|
export interface RecordTurnInput {
|
|
10
10
|
agentId: string;
|
|
11
|
-
start:
|
|
11
|
+
start: TurnStartSnapshot;
|
|
12
12
|
turnId: string;
|
|
13
13
|
userMessageIds: string[];
|
|
14
14
|
}
|
|
@@ -21,7 +21,7 @@ export declare class TurnDiffStore {
|
|
|
21
21
|
private readonly logger;
|
|
22
22
|
private readonly queues;
|
|
23
23
|
constructor(dir: string, logger: Logger);
|
|
24
|
-
captureStart(cwd: string): Promise<
|
|
24
|
+
captureStart(cwd: string): Promise<TurnStartSnapshot | null>;
|
|
25
25
|
recordTurn(input: RecordTurnInput): Promise<void>;
|
|
26
26
|
list(agentId: string): Promise<TurnDiffSummary[]>;
|
|
27
27
|
resolveRange(agentId: string, target: AgentTurnDiffTarget): Promise<TurnDiffRange | null>;
|
|
@@ -4,7 +4,7 @@ import { z } from "zod";
|
|
|
4
4
|
import { withTimeout } from "../../../utils/promise-timeout.js";
|
|
5
5
|
import { writeJsonFileAtomic } from "../../atomic-file.js";
|
|
6
6
|
import { TurnDiffFileStatSchema, } from "../../messages.js";
|
|
7
|
-
import { diffTreeStats, snapshotWorkingTree, syncTreeRefs, } from "./snapshot.js";
|
|
7
|
+
import { diffTreeStats, resolveTurnFromTree, snapshotTurnStart, snapshotWorkingTree, syncTreeRefs, } from "./snapshot.js";
|
|
8
8
|
// The prompt waits for the start snapshot; past this, the turn goes without a diff.
|
|
9
9
|
const START_SNAPSHOT_TIMEOUT_MS = 2000;
|
|
10
10
|
const MAX_STORED_TURNS = 200;
|
|
@@ -17,15 +17,18 @@ const StoredTurnSchema = TreeRangeSchema.extend({
|
|
|
17
17
|
});
|
|
18
18
|
const TurnDiffRecordSchema = z.object({
|
|
19
19
|
repoRoot: z.string(),
|
|
20
|
-
//
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
lastTurn: TreeRangeSchema,
|
|
20
|
+
// Most recent finished turn, kept even when it changed nothing. Absent when the turn moved HEAD
|
|
21
|
+
// in a way its diff couldn't be separated from.
|
|
22
|
+
lastTurn: TreeRangeSchema.optional(),
|
|
24
23
|
// Turns that changed files, oldest first.
|
|
25
24
|
turns: z.array(StoredTurnSchema),
|
|
26
25
|
});
|
|
27
26
|
function referencedTrees(record) {
|
|
28
|
-
const trees = new Set(
|
|
27
|
+
const trees = new Set();
|
|
28
|
+
if (record.lastTurn) {
|
|
29
|
+
trees.add(record.lastTurn.fromTree);
|
|
30
|
+
trees.add(record.lastTurn.toTree);
|
|
31
|
+
}
|
|
29
32
|
for (const turn of record.turns) {
|
|
30
33
|
trees.add(turn.fromTree);
|
|
31
34
|
trees.add(turn.toTree);
|
|
@@ -53,7 +56,7 @@ export class TurnDiffStore {
|
|
|
53
56
|
async captureStart(cwd) {
|
|
54
57
|
try {
|
|
55
58
|
return await withTimeout({
|
|
56
|
-
promise:
|
|
59
|
+
promise: snapshotTurnStart(cwd),
|
|
57
60
|
timeoutMs: START_SNAPSHOT_TIMEOUT_MS,
|
|
58
61
|
label: "Turn start snapshot",
|
|
59
62
|
});
|
|
@@ -77,9 +80,11 @@ export class TurnDiffStore {
|
|
|
77
80
|
const { repoRoot } = record;
|
|
78
81
|
switch (target.kind) {
|
|
79
82
|
case "last_turn":
|
|
80
|
-
return { repoRoot, ...record.lastTurn };
|
|
83
|
+
return record.lastTurn ? { repoRoot, ...record.lastTurn } : null;
|
|
84
|
+
// COMPAT(turnDiffSession): added in v0.11.0-beta.3, remove after 2027-01-04. Older clients
|
|
85
|
+
// can still ask for the removed Chat Session diff; it is always unavailable.
|
|
81
86
|
case "session":
|
|
82
|
-
return
|
|
87
|
+
return null;
|
|
83
88
|
case "turn": {
|
|
84
89
|
const turn = record.turns.find((candidate) => candidate.turnId === target.turnId);
|
|
85
90
|
return turn ? { repoRoot, fromTree: turn.fromTree, toTree: turn.toTree } : null;
|
|
@@ -99,26 +104,27 @@ export class TurnDiffStore {
|
|
|
99
104
|
const end = await snapshotWorkingTree(start.repoRoot);
|
|
100
105
|
if (!end)
|
|
101
106
|
return;
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
+
const fromTree = await resolveTurnFromTree(start);
|
|
108
|
+
if (!fromTree) {
|
|
109
|
+
this.logger.info({ agentId, turnId }, "Turn moved HEAD in a way its diff can't separate");
|
|
110
|
+
}
|
|
111
|
+
const files = fromTree
|
|
112
|
+
? await diffTreeStats({ repoRoot: start.repoRoot, fromTree, toTree: end.tree })
|
|
113
|
+
: [];
|
|
107
114
|
const previous = await this.read(agentId);
|
|
108
115
|
const isSameRepo = previous?.repoRoot === start.repoRoot;
|
|
109
116
|
const record = {
|
|
110
117
|
repoRoot: start.repoRoot,
|
|
111
|
-
|
|
112
|
-
lastTurn: { fromTree: start.tree, toTree: end.tree },
|
|
118
|
+
lastTurn: fromTree ? { fromTree, toTree: end.tree } : undefined,
|
|
113
119
|
turns: isSameRepo ? previous.turns : [],
|
|
114
120
|
};
|
|
115
|
-
if (files.length > 0) {
|
|
121
|
+
if (fromTree && files.length > 0) {
|
|
116
122
|
const completedAt = new Date().toISOString();
|
|
117
123
|
const turn = {
|
|
118
124
|
turnId,
|
|
119
125
|
userMessageIds,
|
|
120
126
|
completedAt,
|
|
121
|
-
fromTree
|
|
127
|
+
fromTree,
|
|
122
128
|
toTree: end.tree,
|
|
123
129
|
files,
|
|
124
130
|
};
|