dsh-pstack 0.2.0 → 0.2.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/README.md +19 -13
- package/README.zh.md +19 -13
- package/cordis.patch.yml +4 -0
- package/dist/client.mjs +116 -9
- package/dist/client.mjs.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{paths-BT77khwm.mjs → paths-yji9SNak.mjs} +0 -1
- package/dist/pstack/docs/harness/dsh.md +7 -7
- package/dist/pstack/skills/poteto-mode/scripts/check-plan.test.mjs +1 -1
- package/dist/pstack/skills/poteto-mode/scripts/watch-pr/github.test.mjs +1 -1
- package/dist/pstack/skills/poteto-mode/scripts/worktree-audit.mjs +1 -1
- package/dist/pstack/skills/statechart/scripts/run.mjs +3 -3
- package/dist/pstack/skills/statechart/scripts/statechart.mjs +1 -1
- package/dist/pstack/skills/statechart/scripts/statechart.test.mjs +2 -2
- package/dist/pstack/skills/statechart/scripts/worker.mjs +1 -1
- package/dist/remote.d.mts +1 -1
- package/dist/remote.mjs +2 -1
- package/dist/role-catalog.d.mts +35 -0
- package/dist/role-catalog.mjs +122 -0
- package/dist/{role-config-NNn5r1JX.mjs → role-config-a4JpVdc-.mjs} +107 -143
- package/dist/role-manifest-79cnFfDM.mjs +112 -0
- package/dist/role-manifest-8OERX9-s.d.mts +90 -0
- package/dist/{role-wire-DZwTn2wF.d.mts → role-wire-CAJsVA6e.d.mts} +2 -3
- package/dist/roles.d.mts +1 -1
- package/dist/roles.mjs +4 -34
- package/dist/script.mjs +1 -1
- package/dist/subagent.d.mts +25 -3
- package/dist/subagent.mjs +67 -37
- package/package.json +13 -11
- package/dist/role-manifest-C3fUzjLI.d.mts +0 -19
|
@@ -1,108 +1,97 @@
|
|
|
1
|
+
import { i as findRoleSpec, n as PSTACK_MODELS_FILENAME, o as normalizeRoleName, r as ROLE_MANIFEST, t as INHERIT_PARENT_ALIASES } from "./role-manifest-79cnFfDM.mjs";
|
|
1
2
|
import { join, resolve } from "node:path";
|
|
2
3
|
import { readFileSync } from "node:fs";
|
|
3
4
|
import { homedir } from "node:os";
|
|
4
|
-
// src/internal/role-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
{
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
autoPanel: false
|
|
86
|
-
},
|
|
87
|
-
{
|
|
88
|
-
key: "swarm workers",
|
|
89
|
-
shape: "list",
|
|
90
|
-
autoPanel: false
|
|
91
|
-
},
|
|
92
|
-
{
|
|
93
|
-
key: "architect runners",
|
|
94
|
-
shape: "list",
|
|
95
|
-
autoPanel: true
|
|
96
|
-
},
|
|
97
|
-
{
|
|
98
|
-
key: "interrogate reviewers",
|
|
99
|
-
shape: "list",
|
|
100
|
-
autoPanel: true
|
|
5
|
+
// src/internal/role-grammar.ts
|
|
6
|
+
function frontmatterBodyStart(lines) {
|
|
7
|
+
if (lines[0]?.trim() !== "---") return 0;
|
|
8
|
+
for (let index = 1; index < lines.length; index += 1) if (lines[index]?.trim() === "---") return index + 1;
|
|
9
|
+
return 0;
|
|
10
|
+
}
|
|
11
|
+
/** One line grammar for role parsing and byte-preserving updates. */
|
|
12
|
+
function scanRoleDocument(text) {
|
|
13
|
+
const lines = text.split("\n");
|
|
14
|
+
if (lines.length > 0 && lines[lines.length - 1] === "") lines.pop();
|
|
15
|
+
const bodyStart = frontmatterBodyStart(lines);
|
|
16
|
+
const scanned = [];
|
|
17
|
+
let offset = 0;
|
|
18
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
19
|
+
const rawLine = lines[index];
|
|
20
|
+
const line = index + 1 - bodyStart;
|
|
21
|
+
const contentEnd = offset + rawLine.length - (rawLine.endsWith("\r") ? 1 : 0);
|
|
22
|
+
if (index < bodyStart) {
|
|
23
|
+
scanned.push({
|
|
24
|
+
kind: "blank",
|
|
25
|
+
line
|
|
26
|
+
});
|
|
27
|
+
offset += rawLine.length + 1;
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
const trimmed = rawLine.trim();
|
|
31
|
+
if (trimmed === "") scanned.push({
|
|
32
|
+
kind: "blank",
|
|
33
|
+
line
|
|
34
|
+
});
|
|
35
|
+
else if (trimmed.startsWith("#")) {
|
|
36
|
+
const match = /^#\s*budget:\s*(.+)$/i.exec(trimmed);
|
|
37
|
+
scanned.push({
|
|
38
|
+
kind: "comment",
|
|
39
|
+
line,
|
|
40
|
+
...match === null ? {} : { budget: match[1].trim() }
|
|
41
|
+
});
|
|
42
|
+
} else {
|
|
43
|
+
const separator = trimmed.indexOf(":");
|
|
44
|
+
if (separator === -1) scanned.push({
|
|
45
|
+
kind: "malformed",
|
|
46
|
+
line,
|
|
47
|
+
rawLine: trimmed
|
|
48
|
+
});
|
|
49
|
+
else {
|
|
50
|
+
const rawKey = trimmed.slice(0, separator).trim();
|
|
51
|
+
const key = normalizeRoleName(rawKey);
|
|
52
|
+
const spec = findRoleSpec(key);
|
|
53
|
+
if (key === "") scanned.push({
|
|
54
|
+
kind: "malformed",
|
|
55
|
+
line,
|
|
56
|
+
rawLine: ""
|
|
57
|
+
});
|
|
58
|
+
else if (spec === void 0) scanned.push({
|
|
59
|
+
kind: "unknown-role",
|
|
60
|
+
line,
|
|
61
|
+
rawKey
|
|
62
|
+
});
|
|
63
|
+
else {
|
|
64
|
+
const valueText = rawLine.slice(0, contentEnd - offset);
|
|
65
|
+
const sourceSeparator = valueText.indexOf(":");
|
|
66
|
+
const afterSeparator = valueText.slice(sourceSeparator + 1);
|
|
67
|
+
const rawValue = afterSeparator.trim();
|
|
68
|
+
const valueLeading = rawValue === "" ? 0 : afterSeparator.length - afterSeparator.trimStart().length;
|
|
69
|
+
const valueTrailing = rawValue === "" ? 0 : afterSeparator.length - afterSeparator.trimEnd().length;
|
|
70
|
+
const valueStart = offset + sourceSeparator + 1 + valueLeading;
|
|
71
|
+
const valueEnd = contentEnd - valueTrailing;
|
|
72
|
+
scanned.push({
|
|
73
|
+
kind: "role",
|
|
74
|
+
line,
|
|
75
|
+
rawKey,
|
|
76
|
+
key,
|
|
77
|
+
rawValue,
|
|
78
|
+
spec,
|
|
79
|
+
valueStart,
|
|
80
|
+
valueEnd
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
offset += rawLine.length + 1;
|
|
101
86
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
87
|
+
return { lines: scanned };
|
|
88
|
+
}
|
|
89
|
+
/** Replace only the winning role's value, retaining every other source byte. */
|
|
90
|
+
function updateRoleDocument(text, spec, value) {
|
|
91
|
+
const winning = scanRoleDocument(text).lines.findLast((line) => line.kind === "role" && line.key === spec.key);
|
|
92
|
+
if (winning?.kind === "role") return `${text.slice(0, winning.valueStart)}${value}${text.slice(winning.valueEnd)}`;
|
|
93
|
+
const eol = text.includes("\r\n") ? "\r\n" : "\n";
|
|
94
|
+
return `${text}${text === "" || text.endsWith("\n") ? "" : eol}${spec.key}: ${value}${eol}`;
|
|
106
95
|
}
|
|
107
96
|
// src/internal/role-config.ts
|
|
108
97
|
/**
|
|
@@ -149,49 +138,36 @@ function parseRoleConfiguration(text, path) {
|
|
|
149
138
|
const issues = [];
|
|
150
139
|
const roles = /* @__PURE__ */ new Map();
|
|
151
140
|
let budget;
|
|
152
|
-
|
|
153
|
-
const line =
|
|
154
|
-
|
|
155
|
-
if (
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
if (match !== null) budget = match[1].trim();
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
const separator = trimmed.indexOf(":");
|
|
162
|
-
if (separator === -1) {
|
|
163
|
-
issues.push({
|
|
164
|
-
line,
|
|
165
|
-
message: `expected \`<role>: <value>\`, found ${JSON.stringify(trimmed)}`
|
|
166
|
-
});
|
|
167
|
-
return;
|
|
141
|
+
for (const scanned of scanRoleDocument(text).lines) {
|
|
142
|
+
const { line } = scanned;
|
|
143
|
+
if (scanned.kind === "blank") continue;
|
|
144
|
+
if (scanned.kind === "comment") {
|
|
145
|
+
if (scanned.budget !== void 0) budget = scanned.budget;
|
|
146
|
+
continue;
|
|
168
147
|
}
|
|
169
|
-
|
|
170
|
-
const rawValue = trimmed.slice(separator + 1).trim();
|
|
171
|
-
const key = normalizeRoleName(rawKey);
|
|
172
|
-
if (key === "") {
|
|
148
|
+
if (scanned.kind === "malformed") {
|
|
173
149
|
issues.push({
|
|
174
150
|
line,
|
|
175
|
-
message: "the role key is empty"
|
|
151
|
+
message: scanned.rawLine === "" ? "the role key is empty" : `expected \`<role>: <value>\`, found ${JSON.stringify(scanned.rawLine)}`
|
|
176
152
|
});
|
|
177
|
-
|
|
153
|
+
continue;
|
|
178
154
|
}
|
|
179
|
-
|
|
180
|
-
if (spec === void 0) {
|
|
155
|
+
if (scanned.kind === "unknown-role") {
|
|
181
156
|
issues.push({
|
|
182
157
|
line,
|
|
183
|
-
message: unknownRoleMessage(rawKey,
|
|
158
|
+
message: unknownRoleMessage(scanned.rawKey, normalizeRoleName(scanned.rawKey))
|
|
184
159
|
});
|
|
185
|
-
|
|
160
|
+
continue;
|
|
186
161
|
}
|
|
187
|
-
const
|
|
162
|
+
const { rawKey, spec } = scanned;
|
|
163
|
+
const parsed = parseRouteValue(scanned.rawValue);
|
|
188
164
|
const entryIssues = [...parsed.issues];
|
|
189
165
|
if (spec.shape === "single" && parsed.routes.length > 1) entryIssues.push("a single-route role cannot hold a comma-separated list");
|
|
190
166
|
for (const issue of entryIssues) issues.push({
|
|
191
167
|
line,
|
|
192
168
|
message: `${rawKey}: ${issue}`
|
|
193
169
|
});
|
|
194
|
-
if (parsed.routes.length === 0)
|
|
170
|
+
if (parsed.routes.length === 0) continue;
|
|
195
171
|
const previous = roles.get(spec.key);
|
|
196
172
|
if (previous !== void 0) issues.push({
|
|
197
173
|
line,
|
|
@@ -205,7 +181,7 @@ function parseRoleConfiguration(text, path) {
|
|
|
205
181
|
routes: parsed.routes,
|
|
206
182
|
issues: entryIssues
|
|
207
183
|
});
|
|
208
|
-
}
|
|
184
|
+
}
|
|
209
185
|
return budget === void 0 ? {
|
|
210
186
|
status: "loaded",
|
|
211
187
|
path,
|
|
@@ -335,10 +311,6 @@ var RoleNameError = class extends Error {
|
|
|
335
311
|
this.name = "RoleNameError";
|
|
336
312
|
}
|
|
337
313
|
};
|
|
338
|
-
/** Normalize a role name for lookup. Case, spacing, spacing around a comma, and a trailing colon are formatting. */
|
|
339
|
-
function normalizeRoleName(raw) {
|
|
340
|
-
return raw.normalize("NFC").trim().toLowerCase().replace(/\s+/g, " ").replace(/\s*,\s*/g, ", ").replace(/:+$/, "").trim();
|
|
341
|
-
}
|
|
342
314
|
/** Resolve a role name, or throw a diagnostic that names the near misses. */
|
|
343
315
|
function requireRole(raw) {
|
|
344
316
|
const spec = findRoleSpec(normalizeRoleName(raw));
|
|
@@ -394,14 +366,6 @@ function editDistance(left, right) {
|
|
|
394
366
|
}
|
|
395
367
|
return previous[right.length];
|
|
396
368
|
}
|
|
397
|
-
function stripFrontmatter(text) {
|
|
398
|
-
const normalized = text.replaceAll("\r\n", "\n");
|
|
399
|
-
if (!normalized.startsWith("---\n")) return normalized;
|
|
400
|
-
const end = normalized.indexOf("\n---", 3);
|
|
401
|
-
if (end === -1) return normalized;
|
|
402
|
-
const after = normalized.indexOf("\n", end + 1);
|
|
403
|
-
return after === -1 ? "" : normalized.slice(after + 1);
|
|
404
|
-
}
|
|
405
369
|
function isMissingFile(error) {
|
|
406
370
|
return typeof error === "object" && error !== null && error.code === "ENOENT";
|
|
407
371
|
}
|
|
@@ -412,4 +376,4 @@ function describeError(error) {
|
|
|
412
376
|
}
|
|
413
377
|
return String(error);
|
|
414
378
|
}
|
|
415
|
-
export {
|
|
379
|
+
export { selectRoleRoutes as a, resolveDshHome as i, readRoleConfiguration as n, updateRoleDocument as o, requireRole as r, modelsFilePath as t };
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
// src/internal/role-manifest.ts
|
|
2
|
+
/**
|
|
3
|
+
* File name the role configuration lives under inside `$DSH_HOME`.
|
|
4
|
+
*
|
|
5
|
+
* It keeps the upstream name `pstack-models.mdc`, so a reader moving from the Cursor docs
|
|
6
|
+
* recognizes it, but stores it directly under `$DSH_HOME`; DSH does not load `.mdc` files
|
|
7
|
+
* on its own, and `pstack_subagent` is the only reader.
|
|
8
|
+
*/
|
|
9
|
+
const PSTACK_MODELS_FILENAME = "pstack-models.mdc";
|
|
10
|
+
/** Values that resolve to "send no `agentOptions` and inherit the parent route". */
|
|
11
|
+
const INHERIT_PARENT_ALIASES = ["inherit-parent", "auto"];
|
|
12
|
+
/** The 17 roles, in manifest order. */
|
|
13
|
+
const ROLE_MANIFEST = [
|
|
14
|
+
{
|
|
15
|
+
key: "feature, refactoring",
|
|
16
|
+
shape: "single",
|
|
17
|
+
autoPanel: false
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
key: "bug-fix",
|
|
21
|
+
shape: "single",
|
|
22
|
+
autoPanel: false
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
key: "perf-issue",
|
|
26
|
+
shape: "single",
|
|
27
|
+
autoPanel: false
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
key: "hillclimb",
|
|
31
|
+
shape: "single",
|
|
32
|
+
autoPanel: false
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
key: "judgment and prose",
|
|
36
|
+
shape: "single",
|
|
37
|
+
autoPanel: false
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
key: "hardest tasks",
|
|
41
|
+
shape: "single",
|
|
42
|
+
autoPanel: false
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
key: "how explorer",
|
|
46
|
+
shape: "single",
|
|
47
|
+
autoPanel: false
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
key: "how explainer",
|
|
51
|
+
shape: "single",
|
|
52
|
+
autoPanel: false
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
key: "why investigators",
|
|
56
|
+
shape: "single",
|
|
57
|
+
autoPanel: false
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
key: "why synthesizer",
|
|
61
|
+
shape: "single",
|
|
62
|
+
autoPanel: false
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
key: "reflect tooling",
|
|
66
|
+
shape: "single",
|
|
67
|
+
autoPanel: false
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
key: "reflect judgment, divergent, synthesizer",
|
|
71
|
+
shape: "single",
|
|
72
|
+
autoPanel: false
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
key: "arena runners",
|
|
76
|
+
shape: "list",
|
|
77
|
+
autoPanel: true
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
key: "arena cross-judge pool",
|
|
81
|
+
shape: "list",
|
|
82
|
+
autoPanel: false
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
key: "swarm workers",
|
|
86
|
+
shape: "list",
|
|
87
|
+
autoPanel: false
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
key: "architect runners",
|
|
91
|
+
shape: "list",
|
|
92
|
+
autoPanel: true
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
key: "interrogate reviewers",
|
|
96
|
+
shape: "list",
|
|
97
|
+
autoPanel: true
|
|
98
|
+
}
|
|
99
|
+
];
|
|
100
|
+
function isRoleKey(value) {
|
|
101
|
+
return ROLE_MANIFEST.some((role) => role.key === value);
|
|
102
|
+
}
|
|
103
|
+
/** Normalize formatting while keeping commas that belong to a role name. */
|
|
104
|
+
function normalizeRoleName(raw) {
|
|
105
|
+
return raw.normalize("NFC").trim().toLowerCase().replace(/\s+/g, " ").replace(/\s*,\s*/g, ", ").replace(/:+$/, "").trim();
|
|
106
|
+
}
|
|
107
|
+
/** Exact manifest lookup. Callers normalize the key first. */
|
|
108
|
+
function findRoleSpec(key) {
|
|
109
|
+
if (!isRoleKey(key)) return void 0;
|
|
110
|
+
return ROLE_MANIFEST.find((role) => role.key === key);
|
|
111
|
+
}
|
|
112
|
+
export { isRoleKey as a, findRoleSpec as i, PSTACK_MODELS_FILENAME as n, normalizeRoleName as o, ROLE_MANIFEST as r, INHERIT_PARENT_ALIASES as t };
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one pstack role manifest.
|
|
3
|
+
*
|
|
4
|
+
* Keys are matched exactly after normalization, and commas belong to some keys
|
|
5
|
+
* (`feature, refactoring`, `reflect judgment, divergent, synthesizer`), so nothing here
|
|
6
|
+
* may split a key on a comma. A second literal role list anywhere is a bug.
|
|
7
|
+
*
|
|
8
|
+
* This module has no Node imports: the bundle imports it directly.
|
|
9
|
+
*/
|
|
10
|
+
/** Whether a role holds one route or a comma-separated list of routes. */
|
|
11
|
+
type RoleValueShape = "single" | "list";
|
|
12
|
+
interface RoleSpec {
|
|
13
|
+
/** Exact key as written in the role file. Commas belong to the key. */
|
|
14
|
+
readonly key: string;
|
|
15
|
+
readonly shape: RoleValueShape;
|
|
16
|
+
/** A list role that starts one child per entry automatically. */
|
|
17
|
+
readonly autoPanel: boolean;
|
|
18
|
+
}
|
|
19
|
+
/** The 17 roles, in manifest order. */
|
|
20
|
+
declare const ROLE_MANIFEST: readonly [{
|
|
21
|
+
readonly key: "feature, refactoring";
|
|
22
|
+
readonly shape: "single";
|
|
23
|
+
readonly autoPanel: false;
|
|
24
|
+
}, {
|
|
25
|
+
readonly key: "bug-fix";
|
|
26
|
+
readonly shape: "single";
|
|
27
|
+
readonly autoPanel: false;
|
|
28
|
+
}, {
|
|
29
|
+
readonly key: "perf-issue";
|
|
30
|
+
readonly shape: "single";
|
|
31
|
+
readonly autoPanel: false;
|
|
32
|
+
}, {
|
|
33
|
+
readonly key: "hillclimb";
|
|
34
|
+
readonly shape: "single";
|
|
35
|
+
readonly autoPanel: false;
|
|
36
|
+
}, {
|
|
37
|
+
readonly key: "judgment and prose";
|
|
38
|
+
readonly shape: "single";
|
|
39
|
+
readonly autoPanel: false;
|
|
40
|
+
}, {
|
|
41
|
+
readonly key: "hardest tasks";
|
|
42
|
+
readonly shape: "single";
|
|
43
|
+
readonly autoPanel: false;
|
|
44
|
+
}, {
|
|
45
|
+
readonly key: "how explorer";
|
|
46
|
+
readonly shape: "single";
|
|
47
|
+
readonly autoPanel: false;
|
|
48
|
+
}, {
|
|
49
|
+
readonly key: "how explainer";
|
|
50
|
+
readonly shape: "single";
|
|
51
|
+
readonly autoPanel: false;
|
|
52
|
+
}, {
|
|
53
|
+
readonly key: "why investigators";
|
|
54
|
+
readonly shape: "single";
|
|
55
|
+
readonly autoPanel: false;
|
|
56
|
+
}, {
|
|
57
|
+
readonly key: "why synthesizer";
|
|
58
|
+
readonly shape: "single";
|
|
59
|
+
readonly autoPanel: false;
|
|
60
|
+
}, {
|
|
61
|
+
readonly key: "reflect tooling";
|
|
62
|
+
readonly shape: "single";
|
|
63
|
+
readonly autoPanel: false;
|
|
64
|
+
}, {
|
|
65
|
+
readonly key: "reflect judgment, divergent, synthesizer";
|
|
66
|
+
readonly shape: "single";
|
|
67
|
+
readonly autoPanel: false;
|
|
68
|
+
}, {
|
|
69
|
+
readonly key: "arena runners";
|
|
70
|
+
readonly shape: "list";
|
|
71
|
+
readonly autoPanel: true;
|
|
72
|
+
}, {
|
|
73
|
+
readonly key: "arena cross-judge pool";
|
|
74
|
+
readonly shape: "list";
|
|
75
|
+
readonly autoPanel: false;
|
|
76
|
+
}, {
|
|
77
|
+
readonly key: "swarm workers";
|
|
78
|
+
readonly shape: "list";
|
|
79
|
+
readonly autoPanel: false;
|
|
80
|
+
}, {
|
|
81
|
+
readonly key: "architect runners";
|
|
82
|
+
readonly shape: "list";
|
|
83
|
+
readonly autoPanel: true;
|
|
84
|
+
}, {
|
|
85
|
+
readonly key: "interrogate reviewers";
|
|
86
|
+
readonly shape: "list";
|
|
87
|
+
readonly autoPanel: true;
|
|
88
|
+
}];
|
|
89
|
+
type RoleKey = (typeof ROLE_MANIFEST)[number]["key"];
|
|
90
|
+
export { RoleSpec as n, RoleValueShape as r, RoleKey as t };
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import "./
|
|
2
|
-
import { n as RoleValueShape } from "./role-manifest-C3fUzjLI.mjs";
|
|
1
|
+
import { r as RoleValueShape, t as RoleKey } from "./role-manifest-8OERX9-s.mjs";
|
|
3
2
|
/** Which spelling of "inherit the parent route" a role line uses. */
|
|
4
3
|
type InheritAlias = "inherit-parent" | "auto";
|
|
5
4
|
/** One role value as the configuration page sees it. */
|
|
@@ -14,7 +13,7 @@ type RouteView = {
|
|
|
14
13
|
};
|
|
15
14
|
/** One of the 17 roles in manifest order. */
|
|
16
15
|
interface RoleView {
|
|
17
|
-
readonly key:
|
|
16
|
+
readonly key: RoleKey;
|
|
18
17
|
readonly shape: RoleValueShape;
|
|
19
18
|
/** Whether the role file configures this role. */
|
|
20
19
|
readonly configured: boolean;
|
package/dist/roles.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CatalogueResult } from "./models.mjs";
|
|
2
|
-
import { n as SaveRoleRequest, r as SaveRoleResult, t as RoleFileSnapshot } from "./role-wire-
|
|
2
|
+
import { n as SaveRoleRequest, r as SaveRoleResult, t as RoleFileSnapshot } from "./role-wire-CAJsVA6e.mjs";
|
|
3
3
|
import { Context, Service } from "@deepseek-ai/cordis";
|
|
4
4
|
import { TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol";
|
|
5
5
|
/** Read and write the role file for the Plugins configuration page. */
|
package/dist/roles.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { collectCatalogue } from "./models.mjs";
|
|
2
|
+
import { i as findRoleSpec, o as normalizeRoleName, r as ROLE_MANIFEST, t as INHERIT_PARENT_ALIASES } from "./role-manifest-79cnFfDM.mjs";
|
|
2
3
|
import { REMOTE_PACKAGE, ROLES_SERVICE, pstackRolesRemote } from "./remote.mjs";
|
|
3
|
-
import {
|
|
4
|
+
import { i as resolveDshHome, n as readRoleConfiguration, o as updateRoleDocument, t as modelsFilePath } from "./role-config-a4JpVdc-.mjs";
|
|
4
5
|
import { dirname } from "node:path";
|
|
5
6
|
import { mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
6
7
|
import { Service } from "@deepseek-ai/cordis";
|
|
@@ -178,40 +179,9 @@ function validateSaveRequest(request, catalogue) {
|
|
|
178
179
|
function renderRoleValue(routes) {
|
|
179
180
|
return routes.map((route) => route.kind === "inherit" ? route.alias ?? "inherit-parent" : route.effort === void 0 ? `${route.provider}/${route.model}` : `${route.provider}/${route.model} [${route.effort}]`).join(", ");
|
|
180
181
|
}
|
|
181
|
-
|
|
182
|
-
if (lines[0]?.trim() !== "---") return 0;
|
|
183
|
-
for (let index = 1; index < lines.length; index += 1) if (lines[index]?.trim() === "---") return index + 1;
|
|
184
|
-
return 0;
|
|
185
|
-
}
|
|
186
|
-
/**
|
|
187
|
-
* Replace the winning line for one role, or append one when absent.
|
|
188
|
-
*
|
|
189
|
-
* Every other line is returned verbatim. A role configured twice keeps its
|
|
190
|
-
* earlier line and replaces the last one, which is the line the parser treats
|
|
191
|
-
* as winning; the duplicate remains visible as a per-line issue.
|
|
192
|
-
*/
|
|
182
|
+
/** Update the winning role through the same line grammar used by the parser. */
|
|
193
183
|
function updateRoleText(text, spec, value) {
|
|
194
|
-
|
|
195
|
-
const crlf = text.includes("\r\n");
|
|
196
|
-
if (lines.length > 0 && lines[lines.length - 1] === "") lines.pop();
|
|
197
|
-
let match = -1;
|
|
198
|
-
for (let index = bodyStart(lines); index < lines.length; index += 1) {
|
|
199
|
-
const line = lines[index];
|
|
200
|
-
const trimmed = line.endsWith("\r") ? line.slice(0, -1).trim() : line.trim();
|
|
201
|
-
if (trimmed === "" || trimmed.startsWith("#")) continue;
|
|
202
|
-
const separator = trimmed.indexOf(":");
|
|
203
|
-
if (separator === -1) continue;
|
|
204
|
-
if (normalizeRoleName(trimmed.slice(0, separator)) !== spec.key) continue;
|
|
205
|
-
match = index;
|
|
206
|
-
}
|
|
207
|
-
const rendered = `${spec.key}: ${value}`;
|
|
208
|
-
if (match >= 0) {
|
|
209
|
-
const original = lines[match];
|
|
210
|
-
const indent = /^\s*/.exec(original)?.[0] ?? "";
|
|
211
|
-
const ending = original.endsWith("\r") ? "\r" : "";
|
|
212
|
-
lines[match] = `${indent}${rendered}${ending}`;
|
|
213
|
-
} else lines.push(`${rendered}${crlf ? "\r" : ""}`);
|
|
214
|
-
return `${lines.join("\n")}\n`;
|
|
184
|
+
return updateRoleDocument(text, spec, value);
|
|
215
185
|
}
|
|
216
186
|
function writeAtomically(path, text) {
|
|
217
187
|
mkdirSync(dirname(path), { recursive: true });
|
package/dist/script.mjs
CHANGED
package/dist/subagent.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { _ as ToolsHost, g as ToolDefinition, h as SubagentsHost, m as SubagentCapabilities, n as AgentOptions, r as AgentsHost, s as LlmHost, t as Agent, v as WorkingDirectoryHost } from "./host-contract-CUPSpeNk.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { n as RoleSpec } from "./role-manifest-8OERX9-s.mjs";
|
|
3
3
|
/** One resolved child route. */
|
|
4
4
|
type Route = {
|
|
5
5
|
readonly kind: "inherit";
|
|
@@ -43,6 +43,13 @@ export interface PstackSubagentConfig {
|
|
|
43
43
|
readonly provider: string;
|
|
44
44
|
readonly maxDepth?: number;
|
|
45
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* Depth a child runs at when a call omits `maxDepth` or passes an unusable value.
|
|
48
|
+
*
|
|
49
|
+
* A child is always at least depth 1 (it is one level below its parent), so this is the
|
|
50
|
+
* smallest value that can start a child while forbidding it from delegating further.
|
|
51
|
+
*/
|
|
52
|
+
export declare const DEFAULT_CHILD_MAX_DEPTH = 1;
|
|
46
53
|
/** What a call asked for, after every required argument has been validated. */
|
|
47
54
|
export interface DelegationArgs {
|
|
48
55
|
readonly description: string;
|
|
@@ -50,7 +57,7 @@ export interface DelegationArgs {
|
|
|
50
57
|
readonly agent: AgentKind;
|
|
51
58
|
readonly role: string | null;
|
|
52
59
|
readonly cwd: string | null;
|
|
53
|
-
readonly maxDepth: number;
|
|
60
|
+
readonly maxDepth: number | null;
|
|
54
61
|
readonly roleIndex: number | null;
|
|
55
62
|
readonly reasoningEffort: string | null;
|
|
56
63
|
}
|
|
@@ -107,6 +114,13 @@ export declare function composeChildPrompt(input: {
|
|
|
107
114
|
}[];
|
|
108
115
|
readonly task: string;
|
|
109
116
|
}): string;
|
|
117
|
+
export declare const DELEGATION_ARGUMENT_KEYS: readonly ["description", "prompt", "agent", "role", "roleIndex", "reasoningEffort", "cwd", "maxDepth"];
|
|
118
|
+
/**
|
|
119
|
+
* Keys a call must pass. `maxDepth` is accepted but not required: a missing or unusable
|
|
120
|
+
* value resolves to `DEFAULT_CHILD_MAX_DEPTH` instead of forcing the caller to guess an
|
|
121
|
+
* integer, which is where the reflexive `0` came from.
|
|
122
|
+
*/
|
|
123
|
+
export declare const REQUIRED_DELEGATION_ARGUMENT_KEYS: readonly ["description", "prompt", "agent", "role", "roleIndex", "reasoningEffort", "cwd"];
|
|
110
124
|
/** Validate every required model-facing argument. Null declines an optional setting. */
|
|
111
125
|
export declare function parseDelegationArgs(raw: unknown): DelegationArgs;
|
|
112
126
|
/** One planned child, before any Host call. */
|
|
@@ -140,7 +154,15 @@ export interface DelegationPlan {
|
|
|
140
154
|
/** Route text as reported to the model. */
|
|
141
155
|
export declare function routeLabel(route: Route, effortOverride?: string): string;
|
|
142
156
|
/** Take the smallest of the requested depth, this row's cap, and the Host setting. */
|
|
143
|
-
export declare function resolveDelegationDepth(configured: number | undefined, requested: number | undefined, hostLimit: number | undefined): number | undefined;
|
|
157
|
+
export declare function resolveDelegationDepth(configured: number | undefined, requested: number | null | undefined, hostLimit: number | undefined): number | undefined;
|
|
158
|
+
/**
|
|
159
|
+
* Turn the per-call `maxDepth` request into an effective depth request.
|
|
160
|
+
*
|
|
161
|
+
* A child is always at least depth 1, so `0` can never start one: it is reported and
|
|
162
|
+
* replaced with `DEFAULT_CHILD_MAX_DEPTH` rather than failing the whole call. Omitting
|
|
163
|
+
* `maxDepth` (null) also uses the default, so a caller never has to guess an integer.
|
|
164
|
+
*/
|
|
165
|
+
export declare function requestedChildDepth(requested: number | null, diagnostics: string[]): number;
|
|
144
166
|
/** Resolve the role file, routes, prompt, and depth into one plan. Pure of service calls. */
|
|
145
167
|
export declare function planDelegation(args: DelegationArgs, runtime: SubagentRuntime, config?: PstackSubagentConfig): DelegationPlan;
|
|
146
168
|
/** Check the backend can enforce what this call asks for. */
|