@deepseek-ai/dsh-jobs 0.2.0-rc.2 → 0.2.1-alpha.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.i18n.yaml CHANGED
@@ -39,14 +39,14 @@
39
39
  en: 2a42e1e06dfc469e
40
40
  zh: 5c2c77eca52846f0
41
41
  /deepseek-ai-dsh-jobs/understand-the-implementation/source-map:
42
- en: 2416d5be526d4dba
43
- zh: 1090a9373258d7bb
42
+ en: d48098f76de74fa9
43
+ zh: e69cb8e7f316ce95
44
44
  /deepseek-ai-dsh-jobs/understand-the-implementation/service-operations:
45
45
  en: b2e4ef34ccf1e749
46
46
  zh: 128b57b57ed09316
47
47
  /deepseek-ai-dsh-jobs/further-exploration:
48
- en: 14a42f5debabd3ea
49
- zh: 16a60585a7280ccf
48
+ en: e8ef9de5f929d7e8
49
+ zh: 850c4aefbdd40c44
50
50
  /deepseek-ai-dsh-jobs/model-experience:
51
51
  en: efb58cac0fc08163
52
52
  zh: 838791f77fd79917
package/README.md CHANGED
@@ -81,7 +81,6 @@ This section explains the design decisions behind the contract and points at the
81
81
  | [`src/view.ts`](src/view.ts) | Client-safe leaf: `JobView`, `JobChunk`, `JobStatus`, and the merge-extensible `JobKindMap` |
82
82
  | [`src/brand.ts`](src/brand.ts) | `JobId` branded identifier, importable without the agent dependency |
83
83
  | [`src/archive-admission.ts`](src/archive-admission.ts) | The `job` family of the Workspace registry's archive admission, installed by the seam's constructor for every implementation |
84
- | [`src/invariant.ts`](src/invariant.ts) | Invariant companion: checks the announced event protocol per job (registered first, one settlement, removal last) and each announced projection against the registry's own read |
85
84
 
86
85
  ### Service operations
87
86
 
@@ -102,7 +101,7 @@ Read these pages when the package-level contract is not enough. They move from t
102
101
  - [jobs group map](../README.md) — the sibling group page and its package table.
103
102
  - [Process-local registry](../jobs-local/README.md) — the shipped implementation that runs jobs in this process.
104
103
  - [Model-facing job controls](../tool-jobs/README.md) — the `job_output`, `job_list`, and `job_kill` tools and completion notices.
105
- - [Generic long-running tool runtime Agent Note](../../../.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md) — the design behind the background-job runtime.
104
+ - [Jobs lifecycle and output ownership](../../../.agents/notes/implemented/architecture/2026-09-03-jobs-seam-consolidation.md) — one lifecycle, output ring, and observation stream.
106
105
  - [job-registry seam Agent Note](../../../.agents/notes/archived/architecture/2026-07-26-job-registry-seam.md) — the owner-fenced registry contract and its rationale.
107
106
  - [Jobs seam consolidation Agent Note](../../../.agents/notes/implemented/architecture/2026-09-03-jobs-seam-consolidation.md) — one output ring, one projection, one event stream.
108
107
 
package/README.zh.md CHANGED
@@ -81,7 +81,6 @@ kind: "package-reference"
81
81
  | [`src/view.ts`](src/view.ts) | 客户端安全叶子:`JobView`、`JobChunk`、`JobStatus` 与可合并扩展的 `JobKindMap` |
82
82
  | [`src/brand.ts`](src/brand.ts) | `JobId` 带类型标记的标识符,无需 agent 依赖即可导入 |
83
83
  | [`src/archive-admission.ts`](src/archive-admission.ts) | Workspace 注册表归档准入中的 `job` 族,由接缝构造函数为每个实现安装 |
84
- | [`src/invariant.ts`](src/invariant.ts) | 不变式伴生插件:校验每个 job 的事件协议(先 registered、恰一次结算、最后 removed)以及每个通告的投影与注册表自身读取的一致性 |
85
84
 
86
85
  ### 服务操作
87
86
 
@@ -102,7 +101,7 @@ kind: "package-reference"
102
101
  - [jobs 组映射](../README.zh.md)——同级组页面及其包表格。
103
102
  - [进程本地注册表](../jobs-local/README.zh.md)——在本进程中运行任务的随附实现。
104
103
  - [模型侧任务控制](../tool-jobs/README.zh.md)——`job_output`、`job_list` 与 `job_kill` 工具及完成通知。
105
- - [通用长时间运行工具运行时 Agent Note](../../../.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.zh.md)——后台任务运行时背后的设计。
104
+ - [Jobs 生命周期与输出归属](../../../.agents/notes/implemented/architecture/2026-09-03-jobs-seam-consolidation.zh.md)——一套生命周期、输出环与观测流。
106
105
  - [任务注册表 seam Agent Note](../../../.agents/notes/archived/architecture/2026-07-26-job-registry-seam.md)——按所有者隔离的注册表约定及其理由。
107
106
  - [jobs seam 收敛 Agent Note](../../../.agents/notes/implemented/architecture/2026-09-03-jobs-seam-consolidation.zh.md)——一个输出环、一个投影、一条事件流。
108
107
 
@@ -115,7 +115,7 @@ export interface JobHooks {
115
115
  * the output ring.
116
116
  */
117
117
  export interface JobSpec {
118
- /** Producer kind — also the id prefix (`bash`, `subagent`, …). */
118
+ /** Producer kind — also the id prefix (`bash`, …). */
119
119
  kind: JobKind;
120
120
  /** One-line model-facing label (the command; the delegation description). */
121
121
  label: string;
@@ -25,7 +25,6 @@ declare module '@deepseek-ai/dsh-workspace/types' {
25
25
  */
26
26
  export interface JobKindMap {
27
27
  bash: 'bash';
28
- subagent: 'subagent';
29
28
  }
30
29
  /** The merge-extensible union of registered producer kind names. */
31
30
  export type JobKind = JobKindMap[keyof JobKindMap];
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-jobs",
3
3
  "description": "Background job registry (ctx.jobs) for the DeepSeek Harness — shared ids, owner isolation, polling, cancellation, and completion listeners for long-running tool work",
4
- "version": "0.2.0-rc.2",
4
+ "version": "0.2.1-alpha.2",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -18,10 +18,6 @@
18
18
  "types": "./lib/types/index.d.ts",
19
19
  "default": "./lib/index.js"
20
20
  },
21
- "./invariant": {
22
- "types": "./lib/types/invariant.d.ts",
23
- "default": "./lib/invariant.js"
24
- },
25
21
  "./brand": {
26
22
  "types": "./lib/types/brand.d.ts",
27
23
  "default": "./lib/types/brand.js"
@@ -35,18 +31,16 @@
35
31
  },
36
32
  "files": [
37
33
  "lib/index.js",
38
- "lib/invariant.js",
39
34
  "lib/types/**/*.js",
40
35
  "lib/types/**/*.d.ts"
41
36
  ],
42
37
  "license": "MIT",
43
38
  "peerDependencies": {
44
- "@deepseek-ai/dsh-brand": "0.2.0-rc.2",
45
- "@deepseek-ai/dsh-agent": "0.2.0-rc.2",
46
- "@deepseek-ai/dsh-invariants": "0.2.0-rc.2",
47
- "@deepseek-ai/dsh-session": "0.2.0-rc.2",
48
- "@deepseek-ai/dsh-workspace": "0.2.0-rc.2",
49
- "@deepseek-ai/cordis": "~4.0.4"
39
+ "@deepseek-ai/dsh-agent": "0.2.1-alpha.2",
40
+ "@deepseek-ai/dsh-brand": "0.2.1-alpha.2",
41
+ "@deepseek-ai/dsh-session": "0.2.1-alpha.2",
42
+ "@deepseek-ai/dsh-workspace": "0.2.1-alpha.2",
43
+ "@deepseek-ai/cordis": "~4.0.5-alpha.1"
50
44
  },
51
45
  "peerDependenciesMeta": {
52
46
  "@deepseek-ai/dsh-workspace": {
@@ -54,11 +48,10 @@
54
48
  }
55
49
  },
56
50
  "devDependencies": {
57
- "@deepseek-ai/dsh-agent": "0.2.0-rc.2",
58
- "@deepseek-ai/dsh-brand": "0.2.0-rc.2",
59
- "@deepseek-ai/dsh-invariants": "0.2.0-rc.2",
60
- "@deepseek-ai/dsh-workspace": "0.2.0-rc.2",
61
- "@deepseek-ai/dsh-session": "0.2.0-rc.2",
62
- "@deepseek-ai/cordis": "~4.0.4"
51
+ "@deepseek-ai/dsh-agent": "0.2.1-alpha.2",
52
+ "@deepseek-ai/dsh-brand": "0.2.1-alpha.2",
53
+ "@deepseek-ai/dsh-session": "0.2.1-alpha.2",
54
+ "@deepseek-ai/dsh-workspace": "0.2.1-alpha.2",
55
+ "@deepseek-ai/cordis": "~4.0.5-alpha.1"
63
56
  }
64
57
  }
package/lib/invariant.js DELETED
@@ -1,90 +0,0 @@
1
- //#region lib/types/invariant.js
2
- /** Package-owned background-job event-protocol invariants. @module @deepseek-ai/dsh-jobs/invariant */
3
- const PACKAGE_NAME = "@deepseek-ai/dsh-jobs";
4
- const TERMINAL_STATUSES = new Set([
5
- "completed",
6
- "killed",
7
- "failed"
8
- ]);
9
- /** Cordis companion plugin name. */
10
- const name = "jobs-invariant";
11
- /** Service required before the companion can reserve package ownership. */
12
- const inject = ["invariants"];
13
- /** The registry's own current projection of `id`, or undefined once the record is gone. */
14
- function readBack(ctx, id, owner) {
15
- try {
16
- return ctx.jobs.get(id, owner);
17
- } catch {
18
- return;
19
- }
20
- }
21
- /**
22
- * The announced projection must agree with the registry's own read: the
23
- * immutable identity matches, and the announced output total is not ahead of
24
- * the committed one.
25
- */
26
- function checkAnnounced(read, announced, what, fail) {
27
- const id = String(announced.id);
28
- for (const key of [
29
- "kind",
30
- "label",
31
- "owner",
32
- "startedAt"
33
- ]) if (read[key] !== announced[key]) fail(`${what} for job ${id} announces ${key} ${JSON.stringify(announced[key])} while the registry reads ${JSON.stringify(read[key])}`);
34
- if (announced.output.total > read.output.total) fail(`${what} for job ${id} announces output total ${announced.output.total} ahead of the registry's ${read.output.total}`);
35
- }
36
- /** Install the per-job protocol and event-versus-read checks over the whole event stream. */
37
- const install = Object.assign((ctx, fail) => {
38
- const phases = /* @__PURE__ */ new Map();
39
- ctx.jobs.events.subscribe({ owners: "all" }, (event) => {
40
- if (event.type === "output") {
41
- const id = String(event.id);
42
- const read = readBack(ctx, event.id, event.owner);
43
- if (read === void 0) fail(`output announced for job ${id} that the registry no longer returns`);
44
- if (event.total > read.output.total) fail(`output announced for job ${id} at total ${event.total} ahead of the registry's ${read.output.total}`);
45
- if (!phases.has(id)) phases.set(id, "live");
46
- return;
47
- }
48
- const { job } = event;
49
- const id = String(job.id);
50
- const phase = phases.get(id);
51
- const terminal = TERMINAL_STATUSES.has(job.status);
52
- switch (event.type) {
53
- case "registered":
54
- if (phase !== void 0) fail(`registered announced for job ${id} after earlier events for the same id`);
55
- if (terminal || job.finishedAt !== void 0) fail(`registered job ${id} must announce a live status without finishedAt`);
56
- break;
57
- case "progress":
58
- case "stopping":
59
- if (phase === "settled") fail(`${event.type} announced for job ${id} after its settlement`);
60
- if (terminal) fail(`${event.type} announced for job ${id} with a terminal status`);
61
- break;
62
- case "settled":
63
- if (phase === "settled") fail(`settled announced twice for job ${id}`);
64
- if (!terminal) fail(`settled job ${id} must announce a terminal status, got ${JSON.stringify(job.status)}`);
65
- if (job.finishedAt === void 0 || job.finishedAt < job.startedAt) fail(`settled job ${id} must announce finishedAt no earlier than startedAt`);
66
- if (job.progress !== void 0) fail(`settled job ${id} must announce a cleared progress line`);
67
- break;
68
- case "removed":
69
- if (phase === "live") fail(`removed announced for job ${id} before its settlement`);
70
- if (readBack(ctx, job.id, job.owner) !== void 0) fail(`removed announced for job ${id} that the registry still returns`);
71
- phases.delete(id);
72
- return;
73
- /* v8 ignore start -- defensive: the lifecycle event union is closed and exhaustive here; a new variant fails loudly */
74
- default: fail(`unknown job event ${String(event)} for job ${id}`);
75
- }
76
- const read = readBack(ctx, job.id, job.owner);
77
- if (read === void 0) fail(`${event.type} announced for job ${id} that the registry does not return`);
78
- checkAnnounced(read, job, event.type, fail);
79
- if (event.type === "settled" && (read.status !== job.status || read.finishedAt !== job.finishedAt)) fail(`settled job ${id} announces ${job.status} at ${String(job.finishedAt)} while the registry reads ${read.status} at ${String(read.finishedAt)}`);
80
- phases.set(id, event.type === "settled" ? "settled" : "live");
81
- });
82
- }, { inject: ["jobs"] });
83
- /**
84
- * Register the job-registry invariant companion.
85
- * @param ctx - Cordis context carrying the invariant service.
86
- * @returns the installed registration's disposer after setup succeeds.
87
- */
88
- const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
89
- //#endregion
90
- export { apply, inject, name };
@@ -1,13 +0,0 @@
1
- /** Package-owned background-job event-protocol invariants. @module @deepseek-ai/dsh-jobs/invariant */
2
- import type { Context } from '@deepseek-ai/cordis';
3
- /** Cordis companion plugin name. */
4
- export declare const name = "jobs-invariant";
5
- /** Service required before the companion can reserve package ownership. */
6
- export declare const inject: string[];
7
- /**
8
- * Register the job-registry invariant companion.
9
- * @param ctx - Cordis context carrying the invariant service.
10
- * @returns the installed registration's disposer after setup succeeds.
11
- */
12
- export declare const apply: (ctx: Context) => Promise<() => void>;
13
- //# sourceMappingURL=invariant.d.ts.map
@@ -1,110 +0,0 @@
1
- /** Package-owned background-job event-protocol invariants. @module @deepseek-ai/dsh-jobs/invariant */
2
- const PACKAGE_NAME = '@deepseek-ai/dsh-jobs';
3
- const TERMINAL_STATUSES = new Set(['completed', 'killed', 'failed']);
4
- /** Cordis companion plugin name. */
5
- export const name = 'jobs-invariant';
6
- /** Service required before the companion can reserve package ownership. */
7
- export const inject = ['invariants'];
8
- /** The registry's own current projection of `id`, or undefined once the record is gone. */
9
- function readBack(ctx, id, owner) {
10
- try {
11
- return ctx.jobs.get(id, owner);
12
- }
13
- catch {
14
- // The registry throws for an id outside the caller's set; after a removal that is the expected answer.
15
- return undefined;
16
- }
17
- }
18
- /**
19
- * The announced projection must agree with the registry's own read: the
20
- * immutable identity matches, and the announced output total is not ahead of
21
- * the committed one.
22
- */
23
- function checkAnnounced(read, announced, what, fail) {
24
- const id = String(announced.id);
25
- for (const key of ['kind', 'label', 'owner', 'startedAt']) {
26
- if (read[key] !== announced[key]) {
27
- fail(`${what} for job ${id} announces ${key} ${JSON.stringify(announced[key])} while the registry reads ${JSON.stringify(read[key])}`);
28
- }
29
- }
30
- if (announced.output.total > read.output.total) {
31
- fail(`${what} for job ${id} announces output total ${announced.output.total} ahead of the registry's ${read.output.total}`);
32
- }
33
- }
34
- /** Install the per-job protocol and event-versus-read checks over the whole event stream. */
35
- const install = Object.assign((ctx, fail) => {
36
- const phases = new Map();
37
- ctx.jobs.events.subscribe({ owners: 'all' }, (event) => {
38
- if (event.type === 'output') {
39
- const id = String(event.id);
40
- const read = readBack(ctx, event.id, event.owner);
41
- if (read === undefined)
42
- fail(`output announced for job ${id} that the registry no longer returns`);
43
- if (event.total > read.output.total) {
44
- fail(`output announced for job ${id} at total ${event.total} ahead of the registry's ${read.output.total}`);
45
- }
46
- if (!phases.has(id))
47
- phases.set(id, 'live');
48
- return;
49
- }
50
- const { job } = event;
51
- const id = String(job.id);
52
- const phase = phases.get(id);
53
- const terminal = TERMINAL_STATUSES.has(job.status);
54
- switch (event.type) {
55
- case 'registered':
56
- if (phase !== undefined)
57
- fail(`registered announced for job ${id} after earlier events for the same id`);
58
- if (terminal || job.finishedAt !== undefined)
59
- fail(`registered job ${id} must announce a live status without finishedAt`);
60
- break;
61
- case 'progress':
62
- case 'stopping':
63
- if (phase === 'settled')
64
- fail(`${event.type} announced for job ${id} after its settlement`);
65
- if (terminal)
66
- fail(`${event.type} announced for job ${id} with a terminal status`);
67
- break;
68
- case 'settled':
69
- if (phase === 'settled')
70
- fail(`settled announced twice for job ${id}`);
71
- if (!terminal)
72
- fail(`settled job ${id} must announce a terminal status, got ${JSON.stringify(job.status)}`);
73
- if (job.finishedAt === undefined || job.finishedAt < job.startedAt) {
74
- fail(`settled job ${id} must announce finishedAt no earlier than startedAt`);
75
- }
76
- if (job.progress !== undefined)
77
- fail(`settled job ${id} must announce a cleared progress line`);
78
- break;
79
- case 'removed':
80
- if (phase === 'live')
81
- fail(`removed announced for job ${id} before its settlement`);
82
- if (readBack(ctx, job.id, job.owner) !== undefined)
83
- fail(`removed announced for job ${id} that the registry still returns`);
84
- phases.delete(id);
85
- return;
86
- /* v8 ignore start -- defensive: the lifecycle event union is closed and exhaustive here; a new variant fails loudly */
87
- default: {
88
- const exhaustive = event;
89
- fail(`unknown job event ${String(exhaustive)} for job ${id}`);
90
- }
91
- /* v8 ignore stop */
92
- }
93
- const read = readBack(ctx, job.id, job.owner);
94
- if (read === undefined)
95
- fail(`${event.type} announced for job ${id} that the registry does not return`);
96
- checkAnnounced(read, job, event.type, fail);
97
- if (event.type === 'settled' && (read.status !== job.status || read.finishedAt !== job.finishedAt)) {
98
- fail(`settled job ${id} announces ${job.status} at ${String(job.finishedAt)}`
99
- + ` while the registry reads ${read.status} at ${String(read.finishedAt)}`);
100
- }
101
- phases.set(id, event.type === 'settled' ? 'settled' : 'live');
102
- });
103
- }, { inject: ['jobs'] });
104
- /**
105
- * Register the job-registry invariant companion.
106
- * @param ctx - Cordis context carrying the invariant service.
107
- * @returns the installed registration's disposer after setup succeeds.
108
- */
109
- export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
110
- //# sourceMappingURL=invariant.js.map