@qilin-agent/brand 0.0.0-stage → 3.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 kkutysllb
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,46 @@
1
+ # Bilingual-pair consistency record for README.md (docs/i18n/README.md): per heading
2
+ # section, a hash of its English and Chinese blocks outside code blocks and generated regions.
3
+ # After editing either side, bring the other along and re-record with:
4
+ # pnpm run verify-translation-pairing --write packages/util/brand/README.md
5
+ /:
6
+ en: 9c53a07c1a04a19a
7
+ zh: 1fd4666fbc6c39a8
8
+ /qilin-agent-brand:
9
+ en: ed14efbbe8b6cfcf
10
+ zh: 7ae20e3c6d72185f
11
+ /qilin-agent-brand/summary:
12
+ en: 57d5a106e98e6b9d
13
+ zh: 664ed658a6c38e60
14
+ /qilin-agent-brand/table-of-contents:
15
+ en: c992e0cd2e7042d6
16
+ zh: 2e8cd826664632d1
17
+ /qilin-agent-brand/use-this-package:
18
+ en: abdf7a28d3af06f0
19
+ zh: 8d68807326b03898
20
+ /qilin-agent-brand/use-this-package/branding-a-string:
21
+ en: 49b137dc146f5c0a
22
+ zh: 7fe82acb5ba633e8
23
+ /qilin-agent-brand/use-this-package/branding-a-number:
24
+ en: fd9617ca2804f47b
25
+ zh: cd3c0e6bda613509
26
+ /qilin-agent-brand/use-this-package/when-to-brand:
27
+ en: 4224e7edc4200bfe
28
+ zh: b1cec114c5ba4024
29
+ /qilin-agent-brand/understand-the-implementation:
30
+ en: 98a62299f46d5050
31
+ zh: 042d3c626e1fbe34
32
+ /qilin-agent-brand/understand-the-implementation/source-map:
33
+ en: 5032eec37cf68046
34
+ zh: 971402fa5c6c0e63
35
+ /qilin-agent-brand/understand-the-implementation/how-values-stay-portable:
36
+ en: 6a126aa2e31591c0
37
+ zh: c85e395cdb0bbb0e
38
+ /qilin-agent-brand/understand-the-implementation/why-it-stays-dependency-free:
39
+ en: 5bcb11c1ef6fa468
40
+ zh: 9c389300baa819a8
41
+ /qilin-agent-brand/further-exploration:
42
+ en: ee41e38fb8fc21cb
43
+ zh: 67a6a94d3cd29983
44
+ /qilin-agent-brand/dev-note:
45
+ en: 5de1d6304e00c58f
46
+ zh: 8d8225361cfa29e5
package/README.md CHANGED
@@ -1,3 +1,107 @@
1
- # Temporary Holding Version
1
+ ---
2
+ description: "Nominal string and number types with stateless constructors for packages that own confusable domain values."
3
+ kind: "package-library"
4
+ ---
2
5
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
6
+ # @qilin-agent/brand
7
+
8
+ English | [中文](README.zh.md)
9
+
10
+ ## Summary
11
+
12
+ `qilin-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
+
14
+ ## Table of Contents
15
+
16
+ - [Use this package](#use-this-package)
17
+ - [Understand the implementation](#understand-the-implementation)
18
+ - [Further Exploration](#further-exploration)
19
+ - [Dev Note](#dev-note)
20
+
21
+ -----
22
+
23
+ <a id="use-this-package"></a>
24
+ ## Use this package
25
+
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
+
28
+ ### Branding a string
29
+
30
+ Declare the branded type in the owning package and apply it at the point where that package admits a string:
31
+
32
+ ```ts
33
+ import { brandString, type Branded } from '@qilin-agent/brand'
34
+
35
+ export type SessionId = Branded<'SessionId'>
36
+
37
+ const sessionId = brandString<SessionId>('session-1')
38
+ ```
39
+
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
+
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 '@qilin-agent/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
+
56
+ ### When to brand
57
+
58
+ Brand values that cross package boundaries and could plausibly be confused — `ToolCallId` in `qilin-llm`, the shared agent/session `SessionId` in `qilin-session`, `JobId` in `qilin-jobs`, and `SessionSeq` versus `SessionLogOffset` in `qilin-session`. Values that stay local or cannot be confused do not need this abstraction.
59
+
60
+ -----
61
+
62
+ <a id="understand-the-implementation"></a>
63
+ ## Understand the implementation
64
+
65
+ <details>
66
+ <summary>Implementation internals — click to expand</summary>
67
+
68
+ The package defines two intersection types, `string & { readonly [BRAND]: B }` and `number & { readonly [BRAND]: B }`, where `BRAND` is a module-private `unique symbol`.
69
+
70
+ ### Source map
71
+
72
+ | File | Role |
73
+ |---|---|
74
+ | [`src/index.ts`](src/index.ts) | Branded string and number types with stateless constructors |
75
+
76
+ ### How values stay portable
77
+
78
+ 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.
79
+
80
+ ### Why it stays dependency-free
81
+
82
+ Keeping these helpers in their own package means `qilin-jobs` can brand `JobId` without importing an unrelated capability package, while each capability still owns the meaning and validation of its concrete ids.
83
+
84
+ </details>
85
+
86
+ -----
87
+
88
+ <a id="further-exploration"></a>
89
+ ## Further Exploration
90
+
91
+ Read these pages when you need the values these primitives brand or the type conventions around them.
92
+
93
+ - [Core subsystem](../../../docs/subsystems/core.md) — where the shared `SessionId` brand and the type rules are documented.
94
+ - [LSP subsystem](../../../docs/subsystems/lsp.md) — `LspProviderId`, a branded provider id built on this primitive.
95
+ - [Jobs package](../../jobs/jobs/README.md) — the `JobId` brand owned by the jobs capability.
96
+
97
+ -----
98
+
99
+ <a id="dev-note"></a>
100
+ ## Dev Note
101
+
102
+ <details>
103
+ <summary>Working context for maintainers — click to expand</summary>
104
+
105
+ None.
106
+
107
+ </details>
package/README.zh.md ADDED
@@ -0,0 +1,107 @@
1
+ ---
2
+ description: "供拥有易混淆领域值的包使用的名义字符串与数字类型及无状态构造函数。"
3
+ kind: "package-library"
4
+ ---
5
+
6
+ # @qilin-agent/brand
7
+
8
+ [English](README.md) | 中文
9
+
10
+ ## 概述
11
+
12
+ `qilin-brand` 让结构相同的字符串或数字在类型层面不可互换:`SessionId` 无法传给期望 `ToolCallId` 的位置,事件序号也无法传给需要日志偏移量的位置。`brandString<T>()` 与 `brandNumber<T>()` 在不持有共享运行时状态的情况下应用名义品牌,让所属包可以定义领域类型,而无需导入不相关的能力。
13
+
14
+ ## 目录
15
+
16
+ - [使用本包](#use-this-package)
17
+ - [理解实现](#understand-the-implementation)
18
+ - [进一步探索](#further-exploration)
19
+ - [开发备注](#dev-note)
20
+
21
+ -----
22
+
23
+ <a id="use-this-package"></a>
24
+ ## 使用本包
25
+
26
+ 当领域值跨越包边界,并可能与使用同一原语表示的另一个值混淆时,为其添加品牌;并非每个字符串或数字都需要品牌。品牌化值是给 TypeScript 调用方的约定:它只会进入期望该领域的函数,不同品牌会在编译期被拒绝。
27
+
28
+ ### 为字符串添加品牌
29
+
30
+ 在所属包中声明品牌化类型,并在该包准入字符串的位置应用品牌:
31
+
32
+ ```ts
33
+ import { brandString, type Branded } from '@qilin-agent/brand'
34
+
35
+ export type SessionId = Branded<'SessionId'>
36
+
37
+ const sessionId = brandString<SessionId>('session-1')
38
+ ```
39
+
40
+ `brandString()` 只改变静态类型,不执行运行时校验。所属类型若有领域文法,应在调用前完成校验。添加品牌后,该 id 在比较、日志记录、JSON 序列化和协议传输中仍表现为普通字符串。
41
+
42
+ ### 为数字添加品牌
43
+
44
+ 在所属包中声明数字品牌,并且仅在该包准入数字之后应用品牌:
45
+
46
+ ```ts
47
+ import { brandNumber, type BrandedNumber } from '@qilin-agent/brand'
48
+
49
+ export type SessionSeq = BrandedNumber<'SessionSeq'>
50
+
51
+ const seq = brandNumber<SessionSeq>(7)
52
+ ```
53
+
54
+ `brandNumber()` 原样返回数字,不执行校验。所属包会在添加品牌前校验非负安全整数范围等要求。比较、算术、日志、JSON 序列化与协议传输保留普通数字行为;算术会产生未品牌化数字,所属包必须重新准入该数字,才能让它再次进入领域。
55
+
56
+ ### 何时添加品牌
57
+
58
+ 为跨包边界且可能被混淆的值添加品牌——`qilin-llm` 中的 `ToolCallId`、`qilin-session` 中由 agent(智能体)和会话共享的 `SessionId`、`qilin-jobs` 中的 `JobId`,以及 `qilin-session` 中的 `SessionSeq` 与 `SessionLogOffset`。保持局部或无法混淆的值不需要这种抽象。
59
+
60
+ -----
61
+
62
+ <a id="understand-the-implementation"></a>
63
+ ## 理解实现
64
+
65
+ <details>
66
+ <summary>实现细节——点击展开</summary>
67
+
68
+ 该包定义两个交叉类型:`string & { readonly [BRAND]: B }` 与 `number & { readonly [BRAND]: B }`,其中 `BRAND` 是模块私有的 `unique symbol`。
69
+
70
+ ### 源码地图
71
+
72
+ | 文件 | 职责 |
73
+ |---|---|
74
+ | [`src/index.ts`](src/index.ts) | 品牌化字符串与数字类型及其无状态构造函数 |
75
+
76
+ ### 值为何可移植
77
+
78
+ 私有 symbol 在运行时不存在:TypeScript 会将其擦除,因此品牌化值没有标签或 prototype。`brandString()` 与 `brandNumber()` 都原样返回输入。因此,彼此独立安装的副本无需共享注册表或 constructor identity,也会生成可互换的值。
79
+
80
+ ### 为何保持无依赖
81
+
82
+ 把这些 helper 放在独立包中,意味着 `qilin-jobs` 可以为 `JobId` 添加品牌,而无需导入不相关的能力包;每个能力仍然拥有其具体 id 的含义与校验。
83
+
84
+ </details>
85
+
86
+ -----
87
+
88
+ <a id="further-exploration"></a>
89
+ ## 进一步探索
90
+
91
+ 当你需要这些原语所品牌化的值或围绕它们的类型约定时,阅读以下页面。
92
+
93
+ - [核心子系统](../../../docs/subsystems/core.zh.md)——共享 `SessionId` 品牌与类型规则的记录位置。
94
+ - [LSP 子系统](../../../docs/subsystems/lsp.zh.md)——构建在本原语之上的品牌化提供方 id `LspProviderId`。
95
+ - [jobs 包](../../jobs/jobs/README.zh.md)——由 jobs 能力拥有的 `JobId` 品牌。
96
+
97
+ -----
98
+
99
+ <a id="dev-note"></a>
100
+ ## 开发备注
101
+
102
+ <details>
103
+ <summary>维护者的工作上下文——点击展开</summary>
104
+
105
+ 无。
106
+
107
+ </details>
package/lib/index.js ADDED
@@ -0,0 +1,32 @@
1
+ //#region lib/types/index.js
2
+ /**
3
+ * Duplicate-install-safe nominal primitive helpers.
4
+ *
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
+ *
10
+ * This package owns no concrete domain value and keeps no runtime identity or mutable
11
+ * state, so independently installed copies produce interchangeable values.
12
+ *
13
+ * @module @qilin-agent/brand
14
+ */
15
+ /**
16
+ * Apply a compile-time string brand without changing the value.
17
+ * @param value - string admitted by the domain that owns the target brand.
18
+ * @returns the same string with the requested compile-time brand.
19
+ */
20
+ function brandString(value) {
21
+ return value;
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
+ }
31
+ //#endregion
32
+ export { brandNumber, brandString };
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Duplicate-install-safe nominal primitive helpers.
3
+ *
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
+ *
9
+ * This package owns no concrete domain value and keeps no runtime identity or mutable
10
+ * state, so independently installed copies produce interchangeable values.
11
+ *
12
+ * @module @qilin-agent/brand
13
+ */
14
+ declare const BRAND: unique symbol;
15
+ /** A string carrying a compile-time-only brand `B`. */
16
+ export type Branded<B extends string> = string & {
17
+ readonly [BRAND]: B;
18
+ };
19
+ /** A number carrying a compile-time-only brand `B`. */
20
+ export type BrandedNumber<B extends string> = number & {
21
+ readonly [BRAND]: B;
22
+ };
23
+ /**
24
+ * Apply a compile-time string brand without changing the value.
25
+ * @param value - string admitted by the domain that owns the target brand.
26
+ * @returns the same string with the requested compile-time brand.
27
+ */
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;
35
+ export {};
36
+ //# sourceMappingURL=index.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,38 @@
1
1
  {
2
2
  "name": "@qilin-agent/brand",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "description": "Stateless branded primitive types for the QiLin",
4
+ "version": "3.1.4",
5
+ "publishConfig": {
6
+ "access": "public"
7
+ },
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/kkutysllb/QiLin.git",
11
+ "directory": "packages/util/brand"
12
+ },
13
+ "engines": {
14
+ "node": "^22.19.0 || >=24.0.0"
15
+ },
16
+ "type": "module",
17
+ "main": "lib/index.js",
18
+ "types": "lib/types/index.d.ts",
19
+ "exports": {
20
+ ".": {
21
+ "types": "./lib/types/index.d.ts",
22
+ "default": "./lib/index.js"
23
+ },
24
+ "./src/*": "./src/*",
25
+ "./package.json": "./package.json"
26
+ },
27
+ "files": [
28
+ "lib/index.js",
29
+ "lib/types/**/*.d.ts"
30
+ ],
31
+ "license": "MIT",
32
+ "peerDependencies": {
33
+ "@qilin-agent/kylin": "~4.0.3"
34
+ },
35
+ "devDependencies": {
36
+ "@qilin-agent/kylin": "~4.0.3"
37
+ }
6
38
  }