@huanlin/dsh-plugin-yet-another-subagent 0.1.6 → 0.3.0

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.
@@ -15,9 +15,17 @@
15
15
  * Both units are pure synchronous folds; the framework drives them and the
16
16
  * host wire layer ships the validated views.
17
17
  *
18
+ * Alpha.3 change-feed contract (`@deepseek-ai/dsh-session-projection`): the
19
+ * drive publishes a client view only when its raw output changes by
20
+ * `Object.is`, so an object-valued view MUST reuse its reference while the
21
+ * wire content is unchanged — a fresh object per call republishes on every
22
+ * internal-only state change (e.g. the excluded `streamingText`
23
+ * accumulator). Both `view`s below go through {@link memoizeView} for that
24
+ * reference-stability guarantee.
25
+ *
18
26
  * @module @huanlin/dsh-plugin-yet-another-subagent/projection
19
27
  */
20
- import type { ProjectionDefinition } from '@deepseek-ai/dsh-session-projection';
28
+ import { z } from 'zod';
21
29
  import type { SessionEvent } from '@deepseek-ai/dsh-session';
22
30
  /** `subagentProfile` wire shape: childId → profileId, plus callId → childId. */
23
31
  export interface SubagentProfileProjection {
@@ -26,10 +34,14 @@ export interface SubagentProfileProjection {
26
34
  /** callId → childId (for foreground calls where the result text has no embedded id). */
27
35
  readonly calls: Record<string, string>;
28
36
  }
29
- /** Internal fold state for `subagentProfile`. */
37
+ /**
38
+ * Internal fold state for `subagentProfile`. Plain JSON only (the persisted
39
+ * projection-cache precondition), so the pending callId map is a Record,
40
+ * not a Map.
41
+ */
30
42
  interface ProfileState {
31
43
  /** callId → profileId, awaiting the matching `tool/result`. */
32
- readonly pending: Map<string, string>;
44
+ readonly pending: Record<string, string>;
33
45
  /** childId → profileId (the durable mapping). */
34
46
  readonly mapping: Record<string, string>;
35
47
  /** callId → childId (survives after the pending entry is consumed). */
@@ -42,7 +54,31 @@ interface ProfileState {
42
54
  * or `runId` (foreground branch); the continuable branch is the durable
43
55
  * child identity that survives across activations.
44
56
  */
45
- export declare const subagentProfileProjection: ProjectionDefinition<'subagentProfile', ProfileState>;
57
+ export declare const subagentProfileProjection: {
58
+ key: "subagentProfile";
59
+ stateSchema: z.ZodObject<{
60
+ pending: z.ZodRecord<z.ZodString, z.ZodString>;
61
+ mapping: z.ZodRecord<z.ZodString, z.ZodString>;
62
+ callToChild: z.ZodRecord<z.ZodString, z.ZodString>;
63
+ }, z.core.$strict>;
64
+ stateVersion: number;
65
+ init: () => {
66
+ pending: {};
67
+ mapping: {};
68
+ callToChild: {};
69
+ };
70
+ apply: (state: NoInfer<ProfileState>, event: SessionEvent) => ProfileState;
71
+ wire: {
72
+ viewSchema: z.ZodObject<{
73
+ children: z.ZodRecord<z.ZodString, z.ZodString>;
74
+ calls: z.ZodRecord<z.ZodString, z.ZodString>;
75
+ }, z.core.$strict>;
76
+ view: (state: NoInfer<ProfileState>) => {
77
+ children: Record<string, string>;
78
+ calls: Record<string, string>;
79
+ };
80
+ };
81
+ };
46
82
  /** `yaSubagentProgress` wire shape: live child progress for the parent's card. */
47
83
  export interface YaSubagentProgressProjection {
48
84
  /** Number of `tool/call` events folded so far. */
@@ -88,16 +124,91 @@ interface ProgressState {
88
124
  * usage accumulates from `assistant/message.usage` (cache fields are
89
125
  * optional); tool calls are counted; lifecycle follows turn boundaries.
90
126
  */
91
- export declare const yaSubagentProgressProjection: ProjectionDefinition<'yaSubagentProgress', ProgressState>;
127
+ export declare const yaSubagentProgressProjection: {
128
+ key: "yaSubagentProgress";
129
+ stateSchema: z.ZodObject<{
130
+ toolCallCount: z.ZodNumber;
131
+ tokens: z.ZodObject<{
132
+ input: z.ZodNumber;
133
+ output: z.ZodNumber;
134
+ cacheRead: z.ZodNumber;
135
+ cacheWrite: z.ZodNumber;
136
+ reasoning: z.ZodNumber;
137
+ }, z.core.$strict>;
138
+ state: z.ZodUnion<readonly [z.ZodLiteral<"running">, z.ZodLiteral<"idle">, z.ZodLiteral<"settled">]>;
139
+ activity: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
140
+ kind: z.ZodLiteral<"text">;
141
+ text: z.ZodString;
142
+ }, z.core.$strict>, z.ZodObject<{
143
+ kind: z.ZodLiteral<"tool">;
144
+ name: z.ZodString;
145
+ args: z.ZodOptional<z.ZodString>;
146
+ }, z.core.$strict>]>>;
147
+ streamingText: z.ZodString;
148
+ }, z.core.$strict>;
149
+ stateVersion: number;
150
+ init: () => {
151
+ toolCallCount: number;
152
+ tokens: {
153
+ input: number;
154
+ output: number;
155
+ cacheRead: number;
156
+ cacheWrite: number;
157
+ reasoning: number;
158
+ };
159
+ state: "idle";
160
+ streamingText: string;
161
+ };
162
+ apply: (state: NoInfer<ProgressState>, event: SessionEvent) => ProgressState;
163
+ wire: {
164
+ viewSchema: z.ZodObject<{
165
+ toolCallCount: z.ZodNumber;
166
+ tokens: z.ZodObject<{
167
+ input: z.ZodNumber;
168
+ output: z.ZodNumber;
169
+ cacheRead: z.ZodNumber;
170
+ cacheWrite: z.ZodNumber;
171
+ reasoning: z.ZodNumber;
172
+ }, z.core.$strict>;
173
+ state: z.ZodUnion<readonly [z.ZodLiteral<"running">, z.ZodLiteral<"idle">, z.ZodLiteral<"settled">]>;
174
+ activity: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
175
+ kind: z.ZodLiteral<"text">;
176
+ text: z.ZodString;
177
+ }, z.core.$strict>, z.ZodObject<{
178
+ kind: z.ZodLiteral<"tool">;
179
+ name: z.ZodString;
180
+ args: z.ZodOptional<z.ZodString>;
181
+ }, z.core.$strict>]>>;
182
+ }, z.core.$strict>;
183
+ view: (state: NoInfer<ProgressState>) => {
184
+ toolCallCount: number;
185
+ tokens: {
186
+ readonly input: number;
187
+ readonly output: number;
188
+ readonly cacheRead: number;
189
+ readonly cacheWrite: number;
190
+ readonly reasoning: number;
191
+ };
192
+ state: "running" | "idle" | "settled";
193
+ activity?: Activity;
194
+ };
195
+ };
196
+ };
92
197
  /** Convenience: the projection keys registered by this plugin. */
93
198
  export declare const PROJECTION_KEYS: readonly ["subagentProfile", "yaSubagentProgress"];
94
- /** Type-side declaration merge so consumers can read these keys via the projection registry. */
199
+ /** Type-side declaration merges so consumers can read these keys via the projection registry. */
95
200
  declare module '@deepseek-ai/dsh-session-projection/types' {
96
201
  interface SessionProjectionMap {
97
- /** Parent-session map of childId → profileId. Empty object when no children yet. */
202
+ /** Parent-session map of childId → profileId. */
98
203
  subagentProfile: SubagentProfileProjection;
99
204
  /** Child-session live progress (toolcall count + token usage + state). */
100
205
  yaSubagentProgress: YaSubagentProgressProjection;
101
206
  }
207
+ interface SessionProjectionStateMap {
208
+ /** Host fold state behind {@link SubagentProfileProjection}. */
209
+ subagentProfile: ProfileState;
210
+ /** Host fold state behind {@link YaSubagentProgressProjection}. */
211
+ yaSubagentProgress: ProgressState;
212
+ }
102
213
  }
103
214
  export type { SessionEvent };
@@ -1,15 +1,27 @@
1
1
  /**
2
- * One-shot session-log repair: stamp `"ignorable": true` onto legacy
3
- * `ya-subagent/started` events so the harness persistence read path
4
- * (`assertEventsSupported`) will skip them instead of refusing the whole log.
5
- *
6
- * Background: older plugin versions wrote `ya-subagent/started` via
7
- * `session.append(...)`, but `session.append` cannot set the `ignorable`
8
- * envelope flag, and `KNOWN_SESSION_EVENT_TYPES` is code-generated with no
9
- * plugin registration surface. The read path therefore refuses any log
10
- * containing the type unless each occurrence carries `ignorable: true`.
11
- * This module rewrites on-disk artifacts in place (after a `.bak` backup) to
12
- * add that flag to every `ya-subagent/started` row missing it.
2
+ * One-shot session-log repair: physically REMOVE legacy `ya-subagent/started`
3
+ * event rows so the harness persistence read path (`assertEventsSupported`)
4
+ * loads the log again.
5
+ *
6
+ * Background: plugin versions ≤0.1.2 appended `ya-subagent/started` via
7
+ * `session.append(...)`. `KNOWN_SESSION_EVENT_TYPES` is code-generated with no
8
+ * plugin registration surface, and v0.1.2-alpha.1 refuses EVERY log row whose
9
+ * type is outside that set the old `ignorable` envelope flag no longer
10
+ * exists, so stamping it (the ≤0.1.5 repair) cannot help. The only repair is
11
+ * removal.
12
+ *
13
+ * Rows cannot simply be deleted: the read path enforces contiguous `seq`
14
+ * numbers. This module therefore rewrites the log in place (after a `.bak`
15
+ * backup):
16
+ *
17
+ * - drops every `ya-subagent/started` row;
18
+ * - decrements the `seq` of every later ordinary event row (packed
19
+ * `text-chunks` / `reasoning-chunks` / `tool-call-chunks` storage rows
20
+ * shift their `seq0` instead);
21
+ * - shifts every `sourceEventSeqs` citation by the number of dropped rows
22
+ * ahead of it (dropped rows are never cited: only surface events carry
23
+ * provenance and they cite assistant chunks / surface nodes, which a
24
+ * plugin row never is).
13
25
  *
14
26
  * Two physical encodings (mirrors `session-persistence-jsonl`):
15
27
  * - `.jsonl` — plaintext, one JSON record per line.
@@ -17,12 +29,17 @@
17
29
  * frame holds the session header line, subsequent
18
30
  * frames each hold one append batch of event lines.
19
31
  * Each frame is independently decodable + checksummed.
20
- * Only frames whose decoded plaintext contains a target
21
- * row are recompressed; untouched frames are copied
22
- * verbatim so byte-identity is preserved where possible.
32
+ * The first frame containing a dropped row and every
33
+ * frame after it are recompressed (their rows renumber);
34
+ * untouched earlier frames are copied verbatim.
35
+ *
36
+ * Modified rows are re-encoded with `JSON.stringify`, which reproduces the
37
+ * write path's canonical single-line form and preserves the parsed key order;
38
+ * untouched lines stay byte-identical.
23
39
  *
24
- * Idempotent: rows already carrying `ignorable: true` are skipped; files with
25
- * no target rows are left untouched (no backup, no rewrite).
40
+ * Idempotent: a log with no target rows is left untouched (no backup, no
41
+ * rewrite). A corrupt (unparsable) line is left untouched that is the
42
+ * harness's refusal job, not ours.
26
43
  *
27
44
  * @module @huanlin/dsh-plugin-yet-another-subagent/repair
28
45
  */
@@ -30,9 +47,9 @@
30
47
  export interface RepairStats {
31
48
  /** Session log files examined (`.jsonl` + `.jsonl.zstd`). */
32
49
  readonly scanned: number;
33
- /** Files rewritten because at least one target row was patched. */
50
+ /** Files rewritten because at least one target row was removed. */
34
51
  readonly repaired: number;
35
- /** Files with no patchable rows (already clean or no target events). */
52
+ /** Files with no target rows (already clean). */
36
53
  readonly skipped: number;
37
54
  /** Per-file errors (path + message); empty on a clean run. */
38
55
  readonly errors: readonly {
@@ -52,7 +52,9 @@ export type YaSubagentValue = ProfileListResponse | ToolListResponse | RepairSta
52
52
  * Register the ya-subagent RPC channel on the host's connection service.
53
53
  * `connection` is in the plugin's inject list, so `ctx.connection` is
54
54
  * directly available; the channel route rolls back on fiber disposal
55
- * (the inner `owner.effect` owns cleanup).
55
+ * (the inner `owner.effect` owns cleanup). Trust and browser authentication
56
+ * moved to the physical `/api` carrier in v0.1.2-alpha.1, so channels no
57
+ * longer carry an `authority` option.
56
58
  * @param ctx - host context.
57
59
  * @param store - profile store.
58
60
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@huanlin/dsh-plugin-yet-another-subagent",
3
- "version": "0.1.6",
3
+ "version": "0.3.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -17,10 +17,6 @@
17
17
  "types": "./lib/types/index.d.ts",
18
18
  "import": "./lib/index.js"
19
19
  },
20
- "./invariant": {
21
- "types": "./lib/types/invariant.d.ts",
22
- "import": "./lib/invariant.js"
23
- },
24
20
  "./client": {
25
21
  "types": "./lib/types/client/index.d.ts",
26
22
  "default": "./lib/client.js"
@@ -30,7 +26,6 @@
30
26
  },
31
27
  "files": [
32
28
  "lib/index.js",
33
- "lib/invariant.js",
34
29
  "lib/client.js",
35
30
  "lib/types/**/*.d.ts",
36
31
  "cordis.patch.yml"
@@ -41,7 +36,7 @@
41
36
  },
42
37
  "client": {
43
38
  "inject": [
44
- "@deepseek-ai/dsh-client-runtime",
39
+ "@deepseek-ai/dsh-api-session-controller",
45
40
  "@deepseek-ai/dsh-client-locale",
46
41
  "@deepseek-ai/dsh-client-connection",
47
42
  "@deepseek-ai/dsh-client-ui-tool",
@@ -54,23 +49,22 @@
54
49
  }
55
50
  },
56
51
  "peerDependencies": {
57
- "@deepseek-ai/dsh-agent": "^0.0.1-rc.1",
58
- "@deepseek-ai/dsh-client-connection": "^0.0.1-rc.1",
59
- "@deepseek-ai/dsh-client-locale": "^0.0.1-rc.1",
60
- "@deepseek-ai/dsh-client-runtime": "^0.0.1-rc.1",
61
- "@deepseek-ai/dsh-client-ui-conversation": "^0.0.1-rc.1",
62
- "@deepseek-ai/dsh-client-ui-primitives": "^0.0.1-rc.1",
63
- "@deepseek-ai/dsh-client-ui-settings": "^0.0.1-rc.1",
64
- "@deepseek-ai/dsh-client-ui-slots": "^0.0.1-rc.1",
65
- "@deepseek-ai/dsh-client-ui-tool": "^0.0.1-rc.1",
66
- "@deepseek-ai/dsh-host-apiproxy": "^0.0.1-rc.1",
67
- "@deepseek-ai/dsh-invariants": "^0.0.1-rc.1",
68
- "@deepseek-ai/dsh-llm": "^0.0.1-rc.1",
69
- "@deepseek-ai/dsh-session": "^0.0.1-rc.1",
70
- "@deepseek-ai/dsh-session-projection": "^0.0.1-rc.1",
71
- "@deepseek-ai/dsh-subagent": "^0.0.1-rc.1",
72
- "@deepseek-ai/dsh-jobs": "^0.0.1-rc.1",
73
- "@deepseek-ai/dsh-tools": "^0.0.1-rc.1",
52
+ "@deepseek-ai/dsh-agent": "^0.1.2-rc.1",
53
+ "@deepseek-ai/dsh-api-session-controller": "^0.1.2-rc.1",
54
+ "@deepseek-ai/dsh-client-connection": "^0.1.2-rc.1",
55
+ "@deepseek-ai/dsh-client-locale": "^0.1.2-rc.1",
56
+ "@deepseek-ai/dsh-client-ui-conversation": "^0.1.2-rc.1",
57
+ "@deepseek-ai/dsh-client-ui-primitives": "^0.1.2-rc.1",
58
+ "@deepseek-ai/dsh-client-ui-settings": "^0.1.2-rc.1",
59
+ "@deepseek-ai/dsh-client-ui-slots": "^0.1.2-rc.1",
60
+ "@deepseek-ai/dsh-client-ui-tool": "^0.1.2-rc.1",
61
+ "@deepseek-ai/dsh-llm": "^0.1.2-rc.1",
62
+ "@deepseek-ai/dsh-session": "^0.1.2-rc.1",
63
+ "@deepseek-ai/dsh-session-projection": "^0.1.2-rc.1",
64
+ "@deepseek-ai/dsh-subagent": "^0.1.2-rc.1",
65
+ "@deepseek-ai/dsh-jobs": "^0.1.2-rc.1",
66
+ "@deepseek-ai/dsh-tools": "^0.1.2-rc.1",
67
+ "@deepseek-ai/dsh-util-values": "^0.1.2-rc.1",
74
68
  "cordis": "^4.0.0-rc.7",
75
69
  "react": "^18.2.0",
76
70
  "schemastery": "^3.18.0"
@@ -79,13 +73,13 @@
79
73
  "@deepseek-ai/dsh-agent": {
80
74
  "optional": true
81
75
  },
82
- "@deepseek-ai/dsh-client-connection": {
76
+ "@deepseek-ai/dsh-api-session-controller": {
83
77
  "optional": true
84
78
  },
85
- "@deepseek-ai/dsh-client-locale": {
79
+ "@deepseek-ai/dsh-client-connection": {
86
80
  "optional": true
87
81
  },
88
- "@deepseek-ai/dsh-client-runtime": {
82
+ "@deepseek-ai/dsh-client-locale": {
89
83
  "optional": true
90
84
  },
91
85
  "@deepseek-ai/dsh-client-ui-conversation": {
@@ -103,12 +97,6 @@
103
97
  "@deepseek-ai/dsh-client-ui-tool": {
104
98
  "optional": true
105
99
  },
106
- "@deepseek-ai/dsh-host-apiproxy": {
107
- "optional": true
108
- },
109
- "@deepseek-ai/dsh-invariants": {
110
- "optional": true
111
- },
112
100
  "@deepseek-ai/dsh-llm": {
113
101
  "optional": true
114
102
  },
@@ -127,6 +115,9 @@
127
115
  "@deepseek-ai/dsh-tools": {
128
116
  "optional": true
129
117
  },
118
+ "@deepseek-ai/dsh-util-values": {
119
+ "optional": true
120
+ },
130
121
  "cordis": {
131
122
  "optional": true
132
123
  },
package/lib/invariant.js DELETED
@@ -1,21 +0,0 @@
1
- //#region src/invariant.ts
2
- const PACKAGE_NAME = "@huanlin/dsh-plugin-yet-another-subagent";
3
- /** Cordis companion plugin name. */
4
- const name = "yet-another-subagent-invariant";
5
- /** Service required before the companion can reserve package ownership. */
6
- const inject = ["invariants"];
7
- /**
8
- * No runtime invariant: profile tools, the RPC interceptor, and the two
9
- * projections are registry-owned registrations whose disposal is proven by
10
- * the HMR-safety spec. They emit no cordis events and own no cross-plugin
11
- * mutable state (the in-memory ProfileStore's lifetime is the plugin fiber).
12
- */
13
- const install = () => {};
14
- /**
15
- * Register this package's invariant companion.
16
- * @param ctx - Cordis context carrying the invariant service.
17
- * @returns the installed registration's disposer after setup succeeds.
18
- */
19
- const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
20
- //#endregion
21
- export { apply, inject, name };
@@ -1,16 +0,0 @@
1
- /**
2
- * Package-owned invariant companion for `@huanlin/dsh-plugin-yet-another-subagent`.
3
- *
4
- * @module @huanlin/dsh-plugin-yet-another-subagent/invariant
5
- */
6
- import type { Context } from 'cordis';
7
- /** Cordis companion plugin name. */
8
- export declare const name = "yet-another-subagent-invariant";
9
- /** Service required before the companion can reserve package ownership. */
10
- export declare const inject: string[];
11
- /**
12
- * Register this package's invariant companion.
13
- * @param ctx - Cordis context carrying the invariant service.
14
- * @returns the installed registration's disposer after setup succeeds.
15
- */
16
- export declare const apply: (ctx: Context) => Promise<() => void>;