dsh-git-worktree 0.2.0 → 0.3.1
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/CHANGELOG.md +52 -2
- package/README.en.md +334 -0
- package/README.md +300 -65
- package/lib/adapters/lookup.d.ts +4 -2
- package/lib/adapters/lookup.js +31 -3
- package/lib/adapters/lookup.js.map +1 -1
- package/lib/adapters/registry.js +1 -0
- package/lib/adapters/registry.js.map +1 -1
- package/lib/client/console-remote/adapter.js +2 -0
- package/lib/client/console-remote/adapter.js.map +1 -1
- package/lib/client/review-console/ReviewActions.js +20 -5
- package/lib/client/review-console/ReviewActions.js.map +1 -1
- package/lib/client/review-console/review-console.styles.js +2 -1
- package/lib/client/review-console/review-console.styles.js.map +1 -1
- package/lib/client/styles.js +1 -0
- package/lib/client/styles.js.map +1 -1
- package/lib/client/target-console/WorktreeReviewStatus.js +34 -0
- package/lib/client/target-console/WorktreeReviewStatus.js.map +1 -1
- package/lib/client.js +100 -9
- package/lib/commands.js +17 -2
- package/lib/commands.js.map +1 -1
- package/lib/console-contract.d.ts +17 -0
- package/lib/console-contract.js.map +1 -1
- package/lib/console-host/control-plane.d.ts +3 -1
- package/lib/console-host/control-plane.js +65 -6
- package/lib/console-host/control-plane.js.map +1 -1
- package/lib/console-host/projection.js +5 -0
- package/lib/console-host/projection.js.map +1 -1
- package/lib/console-host/service.d.ts +2 -0
- package/lib/console-host/service.js +12 -0
- package/lib/console-host/service.js.map +1 -1
- package/lib/console-remote/descriptors.js +9 -0
- package/lib/console-remote/descriptors.js.map +1 -1
- package/lib/console-remote/remote.d.ts +2 -0
- package/lib/console-remote/schemas.js +2 -0
- package/lib/console-remote/schemas.js.map +1 -1
- package/lib/index.d.ts +4 -2
- package/lib/index.js.map +1 -1
- package/lib/ports.d.ts +2 -0
- package/lib/session-checkout-module.js +250 -8
- package/lib/session-checkout-module.js.map +1 -1
- package/lib/tools.d.ts +2 -1
- package/lib/tools.js +80 -1
- package/lib/tools.js.map +1 -1
- package/package.json +1 -1
- package/scripts/check-publish.mjs +1 -1
- package/scripts/dev-dsh-lib.mjs +83 -27
- package/scripts/dev-dsh.mjs +18 -12
- package/README.zh.md +0 -115
package/lib/tools.d.ts
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* Model-facing worktree tools. Destructive delivery actions are deliberately
|
|
3
3
|
* absent: Finish/Discard/Remove are human commands surfaced by the client
|
|
4
4
|
* ToolView. The model can reserve a real target session, inspect its own
|
|
5
|
-
* scoped worktrees,
|
|
5
|
+
* scoped worktrees, invalidate an unsynced review before further file edits,
|
|
6
|
+
* safely begin a cleaned same-session iteration, and stop at Ready for Review.
|
|
6
7
|
* @module dsh-git-worktree/tools
|
|
7
8
|
*/
|
|
8
9
|
import type { Context } from '@deepseek-ai/cordis';
|
package/lib/tools.js
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* Model-facing worktree tools. Destructive delivery actions are deliberately
|
|
3
3
|
* absent: Finish/Discard/Remove are human commands surfaced by the client
|
|
4
4
|
* ToolView. The model can reserve a real target session, inspect its own
|
|
5
|
-
* scoped worktrees,
|
|
5
|
+
* scoped worktrees, invalidate an unsynced review before further file edits,
|
|
6
|
+
* safely begin a cleaned same-session iteration, and stop at Ready for Review.
|
|
6
7
|
* @module dsh-git-worktree/tools
|
|
7
8
|
*/
|
|
8
9
|
import { randomUUID } from 'node:crypto';
|
|
@@ -107,6 +108,83 @@ export function registerTools(ctx, module) {
|
|
|
107
108
|
},
|
|
108
109
|
presentCall: () => ({ card: 'generic', title: 'List managed worktrees', kind: 'other', rawInput: {} }),
|
|
109
110
|
}));
|
|
111
|
+
ctx.tools.register(defineTool({
|
|
112
|
+
name: 'worktree_resume_revision',
|
|
113
|
+
description: '当前 Isolated Session 处于尚未同步 Local 的 Ready for Review,且用户提出新的代码或文件修改时,必须先自动调用本工具使旧 Review 失效并恢复同一轮 Working,然后直接继续执行请求。纯讨论、问答或补充信息不要调用;不要要求用户点击恢复编辑,也不要先同步 Local。',
|
|
114
|
+
parameters: {},
|
|
115
|
+
output: {
|
|
116
|
+
schema: {
|
|
117
|
+
type: 'object',
|
|
118
|
+
additionalProperties: false,
|
|
119
|
+
properties: {
|
|
120
|
+
kind: { type: 'string', required: true },
|
|
121
|
+
checkoutId: { type: 'string', required: true },
|
|
122
|
+
iteration: { type: 'number', required: true },
|
|
123
|
+
revision: { type: 'number', required: true },
|
|
124
|
+
phase: { type: 'string', required: true },
|
|
125
|
+
sessionId: { type: 'string', required: true },
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
render: (_args, value) => renderJson(value),
|
|
129
|
+
},
|
|
130
|
+
async execute(_args, exec) {
|
|
131
|
+
const sessionId = sessionIdOf(exec.agent);
|
|
132
|
+
const current = await module.inspect(sessionId);
|
|
133
|
+
if (current.delivery?.state !== 'ready_for_review') {
|
|
134
|
+
throw new Error(`当前 Worktree 没有可恢复的未同步 Review: ${current.delivery?.state ?? 'unknown'}`);
|
|
135
|
+
}
|
|
136
|
+
const target = await module.resumeRevision(sessionId, current.revision, current.delivery.review.reviewId);
|
|
137
|
+
if (target.delivery?.state !== 'working') {
|
|
138
|
+
throw new Error(`Worktree 未恢复到 working 状态: ${target.delivery?.state ?? 'unknown'}`);
|
|
139
|
+
}
|
|
140
|
+
return {
|
|
141
|
+
kind: 'worktree_revision_resumed',
|
|
142
|
+
checkoutId: target.checkout.id,
|
|
143
|
+
iteration: target.delivery.iteration,
|
|
144
|
+
revision: target.revision,
|
|
145
|
+
phase: target.checkout.phase,
|
|
146
|
+
sessionId,
|
|
147
|
+
};
|
|
148
|
+
},
|
|
149
|
+
presentCall: () => ({ card: 'generic', title: 'Resume Worktree revision', kind: 'other', rawInput: {} }),
|
|
150
|
+
}));
|
|
151
|
+
ctx.tools.register(defineTool({
|
|
152
|
+
name: 'worktree_begin_next_iteration',
|
|
153
|
+
description: '当当前 Isolated Session 已交付并完成 cleanup,而用户在同一对话中提出新的代码或文件修改时,先调用本工具安全重建同一个 immutable cwd 并进入下一轮,然后继续执行用户请求。不要改用 worktree_create;retained 或 cleanup_pending 状态不能调用。',
|
|
154
|
+
parameters: {},
|
|
155
|
+
output: {
|
|
156
|
+
schema: {
|
|
157
|
+
type: 'object',
|
|
158
|
+
additionalProperties: false,
|
|
159
|
+
properties: {
|
|
160
|
+
kind: { type: 'string', required: true },
|
|
161
|
+
checkoutId: { type: 'string', required: true },
|
|
162
|
+
iteration: { type: 'number', required: true },
|
|
163
|
+
phase: { type: 'string', required: true },
|
|
164
|
+
currentOid: { type: 'string', required: true },
|
|
165
|
+
sessionId: { type: 'string', required: true },
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
render: (_args, value) => renderJson(value),
|
|
169
|
+
},
|
|
170
|
+
async execute(_args, exec) {
|
|
171
|
+
const sessionId = sessionIdOf(exec.agent);
|
|
172
|
+
const current = await module.inspect(sessionId);
|
|
173
|
+
const target = await module.beginNextIteration(sessionId, current.revision);
|
|
174
|
+
if (target.delivery?.state !== 'working') {
|
|
175
|
+
throw new Error(`下一轮 Worktree 未进入 working 状态: ${target.delivery?.state ?? 'unknown'}`);
|
|
176
|
+
}
|
|
177
|
+
return {
|
|
178
|
+
kind: 'worktree_next_iteration_started',
|
|
179
|
+
checkoutId: target.checkout.id,
|
|
180
|
+
iteration: target.delivery.iteration,
|
|
181
|
+
phase: target.checkout.phase,
|
|
182
|
+
currentOid: target.current.oid,
|
|
183
|
+
sessionId,
|
|
184
|
+
};
|
|
185
|
+
},
|
|
186
|
+
presentCall: () => ({ card: 'generic', title: 'Start next Worktree iteration', kind: 'other', rawInput: {} }),
|
|
187
|
+
}));
|
|
110
188
|
ctx.tools.register(defineTool({
|
|
111
189
|
name: 'worktree_ready_for_review',
|
|
112
190
|
description: 'Isolated Session 的最后一个模型动作:把完整交付报告、验证证据和建议 Commit Message 仅写入本工具参数,然后立即停止。不要在调用前后用普通回复重复完整报告;最多用一句话提示用户通过底部验收条处理。用户会显式决定是否提交或放弃,模型不得自动提交或清理。',
|
|
@@ -157,6 +235,7 @@ export function registerTools(ctx, module) {
|
|
|
157
235
|
state: { type: 'string', required: true },
|
|
158
236
|
reviewId: { type: 'string', required: true },
|
|
159
237
|
revision: { type: 'number', required: true },
|
|
238
|
+
iteration: { type: 'number', required: true },
|
|
160
239
|
changedFiles: { type: 'array', required: true, items: { type: 'string' } },
|
|
161
240
|
},
|
|
162
241
|
},
|
package/lib/tools.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAExC,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAInD,SAAS,WAAW,CAAC,KAAc;IACjC,MAAM,OAAO,GAAI,KAAmD,EAAE,OAAO,CAAA;IAC7E,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,CAAC,EAAE,KAAK,QAAQ,EAAE,CAAC;QAC/C,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAA;IACnD,CAAC;IACD,OAAO,OAAO,CAAC,EAAE,CAAA;AACnB,CAAC;AAED,kFAAkF;AAClF,SAAS,UAAU,CAAC,KAAc;IAChC,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;AACxD,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,aAAa,CAAC,GAAY,EAAE,MAA6B;IACvE,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC;QAC5B,IAAI,EAAE,iBAAiB;QACvB,WAAW,EAAE,2PAA2P;QACxQ,UAAU,EAAE,EAAE;QACd,MAAM,EAAE;YACN,MAAM,EAAE;gBACN,IAAI,EAAE,QAAQ;gBACd,oBAAoB,EAAE,KAAK;gBAC3B,UAAU,EAAE;oBACV,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;oBACxC,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;oBAC9C,eAAe,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;oBACnD,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;oBAC/C,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;oBACzC,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;oBAC9C,eAAe,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;iBACpD;aACF;YACD,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC;SAC5C;QACD,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI;YACvB,MAAM,eAAe,GAAG,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YAC/C,MAAM,eAAe,GAAG,UAAU,EAAE,CAAA;YACpC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,eAAe,EAAE,eAAe,CAAC,CAAA;YAClF,OAAO;gBACL,IAAI,EAAE,yBAAyB;gBAC/B,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE;gBACrC,eAAe;gBACf,WAAW,EAAE,MAAM,CAAC,WAAW;gBAC/B,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK;gBACnC,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG;gBACrC,eAAe;aAChB,CAAA;QACH,CAAC;QACD,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,gCAAgC,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;KAC/G,CAAC,CAAC,CAAA;IAEH,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC;QAC5B,IAAI,EAAE,eAAe;QACrB,WAAW,EAAE,kJAAkJ;QAC/J,UAAU,EAAE,EAAE;QACd,MAAM,EAAE;YACN,MAAM,EAAE;gBACN,IAAI,EAAE,QAAQ;gBACd,oBAAoB,EAAE,KAAK;gBAC3B,UAAU,EAAE;oBACV,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;oBACxC,SAAS,EAAE;wBACT,IAAI,EAAE,OAAO;wBACb,QAAQ,EAAE,IAAI;wBACd,KAAK,EAAE;4BACL,IAAI,EAAE,QAAQ;4BACd,oBAAoB,EAAE,KAAK;4BAC3B,UAAU,EAAE;gCACV,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;gCAC9C,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;gCAC/C,cAAc,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;gCAClD,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;gCAC7C,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;gCACzC,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;gCACzC,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE;gCAC1C,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;6BAC9B;yBACF;qBACF;iBACF;aACF;YACD,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC;SAC5C;QACD,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI;YACvB,MAAM,SAAS,GAAG,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YACzC,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,8BAA8B,CAAC,SAAS,CAAC,CAAA;YACxE,OAAO;gBACL,IAAI,EAAE,eAAe;gBACrB,SAAS,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;oBACrC,UAAU,EAAE,OAAO,CAAC,UAAU;oBAC9B,WAAW,EAAE,OAAO,CAAC,OAAO,CAAC,IAAI;oBACjC,cAAc,EAAE,OAAO,CAAC,cAAc;oBACtC,SAAS,EAAE,OAAO,CAAC,SAAS;oBAC5B,KAAK,EAAE,OAAO,CAAC,KAAK;oBACpB,KAAK,EAAE,OAAO,CAAC,KAAK;oBACpB,KAAK,EAAE,OAAO,CAAC,KAAK;oBACpB,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,SAAS;iBAC1C,CAAC,CAAC;aACJ,CAAA;QACH,CAAC;QACD,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,wBAAwB,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;KACvG,CAAC,CAAC,CAAA;IAEH,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC;QAC5B,IAAI,EAAE,0BAA0B;QAChC,WAAW,EAAE,gKAAgK;QAC7K,UAAU,EAAE,EAAE;QACd,MAAM,EAAE;YACN,MAAM,EAAE;gBACN,IAAI,EAAE,QAAQ;gBACd,oBAAoB,EAAE,KAAK;gBAC3B,UAAU,EAAE;oBACV,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;oBACxC,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;oBAC9C,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;oBAC7C,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;oBAC5C,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;oBACzC,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;iBAC9C;aACF;YACD,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC;SAC5C;QACD,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI;YACvB,MAAM,SAAS,GAAG,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YACzC,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;YAC/C,IAAI,OAAO,CAAC,QAAQ,EAAE,KAAK,KAAK,kBAAkB,EAAE,CAAC;gBACnD,MAAM,IAAI,KAAK,CAAC,iCAAiC,OAAO,CAAC,QAAQ,EAAE,KAAK,IAAI,SAAS,EAAE,CAAC,CAAA;YAC1F,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,cAAc,CACxC,SAAS,EACT,OAAO,CAAC,QAAQ,EAChB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CACjC,CAAA;YACD,IAAI,MAAM,CAAC,QAAQ,EAAE,KAAK,KAAK,SAAS,EAAE,CAAC;gBACzC,MAAM,IAAI,KAAK,CAAC,6BAA6B,MAAM,CAAC,QAAQ,EAAE,KAAK,IAAI,SAAS,EAAE,CAAC,CAAA;YACrF,CAAC;YACD,OAAO;gBACL,IAAI,EAAE,2BAA2B;gBACjC,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE;gBAC9B,SAAS,EAAE,MAAM,CAAC,QAAQ,CAAC,SAAS;gBACpC,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,KAAK;gBAC5B,SAAS;aACV,CAAA;QACH,CAAC;QACD,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,0BAA0B,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;KACzG,CAAC,CAAC,CAAA;IAEH,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC;QAC5B,IAAI,EAAE,+BAA+B;QACrC,WAAW,EAAE,iKAAiK;QAC9K,UAAU,EAAE,EAAE;QACd,MAAM,EAAE;YACN,MAAM,EAAE;gBACN,IAAI,EAAE,QAAQ;gBACd,oBAAoB,EAAE,KAAK;gBAC3B,UAAU,EAAE;oBACV,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;oBACxC,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;oBAC9C,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;oBAC7C,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;oBACzC,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;oBAC9C,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;iBAC9C;aACF;YACD,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC;SAC5C;QACD,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI;YACvB,MAAM,SAAS,GAAG,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YACzC,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;YAC/C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,SAAS,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAA;YAC3E,IAAI,MAAM,CAAC,QAAQ,EAAE,KAAK,KAAK,SAAS,EAAE,CAAC;gBACzC,MAAM,IAAI,KAAK,CAAC,gCAAgC,MAAM,CAAC,QAAQ,EAAE,KAAK,IAAI,SAAS,EAAE,CAAC,CAAA;YACxF,CAAC;YACD,OAAO;gBACL,IAAI,EAAE,iCAAiC;gBACvC,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE;gBAC9B,SAAS,EAAE,MAAM,CAAC,QAAQ,CAAC,SAAS;gBACpC,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,KAAK;gBAC5B,UAAU,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG;gBAC9B,SAAS;aACV,CAAA;QACH,CAAC;QACD,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,+BAA+B,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;KAC9G,CAAC,CAAC,CAAA;IAEH,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC;QAC5B,IAAI,EAAE,2BAA2B;QACjC,WAAW,EAAE,8IAA8I;QAC3J,UAAU,EAAE;YACV,OAAO,EAAE;gBACP,IAAI,EAAE,QAAQ;gBACd,QAAQ,EAAE,IAAI;gBACd,WAAW,EAAE,iDAAiD;aAC/D;YACD,OAAO,EAAE;gBACP,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,mDAAmD;aACjE;YACD,gBAAgB,EAAE;gBAChB,IAAI,EAAE,QAAQ;gBACd,QAAQ,EAAE,IAAI;gBACd,IAAI,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,CAAC;aACjD;YACD,iBAAiB,EAAE;gBACjB,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,uCAAuC;aACrD;YACD,KAAK,EAAE;gBACL,IAAI,EAAE,OAAO;gBACb,QAAQ,EAAE,IAAI;gBACd,KAAK,EAAE;oBACL,IAAI,EAAE,QAAQ;oBACd,oBAAoB,EAAE,KAAK;oBAC3B,UAAU,EAAE;wBACV,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;wBAC3C,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAC,EAAE;wBACjF,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;qBAC5B;iBACF;aACF;YACD,sBAAsB,EAAE;gBACtB,IAAI,EAAE,QAAQ;gBACd,QAAQ,EAAE,IAAI;gBACd,WAAW,EAAE,2DAA2D;aACzE;SACF;QACD,MAAM,EAAE;YACN,MAAM,EAAE;gBACN,IAAI,EAAE,QAAQ;gBACd,oBAAoB,EAAE,KAAK;gBAC3B,UAAU,EAAE;oBACV,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;oBACxC,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;oBACzC,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;oBAC5C,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;oBAC5C,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;oBAC7C,YAAY,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;iBAC3E;aACF;YACD,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC;SAC5C;QACD,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI;YACtB,MAAM,SAAS,GAAG,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YACzC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,SAAS,EAAE;gBACxD,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,eAAe,EAAE,IAAI,CAAC,OAAO;gBAC7B,gBAAgB,EAAE,IAAI,CAAC,gBAA4C;gBACnE,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;gBACzC,KAAK,EAAE,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;oBACvC,OAAO,EAAE,IAAI,CAAC,OAAO;oBACrB,MAAM,EAAE,IAAI,CAAC,MAAyC;oBACtD,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBACnD,CAAC,CAAC;gBACH,sBAAsB,EAAE,IAAI,CAAC,sBAAsB;aACpD,CAAC,CAAA;YACF,IAAI,MAAM,CAAC,QAAQ,EAAE,KAAK,KAAK,kBAAkB,EAAE,CAAC;gBAClD,MAAM,IAAI,KAAK,CAAC,sBAAsB,MAAM,CAAC,QAAQ,EAAE,KAAK,IAAI,SAAS,EAAE,CAAC,CAAA;YAC9E,CAAC;YACD,OAAO;gBACL,IAAI,EAAE,2BAA2B;gBACjC,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,KAAK;gBAC5B,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ;gBACzC,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,SAAS,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS;gBAC3C,YAAY,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,YAAY;aAClD,CAAA;QACH,CAAC;QACD,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,2BAA2B,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;KAC1G,CAAC,CAAC,CAAA;AACL,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-git-worktree",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Experimental Git worktree Session Targets for DeepSeek Harness with real isolated sessions, review ToolViews, human-confirmed delivery, and safe cleanup.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -94,7 +94,7 @@ try {
|
|
|
94
94
|
if (hostContribution?.package !== manifest.name || hostContribution.face !== 'host') fail('./typert has invalid package/face identity')
|
|
95
95
|
if (remoteContribution?.package !== manifest.name) fail('./remote has invalid package identity')
|
|
96
96
|
if (hostContribution.invocations !== remoteContribution.descriptors) fail('./typert and ./remote must share one descriptor array instance')
|
|
97
|
-
const expectedRemoteMethods = ['current', 'list', 'create', 'inspect', 'reviewDiff', 'preflight', 'preview', 'rollbackPreview', 'discard', 'finalize', 'finalizePreview', 'setRetention', 'retryCleanup']
|
|
97
|
+
const expectedRemoteMethods = ['current', 'list', 'create', 'inspect', 'reviewDiff', 'preflight', 'preview', 'resumeRevision', 'rollbackPreview', 'discard', 'finalize', 'finalizePreview', 'setRetention', 'retryCleanup', 'beginNextIteration']
|
|
98
98
|
if (JSON.stringify(hostContribution.invocations.map(value => value.method)) !== JSON.stringify(expectedRemoteMethods)) {
|
|
99
99
|
fail(`manual Remote methods differ from the required surface: ${hostContribution.invocations.map(value => value.method).join(', ')}`)
|
|
100
100
|
}
|
package/scripts/dev-dsh-lib.mjs
CHANGED
|
@@ -199,6 +199,11 @@ function isHarnessRoot(path) {
|
|
|
199
199
|
&& existsSync(join(path, 'apps', 'cli', 'src', 'bin.ts'))
|
|
200
200
|
}
|
|
201
201
|
|
|
202
|
+
function isHarnessSourceReady(path) {
|
|
203
|
+
return isHarnessRoot(path)
|
|
204
|
+
&& existsSync(join(path, 'node_modules', 'tsx', 'package.json'))
|
|
205
|
+
}
|
|
206
|
+
|
|
202
207
|
export function discoverHarnessRoot(projectRoot, environment = process.env) {
|
|
203
208
|
if (environment.DSH_HARNESS_ROOT) {
|
|
204
209
|
const configured = resolve(environment.DSH_HARNESS_ROOT)
|
|
@@ -210,8 +215,14 @@ export function discoverHarnessRoot(projectRoot, environment = process.env) {
|
|
|
210
215
|
try {
|
|
211
216
|
const commonDir = git(projectRoot, ['rev-parse', '--path-format=absolute', '--git-common-dir'])
|
|
212
217
|
const localProjectRoot = dirname(resolve(projectRoot, commonDir))
|
|
213
|
-
const
|
|
214
|
-
|
|
218
|
+
const parent = dirname(localProjectRoot)
|
|
219
|
+
const candidates = [
|
|
220
|
+
join(parent, 'deepseek-harness'),
|
|
221
|
+
join(dirname(parent), 'deepseek-harness'),
|
|
222
|
+
join(parent, 'DeepSeek', 'deepseek-harness'),
|
|
223
|
+
]
|
|
224
|
+
const validCandidates = candidates.filter(isHarnessRoot)
|
|
225
|
+
return validCandidates.find(isHarnessSourceReady) ?? validCandidates[0]
|
|
215
226
|
} catch {
|
|
216
227
|
return undefined
|
|
217
228
|
}
|
|
@@ -221,34 +232,51 @@ export function executable(name, platform = process.platform) {
|
|
|
221
232
|
return platform === 'win32' ? `${name}.cmd` : name
|
|
222
233
|
}
|
|
223
234
|
|
|
224
|
-
export function
|
|
235
|
+
export function createDshInvocation(options) {
|
|
236
|
+
const cwd = options.cwd ?? options.projectRoot
|
|
237
|
+
const args = options.args ?? []
|
|
225
238
|
if (!options.harnessRoot) {
|
|
226
239
|
return {
|
|
227
240
|
command: executable('dsh', options.platform),
|
|
228
|
-
args
|
|
229
|
-
cwd
|
|
241
|
+
args,
|
|
242
|
+
cwd,
|
|
230
243
|
source: false,
|
|
231
244
|
}
|
|
232
245
|
}
|
|
233
|
-
|
|
234
|
-
|
|
246
|
+
const harnessRoot = resolve(options.harnessRoot)
|
|
247
|
+
if (!isHarnessRoot(harnessRoot)) {
|
|
248
|
+
throw new Error(`Harness source checkout is invalid: ${harnessRoot}`)
|
|
249
|
+
}
|
|
250
|
+
if (!isHarnessSourceReady(harnessRoot)) {
|
|
251
|
+
throw new Error(
|
|
252
|
+
`Harness source checkout is not prepared: ${harnessRoot}. Run pnpm --dir "${harnessRoot}" install before dev preview.`,
|
|
253
|
+
)
|
|
235
254
|
}
|
|
236
255
|
return {
|
|
237
256
|
command: executable('pnpm', options.platform),
|
|
238
257
|
args: [
|
|
239
|
-
'--dir',
|
|
258
|
+
'--dir', harnessRoot,
|
|
240
259
|
'exec', 'node', '--import', 'tsx/esm',
|
|
241
260
|
join(options.projectRoot, 'scripts', 'dsh-source-runner.mjs'),
|
|
242
|
-
|
|
243
|
-
join(
|
|
244
|
-
|
|
245
|
-
'--port', String(options.port),
|
|
261
|
+
cwd,
|
|
262
|
+
join(harnessRoot, 'apps', 'cli', 'src', 'bin.ts'),
|
|
263
|
+
...args,
|
|
246
264
|
],
|
|
247
265
|
cwd: options.projectRoot,
|
|
248
266
|
source: true,
|
|
249
267
|
}
|
|
250
268
|
}
|
|
251
269
|
|
|
270
|
+
export function createDshLaunch(options) {
|
|
271
|
+
return createDshInvocation({
|
|
272
|
+
projectRoot: options.projectRoot,
|
|
273
|
+
harnessRoot: options.harnessRoot,
|
|
274
|
+
platform: options.platform,
|
|
275
|
+
cwd: options.workspaceRoot,
|
|
276
|
+
args: ['--profile', options.profile, '--port', String(options.port)],
|
|
277
|
+
})
|
|
278
|
+
}
|
|
279
|
+
|
|
252
280
|
function assertWindowsCommandSafe(command, args) {
|
|
253
281
|
for (const value of [command, ...args]) {
|
|
254
282
|
if (/[\0\r\n"&|<>^%!]/.test(value)) {
|
|
@@ -371,11 +399,46 @@ function repairMissingCurrentProfileArchive(options, archivePath) {
|
|
|
371
399
|
copyFileSync(archivePath, previous)
|
|
372
400
|
}
|
|
373
401
|
|
|
402
|
+
function assertDshRuntimeAvailable(options) {
|
|
403
|
+
if (options.harnessRoot) {
|
|
404
|
+
createDshInvocation({
|
|
405
|
+
projectRoot: options.projectRoot,
|
|
406
|
+
harnessRoot: options.harnessRoot,
|
|
407
|
+
platform: options.platform,
|
|
408
|
+
args: [],
|
|
409
|
+
})
|
|
410
|
+
return
|
|
411
|
+
}
|
|
412
|
+
if (options.run) return
|
|
413
|
+
try {
|
|
414
|
+
runProcess(executable('dsh', options.platform), ['--version'], { capture: true })
|
|
415
|
+
} catch (cause) {
|
|
416
|
+
throw new Error(
|
|
417
|
+
'No Harness source checkout was selected and the installed dsh CLI is unavailable. Pass --harness <path>, set DSH_HARNESS_ROOT, or install dsh on PATH.',
|
|
418
|
+
{ cause },
|
|
419
|
+
)
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
function runDsh(options, args, runOptions = {}) {
|
|
424
|
+
const invocation = createDshInvocation({
|
|
425
|
+
projectRoot: options.projectRoot,
|
|
426
|
+
harnessRoot: options.harnessRoot,
|
|
427
|
+
platform: options.platform,
|
|
428
|
+
cwd: runOptions.cwd ?? options.projectRoot,
|
|
429
|
+
args,
|
|
430
|
+
})
|
|
431
|
+
return (options.run ?? runProcess)(invocation.command, invocation.args, {
|
|
432
|
+
cwd: invocation.cwd,
|
|
433
|
+
...(runOptions.capture === true ? { capture: true } : {}),
|
|
434
|
+
})
|
|
435
|
+
}
|
|
436
|
+
|
|
374
437
|
/** Build, pack and install only the current local snapshot. No registry publish occurs. */
|
|
375
438
|
export function installLocalSnapshot(options) {
|
|
376
439
|
const run = options.run ?? runProcess
|
|
377
440
|
const pnpm = executable('pnpm', options.platform)
|
|
378
|
-
|
|
441
|
+
assertDshRuntimeAvailable(options)
|
|
379
442
|
mkdirSync(options.cacheRoot, { recursive: true })
|
|
380
443
|
|
|
381
444
|
if (!existsSync(join(options.projectRoot, 'node_modules'))) {
|
|
@@ -399,7 +462,7 @@ export function installLocalSnapshot(options) {
|
|
|
399
462
|
scripts: {},
|
|
400
463
|
}
|
|
401
464
|
writeFileSync(join(stagingRoot, 'package.json'), `${JSON.stringify(stagedManifest, null, 2)}\n`)
|
|
402
|
-
for (const entry of ['lib', 'cordis.patch.yml', 'README.md', 'README.
|
|
465
|
+
for (const entry of ['lib', 'cordis.patch.yml', 'README.md', 'README.en.md', 'LICENSE']) {
|
|
403
466
|
const source = join(options.projectRoot, entry)
|
|
404
467
|
if (existsSync(source)) copyPackageEntry(source, join(stagingRoot, entry))
|
|
405
468
|
}
|
|
@@ -413,15 +476,12 @@ export function installLocalSnapshot(options) {
|
|
|
413
476
|
// replace it. Repair only our own missing cache path with the new snapshot;
|
|
414
477
|
// after the add succeeds the obsolete recovery copy becomes collectible.
|
|
415
478
|
repairMissingCurrentProfileArchive(options, archivePath)
|
|
416
|
-
|
|
479
|
+
runDsh(options, ['plugin', '--profile', options.profile, 'add', archivePath])
|
|
417
480
|
const referencedArchive = profileArchiveReference(options)
|
|
418
481
|
if (comparablePath(referencedArchive) !== comparablePath(archivePath)) {
|
|
419
482
|
throw new Error(`DSH profile ${options.profile} still references ${referencedArchive}; preserving old and new archives for recovery.`)
|
|
420
483
|
}
|
|
421
|
-
const dump =
|
|
422
|
-
cwd: options.projectRoot,
|
|
423
|
-
capture: true,
|
|
424
|
-
}).stdout
|
|
484
|
+
const dump = runDsh(options, ['--profile', options.profile, '--dump-config'], { capture: true }).stdout
|
|
425
485
|
if (!dump.includes('dsh-git-worktree')) {
|
|
426
486
|
throw new Error(`Profile ${options.profile} installed the tarball but did not compose dsh-git-worktree.`)
|
|
427
487
|
}
|
|
@@ -430,10 +490,8 @@ export function installLocalSnapshot(options) {
|
|
|
430
490
|
}
|
|
431
491
|
|
|
432
492
|
export function removeLocalSnapshot(options) {
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
'plugin', '--profile', options.profile, 'remove', 'dsh-git-worktree',
|
|
436
|
-
], { cwd: options.projectRoot })
|
|
493
|
+
assertDshRuntimeAvailable(options)
|
|
494
|
+
runDsh(options, ['plugin', '--profile', options.profile, 'remove', 'dsh-git-worktree'])
|
|
437
495
|
if (existsSync(options.cacheRoot)) {
|
|
438
496
|
for (const entry of readdirSync(options.cacheRoot)) {
|
|
439
497
|
if (/^dsh-git-worktree-\d+\.tgz$/.test(entry)) rmSync(join(options.cacheRoot, entry), { force: true })
|
|
@@ -442,10 +500,8 @@ export function removeLocalSnapshot(options) {
|
|
|
442
500
|
}
|
|
443
501
|
|
|
444
502
|
export function smokeLocalSnapshot(options) {
|
|
445
|
-
|
|
446
|
-
const dump =
|
|
447
|
-
'--profile', options.profile, '--dump-config',
|
|
448
|
-
], { cwd: options.projectRoot, capture: true }).stdout
|
|
503
|
+
assertDshRuntimeAvailable(options)
|
|
504
|
+
const dump = runDsh(options, ['--profile', options.profile, '--dump-config'], { capture: true }).stdout
|
|
449
505
|
if (!dump.includes('dsh-git-worktree')) {
|
|
450
506
|
throw new Error(`Profile ${options.profile} does not compose dsh-git-worktree.`)
|
|
451
507
|
}
|
package/scripts/dev-dsh.mjs
CHANGED
|
@@ -27,14 +27,17 @@ function printUsage() {
|
|
|
27
27
|
|
|
28
28
|
Usage:
|
|
29
29
|
pnpm run dev:dsh -- [--profile web] [--repo <git-root>] [--port 3081] [--harness <path>]
|
|
30
|
-
pnpm run dev:dsh:install -- [--profile web]
|
|
31
|
-
pnpm run dev:dsh:smoke -- [--profile web]
|
|
32
|
-
pnpm run dev:dsh:remove -- [--profile web]
|
|
30
|
+
pnpm run dev:dsh:install -- [--profile web] [--harness <path>]
|
|
31
|
+
pnpm run dev:dsh:smoke -- [--profile web] [--harness <path>]
|
|
32
|
+
pnpm run dev:dsh:remove -- [--profile web] [--harness <path>]
|
|
33
33
|
|
|
34
34
|
The install path is a local tarball under the OS temporary directory. Nothing is
|
|
35
|
-
published to npm or pushed to Git.
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
published to npm or pushed to Git. Nearby Harness source checkouts are scanned
|
|
36
|
+
and a candidate with node_modules/tsx is preferred; an arbitrary checkout can be
|
|
37
|
+
selected with DSH_HARNESS_ROOT or --harness. Every profile and launch command
|
|
38
|
+
then uses that source CLI instead of a globally installed dsh executable. An
|
|
39
|
+
explicit checkout without dependencies fails early with its pnpm install command.
|
|
40
|
+
Without --repo, a marker-protected disposable Git repository is created at:
|
|
38
41
|
${defaults.repo}
|
|
39
42
|
`)
|
|
40
43
|
}
|
|
@@ -45,24 +48,27 @@ try {
|
|
|
45
48
|
process.exitCode = 0
|
|
46
49
|
} else {
|
|
47
50
|
const options = parseDevDshArgs(process.argv.slice(2), defaults)
|
|
51
|
+
const runtime = {
|
|
52
|
+
projectRoot,
|
|
53
|
+
profile: options.profile,
|
|
54
|
+
harnessRoot: options.harnessRoot,
|
|
55
|
+
}
|
|
48
56
|
if (options.mode === 'install') {
|
|
49
57
|
const installed = installLocalSnapshot({
|
|
50
|
-
|
|
51
|
-
profile: options.profile,
|
|
58
|
+
...runtime,
|
|
52
59
|
cacheRoot,
|
|
53
60
|
})
|
|
54
61
|
console.log(`\nLocal snapshot installed in profile "${options.profile}".`)
|
|
55
62
|
console.log(`Archive retained for profile reproducibility: ${installed.archivePath}`)
|
|
56
63
|
} else if (options.mode === 'smoke') {
|
|
57
|
-
smokeLocalSnapshot(
|
|
64
|
+
smokeLocalSnapshot(runtime)
|
|
58
65
|
console.log(`Profile "${options.profile}" composes dsh-git-worktree.`)
|
|
59
66
|
} else if (options.mode === 'remove') {
|
|
60
|
-
removeLocalSnapshot({
|
|
67
|
+
removeLocalSnapshot({ ...runtime, cacheRoot })
|
|
61
68
|
console.log(`Removed dsh-git-worktree from profile "${options.profile}" and cleared local archives.`)
|
|
62
69
|
} else {
|
|
63
70
|
const installed = installLocalSnapshot({
|
|
64
|
-
|
|
65
|
-
profile: options.profile,
|
|
71
|
+
...runtime,
|
|
66
72
|
cacheRoot,
|
|
67
73
|
})
|
|
68
74
|
const fixture = ensureDevFixture(options.repo, { explicit: options.repoExplicit })
|
package/README.zh.md
DELETED
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
# dsh-git-worktree
|
|
2
|
-
|
|
3
|
-
面向 DeepSeek Harness 的**实验性** Git Worktree Session Target 插件。它保留 Domi 中经过生产验证的 checkout / apply engine 安全核心,并按 Harness 的权威 Workspace / Session cwd 模型重做产品闭环。
|
|
4
|
-
|
|
5
|
-
> 当前范围:真实隔离 Session、Harness-native Session Target/Worktree Console、可撤回的 Local Preview、验收提交/撤回/跳过验收直接提交、项目级验收槽位、持久恢复凭据、保留策略、崩溃恢复、指纹 CAS 与保守清理。它还不是 Domi 的跨项目全局 Worktree Manager。
|
|
6
|
-
|
|
7
|
-
## 工作流程
|
|
8
|
-
|
|
9
|
-
1. 在 blank/new Local Session 中,用户点击 composer 工具栏的 **Worktree** 开关后先看到确认弹窗。取消不会创建任何资源;确认后插件才冻结 Local composer、创建 isolated target,把尚未发送的文本/图片草稿迁移过去并打开 target。首条消息仍由用户在 target 的原生 composer 中发送,任何 prompt 都不会先进入 Local。
|
|
10
|
-
2. 已存在的 Local Session 仍可通过模型拥有的 `worktree_create` ToolView 创建 target。主流程稳定前,原项目级 **Worktree** 标签页暂不挂载。
|
|
11
|
-
3. 插件在仓库同级容器中创建唯一 detached Worktree(不可用时回退到插件 stateDir),并预留一个独立 target Session ID;源 Session 始终保持 Local。
|
|
12
|
-
4. Harness 把 Worktree 路径注册为 Workspace,使用 Host 预留的精确 ID 创建并打开 Session。持久化 Session header 的 cwd 才是权威 Session Target。
|
|
13
|
-
5. Agent 只在该 isolated cwd 中修改和验证,完成后把 `worktree_ready_for_review` 作为最后一个模型操作。
|
|
14
|
-
6. Worktree Ready 后,target composer 上方常驻 Domi 式中文状态条;紧凑验收卡默认只展示摘要、验证状态、文件数量和折叠的测试证据,不再展示 Diff/Inspect 或平铺多个保留按钮。
|
|
15
|
-
7. Ready 主操作是**同步到 Local 验收**:Host 先执行只读 preflight,再把精确 review 增量同步成不提交、可撤回的 Local Preview。Preview active 后主操作变为**验收通过并提交**;更多菜单可撤回本次预览并让 Worktree 回到继续修改状态。Ready 更多菜单还提供**跳过验收,直接提交**与放弃任务。
|
|
16
|
-
8. Preview、rollback 和 finalize 都绑定 revision、review ID、HEAD 与 fingerprint CAS。同一 Local 项目同时只允许一个活动 Preview;放弃 active Preview 时必须先安全 rollback。rollback 可在分支未变且 HEAD 仅安全快进时,通过三方树证明只移除 Preview、保留新 Commit 与原 Local 层;切分支、改写历史、Preview 已进入 Commit 或内容冲突仍 fail closed,保留 Worktree 与恢复凭据,绝不覆盖用户修改。
|
|
17
|
-
|
|
18
|
-
## 能力面
|
|
19
|
-
|
|
20
|
-
### 模型工具
|
|
21
|
-
|
|
22
|
-
| 工具 | 作用 |
|
|
23
|
-
| --- | --- |
|
|
24
|
-
| `worktree_create` | 预留唯一 Worktree 与独立 owner Session;不会修改当前 Session cwd |
|
|
25
|
-
| `worktree_list` | 仅列出当前 Session 在原始项目中拥有或创建的 Worktree |
|
|
26
|
-
| `worktree_ready_for_review` | 持久化完整交付报告并停止,等待用户验收 |
|
|
27
|
-
|
|
28
|
-
Apply、Finish、Discard、Remove **不再作为模型工具**暴露。模型参数不能替代可信的用户授权。
|
|
29
|
-
|
|
30
|
-
### Harness-native Worktree Console
|
|
31
|
-
|
|
32
|
-
Client 通过官方 Gateway 挂载本包拥有的 strict Typert Remote contribution。blank Local Session 会在 Harness 官方 `conversation.input.left` composer 工具栏 Slot 中显示紧凑的 **Worktree** 开关;点击只打开确认弹窗,确认后才准备 Host 分配的 target,并在导航前迁移尚未发送的文本/图片草稿,标准 Harness Send 仍是唯一 prompt 路径。每个持久 Session 都可看到只读 target 状态胶囊;Ready 后由 `conversation.input.dock` 显示始终可见的紧凑验收条,只保留一个主操作和“更多”菜单。高级 `WorktreeConsoleView`、Host 控制面和 strict Remote 方法仍完整保留,但 v0.2.0 暂不挂载项目级 `conversation.view` 标签页。列表行不包含路径;只有通过身份验证的 `current`、`create` 或 `inspect` 才返回 managed root。
|
|
33
|
-
|
|
34
|
-
### 用户命令
|
|
35
|
-
|
|
36
|
-
```text
|
|
37
|
-
/worktree status
|
|
38
|
-
/worktree list
|
|
39
|
-
/worktree finalize [cleanup|retain_24h|retain_3d|retain_manual]
|
|
40
|
-
/worktree finish <自定义 Commit Message>
|
|
41
|
-
/worktree discard
|
|
42
|
-
/worktree remove <checkoutId>
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
Client 通过 strict Remote 调用 `preflight`、`preview`、`rollbackPreview`、`finalizePreview`,或在用户明确选择跳过验收时调用 `finalize`。所有路径携带精确 review ID/revision;提交路径还携带用户确认的 1–500 字符 Commit Message 与 retention。Host 会再次校验 caller、project、managed cwd、review、HEAD/fingerprint 和 Local CAS;历史卡片、Ready 后新增修改或 Local 漂移都 fail closed。
|
|
46
|
-
|
|
47
|
-
## 安全不变量
|
|
48
|
-
|
|
49
|
-
- source 与 target 使用不同 Session ID;不会再用插件私有 registry 把 Local Session 伪装成 isolated。
|
|
50
|
-
- Worktree 开关的确认弹窗不创建资源;用户确认后 Pre-session 事务才同步 block source composer。只有 managed Workspace、精确 target Session、草稿迁移与 source draft revision CAS 全部成功后才打开 target,失败时 source 草稿保持原样。
|
|
51
|
-
- target Harness Workspace 必须 canonicalize 到记录的 managed root,否则访问 fail closed。
|
|
52
|
-
- 新 Worktree 使用 `<repo>--worktrees/<repo>--<checkout-short>--worktree`;短 ID 冲突时扩展 identity,不覆盖未知目录。不安全 sibling 回退到 `<stateDir>/worktrees/<repository-key>/`,旧 registry 路径仍可管理。
|
|
53
|
-
- 已走过旧版不可逆 Apply 的历史记录禁止自动 Finish / Discard,必须先人工核对 Local。
|
|
54
|
-
- list 与 manage 都按真实 caller 作用域过滤;持久化 `ownerSessionId` 本身不是授权。
|
|
55
|
-
- Preview receipt 在触碰 Local 前持久化并保留 Local working tree、index、Preview tree 与 Isolated snapshot;rollback/finalize 可在 Host 重启后恢复;同分支 fast-forward rollback 会先证明新 HEAD 未包含 Preview,再重放原 Local 层并做写前/写后 CAS。
|
|
56
|
-
- 同一 canonical Local root 只有一个活动验收槽位;Preview detached 会释放槽位,但保留恢复证据。
|
|
57
|
-
- Finish 保留 Local 无关 staged/working 状态,并拒绝 stale Local / stale Isolated;active Preview 的 Discard 必须先安全 rollback。
|
|
58
|
-
- 清理前验证路径、Git common-dir、git-dir、目录身份和最终指纹;不确定残余会保留或 quarantine。
|
|
59
|
-
|
|
60
|
-
## 安装
|
|
61
|
-
|
|
62
|
-
```bash
|
|
63
|
-
# npm(推荐)
|
|
64
|
-
dsh plugin --profile web add dsh-git-worktree
|
|
65
|
-
|
|
66
|
-
# Git 源码安装(prepare 构建 Host + Client bundle)
|
|
67
|
-
dsh plugin --profile web add github:wloops/dsh-git-worktree#v0.2.0
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
pnpm >= 10 可能会拦截 Git 依赖的构建脚本;在 profile 的 `pnpm-workspace.yaml` 的 `allowBuilds` 下加入 `dsh-git-worktree: true` 后重试。
|
|
71
|
-
|
|
72
|
-
要求 DeepSeek Harness `0.1.0-rc.6` 包线;交互 ToolView 需要 Web Client。
|
|
73
|
-
|
|
74
|
-
## 一键本地开发测试
|
|
75
|
-
|
|
76
|
-
持续迭代时,在任意当前 checkout(包括 Domi managed Worktree)中运行:
|
|
77
|
-
|
|
78
|
-
```bash
|
|
79
|
-
pnpm run dev:dsh
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
该命令会自动执行 typecheck/build,把**当前 checkout 快照**打成 OS 临时目录中的本地 tarball,安装到 `web` profile,检查组合配置,创建或复用 marker 保护的临时 Git fixture,最后从 fixture cwd 启动 `dsh web`(默认 `http://127.0.0.1:3081`)。如果检测到同一开发目录下的 `DeepSeek/deepseek-harness` 源码 checkout,会优先用它启动 DSH,同时仍把 Session workspace 保持为 fixture;也可用 `DSH_HARNESS_ROOT` 或 `--harness <path>` 指定。找不到源码 checkout 时才使用 PATH 中已安装的 `dsh`。它不会运行 `npm publish`、Git push 或创建 tag,也不会留下指向已清理 managed Worktree 的软链接。profile 当前引用的 tarball 会保留,成功安装新快照后会清理旧 tarball。
|
|
83
|
-
|
|
84
|
-
常用入口:
|
|
85
|
-
|
|
86
|
-
```bash
|
|
87
|
-
# 只安装当前快照并验证配置,不启动 Web
|
|
88
|
-
pnpm run dev:dsh:install
|
|
89
|
-
|
|
90
|
-
# 只检查已安装 profile
|
|
91
|
-
pnpm run dev:dsh:smoke
|
|
92
|
-
|
|
93
|
-
# 使用现有 Git 仓库或其他端口/profile
|
|
94
|
-
pnpm run dev:dsh -- --repo G:/path/to/repo --port 4090 --profile web
|
|
95
|
-
|
|
96
|
-
# 显式从 profile 卸载,并清理本地开发 tarball
|
|
97
|
-
pnpm run dev:dsh:remove
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
默认 fixture 位于系统临时目录 `dsh-git-worktree-dev/fixture`。它只会初始化不存在或为空的目录;复用时必须具有插件 marker、Git 根身份正确、状态干净且没有遗留 linked Worktree。遇到未知文件、脏状态、符号链接或残留 Worktree 会 fail closed,脚本绝不会自动 reset 或删除内容。显式 `--repo` 必须指向已经存在的 Git 根,脚本只验证、不初始化或改写它。
|
|
101
|
-
|
|
102
|
-
## 当前限制
|
|
103
|
-
|
|
104
|
-
- 旧 `worktree_apply` 入口仍禁用;公开交付路径只允许用户触发的 Preview/rollback/finalize/direct finish。
|
|
105
|
-
- 尚无跨项目全局侧栏 Manager。项目级 Worktree Console 实现仍保留用于恢复与后续重做,但其可见 `conversation.view` 标签页暂不挂载。
|
|
106
|
-
- Harness 仍未开放 Workflow `agent({ isolation })`。
|
|
107
|
-
- 子 Agent 继承父 Session cwd;只有父 Session 已真实进入 Worktree 后才形成隔离。
|
|
108
|
-
- dependency snapshot、完整 collaborator handoff UI 延后。
|
|
109
|
-
- 选择立即清理后,isolated Session 的 cwd 会被删除,因此该 Session 视为终态;后续应回到 Local 或开启下一轮 Session。
|
|
110
|
-
|
|
111
|
-
Domi 与 Harness 的边界见 [docs/PORTING.md](docs/PORTING.md),发布门禁见 [docs/RELEASE.md](docs/RELEASE.md)。
|
|
112
|
-
|
|
113
|
-
## 许可证
|
|
114
|
-
|
|
115
|
-
MIT
|