@ran-sh/dsh-crew 0.3.0 → 0.3.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.
Files changed (78) hide show
  1. package/.claude-plugin/marketplace.json +17 -17
  2. package/.claude-plugin/plugin.json +8 -8
  3. package/.mcp.json +8 -8
  4. package/LICENSE +21 -21
  5. package/README.de.md +359 -359
  6. package/README.es.md +359 -359
  7. package/README.fr.md +359 -359
  8. package/README.hi.md +359 -359
  9. package/README.id.md +359 -359
  10. package/README.ja.md +359 -359
  11. package/README.ko.md +359 -359
  12. package/README.md +140 -360
  13. package/README.pt.md +359 -359
  14. package/README.ru.md +359 -359
  15. package/README.th.md +359 -359
  16. package/README.tr.md +359 -359
  17. package/README.vi.md +359 -359
  18. package/README.zh-TW.md +359 -359
  19. package/README.zh.md +140 -305
  20. package/agents/ds-flash.md +26 -26
  21. package/agents/ds-pro.md +32 -32
  22. package/agents/ds-reviewer.md +23 -23
  23. package/agents/ds-worker.md +22 -22
  24. package/codex/agents/ds-flash.toml +30 -30
  25. package/codex/agents/ds-pro.toml +31 -31
  26. package/codex/agents/ds-reviewer.toml +28 -28
  27. package/codex/agents/ds-worker.toml +28 -28
  28. package/codex/prompts/dsh-config.md +3 -3
  29. package/codex/prompts/dsh-status.md +1 -1
  30. package/commands/config.md +11 -11
  31. package/commands/off.md +5 -5
  32. package/commands/on.md +5 -5
  33. package/commands/status.md +5 -5
  34. package/cordis.patch.yml +4 -4
  35. package/lib/client.js +2765 -2765
  36. package/package.json +127 -125
  37. package/scripts/build-client.mjs +28 -28
  38. package/scripts/live-crew-smoke.mjs +39 -39
  39. package/scripts/live-policy-matrix.mjs +177 -177
  40. package/scripts/policy-probe.mjs +101 -101
  41. package/scripts/setup.mjs +295 -294
  42. package/scripts/smoke-real.mjs +110 -110
  43. package/scripts/smoke.mjs +78 -78
  44. package/scripts/verify-installer-fix.mjs +26 -26
  45. package/scripts/verify-npm-install.mjs +297 -0
  46. package/src/adaptive-routing.mjs +260 -260
  47. package/src/client/activation-summary.tsx +64 -64
  48. package/src/client/entry.tsx +236 -236
  49. package/src/client/index.tsx +1120 -1120
  50. package/src/config-readiness.mjs +59 -59
  51. package/src/delivery.mjs +205 -205
  52. package/src/dsh-cli-runtime.mjs +435 -251
  53. package/src/failure-classification.mjs +172 -172
  54. package/src/hub/entry.mjs +98 -98
  55. package/src/hub-client.mjs +132 -132
  56. package/src/hub-compatibility.mjs +49 -49
  57. package/src/i18n.mjs +19 -19
  58. package/src/install/cli.mjs +28 -28
  59. package/src/install/install-legacy.mjs +460 -460
  60. package/src/install/install.mjs +451 -451
  61. package/src/mcp-runtime.mjs +257 -257
  62. package/src/model-catalog.mjs +173 -173
  63. package/src/model-routing.mjs +391 -391
  64. package/src/policy.mjs +197 -197
  65. package/src/readiness-matrix.mjs +169 -169
  66. package/src/runtime-controls.mjs +90 -90
  67. package/src/runtime-identity.mjs +108 -108
  68. package/src/server.mjs +477 -477
  69. package/src/status-shard.mjs +52 -52
  70. package/src/structured-error-code.mjs +38 -38
  71. package/src/vision-route.mjs +138 -138
  72. package/src/workflow-runtime.mjs +573 -567
  73. package/src/workflow.mjs +160 -160
  74. package/src/workspace-audit.mjs +231 -231
  75. package/src/workspace-isolation.mjs +365 -306
  76. package/statusline/statusline.sh +14 -14
  77. package/statusline/worker-segment.sh +35 -35
  78. package/worker.cordis.yml +77 -77
package/src/workflow.mjs CHANGED
@@ -1,160 +1,160 @@
1
- // Unified job workflow: the shared state machine + structured outcome that
2
- // every worker job goes through, whether it was started with dsh_run_worker
3
- // (blocking) or dsh_spawn_worker (async). run and spawn differ only in whether
4
- // the caller awaits the job; the business steps — created → running →
5
- // verifying → (escalating | reviewing) → ready/completed/failed — are the
6
- // same, driven by evidence rather than by which transport started the job.
7
- //
8
- // Everything in this module is a pure function (no DSH, hub or worker runtime,
9
- // no I/O), so the workflow rules are unit-testable in isolation. The runtime
10
- // layers stamp phase + outcome through these helpers so server.mjs stays a
11
- // transport adapter.
12
-
13
- import { evaluateAttempt } from './policy.mjs';
14
- import { parseDeliveryReport } from './delivery.mjs';
15
-
16
- export const JOB_PHASES = Object.freeze({
17
- CREATED: 'created',
18
- QUEUED: 'queued',
19
- RUNNING: 'running',
20
- VERIFYING: 'verifying',
21
- ESCALATING: 'escalating',
22
- REVIEWING: 'reviewing',
23
- READY: 'ready',
24
- COMPLETED: 'completed',
25
- FAILED: 'failed',
26
- CANCELLED: 'cancelled',
27
- INTERRUPTED: 'interrupted',
28
- });
29
-
30
- const TERMINAL_PHASES = new Set([JOB_PHASES.COMPLETED, JOB_PHASES.FAILED, JOB_PHASES.CANCELLED, JOB_PHASES.INTERRUPTED]);
31
-
32
- export function isTerminalPhase(phase) {
33
- return TERMINAL_PHASES.has(phase);
34
- }
35
-
36
- // Legal phase transitions (pure guard — the runtime never just assigns a phase).
37
- const ALLOWED_TRANSITIONS = {
38
- [JOB_PHASES.CREATED]: [JOB_PHASES.QUEUED, JOB_PHASES.RUNNING, JOB_PHASES.CANCELLED, JOB_PHASES.FAILED],
39
- [JOB_PHASES.QUEUED]: [JOB_PHASES.RUNNING, JOB_PHASES.CANCELLED],
40
- [JOB_PHASES.RUNNING]: [JOB_PHASES.VERIFYING, JOB_PHASES.REVIEWING, JOB_PHASES.CANCELLED, JOB_PHASES.FAILED],
41
- [JOB_PHASES.VERIFYING]: [JOB_PHASES.ESCALATING, JOB_PHASES.REVIEWING, JOB_PHASES.READY, JOB_PHASES.FAILED, JOB_PHASES.CANCELLED],
42
- [JOB_PHASES.ESCALATING]: [JOB_PHASES.RUNNING, JOB_PHASES.CANCELLED, JOB_PHASES.FAILED],
43
- [JOB_PHASES.REVIEWING]: [JOB_PHASES.READY, JOB_PHASES.FAILED, JOB_PHASES.CANCELLED],
44
- [JOB_PHASES.READY]: [JOB_PHASES.COMPLETED, JOB_PHASES.FAILED, JOB_PHASES.CANCELLED],
45
- };
46
-
47
- /**
48
- * May a workflow transition from one phase to another? Terminal phases never
49
- * leave. A terminal destination is allowed only from a non-terminal phase;
50
- * every non-terminal transition must be listed above.
51
- */
52
- export function canTransition(from, to) {
53
- const fromKey = from ?? JOB_PHASES.CREATED;
54
- if (isTerminalPhase(fromKey)) return false;
55
- if (isTerminalPhase(to)) return true;
56
- const allowed = ALLOWED_TRANSITIONS[fromKey];
57
- if (!allowed) return false;
58
- return allowed.includes(to);
59
- }
60
-
61
- function splitSection(value) {
62
- if (typeof value !== 'string' || value.trim() === '') return [];
63
- return value.split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
64
- }
65
-
66
- function parseTests(section) {
67
- return splitSection(section).map((line) => {
68
- const m = line.match(/^(?:[-*+]\s+)?(PASS|FAIL|NOT RUN)\s+—\s+(.+?)\s+—\s+(.+)$/);
69
- if (!m) return { line };
70
- const [, status, command, summary] = m;
71
- return { status, command: command.trim(), summary: summary.trim() };
72
- });
73
- }
74
-
75
- /**
76
- * Classify a worker run into a canonical task status. Completion of the
77
- * process is not success: FAIL/not-run tests and missing delivery all downgrade
78
- * the verdict. Returns 'success' | 'partial' | 'blocked' | 'failed'.
79
- */
80
- export function classifyTaskStatus({ executionStatus = 'completed', testsStatus, deliveryComplete = true, deliveryMissing = [] } = {}) {
81
- void deliveryMissing;
82
- if (executionStatus !== 'completed') return 'failed';
83
- if (testsStatus === 'FAIL') return 'partial';
84
- if (!deliveryComplete) return 'blocked';
85
- if (testsStatus === 'NOT RUN') return 'partial';
86
- return 'success';
87
- }
88
-
89
- /**
90
- * Normalize a worker's final message (+ delivery metadata) into the canonical
91
- * structured outcome the workflow consumes. The Markdown Delivery Report stays
92
- * the human-readable layer; this is the runtime's internal standard.
93
- */
94
- export function buildOutcome({ result = '', deliveryMeta, executionStatus, stopReason, deliveryMissing } = {}) {
95
- const parsed = parseDeliveryReport(result);
96
- const testsStatus = parsed.tests_status ?? deliveryMeta?.tests_status;
97
- const tests = parseTests(parsed.sections.Tests);
98
- const execStatus = executionStatus ?? (stopReason === 'completed' ? 'completed' : 'failed');
99
- return {
100
- execution_status: execStatus,
101
- task_status: classifyTaskStatus({
102
- executionStatus: execStatus,
103
- testsStatus,
104
- deliveryComplete: parsed.complete,
105
- deliveryMissing: deliveryMissing ?? parsed.missing,
106
- }),
107
- confidence: null,
108
- needs_escalation: false,
109
- changes: splitSection(parsed.sections.Diff),
110
- tests,
111
- tests_status: testsStatus ?? null,
112
- risks: splitSection(parsed.sections.Risks),
113
- unverified: splitSection(parsed.sections.Unverified),
114
- delivery: {
115
- complete: parsed.complete,
116
- missing: [...(parsed.missing ?? [])],
117
- format: parsed.format,
118
- sections: [...(parsed.present ?? [])],
119
- },
120
- };
121
- }
122
-
123
- /**
124
- * Decide what happens next after a worker attempt completes. Pure: consumes
125
- * the canonical outcome + the role's model policy + the attempt number, and
126
- * returns the workflow step (accept / escalate / review / fail) with a reason.
127
- * This is the single rule for blocking AND async jobs — server.mjs only
128
- * transports the result.
129
- */
130
- export function decideNextStep({ outcome, policy, attempt = 0, reviewRequested = false, reviewerAuto = false } = {}) {
131
- const o = outcome ?? {};
132
- const evaluation = evaluateAttempt({
133
- execution: o.execution_status,
134
- taskStatus: o.task_status,
135
- testsStatus: o.tests_status,
136
- deliveryComplete: o.delivery?.complete,
137
- workspaceEvidenceOK: o.workspace_evidence_ok !== false,
138
- policy,
139
- attempt,
140
- });
141
- if (evaluation.decision === 'escalate') {
142
- return { step: 'escalate', phase: JOB_PHASES.ESCALATING, reason: evaluation.reason, evaluation };
143
- }
144
- if (reviewRequested && reviewerAuto && evaluation.decision === 'accept') {
145
- return { step: 'review', phase: JOB_PHASES.REVIEWING, reason: 'review requested', evaluation };
146
- }
147
- if (evaluation.decision === 'accept') {
148
- return { step: 'accept', phase: JOB_PHASES.READY, reason: 'verified', evaluation };
149
- }
150
- return { step: 'fail', phase: JOB_PHASES.FAILED, reason: evaluation.reason ?? 'no accept path', evaluation };
151
- }
152
-
153
- /**
154
- * Pure run/spawn parity check helper: given the same spec + outcome, blocking
155
- * and async jobs must reach the same next step. Exported for tests so the
156
- * "run and spawn share one workflow" guarantee is asserted directly.
157
- */
158
- export function parityStep(spec) {
159
- return decideNextStep(spec).step;
160
- }
1
+ // Unified job workflow: the shared state machine + structured outcome that
2
+ // every worker job goes through, whether it was started with dsh_run_worker
3
+ // (blocking) or dsh_spawn_worker (async). run and spawn differ only in whether
4
+ // the caller awaits the job; the business steps — created → running →
5
+ // verifying → (escalating | reviewing) → ready/completed/failed — are the
6
+ // same, driven by evidence rather than by which transport started the job.
7
+ //
8
+ // Everything in this module is a pure function (no DSH, hub or worker runtime,
9
+ // no I/O), so the workflow rules are unit-testable in isolation. The runtime
10
+ // layers stamp phase + outcome through these helpers so server.mjs stays a
11
+ // transport adapter.
12
+
13
+ import { evaluateAttempt } from './policy.mjs';
14
+ import { parseDeliveryReport } from './delivery.mjs';
15
+
16
+ export const JOB_PHASES = Object.freeze({
17
+ CREATED: 'created',
18
+ QUEUED: 'queued',
19
+ RUNNING: 'running',
20
+ VERIFYING: 'verifying',
21
+ ESCALATING: 'escalating',
22
+ REVIEWING: 'reviewing',
23
+ READY: 'ready',
24
+ COMPLETED: 'completed',
25
+ FAILED: 'failed',
26
+ CANCELLED: 'cancelled',
27
+ INTERRUPTED: 'interrupted',
28
+ });
29
+
30
+ const TERMINAL_PHASES = new Set([JOB_PHASES.COMPLETED, JOB_PHASES.FAILED, JOB_PHASES.CANCELLED, JOB_PHASES.INTERRUPTED]);
31
+
32
+ export function isTerminalPhase(phase) {
33
+ return TERMINAL_PHASES.has(phase);
34
+ }
35
+
36
+ // Legal phase transitions (pure guard — the runtime never just assigns a phase).
37
+ const ALLOWED_TRANSITIONS = {
38
+ [JOB_PHASES.CREATED]: [JOB_PHASES.QUEUED, JOB_PHASES.RUNNING, JOB_PHASES.CANCELLED, JOB_PHASES.FAILED],
39
+ [JOB_PHASES.QUEUED]: [JOB_PHASES.RUNNING, JOB_PHASES.CANCELLED],
40
+ [JOB_PHASES.RUNNING]: [JOB_PHASES.VERIFYING, JOB_PHASES.REVIEWING, JOB_PHASES.CANCELLED, JOB_PHASES.FAILED],
41
+ [JOB_PHASES.VERIFYING]: [JOB_PHASES.ESCALATING, JOB_PHASES.REVIEWING, JOB_PHASES.READY, JOB_PHASES.FAILED, JOB_PHASES.CANCELLED],
42
+ [JOB_PHASES.ESCALATING]: [JOB_PHASES.RUNNING, JOB_PHASES.CANCELLED, JOB_PHASES.FAILED],
43
+ [JOB_PHASES.REVIEWING]: [JOB_PHASES.READY, JOB_PHASES.FAILED, JOB_PHASES.CANCELLED],
44
+ [JOB_PHASES.READY]: [JOB_PHASES.COMPLETED, JOB_PHASES.FAILED, JOB_PHASES.CANCELLED],
45
+ };
46
+
47
+ /**
48
+ * May a workflow transition from one phase to another? Terminal phases never
49
+ * leave. A terminal destination is allowed only from a non-terminal phase;
50
+ * every non-terminal transition must be listed above.
51
+ */
52
+ export function canTransition(from, to) {
53
+ const fromKey = from ?? JOB_PHASES.CREATED;
54
+ if (isTerminalPhase(fromKey)) return false;
55
+ if (isTerminalPhase(to)) return true;
56
+ const allowed = ALLOWED_TRANSITIONS[fromKey];
57
+ if (!allowed) return false;
58
+ return allowed.includes(to);
59
+ }
60
+
61
+ function splitSection(value) {
62
+ if (typeof value !== 'string' || value.trim() === '') return [];
63
+ return value.split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
64
+ }
65
+
66
+ function parseTests(section) {
67
+ return splitSection(section).map((line) => {
68
+ const m = line.match(/^(?:[-*+]\s+)?(PASS|FAIL|NOT RUN)\s+—\s+(.+?)\s+—\s+(.+)$/);
69
+ if (!m) return { line };
70
+ const [, status, command, summary] = m;
71
+ return { status, command: command.trim(), summary: summary.trim() };
72
+ });
73
+ }
74
+
75
+ /**
76
+ * Classify a worker run into a canonical task status. Completion of the
77
+ * process is not success: FAIL/not-run tests and missing delivery all downgrade
78
+ * the verdict. Returns 'success' | 'partial' | 'blocked' | 'failed'.
79
+ */
80
+ export function classifyTaskStatus({ executionStatus = 'completed', testsStatus, deliveryComplete = true, deliveryMissing = [] } = {}) {
81
+ void deliveryMissing;
82
+ if (executionStatus !== 'completed') return 'failed';
83
+ if (testsStatus === 'FAIL') return 'partial';
84
+ if (!deliveryComplete) return 'blocked';
85
+ if (testsStatus === 'NOT RUN') return 'partial';
86
+ return 'success';
87
+ }
88
+
89
+ /**
90
+ * Normalize a worker's final message (+ delivery metadata) into the canonical
91
+ * structured outcome the workflow consumes. The Markdown Delivery Report stays
92
+ * the human-readable layer; this is the runtime's internal standard.
93
+ */
94
+ export function buildOutcome({ result = '', deliveryMeta, executionStatus, stopReason, deliveryMissing } = {}) {
95
+ const parsed = parseDeliveryReport(result);
96
+ const testsStatus = parsed.tests_status ?? deliveryMeta?.tests_status;
97
+ const tests = parseTests(parsed.sections.Tests);
98
+ const execStatus = executionStatus ?? (stopReason === 'completed' ? 'completed' : 'failed');
99
+ return {
100
+ execution_status: execStatus,
101
+ task_status: classifyTaskStatus({
102
+ executionStatus: execStatus,
103
+ testsStatus,
104
+ deliveryComplete: parsed.complete,
105
+ deliveryMissing: deliveryMissing ?? parsed.missing,
106
+ }),
107
+ confidence: null,
108
+ needs_escalation: false,
109
+ changes: splitSection(parsed.sections.Diff),
110
+ tests,
111
+ tests_status: testsStatus ?? null,
112
+ risks: splitSection(parsed.sections.Risks),
113
+ unverified: splitSection(parsed.sections.Unverified),
114
+ delivery: {
115
+ complete: parsed.complete,
116
+ missing: [...(parsed.missing ?? [])],
117
+ format: parsed.format,
118
+ sections: [...(parsed.present ?? [])],
119
+ },
120
+ };
121
+ }
122
+
123
+ /**
124
+ * Decide what happens next after a worker attempt completes. Pure: consumes
125
+ * the canonical outcome + the role's model policy + the attempt number, and
126
+ * returns the workflow step (accept / escalate / review / fail) with a reason.
127
+ * This is the single rule for blocking AND async jobs — server.mjs only
128
+ * transports the result.
129
+ */
130
+ export function decideNextStep({ outcome, policy, attempt = 0, reviewRequested = false, reviewerAuto = false } = {}) {
131
+ const o = outcome ?? {};
132
+ const evaluation = evaluateAttempt({
133
+ execution: o.execution_status,
134
+ taskStatus: o.task_status,
135
+ testsStatus: o.tests_status,
136
+ deliveryComplete: o.delivery?.complete,
137
+ workspaceEvidenceOK: o.workspace_evidence_ok !== false,
138
+ policy,
139
+ attempt,
140
+ });
141
+ if (evaluation.decision === 'escalate') {
142
+ return { step: 'escalate', phase: JOB_PHASES.ESCALATING, reason: evaluation.reason, evaluation };
143
+ }
144
+ if (reviewRequested && reviewerAuto && evaluation.decision === 'accept') {
145
+ return { step: 'review', phase: JOB_PHASES.REVIEWING, reason: 'review requested', evaluation };
146
+ }
147
+ if (evaluation.decision === 'accept') {
148
+ return { step: 'accept', phase: JOB_PHASES.READY, reason: 'verified', evaluation };
149
+ }
150
+ return { step: 'fail', phase: JOB_PHASES.FAILED, reason: evaluation.reason ?? 'no accept path', evaluation };
151
+ }
152
+
153
+ /**
154
+ * Pure run/spawn parity check helper: given the same spec + outcome, blocking
155
+ * and async jobs must reach the same next step. Exported for tests so the
156
+ * "run and spawn share one workflow" guarantee is asserted directly.
157
+ */
158
+ export function parityStep(spec) {
159
+ return decideNextStep(spec).step;
160
+ }