@co0ontty/wand 1.7.0 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/git-worktree.d.ts +17 -1
- package/dist/git-worktree.js +244 -0
- package/dist/resume-policy.d.ts +0 -77
- package/dist/resume-policy.js +0 -162
- package/dist/server-session-routes.js +153 -0
- package/dist/server.js +27 -1
- package/dist/storage.d.ts +1 -0
- package/dist/storage.js +205 -141
- package/dist/types.d.ts +34 -0
- package/dist/web-ui/content/scripts.js +850 -174
- package/dist/web-ui/content/styles.css +854 -144
- package/dist/web-ui/scripts.js +3 -6
- package/package.json +1 -1
package/dist/git-worktree.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { SessionSnapshot } from "./types.js";
|
|
1
|
+
import { SessionSnapshot, WorktreeMergeCheckResult, WorktreeMergeResult } from "./types.js";
|
|
2
2
|
interface WorktreeSetupOptions {
|
|
3
3
|
cwd: string;
|
|
4
4
|
sessionId: string;
|
|
@@ -8,5 +8,21 @@ interface WorktreeSetupResult {
|
|
|
8
8
|
worktreeEnabled: boolean;
|
|
9
9
|
worktree: NonNullable<SessionSnapshot["worktree"]>;
|
|
10
10
|
}
|
|
11
|
+
interface WorktreeOperationOptions {
|
|
12
|
+
worktree: NonNullable<SessionSnapshot["worktree"]>;
|
|
13
|
+
}
|
|
14
|
+
interface WorktreeMergeOptions extends WorktreeOperationOptions {
|
|
15
|
+
targetBranch?: string;
|
|
16
|
+
}
|
|
17
|
+
export declare class WorktreeMergeError extends Error {
|
|
18
|
+
readonly code: string;
|
|
19
|
+
readonly result?: Partial<WorktreeMergeResult> | undefined;
|
|
20
|
+
constructor(code: string, message: string, result?: Partial<WorktreeMergeResult> | undefined);
|
|
21
|
+
}
|
|
22
|
+
export declare function getDefaultBaseBranch(repoRoot: string): string;
|
|
23
|
+
export declare function getWorktreeMergeErrorCode(error: unknown): string | undefined;
|
|
24
|
+
export declare function checkSessionWorktreeMergeability(options: WorktreeMergeOptions): WorktreeMergeCheckResult;
|
|
25
|
+
export declare function cleanupSessionWorktree(options: WorktreeOperationOptions): boolean;
|
|
26
|
+
export declare function mergeSessionWorktree(options: WorktreeMergeOptions): WorktreeMergeResult;
|
|
11
27
|
export declare function prepareSessionWorktree(options: WorktreeSetupOptions): WorktreeSetupResult;
|
|
12
28
|
export {};
|
package/dist/git-worktree.js
CHANGED
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
import { existsSync, mkdirSync } from "node:fs";
|
|
2
2
|
import { execFileSync } from "node:child_process";
|
|
3
3
|
import path from "node:path";
|
|
4
|
+
const WORKTREE_MERGE_ERROR_CODES = {
|
|
5
|
+
MISSING: "WORKTREE_MISSING",
|
|
6
|
+
DIRTY: "WORKTREE_DIRTY",
|
|
7
|
+
TARGET_MISSING: "TARGET_BRANCH_MISSING",
|
|
8
|
+
NOTHING_TO_MERGE: "NOTHING_TO_MERGE",
|
|
9
|
+
CONFLICT: "WORKTREE_MERGE_CONFLICT",
|
|
10
|
+
CLEANUP_FAILED: "WORKTREE_CLEANUP_FAILED",
|
|
11
|
+
};
|
|
12
|
+
export class WorktreeMergeError extends Error {
|
|
13
|
+
code;
|
|
14
|
+
result;
|
|
15
|
+
constructor(code, message, result) {
|
|
16
|
+
super(message);
|
|
17
|
+
this.code = code;
|
|
18
|
+
this.result = result;
|
|
19
|
+
this.name = "WorktreeMergeError";
|
|
20
|
+
}
|
|
21
|
+
}
|
|
4
22
|
function runGit(args, cwd) {
|
|
5
23
|
return execFileSync("git", args, {
|
|
6
24
|
cwd,
|
|
@@ -19,6 +37,232 @@ function getCurrentBranch(repoRoot) {
|
|
|
19
37
|
const branch = runGit(["branch", "--show-current"], repoRoot);
|
|
20
38
|
return branch || "master";
|
|
21
39
|
}
|
|
40
|
+
function isGitCommandError(error) {
|
|
41
|
+
return error instanceof Error;
|
|
42
|
+
}
|
|
43
|
+
function getGitCommandMessage(error) {
|
|
44
|
+
if (isGitCommandError(error)) {
|
|
45
|
+
return error.stderr?.trim() || error.stdout?.trim() || error.message;
|
|
46
|
+
}
|
|
47
|
+
return String(error);
|
|
48
|
+
}
|
|
49
|
+
function refExists(repoRoot, ref) {
|
|
50
|
+
try {
|
|
51
|
+
runGit(["rev-parse", "--verify", ref], repoRoot);
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function getRepoRootFromWorktree(worktreePath) {
|
|
59
|
+
const repoRoot = runGit(["rev-parse", "--show-toplevel"], worktreePath);
|
|
60
|
+
if (!repoRoot || !existsSync(repoRoot)) {
|
|
61
|
+
throw new WorktreeMergeError(WORKTREE_MERGE_ERROR_CODES.MISSING, "Worktree 仓库根目录不存在。", {
|
|
62
|
+
cleanupDone: false,
|
|
63
|
+
conflict: false,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
return repoRoot;
|
|
67
|
+
}
|
|
68
|
+
function ensureWorktreePath(worktree) {
|
|
69
|
+
const worktreePath = path.resolve(worktree.path);
|
|
70
|
+
if (!existsSync(worktreePath)) {
|
|
71
|
+
throw new WorktreeMergeError(WORKTREE_MERGE_ERROR_CODES.MISSING, "Worktree 目录不存在,可能已被手动删除。", {
|
|
72
|
+
cleanupDone: false,
|
|
73
|
+
conflict: false,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
return worktreePath;
|
|
77
|
+
}
|
|
78
|
+
function getMainRepoRoot(repoRoot) {
|
|
79
|
+
const commonDir = runGit(["rev-parse", "--git-common-dir"], repoRoot);
|
|
80
|
+
if (commonDir) {
|
|
81
|
+
const maybeRoot = path.resolve(repoRoot, commonDir, "..");
|
|
82
|
+
if (existsSync(maybeRoot)) {
|
|
83
|
+
return maybeRoot;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return repoRoot;
|
|
87
|
+
}
|
|
88
|
+
export function getDefaultBaseBranch(repoRoot) {
|
|
89
|
+
try {
|
|
90
|
+
const symbolicRef = runGit(["symbolic-ref", "refs/remotes/origin/HEAD"], repoRoot);
|
|
91
|
+
const match = symbolicRef.match(/^refs\/remotes\/origin\/(.+)$/);
|
|
92
|
+
if (match && match[1]) {
|
|
93
|
+
return match[1];
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
// ignore and fallback below
|
|
98
|
+
}
|
|
99
|
+
const candidates = ["master", "main", getCurrentBranch(repoRoot)];
|
|
100
|
+
for (const candidate of candidates) {
|
|
101
|
+
if (candidate && refExists(repoRoot, candidate)) {
|
|
102
|
+
return candidate;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return "master";
|
|
106
|
+
}
|
|
107
|
+
function getMainRepoContext(options) {
|
|
108
|
+
const worktreePath = ensureWorktreePath(options.worktree);
|
|
109
|
+
const worktreeRepoRoot = getRepoRootFromWorktree(worktreePath);
|
|
110
|
+
const repoRoot = getMainRepoRoot(worktreeRepoRoot);
|
|
111
|
+
const sourceBranch = options.worktree.branch;
|
|
112
|
+
if (!refExists(repoRoot, sourceBranch)) {
|
|
113
|
+
throw new WorktreeMergeError(WORKTREE_MERGE_ERROR_CODES.MISSING, "Worktree 分支不存在,可能已被手动删除。", {
|
|
114
|
+
cleanupDone: false,
|
|
115
|
+
conflict: false,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
const targetBranch = options.targetBranch?.trim() || getDefaultBaseBranch(repoRoot);
|
|
119
|
+
if (!refExists(repoRoot, targetBranch)) {
|
|
120
|
+
throw new WorktreeMergeError(WORKTREE_MERGE_ERROR_CODES.TARGET_MISSING, `目标分支不存在:${targetBranch}`, {
|
|
121
|
+
cleanupDone: false,
|
|
122
|
+
conflict: false,
|
|
123
|
+
targetBranch,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
return { repoRoot, worktreePath, sourceBranch, targetBranch };
|
|
127
|
+
}
|
|
128
|
+
function hasUncommittedChanges(worktreePath) {
|
|
129
|
+
const worktreeRepoRoot = getRepoRootFromWorktree(worktreePath);
|
|
130
|
+
return runGit(["status", "--porcelain"], worktreeRepoRoot).length > 0;
|
|
131
|
+
}
|
|
132
|
+
function getAheadCount(repoRoot, targetBranch, sourceBranch) {
|
|
133
|
+
const count = runGit(["rev-list", "--count", `${targetBranch}..${sourceBranch}`], repoRoot);
|
|
134
|
+
return Number.parseInt(count || "0", 10) || 0;
|
|
135
|
+
}
|
|
136
|
+
function checkConflicts(repoRoot, targetBranch, sourceBranch) {
|
|
137
|
+
try {
|
|
138
|
+
runGit(["merge-tree", targetBranch, sourceBranch], repoRoot);
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
function ensureMergeableContext(options) {
|
|
146
|
+
const context = getMainRepoContext(options);
|
|
147
|
+
if (hasUncommittedChanges(context.worktreePath)) {
|
|
148
|
+
throw new WorktreeMergeError(WORKTREE_MERGE_ERROR_CODES.DIRTY, "Worktree 中仍有未提交改动,请先提交后再合并。", {
|
|
149
|
+
sourceBranch: context.sourceBranch,
|
|
150
|
+
targetBranch: context.targetBranch,
|
|
151
|
+
repoRoot: context.repoRoot,
|
|
152
|
+
cleanupDone: false,
|
|
153
|
+
conflict: false,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
const aheadCount = getAheadCount(context.repoRoot, context.targetBranch, context.sourceBranch);
|
|
157
|
+
if (aheadCount <= 0) {
|
|
158
|
+
throw new WorktreeMergeError(WORKTREE_MERGE_ERROR_CODES.NOTHING_TO_MERGE, "当前 worktree 没有可合并到主分支的新提交。", {
|
|
159
|
+
sourceBranch: context.sourceBranch,
|
|
160
|
+
targetBranch: context.targetBranch,
|
|
161
|
+
repoRoot: context.repoRoot,
|
|
162
|
+
cleanupDone: false,
|
|
163
|
+
conflict: false,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
return { ...context, aheadCount };
|
|
167
|
+
}
|
|
168
|
+
function buildCheckResult(context, aheadCount, hasDirtyChanges, hasConflicts) {
|
|
169
|
+
const ok = !hasDirtyChanges && aheadCount > 0 && !hasConflicts;
|
|
170
|
+
return {
|
|
171
|
+
ok,
|
|
172
|
+
sourceBranch: context.sourceBranch,
|
|
173
|
+
targetBranch: context.targetBranch,
|
|
174
|
+
worktreePath: context.worktreePath,
|
|
175
|
+
repoRoot: context.repoRoot,
|
|
176
|
+
hasUncommittedChanges: hasDirtyChanges,
|
|
177
|
+
aheadCount,
|
|
178
|
+
hasConflicts,
|
|
179
|
+
recommendedAction: hasConflicts ? "resolve-conflict" : aheadCount > 0 ? "merge" : "noop",
|
|
180
|
+
reason: hasDirtyChanges
|
|
181
|
+
? "Worktree 中仍有未提交改动。"
|
|
182
|
+
: aheadCount <= 0
|
|
183
|
+
? "当前 worktree 没有可合并的新提交。"
|
|
184
|
+
: hasConflicts
|
|
185
|
+
? "检测到潜在冲突,请先处理。"
|
|
186
|
+
: undefined,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
function getHeadCommit(repoRoot) {
|
|
190
|
+
return runGit(["rev-parse", "HEAD"], repoRoot);
|
|
191
|
+
}
|
|
192
|
+
function cleanupMergedWorktree(context) {
|
|
193
|
+
runGit(["worktree", "remove", context.worktreePath], context.repoRoot);
|
|
194
|
+
runGit(["branch", "-d", context.sourceBranch], context.repoRoot);
|
|
195
|
+
return true;
|
|
196
|
+
}
|
|
197
|
+
export function getWorktreeMergeErrorCode(error) {
|
|
198
|
+
return error instanceof WorktreeMergeError ? error.code : undefined;
|
|
199
|
+
}
|
|
200
|
+
export function checkSessionWorktreeMergeability(options) {
|
|
201
|
+
const context = getMainRepoContext(options);
|
|
202
|
+
const hasDirtyChanges = hasUncommittedChanges(context.worktreePath);
|
|
203
|
+
const aheadCount = getAheadCount(context.repoRoot, context.targetBranch, context.sourceBranch);
|
|
204
|
+
const hasConflicts = !hasDirtyChanges && aheadCount > 0
|
|
205
|
+
? checkConflicts(context.repoRoot, context.targetBranch, context.sourceBranch)
|
|
206
|
+
: false;
|
|
207
|
+
return buildCheckResult(context, aheadCount, hasDirtyChanges, hasConflicts);
|
|
208
|
+
}
|
|
209
|
+
export function cleanupSessionWorktree(options) {
|
|
210
|
+
const context = getMainRepoContext({ worktree: options.worktree });
|
|
211
|
+
return cleanupMergedWorktree(context);
|
|
212
|
+
}
|
|
213
|
+
export function mergeSessionWorktree(options) {
|
|
214
|
+
const context = ensureMergeableContext(options);
|
|
215
|
+
const hasConflicts = checkConflicts(context.repoRoot, context.targetBranch, context.sourceBranch);
|
|
216
|
+
if (hasConflicts) {
|
|
217
|
+
throw new WorktreeMergeError(WORKTREE_MERGE_ERROR_CODES.CONFLICT, "合并检测到冲突,请先手动处理。", {
|
|
218
|
+
sourceBranch: context.sourceBranch,
|
|
219
|
+
targetBranch: context.targetBranch,
|
|
220
|
+
repoRoot: context.repoRoot,
|
|
221
|
+
cleanupDone: false,
|
|
222
|
+
conflict: true,
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
try {
|
|
226
|
+
runGit(["checkout", context.targetBranch], context.repoRoot);
|
|
227
|
+
runGit(["merge", "--no-ff", "--no-edit", context.sourceBranch], context.repoRoot);
|
|
228
|
+
}
|
|
229
|
+
catch (error) {
|
|
230
|
+
const message = getGitCommandMessage(error);
|
|
231
|
+
throw new WorktreeMergeError(WORKTREE_MERGE_ERROR_CODES.CONFLICT, message || "合并失败,可能存在冲突。", {
|
|
232
|
+
sourceBranch: context.sourceBranch,
|
|
233
|
+
targetBranch: context.targetBranch,
|
|
234
|
+
repoRoot: context.repoRoot,
|
|
235
|
+
cleanupDone: false,
|
|
236
|
+
conflict: true,
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
const mergedAt = new Date().toISOString();
|
|
240
|
+
const mergeCommit = getHeadCommit(context.repoRoot);
|
|
241
|
+
try {
|
|
242
|
+
cleanupMergedWorktree(context);
|
|
243
|
+
return {
|
|
244
|
+
ok: true,
|
|
245
|
+
sourceBranch: context.sourceBranch,
|
|
246
|
+
targetBranch: context.targetBranch,
|
|
247
|
+
repoRoot: context.repoRoot,
|
|
248
|
+
mergeCommit,
|
|
249
|
+
mergedAt,
|
|
250
|
+
cleanupDone: true,
|
|
251
|
+
conflict: false,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
catch (error) {
|
|
255
|
+
throw new WorktreeMergeError(WORKTREE_MERGE_ERROR_CODES.CLEANUP_FAILED, getGitCommandMessage(error) || "已合并,但清理 worktree 失败。", {
|
|
256
|
+
sourceBranch: context.sourceBranch,
|
|
257
|
+
targetBranch: context.targetBranch,
|
|
258
|
+
repoRoot: context.repoRoot,
|
|
259
|
+
mergeCommit,
|
|
260
|
+
mergedAt,
|
|
261
|
+
cleanupDone: false,
|
|
262
|
+
conflict: false,
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
}
|
|
22
266
|
export function prepareSessionWorktree(options) {
|
|
23
267
|
const resolvedCwd = path.resolve(options.cwd);
|
|
24
268
|
const repoRoot = runGit(["rev-parse", "--show-toplevel"], resolvedCwd);
|
package/dist/resume-policy.d.ts
CHANGED
|
@@ -1,80 +1,3 @@
|
|
|
1
1
|
import { ConversationTurn } from "./types.js";
|
|
2
2
|
export declare function hasRealConversationMessages(messages: ConversationTurn[] | undefined): boolean;
|
|
3
|
-
export declare function hasRuntimeConversationSignal(messages: ConversationTurn[] | undefined): boolean;
|
|
4
|
-
export declare function hasStoredConversationHistory(messages: ConversationTurn[] | undefined): boolean;
|
|
5
|
-
export declare function shouldBindClaudeSessionId(record: {
|
|
6
|
-
messages: ConversationTurn[] | undefined;
|
|
7
|
-
}): boolean;
|
|
8
|
-
export declare function shouldAllowResume(record: {
|
|
9
|
-
claudeSessionId: string | null | undefined;
|
|
10
|
-
messages: ConversationTurn[] | undefined;
|
|
11
|
-
}): boolean;
|
|
12
|
-
export declare function shouldBackfillFromStoredHistory(record: {
|
|
13
|
-
messages: ConversationTurn[] | undefined;
|
|
14
|
-
}): boolean;
|
|
15
|
-
export declare function shouldDisplayResumeAction(messages: ConversationTurn[] | undefined): boolean;
|
|
16
|
-
export declare function shouldAutoResumeMessages(messages: ConversationTurn[] | undefined): boolean;
|
|
17
|
-
export declare function shouldBackfillMessages(messages: ConversationTurn[] | undefined): boolean;
|
|
18
|
-
export declare function shouldPromoteProjectSessionId(record: {
|
|
19
|
-
messages: ConversationTurn[] | undefined;
|
|
20
|
-
}): boolean;
|
|
21
|
-
export declare function shouldPromoteStoredSessionId(record: {
|
|
22
|
-
messages: ConversationTurn[] | undefined;
|
|
23
|
-
}): boolean;
|
|
24
|
-
export declare function shouldPromoteUiSessionId(messages: ConversationTurn[] | undefined): boolean;
|
|
25
|
-
export declare function shouldPromoteResumeSessionId(messages: ConversationTurn[] | undefined): boolean;
|
|
26
|
-
export declare function hasBindableConversation(messages: ConversationTurn[] | undefined): boolean;
|
|
27
|
-
export declare function hasBackfillableConversation(messages: ConversationTurn[] | undefined): boolean;
|
|
28
|
-
export declare function hasUiConversation(messages: ConversationTurn[] | undefined): boolean;
|
|
29
|
-
export declare function hasResumeConversation(messages: ConversationTurn[] | undefined): boolean;
|
|
30
|
-
export declare function isRuntimeConversationReady(messages: ConversationTurn[] | undefined): boolean;
|
|
31
|
-
export declare function isStoredConversationReady(messages: ConversationTurn[] | undefined): boolean;
|
|
32
|
-
export declare function isResumeConversationReady(messages: ConversationTurn[] | undefined): boolean;
|
|
33
|
-
export declare function shouldBindFromRuntimeMessages(record: {
|
|
34
|
-
messages: ConversationTurn[] | undefined;
|
|
35
|
-
}): boolean;
|
|
36
|
-
export declare function shouldAllowUiResume(messages: ConversationTurn[] | undefined): boolean;
|
|
37
|
-
export declare function shouldPromoteResumeAction(record: {
|
|
38
|
-
claudeSessionId: string | null | undefined;
|
|
39
|
-
messages: ConversationTurn[] | undefined;
|
|
40
|
-
}): boolean;
|
|
41
|
-
export declare function shouldBackfillClaudeSessionIdFromDisk(record: {
|
|
42
|
-
messages: ConversationTurn[] | undefined;
|
|
43
|
-
}): boolean;
|
|
44
|
-
export declare function shouldUseProjectCandidate(record: {
|
|
45
|
-
messages: ConversationTurn[] | undefined;
|
|
46
|
-
}): boolean;
|
|
47
|
-
export declare function shouldResumeProjectCandidate(record: {
|
|
48
|
-
claudeSessionId: string | null | undefined;
|
|
49
|
-
messages: ConversationTurn[] | undefined;
|
|
50
|
-
}): boolean;
|
|
51
|
-
export declare function shouldBackfillProjectCandidate(record: {
|
|
52
|
-
messages: ConversationTurn[] | undefined;
|
|
53
|
-
}): boolean;
|
|
54
|
-
export declare function hasMinimumRuntimeConversation(messages: ConversationTurn[] | undefined): boolean;
|
|
55
|
-
export declare function hasMinimumStoredConversation(messages: ConversationTurn[] | undefined): boolean;
|
|
56
|
-
export declare function hasMinimumResumeConversation(messages: ConversationTurn[] | undefined): boolean;
|
|
57
|
-
export declare function hasMinimumBackfillConversation(messages: ConversationTurn[] | undefined): boolean;
|
|
58
|
-
export declare function hasProjectConversationSignal(messages: ConversationTurn[] | undefined): boolean;
|
|
59
|
-
export declare function hasStoredProjectConversationSignal(messages: ConversationTurn[] | undefined): boolean;
|
|
60
|
-
export declare function hasUiProjectConversationSignal(messages: ConversationTurn[] | undefined): boolean;
|
|
61
|
-
export declare function hasResumeProjectConversationSignal(messages: ConversationTurn[] | undefined): boolean;
|
|
62
|
-
export declare function canBindFromProjectConversation(messages: ConversationTurn[] | undefined): boolean;
|
|
63
|
-
export declare function canBackfillFromProjectConversation(messages: ConversationTurn[] | undefined): boolean;
|
|
64
|
-
export declare function canShowUiProjectConversation(messages: ConversationTurn[] | undefined): boolean;
|
|
65
|
-
export declare function canResumeProjectConversation(messages: ConversationTurn[] | undefined): boolean;
|
|
66
|
-
export declare function shouldUseRuntimeProjectConversation(messages: ConversationTurn[] | undefined): boolean;
|
|
67
|
-
export declare function shouldUseStoredProjectConversation(messages: ConversationTurn[] | undefined): boolean;
|
|
68
|
-
export declare function shouldUseUiProjectConversation(messages: ConversationTurn[] | undefined): boolean;
|
|
69
|
-
export declare function shouldUseResumeProjectConversation(messages: ConversationTurn[] | undefined): boolean;
|
|
70
|
-
export declare function hasProjectConversationForBinding(messages: ConversationTurn[] | undefined): boolean;
|
|
71
|
-
export declare function hasProjectConversationForBackfill(messages: ConversationTurn[] | undefined): boolean;
|
|
72
|
-
export declare function hasProjectConversationForUi(messages: ConversationTurn[] | undefined): boolean;
|
|
73
|
-
export declare function hasProjectConversationForResume(messages: ConversationTurn[] | undefined): boolean;
|
|
74
|
-
export declare function isBindableProjectConversation(messages: ConversationTurn[] | undefined): boolean;
|
|
75
|
-
export declare function isBackfillableProjectConversation(messages: ConversationTurn[] | undefined): boolean;
|
|
76
|
-
export declare function isUiProjectConversation(messages: ConversationTurn[] | undefined): boolean;
|
|
77
|
-
export declare function isResumeProjectConversation(messages: ConversationTurn[] | undefined): boolean;
|
|
78
|
-
export declare function hasLiveProjectConversation(messages: ConversationTurn[] | undefined): boolean;
|
|
79
|
-
export declare function hasStoredProjectConversation(messages: ConversationTurn[] | undefined): boolean;
|
|
80
3
|
export declare function getResumeCommandSessionId(command: string): string | null;
|
package/dist/resume-policy.js
CHANGED
|
@@ -10,168 +10,6 @@ export function hasRealConversationMessages(messages) {
|
|
|
10
10
|
&& turn.content.some((block) => block.type === "text" && block.text.trim().length > 0));
|
|
11
11
|
return hasUser && hasAssistant;
|
|
12
12
|
}
|
|
13
|
-
export function hasRuntimeConversationSignal(messages) {
|
|
14
|
-
if (!messages || messages.length === 0) {
|
|
15
|
-
return false;
|
|
16
|
-
}
|
|
17
|
-
const hasUser = messages.some((turn) => turn.role === "user"
|
|
18
|
-
&& turn.content.some((block) => block.type === "text" && block.text.trim().length > 0));
|
|
19
|
-
const hasAssistant = messages.some((turn) => turn.role === "assistant");
|
|
20
|
-
return hasUser && hasAssistant;
|
|
21
|
-
}
|
|
22
|
-
export function hasStoredConversationHistory(messages) {
|
|
23
|
-
return hasRealConversationMessages(messages);
|
|
24
|
-
}
|
|
25
|
-
export function shouldBindClaudeSessionId(record) {
|
|
26
|
-
return hasRuntimeConversationSignal(record.messages);
|
|
27
|
-
}
|
|
28
|
-
export function shouldAllowResume(record) {
|
|
29
|
-
return Boolean(record.claudeSessionId) && hasStoredConversationHistory(record.messages);
|
|
30
|
-
}
|
|
31
|
-
export function shouldBackfillFromStoredHistory(record) {
|
|
32
|
-
return hasStoredConversationHistory(record.messages);
|
|
33
|
-
}
|
|
34
|
-
export function shouldDisplayResumeAction(messages) {
|
|
35
|
-
return hasStoredConversationHistory(messages);
|
|
36
|
-
}
|
|
37
|
-
export function shouldAutoResumeMessages(messages) {
|
|
38
|
-
return hasStoredConversationHistory(messages);
|
|
39
|
-
}
|
|
40
|
-
export function shouldBackfillMessages(messages) {
|
|
41
|
-
return hasStoredConversationHistory(messages);
|
|
42
|
-
}
|
|
43
|
-
export function shouldPromoteProjectSessionId(record) {
|
|
44
|
-
return shouldBindClaudeSessionId(record);
|
|
45
|
-
}
|
|
46
|
-
export function shouldPromoteStoredSessionId(record) {
|
|
47
|
-
return shouldBackfillMessages(record.messages);
|
|
48
|
-
}
|
|
49
|
-
export function shouldPromoteUiSessionId(messages) {
|
|
50
|
-
return shouldDisplayResumeAction(messages);
|
|
51
|
-
}
|
|
52
|
-
export function shouldPromoteResumeSessionId(messages) {
|
|
53
|
-
return shouldAutoResumeMessages(messages);
|
|
54
|
-
}
|
|
55
|
-
export function hasBindableConversation(messages) {
|
|
56
|
-
return shouldBindFromRuntimeMessages({ messages: messages ?? [] });
|
|
57
|
-
}
|
|
58
|
-
export function hasBackfillableConversation(messages) {
|
|
59
|
-
return shouldBackfillMessages(messages);
|
|
60
|
-
}
|
|
61
|
-
export function hasUiConversation(messages) {
|
|
62
|
-
return shouldPromoteUiSessionId(messages);
|
|
63
|
-
}
|
|
64
|
-
export function hasResumeConversation(messages) {
|
|
65
|
-
return shouldPromoteResumeSessionId(messages);
|
|
66
|
-
}
|
|
67
|
-
export function isRuntimeConversationReady(messages) {
|
|
68
|
-
return hasBindableConversation(messages);
|
|
69
|
-
}
|
|
70
|
-
export function isStoredConversationReady(messages) {
|
|
71
|
-
return hasBackfillableConversation(messages);
|
|
72
|
-
}
|
|
73
|
-
export function isResumeConversationReady(messages) {
|
|
74
|
-
return hasResumeConversation(messages);
|
|
75
|
-
}
|
|
76
|
-
export function shouldBindFromRuntimeMessages(record) {
|
|
77
|
-
return isRuntimeConversationReady(record.messages);
|
|
78
|
-
}
|
|
79
|
-
export function shouldAllowUiResume(messages) {
|
|
80
|
-
return hasUiConversation(messages);
|
|
81
|
-
}
|
|
82
|
-
export function shouldPromoteResumeAction(record) {
|
|
83
|
-
return shouldAllowResume(record);
|
|
84
|
-
}
|
|
85
|
-
export function shouldBackfillClaudeSessionIdFromDisk(record) {
|
|
86
|
-
return isStoredConversationReady(record.messages);
|
|
87
|
-
}
|
|
88
|
-
export function shouldUseProjectCandidate(record) {
|
|
89
|
-
return shouldBindFromRuntimeMessages(record);
|
|
90
|
-
}
|
|
91
|
-
export function shouldResumeProjectCandidate(record) {
|
|
92
|
-
return shouldPromoteResumeAction(record);
|
|
93
|
-
}
|
|
94
|
-
export function shouldBackfillProjectCandidate(record) {
|
|
95
|
-
return shouldBackfillClaudeSessionIdFromDisk(record);
|
|
96
|
-
}
|
|
97
|
-
export function hasMinimumRuntimeConversation(messages) {
|
|
98
|
-
return shouldBindFromRuntimeMessages({ messages: messages ?? [] });
|
|
99
|
-
}
|
|
100
|
-
export function hasMinimumStoredConversation(messages) {
|
|
101
|
-
return shouldAllowUiResume(messages);
|
|
102
|
-
}
|
|
103
|
-
export function hasMinimumResumeConversation(messages) {
|
|
104
|
-
return isResumeConversationReady(messages);
|
|
105
|
-
}
|
|
106
|
-
export function hasMinimumBackfillConversation(messages) {
|
|
107
|
-
return isStoredConversationReady(messages);
|
|
108
|
-
}
|
|
109
|
-
export function hasProjectConversationSignal(messages) {
|
|
110
|
-
return hasMinimumRuntimeConversation(messages);
|
|
111
|
-
}
|
|
112
|
-
export function hasStoredProjectConversationSignal(messages) {
|
|
113
|
-
return hasMinimumBackfillConversation(messages);
|
|
114
|
-
}
|
|
115
|
-
export function hasUiProjectConversationSignal(messages) {
|
|
116
|
-
return hasMinimumStoredConversation(messages);
|
|
117
|
-
}
|
|
118
|
-
export function hasResumeProjectConversationSignal(messages) {
|
|
119
|
-
return hasMinimumResumeConversation(messages);
|
|
120
|
-
}
|
|
121
|
-
export function canBindFromProjectConversation(messages) {
|
|
122
|
-
return hasProjectConversationSignal(messages);
|
|
123
|
-
}
|
|
124
|
-
export function canBackfillFromProjectConversation(messages) {
|
|
125
|
-
return hasStoredProjectConversationSignal(messages);
|
|
126
|
-
}
|
|
127
|
-
export function canShowUiProjectConversation(messages) {
|
|
128
|
-
return hasUiProjectConversationSignal(messages);
|
|
129
|
-
}
|
|
130
|
-
export function canResumeProjectConversation(messages) {
|
|
131
|
-
return hasResumeProjectConversationSignal(messages);
|
|
132
|
-
}
|
|
133
|
-
export function shouldUseRuntimeProjectConversation(messages) {
|
|
134
|
-
return canBindFromProjectConversation(messages);
|
|
135
|
-
}
|
|
136
|
-
export function shouldUseStoredProjectConversation(messages) {
|
|
137
|
-
return canBackfillFromProjectConversation(messages);
|
|
138
|
-
}
|
|
139
|
-
export function shouldUseUiProjectConversation(messages) {
|
|
140
|
-
return canShowUiProjectConversation(messages);
|
|
141
|
-
}
|
|
142
|
-
export function shouldUseResumeProjectConversation(messages) {
|
|
143
|
-
return canResumeProjectConversation(messages);
|
|
144
|
-
}
|
|
145
|
-
export function hasProjectConversationForBinding(messages) {
|
|
146
|
-
return shouldUseRuntimeProjectConversation(messages);
|
|
147
|
-
}
|
|
148
|
-
export function hasProjectConversationForBackfill(messages) {
|
|
149
|
-
return shouldUseStoredProjectConversation(messages);
|
|
150
|
-
}
|
|
151
|
-
export function hasProjectConversationForUi(messages) {
|
|
152
|
-
return shouldUseUiProjectConversation(messages);
|
|
153
|
-
}
|
|
154
|
-
export function hasProjectConversationForResume(messages) {
|
|
155
|
-
return shouldUseResumeProjectConversation(messages);
|
|
156
|
-
}
|
|
157
|
-
export function isBindableProjectConversation(messages) {
|
|
158
|
-
return hasProjectConversationForBinding(messages);
|
|
159
|
-
}
|
|
160
|
-
export function isBackfillableProjectConversation(messages) {
|
|
161
|
-
return hasProjectConversationForBackfill(messages);
|
|
162
|
-
}
|
|
163
|
-
export function isUiProjectConversation(messages) {
|
|
164
|
-
return hasProjectConversationForUi(messages);
|
|
165
|
-
}
|
|
166
|
-
export function isResumeProjectConversation(messages) {
|
|
167
|
-
return hasProjectConversationForResume(messages);
|
|
168
|
-
}
|
|
169
|
-
export function hasLiveProjectConversation(messages) {
|
|
170
|
-
return isBindableProjectConversation(messages);
|
|
171
|
-
}
|
|
172
|
-
export function hasStoredProjectConversation(messages) {
|
|
173
|
-
return isBackfillableProjectConversation(messages);
|
|
174
|
-
}
|
|
175
13
|
export function getResumeCommandSessionId(command) {
|
|
176
14
|
const match = RESUME_COMMAND_ID_PATTERN.exec(command);
|
|
177
15
|
return match?.[1] ?? null;
|