@ran-sh/dsh-crew 1.10.7 → 1.10.9
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/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { createHash, randomUUID } from 'node:crypto';
|
|
2
|
-
import { existsSync, lstatSync, mkdirSync, mkdtempSync, readFileSync,
|
|
2
|
+
import { existsSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
3
3
|
import { dirname, join } from 'node:path';
|
|
4
4
|
import { homedir } from 'node:os';
|
|
5
5
|
import { pathToFileURL } from 'node:url';
|
|
6
|
+
import { renameTree } from './tree-move.mjs';
|
|
6
7
|
|
|
7
8
|
function plan(home, root) {
|
|
8
9
|
const bridge = join(root, 'official-web-bridge');
|
|
@@ -61,13 +62,17 @@ export function installOfficialFrontendAssets({ home = homedir(), root } = {}) {
|
|
|
61
62
|
mkdirSync(dirname(file), { recursive: true });
|
|
62
63
|
writeFileSync(file, bytes);
|
|
63
64
|
}
|
|
64
|
-
|
|
65
|
+
// Windows can refuse this rename for a moment when something else holds a
|
|
66
|
+
// handle under the destination, and the refusal is not about the rename:
|
|
67
|
+
// the same call succeeds shortly after. Producing the snapshot first in a
|
|
68
|
+
// concurrent installer is the other outcome this tolerates.
|
|
69
|
+
try { renameTree(stage, p.snapshotRoot); stage = null; }
|
|
65
70
|
catch (error) { if (!matches(p)) throw error; }
|
|
66
71
|
}
|
|
67
72
|
if (!matches(p)) throw new Error('frontend snapshot conflicts with its revision');
|
|
68
73
|
temp = `${p.overlayFile}.${randomUUID()}.tmp`;
|
|
69
74
|
writeFileSync(temp, p.overlay, { flag: 'wx', mode: 0o600 });
|
|
70
|
-
|
|
75
|
+
renameTree(temp, p.overlayFile); temp = null;
|
|
71
76
|
return { ok: true, changed: true, revision: p.revision, snapshotRoot: p.snapshotRoot, overlayFile: p.overlayFile };
|
|
72
77
|
} catch (error) {
|
|
73
78
|
return { ok: false, code: 'OFFICIAL_FRONTEND_ASSETS_FAILED', error: error.message };
|
package/src/mcp-runtime.mjs
CHANGED
|
@@ -222,6 +222,15 @@ export function buildMcpWorkflowRuntime(deps) {
|
|
|
222
222
|
source,
|
|
223
223
|
preset,
|
|
224
224
|
delivery,
|
|
225
|
+
// Isolation belongs to this client: it already allocated the workspace
|
|
226
|
+
// and `spec.cwd` is the result. Saying so keeps the hub executing in that
|
|
227
|
+
// cwd instead of resolving an isolation of its own and allocating a
|
|
228
|
+
// second workspace — which put the work somewhere the client was not
|
|
229
|
+
// looking and captured no candidate for.
|
|
230
|
+
requested_isolation: 'shared',
|
|
231
|
+
// The same authorization the client was given, so the hub judges the
|
|
232
|
+
// workspace evidence against the same task contract.
|
|
233
|
+
allow_no_changes: spec.allow_no_changes === true,
|
|
225
234
|
});
|
|
226
235
|
spec.onAttemptStarted?.(spawned.id);
|
|
227
236
|
|
package/src/runtime-identity.mjs
CHANGED
|
@@ -36,7 +36,7 @@ export {
|
|
|
36
36
|
// included in the identity contract.
|
|
37
37
|
const RUNTIME_ID = randomUUID();
|
|
38
38
|
|
|
39
|
-
export const RUNTIME_VERSION = '1.10.
|
|
39
|
+
export const RUNTIME_VERSION = '1.10.9';
|
|
40
40
|
export const HUB_PROTOCOL_VERSION = 1;
|
|
41
41
|
|
|
42
42
|
export const HUB_CAPABILITIES = Object.freeze([
|
package/src/workflow-runtime.mjs
CHANGED
|
@@ -38,8 +38,23 @@ function lines(value) {
|
|
|
38
38
|
return value.split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
// A reviewer writes its verdict as one line, and it decorates that line the way
|
|
42
|
+
// prose is decorated: bolded, bulleted, quoted, or introduced by a label. The
|
|
43
|
+
// contract asks for "approved / needs changes / rejected", and every one of
|
|
44
|
+
// those decorations used to fall through to `inconclusive` — which blocks
|
|
45
|
+
// acceptance, so turning on the automatic reviewer could reject correct work
|
|
46
|
+
// because the reviewer wrote **Approved** instead of Approved.
|
|
47
|
+
function stripVerdictDecoration(value) {
|
|
48
|
+
return String(value ?? '')
|
|
49
|
+
.replace(/^[\s>*_`#-]+/, '')
|
|
50
|
+
.replace(/^\**\s*(?:final\s+)?verdict\s*[:\-—]\s*/i, '')
|
|
51
|
+
.replace(/^[\s>*_`#-]+/, '')
|
|
52
|
+
.replace(/[\s*_`]+$/, '')
|
|
53
|
+
.trim();
|
|
54
|
+
}
|
|
55
|
+
|
|
41
56
|
export function normalizeReviewVerdict(value) {
|
|
42
|
-
const s =
|
|
57
|
+
const s = stripVerdictDecoration(value).toLowerCase();
|
|
43
58
|
if (/^(approve|approved|pass)\b/.test(s) || s === 'pass' || s === 'approve') return 'approve';
|
|
44
59
|
if (/request.*chang|chang.*request|reject|needs changes/i.test(s)) return 'request_changes';
|
|
45
60
|
return 'inconclusive';
|
|
@@ -382,6 +397,10 @@ export function createWorkflowRuntime(adapters, {
|
|
|
382
397
|
cwd: job.execution_cwd,
|
|
383
398
|
effort: job.effort,
|
|
384
399
|
timeout_seconds: job.timeout_seconds,
|
|
400
|
+
// Passed through so the executor judges the workspace evidence against
|
|
401
|
+
// the same task contract this workflow was given, instead of against a
|
|
402
|
+
// default that would refuse an authorization the caller granted.
|
|
403
|
+
allow_no_changes: job.allow_no_changes === true,
|
|
385
404
|
policy,
|
|
386
405
|
source: job.source,
|
|
387
406
|
model_class_hint: job.model_class_hint,
|
package/src/workflow.mjs
CHANGED
|
@@ -81,12 +81,18 @@ const NO_CHANGE_ASSERTION_RE = new RegExp(
|
|
|
81
81
|
function isNoChangeAssertion(line) {
|
|
82
82
|
const normalized = line
|
|
83
83
|
.replace(/^(?:[-*+]\s+)+/, '')
|
|
84
|
-
.replace(/[`"'
|
|
84
|
+
.replace(/[`"'“”‘’*_]/g, '')
|
|
85
85
|
.replace(/[.!。!]+$/, '')
|
|
86
86
|
.trim()
|
|
87
87
|
.toLowerCase();
|
|
88
88
|
if (normalized === '') return false;
|
|
89
|
-
|
|
89
|
+
// The assertion is usually a whole line, but a report may also end with it —
|
|
90
|
+
// "**Final state: no files changed.**" is the same declaration stated as a
|
|
91
|
+
// summary. Testing each sentence and clause is what finds it without matching
|
|
92
|
+
// a phrase that merely appears inside an unrelated one.
|
|
93
|
+
return normalized
|
|
94
|
+
.split(/\s*(?:[.:;,—–()\[\]]|->)\s*/)
|
|
95
|
+
.some((fragment) => fragment !== '' && NO_CHANGE_ASSERTION_RE.test(fragment.trim()));
|
|
90
96
|
}
|
|
91
97
|
|
|
92
98
|
// Whether the report claims the workspace holds changes. A report that asserts
|