dsh-plugin-stardeck 0.20.1

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.
@@ -0,0 +1,534 @@
1
+ import z from "@deepseek-ai/schemastery";
2
+ import { Context } from "@deepseek-ai/cordis";
3
+ //#region src/config.d.ts
4
+ /** Resolved plugin configuration. */
5
+ interface Config {
6
+ /**
7
+ * 编制上限: maximum simultaneously active troops per campaign
8
+ * Default 6.
9
+ */
10
+ maxUnits: number;
11
+ /**
12
+ * 重试上限: attempts per bounty before it lands in `failed` (below the cap
13
+ * a failure auto-requeues back onto the board). Default 2.
14
+ */
15
+ maxAttempts: number;
16
+ /**
17
+ * 外勤小队上限 (v2.0 征召制): maximum concurrently in_progress tasks — each
18
+ * holds one conscripted commander. Same-workspace tasks always serialize
19
+ * regardless (the workspace mutex); this caps cross-workspace parallelism.
20
+ * Default 3.
21
+ */
22
+ maxCommanders: number;
23
+ /**
24
+ * Absolute path of the global war-state JSON file. Empty resolves to
25
+ * `$DSH_HOME/warroom-plugin/state.json` (`~/.dsh` when `DSH_HOME` is unset);
26
+ * task event logs live in a `campaigns/` sibling directory.
27
+ */
28
+ statePath: string;
29
+ /**
30
+ * War root: parent of all per-task workspaces. Empty resolves to
31
+ * `<server cwd>/.warroom` — keep it inside the dsh web process's cwd so
32
+ * the workspace-write sandbox covers troop writes.
33
+ */
34
+ warRoot: string;
35
+ /**
36
+ * Boot-time override of war mode for headless compositions: `on`/`off`
37
+ * force at every load; `auto` (default) follows the persisted activation.
38
+ */
39
+ active: 'auto' | 'on' | 'off';
40
+ /**
41
+ * 演示织换(smoke/playground overlay 专用,缺省 false):开机时把播种器写进
42
+ * 事件流的假会话号按 `.demo-sessions.json` manifest 换成宿主真会话——演示板
43
+ * 上所有「直跳原生会话」的点击才有着落。生产配置绝不开。
44
+ */
45
+ demoWeave: boolean;
46
+ /**
47
+ * 装配层附加显式开旗(逗号分隔,缺省空):overlay 自带考题旗用——如 smoke
48
+ * overlay 开 `staff-auto-close` 让 e2e 考题继续覆盖自动收官机制(该旗默认
49
+ * OFF——舰长令 2026-09-01 强制人工验收)。env 的 `!name` 仍可压掉它。
50
+ */
51
+ extraFeatures: string;
52
+ }
53
+ /** Schemastery configuration validated at plugin load. */
54
+ declare const Config: z<Config>;
55
+ //#endregion
56
+ //#region src/flags.d.ts
57
+ /**
58
+ * Feature flags (VERIFICATION.md §8.3, P0-3). The closed-loop SOP demands every
59
+ * new feature ship behind a flag whose OFF state is byte-identical to the
60
+ * pre-change behavior — so the same regression suite can run flag=on/off and
61
+ * diff what changed.
62
+ *
63
+ * Discipline:
64
+ * - Flags only ever ENABLE behavior; absence from the env means OFF.
65
+ * - OFF must equal the old code path exactly — no "off but slightly new".
66
+ * - A flag graduates (flag deleted, behavior unconditional) only after the
67
+ * feature's regression + supervisor thresholds hold (§6 DoD).
68
+ *
69
+ * Read once at startup (or per-call in tests) — never hot-reloaded.
70
+ * @module dsh-plugin-stardeck/flags
71
+ */
72
+ /** A frozen name → enabled map. Unknown names are simply absent (falsy). */
73
+ type FeatureFlags = Readonly<Record<string, boolean>>;
74
+ declare const FEATURE_FLAGS_ENV = "WARROOM_FEATURES";
75
+ /**
76
+ * Parse the `WARROOM_FEATURES` environment variable: a comma-separated flag
77
+ * name list (`WARROOM_FEATURES=thread-paging,button-relay`). Empty/unset →
78
+ * all flags OFF. Whitespace around names is tolerated; empty segments are
79
+ * dropped; duplicates collapse.
80
+ */
81
+ declare function readFeatureFlags(env?: Record<string, string | undefined>): FeatureFlags;
82
+ /** The gate check: false unless the flag was explicitly enabled. */
83
+ declare function featureEnabled(flags: FeatureFlags, name: string): boolean;
84
+ /**
85
+ * Runtime flag set: DEFAULT_ON 为底,`WARROOM_FEATURES` 覆盖——`name` 显式开
86
+ * (探针旗如 v5-spike 仍走这里),`!name` 显式关(回归对照/临时熔断用)。
87
+ * `extra` 是装配层的附加显式开清单(config.extraFeatures,逗号分隔——overlay
88
+ * 自带考题旗用,免环境变量记忆);env 的 `!name` 仍可压掉它(env 最后解析)。
89
+ */
90
+ declare function runtimeFlags(env?: Record<string, string | undefined>, extra?: string): FeatureFlags;
91
+ //#endregion
92
+ //#region src/types.d.ts
93
+ /** A deployed troop, folded from the campaign event log. */
94
+ interface UnitRecord {
95
+ readonly childId: string;
96
+ readonly unitName: string;
97
+ readonly label: string;
98
+ readonly mission: string;
99
+ readonly front: string;
100
+ readonly writes: boolean;
101
+ readonly deployedAt: string;
102
+ readonly orders: ReadonlyArray<{
103
+ ts: string;
104
+ order: string;
105
+ }>;
106
+ lastReport?: string;
107
+ recalled?: {
108
+ reason: string;
109
+ ts: string;
110
+ };
111
+ settled?: {
112
+ stopReason: string;
113
+ ts: string;
114
+ };
115
+ }
116
+ /** One commander attempt (执行会话) on a task — the unit the board's
117
+ * 进行中/已完成/已失败 columns are made of. `sessionId` is the commander's
118
+ * conversation (claimedBy at claim time); clicking the card opens it. */
119
+ interface AttemptRecord {
120
+ /** Capability token issued at claim (empty for v0.2 legacy claims). */
121
+ readonly id: string;
122
+ /** 1-based attempt number. */
123
+ readonly n: number;
124
+ /** The commander session that ran (and still owns) this attempt. */
125
+ readonly sessionId: string;
126
+ readonly startedAt: string;
127
+ endedAt?: string;
128
+ /** undefined = still live; 'failed' | 'reported' | 'succeeded' once settled. */
129
+ outcome?: 'failed' | 'reported' | 'succeeded';
130
+ }
131
+ /** Campaign state derived by folding the append-only event log. */
132
+ interface CampaignState {
133
+ readonly campaignId: string;
134
+ intent: string;
135
+ readonly startedAt: string;
136
+ hqSessionId?: string;
137
+ title?: string;
138
+ brief?: string;
139
+ acceptance?: string;
140
+ priority?: 'normal' | 'high';
141
+ /** Bounty rarity (WoW color language); default common. */
142
+ quality?: QualityTier;
143
+ /** 前置任务 campaignIds — a bounty unlocks only when all deps are closed. */
144
+ deps?: readonly string[];
145
+ /** Daily-quest cron; absent = one-shot bounty. */
146
+ schedule?: TaskSchedule;
147
+ /** How many bounty rounds a cron re-trigger has opened (0 = never re-run). */
148
+ rounds: number;
149
+ workspacePath?: string;
150
+ /** V15:工作区绑定形态(投影字段=治 worktree/未分组误判;旧账本无此字段=undefined 走客户端路径启发式)。 */
151
+ workspaceKind?: 'bound' | 'bound-worktree' | 'instance' | 'auto-worktree' | 'auto-dir';
152
+ status: TaskStatus;
153
+ claimedBy?: string;
154
+ publishedBy?: string;
155
+ /** V5-R4 (quota-recovery flag): 配额熔断原地暂停位(不改 status/attempt——
156
+ * 恢复即续作,不烧 maxAttempts 不换令牌)。 */
157
+ quotaPaused?: boolean;
158
+ /** Capability token of the CURRENT attempt — stale submits are rejected. */
159
+ attempt?: {
160
+ readonly id: string;
161
+ readonly n: number;
162
+ };
163
+ /** Attempts started so far (attempt numbers are 1-based). */
164
+ attempts: number;
165
+ /** Every attempt ever started, in order — the board's session cards. */
166
+ readonly attemptLog: ReadonlyArray<AttemptRecord>;
167
+ /** Last failure reason (shown while failed / during requeue). */
168
+ lastError?: string;
169
+ /** Collected loot (出本掉落) accumulated across submissions. */
170
+ readonly deliverables: ReadonlyArray<Deliverable>;
171
+ readonly reports: ReadonlyArray<{
172
+ ts: string;
173
+ from: string;
174
+ text: string;
175
+ evidence?: SubmissionEvidence;
176
+ }>;
177
+ readonly comments: ReadonlyArray<{
178
+ ts: string;
179
+ from: string;
180
+ text: string;
181
+ }>;
182
+ /** V4-R2 direct messages (troop-mailbox flag): logged first, delivered marked. */
183
+ readonly messages: ReadonlyArray<{
184
+ messageId: string;
185
+ ts: string;
186
+ from: string;
187
+ to: string;
188
+ text: string;
189
+ delivered?: boolean;
190
+ }>;
191
+ /** V4-R3 intra-task subtask graph (troop-scheduler flag). */
192
+ readonly subtasks: Map<string, SubtaskRecord>;
193
+ closedVerdict?: string;
194
+ plan?: string;
195
+ readonly units: Map<string, UnitRecord>;
196
+ /** B1-件⑥:worktree 随链归档释放的账面投影(事件 workspace_released 落 fold)。 */
197
+ workspaceReleased?: {
198
+ at: string;
199
+ path: string;
200
+ ok: boolean;
201
+ note?: string;
202
+ };
203
+ }
204
+ /** One 队内子任务 (V4-R3) — the commander's work breakdown inside a task.
205
+ * attempt tokens mirror the campaign-level discipline: a stale attemptId on
206
+ * subtask_updated means ownership changed. `blocked` returns the subtask to
207
+ * the open pool with its note kept. */
208
+ interface SubtaskRecord {
209
+ readonly subtaskId: string;
210
+ readonly title: string;
211
+ readonly detail?: string;
212
+ readonly deps: readonly string[];
213
+ status: 'open' | 'in_progress' | 'completed';
214
+ claimedBy?: string;
215
+ claimedAt?: string;
216
+ updatedAt?: string;
217
+ /** Capability token of the CURRENT claim. */
218
+ attempt?: {
219
+ readonly id: string;
220
+ readonly n: number;
221
+ };
222
+ attempts: number;
223
+ lastNote?: string;
224
+ /** V4-R4: owner interrupted but attempt kept (park ≠ revoke). */
225
+ parked?: boolean;
226
+ }
227
+ /** Task lifecycle on the strategic board. `failed` is a terminal-for-humans
228
+ * state: retries already exhausted, the 大副 must re-file a new bounty. */
229
+ type TaskStatus = 'draft' | 'published' | 'in_progress' | 'reported' | 'failed' | 'closed';
230
+ /** Bounty quality tier — the WoW rarity color language for task complexity. */
231
+ type QualityTier = 'common' | 'fine' | 'rare' | 'epic' | 'legendary';
232
+ /** KillCredit evidence a commander must attach to war_submit — the system
233
+ * verifies, troops never self-certify). */
234
+ interface SubmissionEvidence {
235
+ /** DoD checklist verdicts, one per acceptance item. */
236
+ readonly checks: ReadonlyArray<{
237
+ readonly item: string;
238
+ readonly passed: boolean;
239
+ }>;
240
+ /** A test command actually run, with its real exit code. */
241
+ readonly tests?: {
242
+ readonly command: string;
243
+ readonly exitCode: number;
244
+ readonly passed: number;
245
+ readonly failed: number;
246
+ };
247
+ /** `git diff --stat` style summary line(s). */
248
+ readonly diffstat?: string;
249
+ /** Touched file paths. */
250
+ readonly files?: readonly string[];
251
+ }
252
+ /** A collected loot item shown on the board card (出本掉落). */
253
+ interface Deliverable {
254
+ readonly kind: 'files' | 'tests' | 'diffstat' | 'note';
255
+ readonly summary: string;
256
+ readonly detail?: string;
257
+ readonly ts: string;
258
+ }
259
+ /** Daily-quest schedule on a bounty. */
260
+ interface TaskSchedule {
261
+ readonly cron: string;
262
+ enabled: boolean;
263
+ nextRunAt?: string;
264
+ lastTriggeredAt?: string;
265
+ }
266
+ /** The tiny global war state. Task history lives in the append-only event
267
+ * logs; only this pointer state is a plain JSON file. */
268
+ interface WarGlobalState {
269
+ version: 2;
270
+ /** War mode on/off — gates the staff persona and the war_* tool surface. */
271
+ active: boolean;
272
+ /** Session id of the 大副部 (the conversation where /war first ran). */
273
+ hqSessionId?: string;
274
+ /** The single durable commander child-session id (lazy-spawned on first publish). */
275
+ commanderChildId?: string;
276
+ /** V5-R4 (quota-recovery flag): 全局配额熔断标记(flag on 才写)。
277
+ * 熔断期间停征召停唤醒,在役任务原地 paused——恢复即续作。 */
278
+ quotaBlocked?: {
279
+ since: string;
280
+ code: string;
281
+ };
282
+ }
283
+ /** Live descendant entry from ctx.subagents.listDescendants (structural slice). */
284
+ interface DescendantFace {
285
+ readonly kind: string;
286
+ readonly id: string;
287
+ readonly activity?: 'running' | 'inactive';
288
+ readonly mode?: 'one-shot' | 'continuable';
289
+ readonly label?: string;
290
+ readonly parentId?: string;
291
+ readonly depth?: number;
292
+ }
293
+ //#endregion
294
+ //#region src/state.d.ts
295
+ /** The store handle shared across command/tool/dashboard wiring. */
296
+ interface WarStore {
297
+ get(): WarGlobalState;
298
+ save(): void;
299
+ }
300
+ //#endregion
301
+ //#region src/relay.d.ts
302
+ /** Structural slice of the harness apiProxy's sessions + workspace domains. */
303
+ interface SessionsApiFace {
304
+ create(request: {
305
+ rpcId: string;
306
+ payload: {
307
+ workspaceId?: string;
308
+ cwd?: string;
309
+ };
310
+ }): Promise<{
311
+ result: {
312
+ ok: true;
313
+ value: {
314
+ sessionId: string;
315
+ };
316
+ } | {
317
+ ok: false;
318
+ error: {
319
+ code: string;
320
+ message: string;
321
+ };
322
+ };
323
+ }>;
324
+ rename(request: {
325
+ rpcId: string;
326
+ payload: {
327
+ sessionId: string;
328
+ title: string;
329
+ };
330
+ }): Promise<{
331
+ result: {
332
+ ok: true;
333
+ value: unknown;
334
+ } | {
335
+ ok: false;
336
+ error: {
337
+ code: string;
338
+ message: string;
339
+ };
340
+ };
341
+ }>;
342
+ prompt(request: {
343
+ rpcId: string;
344
+ payload: {
345
+ sessionId: string;
346
+ mode: 'queue';
347
+ content: Array<{
348
+ type: 'text';
349
+ text: string;
350
+ }>;
351
+ };
352
+ }): Promise<{
353
+ result: {
354
+ ok: true;
355
+ value: unknown;
356
+ } | {
357
+ ok: false;
358
+ error: {
359
+ code: string;
360
+ message: string;
361
+ };
362
+ };
363
+ }>;
364
+ /** V9.12:演示织换复用既有「演示·」会话用(可选——缺面时退回每次新建)。 */
365
+ list?(request: {
366
+ rpcId: string;
367
+ payload: {
368
+ cursor?: string;
369
+ };
370
+ }): Promise<{
371
+ result: {
372
+ ok: true;
373
+ value: {
374
+ items: ReadonlyArray<{
375
+ id: string;
376
+ title?: string;
377
+ displayTitle: string;
378
+ }>;
379
+ };
380
+ } | {
381
+ ok: false;
382
+ error: {
383
+ code: string;
384
+ message: string;
385
+ };
386
+ };
387
+ }>;
388
+ }
389
+ /** Structural slice of the apiProxy workspace domain (registry create is
390
+ * idempotent over an existing directory). */
391
+ interface WorkspaceApiFace {
392
+ create(request: {
393
+ rpcId: string;
394
+ payload: {
395
+ path: string;
396
+ };
397
+ }): Promise<{
398
+ result: {
399
+ ok: true;
400
+ value: {
401
+ workspace: {
402
+ workspaceId: string;
403
+ };
404
+ };
405
+ } | {
406
+ ok: false;
407
+ error: {
408
+ code: string;
409
+ message: string;
410
+ };
411
+ };
412
+ }>;
413
+ /** V17 归档:宿主 registry 全局归档集(分组面隐藏;日志与记账保留,无恢复)。 */
414
+ archiveSession(request: {
415
+ rpcId: string;
416
+ payload: {
417
+ sessionId: string;
418
+ };
419
+ }): Promise<{
420
+ result: {
421
+ ok: true;
422
+ value: unknown;
423
+ } | {
424
+ ok: false;
425
+ error: {
426
+ code: string;
427
+ message: string;
428
+ };
429
+ };
430
+ }>;
431
+ }
432
+ //#endregion
433
+ //#region src/tools.d.ts
434
+ /** Structural slice of `ctx.subagents` (SubagentRuntime) — the operations warroom uses. */
435
+ interface SubagentsServiceFace {
436
+ startContinuable(spec: {
437
+ provider: string;
438
+ label: string;
439
+ request: {
440
+ prompt: ReadonlyArray<{
441
+ type: 'text';
442
+ text: string;
443
+ }>;
444
+ parent: unknown;
445
+ persona?: string;
446
+ toolFilter?: {
447
+ deny?: string[];
448
+ };
449
+ maxDepth?: number;
450
+ /** Per-child LLM route (V4-R1, behind the troop-llm-routing flag). */
451
+ agentOptions?: {
452
+ provider: string;
453
+ model: string;
454
+ };
455
+ };
456
+ signal: AbortSignal;
457
+ }): Promise<{
458
+ childId: string;
459
+ messageId: string;
460
+ }>;
461
+ followup(parent: unknown, childId: string, content: ReadonlyArray<{
462
+ type: 'text';
463
+ text: string;
464
+ }>, options: unknown): Promise<unknown>;
465
+ interrupt(targetSessionId: string, authority: unknown): void;
466
+ listDescendants(rootSessionId: string, signal?: AbortSignal): Promise<ReadonlyArray<DescendantFace>>;
467
+ }
468
+ /** Commander conscription operations (v2.0 征召制) implemented by the host
469
+ * wiring (index.ts): the commander is a top-level session bound to the task
470
+ * workspace via the host apiProxy (sandbox root + depth 0), gated on
471
+ * workspace occupancy, global capacity, and a spawn-once-per-task guard. */
472
+ interface CommanderOps {
473
+ conscript(task: CampaignState, signal: AbortSignal): Promise<{
474
+ spawned: true;
475
+ childId: string;
476
+ } | {
477
+ spawned: false;
478
+ reason: string;
479
+ }>;
480
+ /** Deliver a notice into one commander session (批注转达). */
481
+ relayTo(sessionId: string, text: string): Promise<boolean>;
482
+ /** B1-件⑤ 孤儿 GC:任务终态时清征召器内存表(孤儿/spawned/拒因)并落盘——
483
+ * 可选面,旧假 commander / 无征召器环境 no-op。 */
484
+ forget?(taskId: string): void;
485
+ }
486
+ //#endregion
487
+ //#region src/index.d.ts
488
+ declare const name = "warroom-plugin";
489
+ declare const inject: string[];
490
+ /**
491
+ * The conscriptor (v2.0 征召制): every commander is a TOP-LEVEL session
492
+ * created via the host apiProxy and bound to the TASK WORKSPACE (registry
493
+ * workspace.create + sessions.create({workspaceId}) — the
494
+ * execution-session paradigm). That is what makes the sandbox honest: an
495
+ * in-process continuable child inherits its PARENT session's write root
496
+ * (live R8 catch: a warRoot-rooted commander could not write a bound
497
+ * external workspace), while a session-bound commander roots exactly where
498
+ * the task lives and sits at delegation depth 0. The 外勤任务简报 prompt carries
499
+ * the full commander doctrine (no persona field exists on sessions.create).
500
+ * Gates: spawn-once-per-task, workspace occupancy, global commander cap.
501
+ * The patrol fuse is the crash-recovery net: stranded published tasks get
502
+ * ONE relay ping into the 大副部 conversation per plan signature.
503
+ */
504
+ declare function createConscriptor(deps: {
505
+ store: WarStore;
506
+ stateDir: string;
507
+ warRoot: string;
508
+ maxUnits: number;
509
+ maxCommanders: number;
510
+ maxAttempts: number;
511
+ subagents: SubagentsServiceFace;
512
+ /** B1-件⑤ rescue 判据:会话是否有活体 agent(缺席 → rescue 段整体降级为拒因日志)。 */
513
+ resolveAgent?: (sessionId: string) => unknown;
514
+ /** B1-件⑤ rescue 通道:宿主 agents.resume({resumeSessionId})(缺席 → 只记拒因不回栏)。 */
515
+ resumeAgent?: (sessionId: string) => Promise<unknown>;
516
+ }): CommanderOps & {
517
+ bindRelay(sessions: SessionsApiFace, workspace: WorkspaceApiFace): void;
518
+ patrolNow(): Promise<void>;
519
+ snapshot(): {
520
+ spawned: readonly string[];
521
+ skips: Readonly<Record<string, string>>;
522
+ };
523
+ };
524
+ /**
525
+ * Mount the war room: config, store, roster loader, commander lifecycle,
526
+ * activation-gated tool surface + staff persona, troop-report capture,
527
+ * the patrol fuse, the `/war` + `/peace` commands, and (in web
528
+ * compositions) the strategic board HTTP API.
529
+ * @param ctx - plugin context (tools + systemPrompt + subagents injected).
530
+ * @param config - validated plugin configuration.
531
+ */
532
+ declare function apply(ctx: Context, config: Config): void;
533
+ //#endregion
534
+ export { Config, FEATURE_FLAGS_ENV, apply, createConscriptor, featureEnabled, inject, name, readFeatureFlags, runtimeFlags };