@ran-sh/dsh-crew 0.3.6 → 0.3.8

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 (85) hide show
  1. package/.claude-plugin/plugin.json +8 -8
  2. package/.mcp.json +8 -8
  3. package/LICENSE +21 -21
  4. package/README.de.md +359 -359
  5. package/README.es.md +359 -359
  6. package/README.fr.md +359 -359
  7. package/README.hi.md +359 -359
  8. package/README.id.md +359 -359
  9. package/README.ja.md +359 -359
  10. package/README.ko.md +359 -359
  11. package/README.md +94 -180
  12. package/README.pt.md +359 -359
  13. package/README.ru.md +359 -359
  14. package/README.th.md +359 -359
  15. package/README.tr.md +359 -359
  16. package/README.vi.md +359 -359
  17. package/README.zh-TW.md +359 -359
  18. package/README.zh.md +94 -180
  19. package/agents/ds-flash.md +26 -26
  20. package/agents/ds-pro.md +32 -32
  21. package/agents/ds-reviewer.md +23 -23
  22. package/agents/ds-worker.md +22 -22
  23. package/codex/agents/ds-flash.toml +30 -30
  24. package/codex/agents/ds-pro.toml +31 -31
  25. package/codex/agents/ds-reviewer.toml +28 -28
  26. package/codex/agents/ds-worker.toml +28 -28
  27. package/codex/prompts/dsh-config.md +3 -3
  28. package/codex/prompts/dsh-status.md +1 -1
  29. package/commands/config.md +11 -11
  30. package/commands/off.md +5 -5
  31. package/commands/on.md +5 -5
  32. package/commands/status.md +5 -5
  33. package/cordis.patch.yml +4 -4
  34. package/lib/client.js +1655 -974
  35. package/official-web-bridge/cordis.patch.yml +4 -0
  36. package/official-web-bridge/entry.mjs +1 -0
  37. package/official-web-bridge/lib/client.js +3446 -0
  38. package/official-web-bridge/package.json +26 -0
  39. package/package.json +133 -131
  40. package/scripts/build-client.mjs +32 -28
  41. package/scripts/live-crew-smoke.mjs +39 -39
  42. package/scripts/live-policy-matrix.mjs +177 -177
  43. package/scripts/policy-probe.mjs +101 -101
  44. package/scripts/setup.mjs +284 -284
  45. package/scripts/smoke-real.mjs +110 -110
  46. package/scripts/smoke.mjs +78 -78
  47. package/scripts/verify-installer-fix.mjs +26 -26
  48. package/scripts/verify-official-bridge-e2e.mjs +159 -0
  49. package/src/adaptive-routing.mjs +260 -260
  50. package/src/client/activation-summary.tsx +64 -64
  51. package/src/client/collapsible-sections.mjs +55 -0
  52. package/src/client/entry.tsx +236 -236
  53. package/src/client/index.tsx +1213 -1120
  54. package/src/config-readiness.mjs +59 -59
  55. package/src/delivery.mjs +205 -205
  56. package/src/dsh-cli-runtime.mjs +458 -447
  57. package/src/failure-classification.mjs +172 -172
  58. package/src/hub/entry.mjs +98 -98
  59. package/src/hub-client.mjs +132 -132
  60. package/src/hub-compatibility.mjs +49 -49
  61. package/src/i18n.mjs +19 -19
  62. package/src/install/cli.mjs +28 -28
  63. package/src/install/install-legacy.mjs +462 -462
  64. package/src/install/install.mjs +451 -451
  65. package/src/install/npx-lifecycle.mjs +1119 -1055
  66. package/src/install/official-web.mjs +132 -0
  67. package/src/mcp-runtime.mjs +257 -257
  68. package/src/model-catalog.mjs +173 -173
  69. package/src/model-routing.mjs +391 -391
  70. package/src/official-web-bridge.mjs +196 -0
  71. package/src/policy.mjs +197 -197
  72. package/src/readiness-matrix.mjs +169 -169
  73. package/src/runtime-controls.mjs +90 -90
  74. package/src/runtime-identity.mjs +108 -108
  75. package/src/server.mjs +477 -477
  76. package/src/status-shard.mjs +52 -52
  77. package/src/structured-error-code.mjs +38 -38
  78. package/src/vision-route.mjs +138 -138
  79. package/src/workflow-runtime.mjs +573 -573
  80. package/src/workflow.mjs +160 -160
  81. package/src/workspace-audit.mjs +231 -231
  82. package/src/workspace-isolation.mjs +365 -365
  83. package/statusline/statusline.sh +14 -14
  84. package/statusline/worker-segment.sh +35 -35
  85. package/worker.cordis.yml +77 -77
@@ -1,132 +1,132 @@
1
- // Client for the in-host workers-hub jobs API. When a DSH web instance with the
2
- // dsh-crew bundle is running, jobs run inside it (sessions visible in the
3
- // Web UI); otherwise the MCP server falls back to standalone runtimes.
4
-
5
- import { readGlobalConfig } from './install/install.mjs';
6
- import { evaluateHubHandshake, HUB_COMPATIBILITY_CODES } from './runtime-identity.mjs';
7
- import { buildReadinessMatrix } from './readiness-matrix.mjs';
8
- import { isBoundedMachineCode } from './structured-error-code.mjs';
9
-
10
- const BASE = (process.env.DSH_CREW_HUB ?? readGlobalConfig().hub_url).replace(/\/$/, '');
11
- const API = `${BASE}/_dsh/dsh-crew`;
12
-
13
- export const HUB_REQUEST_FAILED = 'HUB_REQUEST_FAILED';
14
-
15
- const EMPTY_STATUS = Object.freeze({
16
- reachable: false,
17
- compatible: false,
18
- service: null,
19
- runtime_version: null,
20
- protocol_version: null,
21
- capabilities: [],
22
- missing_capabilities: [],
23
- code: HUB_COMPATIBILITY_CODES.UNREACHABLE,
24
- });
25
-
26
- let lastProbe = { at: 0, status: EMPTY_STATUS };
27
-
28
- function withReadiness(status) {
29
- return {
30
- ...status,
31
- readiness_matrix: buildReadinessMatrix({ hubCompatibility: status }),
32
- };
33
- }
34
-
35
- function cacheStatus(status) {
36
- const observed = withReadiness(status);
37
- lastProbe = { at: Date.now(), status: observed };
38
- return observed;
39
- }
40
-
41
- async function fetchJson(path) {
42
- const res = await fetch(`${API}${path}`, { signal: AbortSignal.timeout(800) });
43
- let body;
44
- try { body = await res.json(); } catch { body = null; }
45
- return { res, body };
46
- }
47
-
48
- /**
49
- * Probe reachability and compatibility as separate contracts.
50
- *
51
- * /ping is intentionally legacy-compatible and proves only that a dsh-crew Hub
52
- * is alive. /runtime is the v0.3 compatibility handshake. A legacy Hub that
53
- * lacks /runtime is therefore reachable-but-incompatible instead of looking
54
- * offline or being silently treated as current.
55
- */
56
- export async function hubStatus({ force = false } = {}) {
57
- if (!force && Date.now() - lastProbe.at < 10_000) return lastProbe.status;
58
- try {
59
- const ping = await fetchJson('/ping');
60
- if (!ping.res.ok) {
61
- return cacheStatus({
62
- ...EMPTY_STATUS,
63
- reachable: true,
64
- code: HUB_COMPATIBILITY_CODES.HTTP_ERROR,
65
- http_status: ping.res.status,
66
- endpoint: 'ping',
67
- });
68
- }
69
- if (ping.body?.service !== 'dsh-crew-hub') {
70
- return cacheStatus(evaluateHubHandshake(ping.body));
71
- }
72
-
73
- const runtime = await fetchJson('/runtime');
74
- if (runtime.res.status === 404) {
75
- return cacheStatus({
76
- ...EMPTY_STATUS,
77
- reachable: true,
78
- service: 'dsh-crew-hub',
79
- code: HUB_COMPATIBILITY_CODES.PROTOCOL_MISSING,
80
- endpoint: 'runtime',
81
- });
82
- }
83
- if (!runtime.res.ok) {
84
- return cacheStatus({
85
- ...EMPTY_STATUS,
86
- reachable: true,
87
- service: 'dsh-crew-hub',
88
- code: HUB_COMPATIBILITY_CODES.HTTP_ERROR,
89
- http_status: runtime.res.status,
90
- endpoint: 'runtime',
91
- });
92
- }
93
- return cacheStatus(evaluateHubHandshake(runtime.body));
94
- } catch {
95
- return cacheStatus(EMPTY_STATUS);
96
- }
97
- }
98
-
99
- export async function hubAvailable() {
100
- return (await hubStatus()).compatible;
101
- }
102
-
103
- function structuredCode(body) {
104
- if (isBoundedMachineCode(body?.code)) return body.code;
105
- if (isBoundedMachineCode(body?.policyCode)) return body.policyCode;
106
- return null;
107
- }
108
-
109
- /** Build a bounded Hub request error without copying arbitrary response fields. */
110
- export function hubRequestError(body, status) {
111
- const err = new Error(body?.error ?? `hub request failed (${status})`);
112
- err.code = structuredCode(body) ?? HUB_REQUEST_FAILED;
113
- return err;
114
- }
115
-
116
- async function call(path, init) {
117
- const res = await fetch(`${API}${path}`, init);
118
- const body = await res.json();
119
- if (!res.ok || body.ok === false) throw hubRequestError(body, res.status);
120
- return body;
121
- }
122
-
123
- export const hub = {
124
- spawn: (spec) => call('/jobs', {
125
- method: 'POST',
126
- headers: { 'content-type': 'application/json' },
127
- body: JSON.stringify(spec),
128
- }).then((b) => b.job),
129
- list: () => call('/jobs').then((b) => b.jobs),
130
- get: (id, waitSeconds = 0) => call(`/jobs/${id}?wait=${waitSeconds}`).then((b) => b.job),
131
- cancel: (id) => call(`/jobs/${id}/cancel`, { method: 'POST' }).then((b) => b.job),
132
- };
1
+ // Client for the in-host workers-hub jobs API. When a DSH web instance with the
2
+ // dsh-crew bundle is running, jobs run inside it (sessions visible in the
3
+ // Web UI); otherwise the MCP server falls back to standalone runtimes.
4
+
5
+ import { readGlobalConfig } from './install/install.mjs';
6
+ import { evaluateHubHandshake, HUB_COMPATIBILITY_CODES } from './runtime-identity.mjs';
7
+ import { buildReadinessMatrix } from './readiness-matrix.mjs';
8
+ import { isBoundedMachineCode } from './structured-error-code.mjs';
9
+
10
+ const BASE = (process.env.DSH_CREW_HUB ?? readGlobalConfig().hub_url).replace(/\/$/, '');
11
+ const API = `${BASE}/_dsh/dsh-crew`;
12
+
13
+ export const HUB_REQUEST_FAILED = 'HUB_REQUEST_FAILED';
14
+
15
+ const EMPTY_STATUS = Object.freeze({
16
+ reachable: false,
17
+ compatible: false,
18
+ service: null,
19
+ runtime_version: null,
20
+ protocol_version: null,
21
+ capabilities: [],
22
+ missing_capabilities: [],
23
+ code: HUB_COMPATIBILITY_CODES.UNREACHABLE,
24
+ });
25
+
26
+ let lastProbe = { at: 0, status: EMPTY_STATUS };
27
+
28
+ function withReadiness(status) {
29
+ return {
30
+ ...status,
31
+ readiness_matrix: buildReadinessMatrix({ hubCompatibility: status }),
32
+ };
33
+ }
34
+
35
+ function cacheStatus(status) {
36
+ const observed = withReadiness(status);
37
+ lastProbe = { at: Date.now(), status: observed };
38
+ return observed;
39
+ }
40
+
41
+ async function fetchJson(path) {
42
+ const res = await fetch(`${API}${path}`, { signal: AbortSignal.timeout(800) });
43
+ let body;
44
+ try { body = await res.json(); } catch { body = null; }
45
+ return { res, body };
46
+ }
47
+
48
+ /**
49
+ * Probe reachability and compatibility as separate contracts.
50
+ *
51
+ * /ping is intentionally legacy-compatible and proves only that a dsh-crew Hub
52
+ * is alive. /runtime is the v0.3 compatibility handshake. A legacy Hub that
53
+ * lacks /runtime is therefore reachable-but-incompatible instead of looking
54
+ * offline or being silently treated as current.
55
+ */
56
+ export async function hubStatus({ force = false } = {}) {
57
+ if (!force && Date.now() - lastProbe.at < 10_000) return lastProbe.status;
58
+ try {
59
+ const ping = await fetchJson('/ping');
60
+ if (!ping.res.ok) {
61
+ return cacheStatus({
62
+ ...EMPTY_STATUS,
63
+ reachable: true,
64
+ code: HUB_COMPATIBILITY_CODES.HTTP_ERROR,
65
+ http_status: ping.res.status,
66
+ endpoint: 'ping',
67
+ });
68
+ }
69
+ if (ping.body?.service !== 'dsh-crew-hub') {
70
+ return cacheStatus(evaluateHubHandshake(ping.body));
71
+ }
72
+
73
+ const runtime = await fetchJson('/runtime');
74
+ if (runtime.res.status === 404) {
75
+ return cacheStatus({
76
+ ...EMPTY_STATUS,
77
+ reachable: true,
78
+ service: 'dsh-crew-hub',
79
+ code: HUB_COMPATIBILITY_CODES.PROTOCOL_MISSING,
80
+ endpoint: 'runtime',
81
+ });
82
+ }
83
+ if (!runtime.res.ok) {
84
+ return cacheStatus({
85
+ ...EMPTY_STATUS,
86
+ reachable: true,
87
+ service: 'dsh-crew-hub',
88
+ code: HUB_COMPATIBILITY_CODES.HTTP_ERROR,
89
+ http_status: runtime.res.status,
90
+ endpoint: 'runtime',
91
+ });
92
+ }
93
+ return cacheStatus(evaluateHubHandshake(runtime.body));
94
+ } catch {
95
+ return cacheStatus(EMPTY_STATUS);
96
+ }
97
+ }
98
+
99
+ export async function hubAvailable() {
100
+ return (await hubStatus()).compatible;
101
+ }
102
+
103
+ function structuredCode(body) {
104
+ if (isBoundedMachineCode(body?.code)) return body.code;
105
+ if (isBoundedMachineCode(body?.policyCode)) return body.policyCode;
106
+ return null;
107
+ }
108
+
109
+ /** Build a bounded Hub request error without copying arbitrary response fields. */
110
+ export function hubRequestError(body, status) {
111
+ const err = new Error(body?.error ?? `hub request failed (${status})`);
112
+ err.code = structuredCode(body) ?? HUB_REQUEST_FAILED;
113
+ return err;
114
+ }
115
+
116
+ async function call(path, init) {
117
+ const res = await fetch(`${API}${path}`, init);
118
+ const body = await res.json();
119
+ if (!res.ok || body.ok === false) throw hubRequestError(body, res.status);
120
+ return body;
121
+ }
122
+
123
+ export const hub = {
124
+ spawn: (spec) => call('/jobs', {
125
+ method: 'POST',
126
+ headers: { 'content-type': 'application/json' },
127
+ body: JSON.stringify(spec),
128
+ }).then((b) => b.job),
129
+ list: () => call('/jobs').then((b) => b.jobs),
130
+ get: (id, waitSeconds = 0) => call(`/jobs/${id}?wait=${waitSeconds}`).then((b) => b.job),
131
+ cancel: (id) => call(`/jobs/${id}/cancel`, { method: 'POST' }).then((b) => b.job),
132
+ };
@@ -1,49 +1,49 @@
1
- // Pure execution-mode decision for the Hub compatibility contract.
2
- // Transport probing lives in hub-client.mjs; this module only decides whether
3
- // a session may use Hub, intentionally fall back, or must fail closed.
4
-
5
- import { HUB_COMPATIBILITY_CODES } from './runtime-identity.mjs';
6
-
7
- export function hubCompatibilityMessage(status = {}) {
8
- const code = status.code ?? 'HUB_INCOMPATIBLE';
9
- if (!status.reachable) return `DSH workers hub is not reachable (${code}).`;
10
- const detail = status.missing_capabilities?.length
11
- ? `; missing capabilities: ${status.missing_capabilities.join(', ')}`
12
- : '';
13
- return `DSH workers hub is reachable but incompatible (${code}${detail}). Update/restart the Hub plugin before using Hub execution.`;
14
- }
15
-
16
- export function resolveHubExecutionMode(requestedMode = 'auto', status = {}) {
17
- if (requestedMode === 'standalone') {
18
- return { ok: true, mode: 'standalone', reason: 'explicit-standalone' };
19
- }
20
-
21
- if (status.compatible === true) {
22
- return { ok: true, mode: 'hub', reason: 'compatible-hub' };
23
- }
24
-
25
- if (status.reachable === true) {
26
- return {
27
- ok: false,
28
- code: status.code ?? 'HUB_INCOMPATIBLE',
29
- error: hubCompatibilityMessage(status),
30
- hub: status,
31
- };
32
- }
33
-
34
- if (requestedMode === 'hub') {
35
- return {
36
- ok: false,
37
- code: status.code ?? HUB_COMPATIBILITY_CODES.UNREACHABLE,
38
- error: 'Session mode is "hub" but the DSH workers hub is not reachable.',
39
- hub: status,
40
- };
41
- }
42
-
43
- return {
44
- ok: true,
45
- mode: 'standalone',
46
- reason: 'hub-unreachable-fallback',
47
- hub: status,
48
- };
49
- }
1
+ // Pure execution-mode decision for the Hub compatibility contract.
2
+ // Transport probing lives in hub-client.mjs; this module only decides whether
3
+ // a session may use Hub, intentionally fall back, or must fail closed.
4
+
5
+ import { HUB_COMPATIBILITY_CODES } from './runtime-identity.mjs';
6
+
7
+ export function hubCompatibilityMessage(status = {}) {
8
+ const code = status.code ?? 'HUB_INCOMPATIBLE';
9
+ if (!status.reachable) return `DSH workers hub is not reachable (${code}).`;
10
+ const detail = status.missing_capabilities?.length
11
+ ? `; missing capabilities: ${status.missing_capabilities.join(', ')}`
12
+ : '';
13
+ return `DSH workers hub is reachable but incompatible (${code}${detail}). Update/restart the Hub plugin before using Hub execution.`;
14
+ }
15
+
16
+ export function resolveHubExecutionMode(requestedMode = 'auto', status = {}) {
17
+ if (requestedMode === 'standalone') {
18
+ return { ok: true, mode: 'standalone', reason: 'explicit-standalone' };
19
+ }
20
+
21
+ if (status.compatible === true) {
22
+ return { ok: true, mode: 'hub', reason: 'compatible-hub' };
23
+ }
24
+
25
+ if (status.reachable === true) {
26
+ return {
27
+ ok: false,
28
+ code: status.code ?? 'HUB_INCOMPATIBLE',
29
+ error: hubCompatibilityMessage(status),
30
+ hub: status,
31
+ };
32
+ }
33
+
34
+ if (requestedMode === 'hub') {
35
+ return {
36
+ ok: false,
37
+ code: status.code ?? HUB_COMPATIBILITY_CODES.UNREACHABLE,
38
+ error: 'Session mode is "hub" but the DSH workers hub is not reachable.',
39
+ hub: status,
40
+ };
41
+ }
42
+
43
+ return {
44
+ ok: true,
45
+ mode: 'standalone',
46
+ reason: 'hub-unreachable-fallback',
47
+ hub: status,
48
+ };
49
+ }
package/src/i18n.mjs CHANGED
@@ -1,19 +1,19 @@
1
- // Server-side locale for strings that reach the user: connectivity-test
2
- // reports, model-list labels, error messages and the vision transcription.
3
- //
4
- // The panel owns the authoritative locale (DSH's setting may be absent, in
5
- // which case the browser decides), so it passes `lang` with every request and
6
- // the hub calls setLang(). The host's durable setting seeds the initial value
7
- // for paths with no request behind them, such as the pasted-image pre-step.
8
-
9
- let LANG = 'en';
10
-
11
- export function setLang(lang) {
12
- if (lang === 'zh' || lang === 'en') LANG = lang;
13
- return LANG;
14
- }
15
-
16
- export function getLang() { return LANG; }
17
-
18
- /** Pick the string for the active locale. Both branches are cheap literals. */
19
- export function tr(zh, en) { return LANG === 'zh' ? zh : en; }
1
+ // Server-side locale for strings that reach the user: connectivity-test
2
+ // reports, model-list labels, error messages and the vision transcription.
3
+ //
4
+ // The panel owns the authoritative locale (DSH's setting may be absent, in
5
+ // which case the browser decides), so it passes `lang` with every request and
6
+ // the hub calls setLang(). The host's durable setting seeds the initial value
7
+ // for paths with no request behind them, such as the pasted-image pre-step.
8
+
9
+ let LANG = 'en';
10
+
11
+ export function setLang(lang) {
12
+ if (lang === 'zh' || lang === 'en') LANG = lang;
13
+ return LANG;
14
+ }
15
+
16
+ export function getLang() { return LANG; }
17
+
18
+ /** Pick the string for the active locale. Both branches are cheap literals. */
19
+ export function tr(zh, en) { return LANG === 'zh' ? zh : en; }
@@ -1,28 +1,28 @@
1
- #!/usr/bin/env node
2
- // Usage: node src/install/cli.mjs <claude|codex|all|hud|uninstall-claude|uninstall-codex|uninstall-all> [--statusline] [--project]
3
-
4
- import { installClaudeCode, installCodex, uninstallClaudeCode, uninstallCodex, installHudSegment } from './install.mjs';
5
-
6
- const cmd = process.argv[2];
7
- const flags = new Set(process.argv.slice(3));
8
- const opts = { statusline: flags.has('--statusline'), scope: flags.has('--project') ? 'project' : 'user' };
9
-
10
- const run = {
11
- claude: () => [installClaudeCode(opts)],
12
- codex: () => [installCodex(opts)],
13
- all: () => [installClaudeCode(opts), installHudSegment(opts), installCodex(opts)],
14
- 'uninstall-claude': () => [uninstallClaudeCode(opts)],
15
- 'uninstall-codex': () => [uninstallCodex(opts)],
16
- 'uninstall-all': () => [uninstallClaudeCode(opts), uninstallCodex(opts)],
17
- hud: () => [installHudSegment(opts)],
18
- }[cmd];
19
-
20
- if (!run) {
21
- console.error('usage: cli.mjs <claude|codex|all|hud|uninstall-claude|uninstall-codex|uninstall-all> [--statusline] [--project]');
22
- process.exit(1);
23
- }
24
- for (const p of run()) {
25
- const r = await p;
26
- for (const a of r.actions) console.log('•', a);
27
- }
28
- console.log('done.');
1
+ #!/usr/bin/env node
2
+ // Usage: node src/install/cli.mjs <claude|codex|all|hud|uninstall-claude|uninstall-codex|uninstall-all> [--statusline] [--project]
3
+
4
+ import { installClaudeCode, installCodex, uninstallClaudeCode, uninstallCodex, installHudSegment } from './install.mjs';
5
+
6
+ const cmd = process.argv[2];
7
+ const flags = new Set(process.argv.slice(3));
8
+ const opts = { statusline: flags.has('--statusline'), scope: flags.has('--project') ? 'project' : 'user' };
9
+
10
+ const run = {
11
+ claude: () => [installClaudeCode(opts)],
12
+ codex: () => [installCodex(opts)],
13
+ all: () => [installClaudeCode(opts), installHudSegment(opts), installCodex(opts)],
14
+ 'uninstall-claude': () => [uninstallClaudeCode(opts)],
15
+ 'uninstall-codex': () => [uninstallCodex(opts)],
16
+ 'uninstall-all': () => [uninstallClaudeCode(opts), uninstallCodex(opts)],
17
+ hud: () => [installHudSegment(opts)],
18
+ }[cmd];
19
+
20
+ if (!run) {
21
+ console.error('usage: cli.mjs <claude|codex|all|hud|uninstall-claude|uninstall-codex|uninstall-all> [--statusline] [--project]');
22
+ process.exit(1);
23
+ }
24
+ for (const p of run()) {
25
+ const r = await p;
26
+ for (const a of r.actions) console.log('•', a);
27
+ }
28
+ console.log('done.');