@deepseek-ai/dsh-brand 0.1.2-alpha.2 → 0.1.2-alpha.4

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
@@ -2,5 +2,5 @@
2
2
  # side as of the last confirmed-consistent state. Both languages carry equal authority;
3
3
  # after editing either side, bring the other along and re-record with:
4
4
  # pnpm run verify-translation-pairing --write packages/util/brand/README.md
5
- README.md: 646a3e781ce8540277259f4ffd67b78f3049160b
6
- README.zh.md: 68290b35b64b4f519e2da06fc519d9d008e23646
5
+ README.md: f9bcea11d223645a9bb1d2194a129f353220c684
6
+ README.zh.md: be9d8f828e05655b41b054a11221e382c90ef58b
package/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: "Nominal string types and stateless constructors for packages that own identifiers crossing package boundaries."
2
+ description: "Nominal string and number types with stateless constructors for packages that own confusable domain values."
3
3
  kind: "package-library"
4
4
  ---
5
5
 
@@ -9,7 +9,7 @@ English | [中文](README.zh.md)
9
9
 
10
10
  ## Summary
11
11
 
12
- `dsh-brand` makes structurally identical strings non-interchangeable at the type level: a `SessionId` cannot be passed where a `ToolCallId` is expected even though both are plain strings at runtime. `brandString<T>()` applies a nominal brand to one domain-owned string without shared runtime state and lets capability packages own their concrete id types without importing an unrelated capability.
12
+ `dsh-brand` makes structurally identical strings or numbers non-interchangeable at the type level: a `SessionId` cannot be passed where a `ToolCallId` is expected, and an event sequence cannot be passed where a log offset is required. `brandString<T>()` and `brandNumber<T>()` apply nominal brands without shared runtime state, so owning packages can define domain types without importing an unrelated capability.
13
13
 
14
14
  ## Table of Contents
15
15
 
@@ -23,7 +23,7 @@ English | [中文](README.zh.md)
23
23
  <a id="use-this-package"></a>
24
24
  ## Use this package
25
25
 
26
- Brand the ids a package owns when they cross a package boundary and could plausibly be confused with another package's ids; not every string needs a brand. A branded id is a contract for TypeScript callers: it only ever enters the functions that expect it, and an id from another package is rejected at compile time.
26
+ Brand a domain value when it crosses a package boundary and could plausibly be confused with another value represented by the same primitive; not every string or number needs a brand. A branded value is a contract for TypeScript callers: it enters only functions that expect its domain, and a different brand is rejected at compile time.
27
27
 
28
28
  ### Branding a string
29
29
 
@@ -39,9 +39,23 @@ const sessionId = brandString<SessionId>('session-1')
39
39
 
40
40
  `brandString()` changes only the static type and performs no runtime validation. Validate domain grammar before calling it when the owning type has one. Once branded, the id compares, logs, serializes to JSON, and crosses the wire as an ordinary string.
41
41
 
42
+ ### Branding a number
43
+
44
+ Declare a numeric brand in its owning package and apply it only after that package admits the number:
45
+
46
+ ```ts
47
+ import { brandNumber, type BrandedNumber } from '@deepseek-ai/dsh-brand'
48
+
49
+ export type SessionSeq = BrandedNumber<'SessionSeq'>
50
+
51
+ const seq = brandNumber<SessionSeq>(7)
52
+ ```
53
+
54
+ `brandNumber()` returns the original number and performs no validation. The owning package validates requirements such as non-negative safe-integer range before branding. Comparison, arithmetic, logging, JSON serialization, and wire transport retain ordinary number behavior; arithmetic produces an unbranded number that the owner must admit again before it re-enters the domain.
55
+
42
56
  ### When to brand
43
57
 
44
- Brand ids that cross package boundaries and could plausibly be confused — `ToolCallId` in `dsh-llm`, the shared agent/session `SessionId` in `dsh-session`, `JobId` in `dsh-jobs`, `LspProviderId` in `dsh-lsp`. Strings that never leave their owning package do not need this abstraction.
58
+ Brand values that cross package boundaries and could plausibly be confused — `ToolCallId` in `dsh-llm`, the shared agent/session `SessionId` in `dsh-session`, `JobId` in `dsh-jobs`, and `SessionSeq` versus `SessionLogOffset` in `dsh-session`. Values that stay local or cannot be confused do not need this abstraction.
45
59
 
46
60
  -----
47
61
 
@@ -51,18 +65,18 @@ Brand ids that cross package boundaries and could plausibly be confused — `Too
51
65
  <details>
52
66
  <summary>Implementation internals — click to expand</summary>
53
67
 
54
- The primitive is one intersection type: `string & { readonly [BRAND]: B }`, where `BRAND` is a module-private `unique symbol`.
68
+ The package defines two intersection types, `string & { readonly [BRAND]: B }` and `number & { readonly [BRAND]: B }`, where `BRAND` is a module-private `unique symbol`.
55
69
 
56
70
  ### Source map
57
71
 
58
72
  | File | Role |
59
73
  |---|---|
60
- | [`src/index.ts`](src/index.ts) | Branded string type and its stateless constructor |
61
- | [`src/invariant.ts`](src/invariant.ts) | Invariant companion (no runtime invariant; erasure is enforced by the compiler) |
74
+ | [`src/index.ts`](src/index.ts) | Branded string and number types with stateless constructors |
75
+ | | No runtime invariant companion is published; this pure utility owns no event stream or mutable runtime data; its value algebra is enforced by unit tests. |
62
76
 
63
77
  ### How values stay portable
64
78
 
65
- The private symbol never exists at runtime: TypeScript erases it, so branded values have no tag or prototype. `brandString()` returns its input unchanged. Separate installed copies therefore produce interchangeable values without sharing a registry or constructor identity.
79
+ The private symbol never exists at runtime: TypeScript erases it, so branded values have no tag or prototype. `brandString()` and `brandNumber()` return their inputs unchanged. Separate installed copies therefore produce interchangeable values without sharing a registry or constructor identity.
66
80
 
67
81
  ### Why it stays dependency-free
68
82
 
@@ -75,7 +89,7 @@ Keeping these helpers in their own package means `dsh-jobs` can brand `JobId` wi
75
89
  <a id="further-exploration"></a>
76
90
  ## Further Exploration
77
91
 
78
- Read these pages when you need the ids this primitive brands or the type conventions around it.
92
+ Read these pages when you need the values these primitives brand or the type conventions around them.
79
93
 
80
94
  - [Core subsystem](../../../docs/subsystems/core.md) — where the shared `SessionId` brand and the type rules are documented.
81
95
  - [LSP subsystem](../../../docs/subsystems/lsp.md) — `LspProviderId`, a branded provider id built on this primitive.
package/README.zh.md CHANGED
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: "供拥有跨包标识符的包使用的名义字符串类型与无状态构造函数。"
2
+ description: "供拥有易混淆领域值的包使用的名义字符串与数字类型及无状态构造函数。"
3
3
  kind: "package-library"
4
4
  ---
5
5
 
@@ -9,7 +9,7 @@ kind: "package-library"
9
9
 
10
10
  ## 概述
11
11
 
12
- `dsh-brand` 让结构相同的字符串在类型层面不可互换:即使 `SessionId` `ToolCallId` 在运行时都是普通字符串,前者也无法传给期望后者的位置。`brandString<T>()` 为领域拥有的字符串应用名义品牌且不持有共享运行时状态,让能力包可以拥有自己的具体 id 类型,而无需导入不相关的能力。
12
+ `dsh-brand` 让结构相同的字符串或数字在类型层面不可互换:`SessionId` 无法传给期望 `ToolCallId` 的位置,事件序号也无法传给需要日志偏移量的位置。`brandString<T>()` `brandNumber<T>()` 在不持有共享运行时状态的情况下应用名义品牌,让所属包可以定义领域类型,而无需导入不相关的能力。
13
13
 
14
14
  ## 目录
15
15
 
@@ -23,7 +23,7 @@ kind: "package-library"
23
23
  <a id="use-this-package"></a>
24
24
  ## 使用本包
25
25
 
26
- 当包拥有的 id 跨越包边界、并可能与其他包的 id 混淆时,为其添加品牌;并非每个字符串都需要品牌。品牌化 id 是给 TypeScript 调用方的约定:它只会进入期望它的函数,来自其他包的 id 会在编译期被拒绝。
26
+ 当领域值跨越包边界,并可能与使用同一原语表示的另一个值混淆时,为其添加品牌;并非每个字符串或数字都需要品牌。品牌化值是给 TypeScript 调用方的约定:它只会进入期望该领域的函数,不同品牌会在编译期被拒绝。
27
27
 
28
28
  ### 为字符串添加品牌
29
29
 
@@ -39,9 +39,23 @@ const sessionId = brandString<SessionId>('session-1')
39
39
 
40
40
  `brandString()` 只改变静态类型,不执行运行时校验。所属类型若有领域文法,应在调用前完成校验。添加品牌后,该 id 与普通字符串一样比较、记录日志、序列化为 JSON 和跨 wire 传输。
41
41
 
42
+ ### 为数字添加品牌
43
+
44
+ 在所属包中声明数字品牌,并且仅在该包准入数字之后应用品牌:
45
+
46
+ ```ts
47
+ import { brandNumber, type BrandedNumber } from '@deepseek-ai/dsh-brand'
48
+
49
+ export type SessionSeq = BrandedNumber<'SessionSeq'>
50
+
51
+ const seq = brandNumber<SessionSeq>(7)
52
+ ```
53
+
54
+ `brandNumber()` 原样返回数字,不执行校验。所属包会在添加品牌前校验非负安全整数范围等要求。比较、算术、日志、JSON 序列化与 wire 传输保留普通数字行为;算术会产生未品牌化数字,所属包必须重新准入该数字,才能让它再次进入领域。
55
+
42
56
  ### 何时添加品牌
43
57
 
44
- 为跨包边界且可能被混淆的 id 添加品牌——`dsh-llm` 中的 `ToolCallId`、`dsh-session` 中共享的 agent/会话 `SessionId`、`dsh-jobs` 中的 `JobId`、`dsh-lsp` 中的 `LspProviderId`。从不离开所属包的字符串不需要这种抽象。
58
+ 为跨包边界且可能被混淆的值添加品牌——`dsh-llm` 中的 `ToolCallId`、`dsh-session` 中共享的 agent/会话 `SessionId`、`dsh-jobs` 中的 `JobId`,以及 `dsh-session` 中的 `SessionSeq` 与 `SessionLogOffset`。保持局部或无法混淆的值不需要这种抽象。
45
59
 
46
60
  -----
47
61
 
@@ -51,18 +65,18 @@ const sessionId = brandString<SessionId>('session-1')
51
65
  <details>
52
66
  <summary>实现细节——点击展开</summary>
53
67
 
54
- 该原语是一个交叉类型:`string & { readonly [BRAND]: B }`,其中 `BRAND` 是模块私有的 `unique symbol`。
68
+ 该包定义两个交叉类型:`string & { readonly [BRAND]: B }` 与 `number & { readonly [BRAND]: B }`,其中 `BRAND` 是模块私有的 `unique symbol`。
55
69
 
56
70
  ### 源码地图
57
71
 
58
72
  | 文件 | 职责 |
59
73
  |---|---|
60
- | [`src/index.ts`](src/index.ts) | 品牌化字符串类型及其无状态构造函数 |
61
- | [`src/invariant.ts`](src/invariant.ts) | 不变式伴生插件(无运行时不变式;擦除由编译器保证) |
74
+ | [`src/index.ts`](src/index.ts) | 品牌化字符串与数字类型及其无状态构造函数 |
75
+ | | 不发布运行时不变量伴生入口;擦除由编译器保证。 |
62
76
 
63
77
  ### 值为何可移植
64
78
 
65
- 私有 symbol 在运行时不存在:TypeScript 会将其擦除,因此品牌化值没有标签或 prototype。`brandString()` 原样返回输入。因此,彼此独立安装的副本无需共享注册表或 constructor identity,也会生成可互换的值。
79
+ 私有 symbol 在运行时不存在:TypeScript 会将其擦除,因此品牌化值没有标签或 prototype。`brandString()` `brandNumber()` 都原样返回输入。因此,彼此独立安装的副本无需共享注册表或 constructor identity,也会生成可互换的值。
66
80
 
67
81
  ### 为何保持无依赖
68
82
 
@@ -75,7 +89,7 @@ const sessionId = brandString<SessionId>('session-1')
75
89
  <a id="further-exploration"></a>
76
90
  ## 进一步探索
77
91
 
78
- 当你需要本原语所品牌化的 id 或围绕它的类型约定时,阅读以下页面。
92
+ 当你需要这些原语所品牌化的值或围绕它们的类型约定时,阅读以下页面。
79
93
 
80
94
  - [核心子系统](../../../docs/subsystems/core.zh.md)——共享 `SessionId` 品牌与类型规则的记录位置。
81
95
  - [LSP 子系统](../../../docs/subsystems/lsp.zh.md)——构建在本原语之上的品牌化提供方 id `LspProviderId`。
package/lib/index.js CHANGED
@@ -1,13 +1,13 @@
1
1
  //#region lib/types/index.js
2
2
  /**
3
- * Duplicate-install-safe nominal string helpers.
3
+ * Duplicate-install-safe nominal primitive helpers.
4
4
  *
5
- * A brand makes structurally-identical strings non-interchangeable at the type
6
- * level: a `SessionId` cannot be passed where a `ToolCallId` is expected, even
7
- * though both are plain strings at runtime. Comparison, logging, and
8
- * serialization all behave as ordinary strings.
5
+ * A brand makes structurally identical strings or numbers non-interchangeable
6
+ * at the type level: a `SessionId` cannot be passed where a `ToolCallId` is
7
+ * expected, and an event sequence cannot be passed as a log offset. Comparison,
8
+ * logging, and serialization retain the underlying primitive behavior.
9
9
  *
10
- * This package owns no concrete id and keeps no runtime identity or mutable
10
+ * This package owns no concrete domain value and keeps no runtime identity or mutable
11
11
  * state, so independently installed copies produce interchangeable values.
12
12
  *
13
13
  * @module @deepseek-ai/dsh-brand
@@ -20,5 +20,13 @@
20
20
  function brandString(value) {
21
21
  return value;
22
22
  }
23
+ /**
24
+ * Apply a compile-time number brand without changing the value.
25
+ * @param value - number admitted by the domain that owns the target brand.
26
+ * @returns the same number with the requested compile-time brand.
27
+ */
28
+ function brandNumber(value) {
29
+ return value;
30
+ }
23
31
  //#endregion
24
- export { brandString };
32
+ export { brandNumber, brandString };
@@ -1,12 +1,12 @@
1
1
  /**
2
- * Duplicate-install-safe nominal string helpers.
2
+ * Duplicate-install-safe nominal primitive helpers.
3
3
  *
4
- * A brand makes structurally-identical strings non-interchangeable at the type
5
- * level: a `SessionId` cannot be passed where a `ToolCallId` is expected, even
6
- * though both are plain strings at runtime. Comparison, logging, and
7
- * serialization all behave as ordinary strings.
4
+ * A brand makes structurally identical strings or numbers non-interchangeable
5
+ * at the type level: a `SessionId` cannot be passed where a `ToolCallId` is
6
+ * expected, and an event sequence cannot be passed as a log offset. Comparison,
7
+ * logging, and serialization retain the underlying primitive behavior.
8
8
  *
9
- * This package owns no concrete id and keeps no runtime identity or mutable
9
+ * This package owns no concrete domain value and keeps no runtime identity or mutable
10
10
  * state, so independently installed copies produce interchangeable values.
11
11
  *
12
12
  * @module @deepseek-ai/dsh-brand
@@ -16,11 +16,21 @@ declare const BRAND: unique symbol;
16
16
  export type Branded<B extends string> = string & {
17
17
  readonly [BRAND]: B;
18
18
  };
19
+ /** A number carrying a compile-time-only brand `B`. */
20
+ export type BrandedNumber<B extends string> = number & {
21
+ readonly [BRAND]: B;
22
+ };
19
23
  /**
20
24
  * Apply a compile-time string brand without changing the value.
21
25
  * @param value - string admitted by the domain that owns the target brand.
22
26
  * @returns the same string with the requested compile-time brand.
23
27
  */
24
28
  export declare function brandString<T extends Branded<string>>(value: string | T): T;
29
+ /**
30
+ * Apply a compile-time number brand without changing the value.
31
+ * @param value - number admitted by the domain that owns the target brand.
32
+ * @returns the same number with the requested compile-time brand.
33
+ */
34
+ export declare function brandNumber<T extends BrandedNumber<string>>(value: number | T): T;
25
35
  export {};
26
36
  //# sourceMappingURL=index.d.ts.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-brand",
3
- "description": "Stateless branded-string primitives for the DeepSeek Harness",
4
- "version": "0.1.2-alpha.2",
3
+ "description": "Stateless branded primitive types for the DeepSeek Harness",
4
+ "version": "0.1.2-alpha.4",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -18,25 +18,18 @@
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
  "./src/*": "./src/*",
26
22
  "./package.json": "./package.json"
27
23
  },
28
24
  "files": [
29
25
  "lib/index.js",
30
- "lib/invariant.js",
31
26
  "lib/types/**/*.d.ts"
32
27
  ],
33
28
  "license": "MIT",
34
29
  "peerDependencies": {
35
- "@deepseek-ai/cordis": "^4.0.2",
36
- "@deepseek-ai/dsh-invariants": "^0.1.2-alpha.2"
30
+ "@deepseek-ai/cordis": "^4.0.2"
37
31
  },
38
32
  "devDependencies": {
39
- "@deepseek-ai/cordis": "^4.0.2",
40
- "@deepseek-ai/dsh-invariants": "^0.1.2-alpha.2"
33
+ "@deepseek-ai/cordis": "^4.0.2"
41
34
  }
42
35
  }
package/lib/invariant.js DELETED
@@ -1,22 +0,0 @@
1
- //#region lib/types/invariant.js
2
- /**
3
- * Package-owned invariant companion for `@deepseek-ai/dsh-brand`.
4
- * @module @deepseek-ai/dsh-brand/invariant
5
- */
6
- const PACKAGE_NAME = "@deepseek-ai/dsh-brand";
7
- /** Cordis companion plugin name. */
8
- const name = "brand-invariant";
9
- /** Service required before the companion can reserve package ownership. */
10
- const inject = ["invariants"];
11
- /**
12
- * No runtime invariant: this utility owns no event stream, shared identity, or mutable module state.
13
- */
14
- const install = () => {};
15
- /**
16
- * Register this package's invariant companion.
17
- * @param ctx - Cordis context carrying the invariant service.
18
- * @returns the installed registration's disposer after setup succeeds.
19
- */
20
- const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
21
- //#endregion
22
- export { apply, inject, name };
@@ -1,16 +0,0 @@
1
- /**
2
- * Package-owned invariant companion for `@deepseek-ai/dsh-brand`.
3
- * @module @deepseek-ai/dsh-brand/invariant
4
- */
5
- import type { Context } from '@deepseek-ai/cordis';
6
- /** Cordis companion plugin name. */
7
- export declare const name = "brand-invariant";
8
- /** Service required before the companion can reserve package ownership. */
9
- export declare const inject: string[];
10
- /**
11
- * Register this package's invariant companion.
12
- * @param ctx - Cordis context carrying the invariant service.
13
- * @returns the installed registration's disposer after setup succeeds.
14
- */
15
- export declare const apply: (ctx: Context) => Promise<() => void>;
16
- //# sourceMappingURL=invariant.d.ts.map