@linxin666/dsh-client-ui-task-board 0.4.4 → 0.4.5

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.
Files changed (108) hide show
  1. package/README.i18n.yaml +2 -2
  2. package/README.md +42 -11
  3. package/README.zh.md +42 -11
  4. package/lib/client.js +4958 -472
  5. package/lib/client.js.map +1 -1
  6. package/lib/index.js +2841 -121
  7. package/lib/types/client/PluginSettingsCard.d.ts +7 -0
  8. package/lib/types/client/TaskBoardSettingsCard.d.ts +19 -3
  9. package/lib/types/client/board/ClampedMarkdown.d.ts +3 -0
  10. package/lib/types/client/board/ConfirmDialog.d.ts +4 -1
  11. package/lib/types/client/board/EditTaskModal.d.ts +5 -2
  12. package/lib/types/client/board/LinkSubtaskModal.d.ts +5 -2
  13. package/lib/types/client/board/NewTaskModal.d.ts +4 -1
  14. package/lib/types/client/board/TagManagerModal.d.ts +26 -0
  15. package/lib/types/client/board/TaskBoard.d.ts +10 -1
  16. package/lib/types/client/board/TaskCard.d.ts +14 -1
  17. package/lib/types/client/board/TaskDetail.d.ts +3 -1
  18. package/lib/types/client/board/TaskForm.d.ts +4 -1
  19. package/lib/types/client/board/VerificationReport.d.ts +23 -0
  20. package/lib/types/client/board/card-view.d.ts +113 -0
  21. package/lib/types/client/board/icons.d.ts +32 -0
  22. package/lib/types/client/board/overlay.d.ts +69 -0
  23. package/lib/types/client/board/status-key.d.ts +15 -0
  24. package/lib/types/client/board/task-markdown.d.ts +19 -0
  25. package/lib/types/client/board-card-seat.d.ts +34 -0
  26. package/lib/types/client/index.d.ts +19 -0
  27. package/lib/types/client/locales.d.ts +103 -1
  28. package/lib/types/client/native-panel.d.ts +6 -20
  29. package/lib/types/client/seats.d.ts +18 -0
  30. package/lib/types/client/service.d.ts +32 -0
  31. package/lib/types/client/settings-form.d.ts +16 -0
  32. package/lib/types/core/controller.d.ts +37 -1
  33. package/lib/types/core/extension.d.ts +283 -0
  34. package/lib/types/core/handover.d.ts +13 -1
  35. package/lib/types/core/issue-form.d.ts +16 -0
  36. package/lib/types/core/tasks.d.ts +84 -3
  37. package/lib/types/core/use-cases/task-tag.d.ts +48 -0
  38. package/lib/types/core/use-cases/task-update.d.ts +5 -3
  39. package/lib/types/core/verification.d.ts +386 -0
  40. package/lib/types/core/workspace-target.d.ts +41 -0
  41. package/lib/types/host/agent-tools.d.ts +1 -1
  42. package/lib/types/host/extension-registry.d.ts +111 -0
  43. package/lib/types/host/llm-dispatch.d.ts +63 -0
  44. package/lib/types/host/verification-gate.d.ts +71 -0
  45. package/lib/types/host/verification-runner.d.ts +108 -0
  46. package/lib/types/host/workspace-evidence.d.ts +53 -0
  47. package/lib/types/host-ledger.d.ts +52 -8
  48. package/lib/types/host-runner.d.ts +23 -1
  49. package/lib/types/host-service.d.ts +88 -2
  50. package/lib/types/index.d.ts +80 -26
  51. package/lib/types/protocol.d.ts +49 -5
  52. package/lib/types/tool-surface.d.ts +71 -0
  53. package/package.json +27 -26
  54. package/src/client/PluginSettingsCard.tsx +9 -0
  55. package/src/client/TaskBoardSettingsCard.tsx +304 -65
  56. package/src/client/board/ClampedMarkdown.tsx +69 -0
  57. package/src/client/board/ConfirmDialog.tsx +7 -3
  58. package/src/client/board/EditTaskModal.tsx +5 -2
  59. package/src/client/board/LinkSubtaskModal.tsx +12 -7
  60. package/src/client/board/NewTaskModal.tsx +17 -1
  61. package/src/client/board/TagManagerModal.tsx +235 -0
  62. package/src/client/board/TaskBoard.tsx +259 -103
  63. package/src/client/board/TaskCard.tsx +214 -81
  64. package/src/client/board/TaskDetail.tsx +71 -26
  65. package/src/client/board/TaskForm.tsx +13 -3
  66. package/src/client/board/VerificationReport.tsx +203 -0
  67. package/src/client/board/card-view.ts +220 -0
  68. package/src/client/board/icons.tsx +89 -0
  69. package/src/client/board/overlay.tsx +189 -0
  70. package/src/client/board/status-key.ts +27 -0
  71. package/src/client/board/task-markdown.module.css +137 -0
  72. package/src/client/board/task-markdown.tsx +106 -0
  73. package/src/client/board-card-seat.ts +102 -0
  74. package/src/client/board-settings.module.css +66 -0
  75. package/src/client/board.module.css +488 -63
  76. package/src/client/index.ts +43 -5
  77. package/src/client/locales.ts +208 -4
  78. package/src/client/native-panel.tsx +18 -2
  79. package/src/client/seats.tsx +58 -0
  80. package/src/client/service.ts +94 -0
  81. package/src/client/settings-card.module.css +31 -5
  82. package/src/client/settings-form.ts +27 -1
  83. package/src/core/controller.ts +94 -3
  84. package/src/core/extension.ts +376 -0
  85. package/src/core/freeze-snapshot.ts +2 -2
  86. package/src/core/handover.ts +16 -1
  87. package/src/core/issue-form.ts +19 -0
  88. package/src/core/store.ts +16 -0
  89. package/src/core/tasks.ts +100 -6
  90. package/src/core/use-cases/task-parent.ts +3 -2
  91. package/src/core/use-cases/task-tag.ts +110 -0
  92. package/src/core/use-cases/task-update.ts +10 -4
  93. package/src/core/verification.ts +826 -0
  94. package/src/core/workspace-target.ts +59 -0
  95. package/src/host/agent-tools.ts +20 -18
  96. package/src/host/extension-registry.ts +509 -0
  97. package/src/host/llm-dispatch.ts +87 -0
  98. package/src/host/verification-gate.ts +331 -0
  99. package/src/host/verification-runner.ts +535 -0
  100. package/src/host/workspace-evidence.ts +176 -0
  101. package/src/host-ai.ts +15 -9
  102. package/src/host-ledger.ts +143 -32
  103. package/src/host-routes.ts +15 -2
  104. package/src/host-runner.ts +60 -11
  105. package/src/host-service.ts +253 -10
  106. package/src/index.ts +204 -16
  107. package/src/protocol.ts +102 -8
  108. package/src/tool-surface.ts +95 -0
@@ -35,7 +35,11 @@ export declare const HANDOVER_MAX_REFERENCE_BYTES = 512;
35
35
  export declare const HANDOVER_MAX_TOTAL_BYTES: number;
36
36
  /** Per target-id (workspace/preset) byte cap. */
37
37
  export declare const HANDOVER_MAX_TARGET_BYTES = 256;
38
- /** The board's notion of the deployment session-default permission (fail-safe default). */
38
+ /**
39
+ * Fail-safe baseline for the confirmation gate: what it falls back to when the
40
+ * deployment pins no baseline of its own and the Host's default permission
41
+ * preset cannot be read. Every elevation above it stays gated.
42
+ */
39
43
  export declare const DEFAULT_SESSION_PERMISSION: TaskPermission;
40
44
  /** Permission elevation rank (higher = more authority). */
41
45
  export declare const PERMISSION_RANK: ReadonlyMap<TaskPermission, number>;
@@ -51,6 +55,14 @@ export declare function handoverOf(input: TaskHandoverInput, now: number): TaskH
51
55
  export declare function effectivePermission(task: Pick<TaskRecord, 'permission' | 'handover'>): TaskPermission | undefined;
52
56
  /** Whether a binding's permission is elevated above the session default. */
53
57
  export declare function exceedsSessionDefault(permission: TaskPermission | undefined, sessionDefault: TaskPermission): boolean;
58
+ /**
59
+ * Whether a session running at `holder` already carries `permission`: the
60
+ * permission is absent, or its rank does not exceed the holder's. A teammate
61
+ * inherits the Lead session's permission and cannot be narrowed below it, so a
62
+ * subtask's own pin is carried by a team run exactly when this holds, and a pin
63
+ * it does not carry would be silently dropped instead.
64
+ */
65
+ export declare function permissionCarriedBy(holder: TaskPermission, permission: TaskPermission | undefined): boolean;
54
66
  /**
55
67
  * The confirmation-gate predicate: an elevated permission without a human
56
68
  * confirmation stamp. Manual run/rerun and cron must refuse such a card.
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Issue-form vocabulary the card excerpt recognizes.
3
+ *
4
+ * Issue forms from an issue tracker (and the zh templates this family's repositories use)
5
+ * write the same section headings and empty-field placeholders on every issue.
6
+ * The patterns are data about those forms, not UI copy, so they live in the
7
+ * shared core rather than in a locale dictionary; the browser half imports them.
8
+ *
9
+ * @module @linxin666/dsh-client-ui-task-board/core/issue-form
10
+ */
11
+ /** Section headings whose body is the issue's own summary (zh and en forms). */
12
+ export declare const SUMMARY_HEADING: RegExp;
13
+ /** Values an issue form writes for an empty field. */
14
+ export declare const EMPTY_FIELD: RegExp;
15
+ /** A trailing colon (ASCII or full-width) after a heading. */
16
+ export declare const HEADING_COLON: RegExp;
@@ -5,7 +5,9 @@
5
5
  * unit-testable in isolation.
6
6
  */
7
7
  import type { FreezeSnapshot } from './freeze-snapshot.ts';
8
+ import type { ExecutionVerification } from './verification.ts';
8
9
  import type { TaskHandover, TaskHandoverInput } from './handover.ts';
10
+ import { type TaskBoardExtensionPayload } from './extension.ts';
9
11
  /** Task lifecycle status, one per kanban column. */
10
12
  export type TaskStatus = 'backlog' | 'todo' | 'running' | 'done' | 'failed';
11
13
  /** Settled outcome of one execution attempt. */
@@ -52,6 +54,14 @@ export interface ExecutionRecord {
52
54
  ownResult?: ExecutionOutcome;
53
55
  /** Human failure text that arrived with {@link ownResult}. */
54
56
  ownError?: string;
57
+ /**
58
+ * Goal acceptance state of this execution (task-board goal verification).
59
+ * Fixed when the execution starts and never rewritten from later settings:
60
+ * the contract is frozen here, the attempts accrue here, and the settlement
61
+ * rule reads the pass record here. Absent on an execution that started
62
+ * before the feature existed, which keeps it on the historical verdict.
63
+ */
64
+ verification?: ExecutionVerification;
55
65
  }
56
66
  /**
57
67
  * Maximum number of execution records retained per task. Older settled runs
@@ -231,6 +241,20 @@ export interface TaskRecord {
231
241
  * turn. A session whose `/goal` command is refused still runs the prompt.
232
242
  */
233
243
  goalRun?: boolean;
244
+ /**
245
+ * Run this task's goal executions WITHOUT the board's acceptance gate.
246
+ *
247
+ * Absent means INHERIT: the execution's applicability is decided by the
248
+ * board-wide `goalVerification` switch frozen at start, exactly as a card
249
+ * that never touched this option behaves. Only an explicit `true` opts the
250
+ * card out, and the execution records `applicability: 'disabled'` so the
251
+ * report says plainly that nothing certified this run.
252
+ *
253
+ * The opt-out is per execution, not per run: flipping it never rewrites the
254
+ * verdict rule of an execution already open, and a rerun or a scheduled
255
+ * occurrence reads the card's current value when it freezes its contract.
256
+ */
257
+ skipVerification?: boolean;
234
258
  /**
235
259
  * Frozen context snapshot for a continuation card; absent on plain tasks.
236
260
  * Sanitized before it enters the ledger (redaction, slash-command taint,
@@ -262,6 +286,20 @@ export interface TaskRecord {
262
286
  * absent means on-board.
263
287
  */
264
288
  archivedAt?: number;
289
+ /**
290
+ * Opaque external-provider metadata, keyed by extension id; optional and
291
+ * additive so existing tasks require no ledger migration. The board stores
292
+ * and forwards it without interpreting the keys — each provider owns the
293
+ * shape and validation of its own entry.
294
+ */
295
+ integrations?: Record<string, TaskBoardExtensionPayload>;
296
+ /**
297
+ * Whether the card is held off the board: it exists in the ledger (and its
298
+ * execution history is intact) but no column ever renders it. Providers
299
+ * create hidden cards for work they materialize but do not want displayed;
300
+ * absent means on-board.
301
+ */
302
+ hidden?: boolean;
265
303
  }
266
304
  /**
267
305
  * Statuses a task may be archived from: every status but `running`, whose
@@ -287,7 +325,7 @@ export interface NewTaskInput {
287
325
  * inherits the parent's unset execution targets.
288
326
  */
289
327
  parentId?: string;
290
- /** Workspace the execution must run in; empty/absent = the recent workspace. */
328
+ /** Workspace the execution must run in; empty/absent = the creating session's workspace for a root task, else the recent workspace at execution time. */
291
329
  workspaceId?: string;
292
330
  /** Agent preset the execution session must be composed from; empty/absent = deployment default. */
293
331
  mode?: string;
@@ -304,6 +342,11 @@ export interface NewTaskInput {
304
342
  * default (goal run); an explicit false requests a single plain turn.
305
343
  */
306
344
  goalRun?: boolean;
345
+ /**
346
+ * Run this task's goal executions without the acceptance gate; absent
347
+ * inherits the board-wide `goalVerification` switch.
348
+ */
349
+ skipVerification?: boolean;
307
350
  /**
308
351
  * Optional scheduled-run rule requested at creation time (the new-task
309
352
  * dialog): an enable flag, a 5-field cron expression, and the IANA zone its
@@ -333,13 +376,31 @@ export interface NewTaskInput {
333
376
  * ahead of the execution prompt; a bare name changes nothing at run time.
334
377
  */
335
378
  tags?: TaskTag[];
379
+ /** Opaque external-provider metadata keyed by extension id. */
380
+ integrations?: Record<string, TaskBoardExtensionPayload>;
381
+ /** Column the created card opens in; absent means the board default (todo). */
382
+ status?: TaskStatus;
383
+ /** Create the card off-board (held in the ledger, never rendered). */
384
+ hidden?: boolean;
336
385
  }
337
386
  /** The five kanban columns, in display order. */
338
387
  export declare const COLUMNS: readonly {
339
388
  status: TaskStatus;
340
389
  label: string;
341
390
  }[];
342
- /** Statuses a user may move a card to manually (execution states are owned by the runner). */
391
+ /**
392
+ * Statuses a card may be moved to by hand: every column. The board UI and the
393
+ * agent tool surface share this one list, so no column can be manual on one
394
+ * surface and locked on the other.
395
+ *
396
+ * The column is a board statement, not a claim about a run. A hand-written
397
+ * `done`/`failed` declares that the work finished (or failed) outside a
398
+ * Host-run execution — human hands, an external system — and a hand-written
399
+ * `running` says the work is under way without a tracked session. None of them
400
+ * creates an {@link ExecutionRecord}, which is what keeps a declaration
401
+ * distinguishable from a recorded outcome in the card's execution history; the
402
+ * next settled run overwrites the column with the real one.
403
+ */
343
404
  export declare const MANUAL_STATUSES: readonly TaskStatus[];
344
405
  /** Statuses the runner may move a card to from 'running'. */
345
406
  export declare const RUNNER_SETTLE_STATUSES: readonly TaskStatus[];
@@ -347,8 +408,28 @@ export declare const RUNNER_SETTLE_STATUSES: readonly TaskStatus[];
347
408
  export declare const ALL_STATUSES: readonly TaskStatus[];
348
409
  /** Brand an unknown string as a status; undefined when it is not one. */
349
410
  export declare function isTaskStatus(value: unknown): value is TaskStatus;
350
- /** Whether a manual move target is allowed from the given status. */
411
+ /**
412
+ * Whether the manual move `from` -> `to` is a legal *column* change: any
413
+ * column, and never the one the card already shows.
414
+ *
415
+ * Whether the card may be moved at all is a separate question. The lock an
416
+ * executing card carries belongs to its open execution, never to the column
417
+ * text, so it is {@link canMoveTask} — not this predicate — that expresses it.
418
+ */
351
419
  export declare function canMoveManually(from: TaskStatus, to: TaskStatus): boolean;
420
+ /**
421
+ * Whether the board may move `task` to `to` by hand: the card is on-board,
422
+ * holds no open execution, and the target is a legal column change. The ledger,
423
+ * the detail view's status buttons and the board's drop handler all decide
424
+ * through this one predicate, so no two surfaces can disagree about a card.
425
+ */
426
+ export declare function canMoveTask(task: TaskRecord, to: TaskStatus): boolean;
427
+ /**
428
+ * Whether the task still has an execution the runner has not settled. This —
429
+ * not the `running` column — is what "the runner owns this card" means: a card
430
+ * parked in `running` by hand has no session and stays fully movable.
431
+ */
432
+ export declare function hasOpenExecution(task: TaskRecord): boolean;
352
433
  /** Normalize one optional execution-target string: trim; blank collapses to undefined. */
353
434
  export declare function normalizeTargetId(value: string | undefined): string | undefined;
354
435
  /**
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Label-management use cases (issue: labels could not be cleaned up).
3
+ *
4
+ * A label lives on every task that carries it, so renaming or removing one is a
5
+ * ledger-wide edit, not a task edit: the board's label row is the union of the
6
+ * labels in use, and without these two transitions a label created by an
7
+ * afternoon experiment stayed on the board forever.
8
+ *
9
+ * Both transitions are pure ledger rewrites (no persistence, no notify — the
10
+ * controller and the Host ledger orchestrate those), and both are idempotent:
11
+ * a label that no task carries changes nothing and reports no error for the
12
+ * delete path (the desired end state already holds), while a rename from an
13
+ * unknown label is refused so a stale tab cannot silently do nothing.
14
+ *
15
+ * Renaming onto a name that is already in use MERGES the two: a task carrying
16
+ * both keeps the row it already had (with its execution hint) and loses the
17
+ * duplicate, which is the only reading that cannot lose a hint the user typed.
18
+ */
19
+ import { type TaskRecord } from '../tasks.ts';
20
+ /** Outcome of one ledger-wide label edit. */
21
+ export interface TagEditResult {
22
+ /** The ledger after the edit, or the input unchanged when nothing applied. */
23
+ tasks: readonly TaskRecord[];
24
+ /** Whether any task actually changed (drives whether the caller persists). */
25
+ changed: boolean;
26
+ /** Refusal reason; the ledger is unchanged when set. */
27
+ error?: string;
28
+ }
29
+ /**
30
+ * Rename one label everywhere, merging into an existing label of the target
31
+ * name. Every touched task gets a fresh updatedAt; untouched tasks keep theirs.
32
+ * @param tasks - current ledger.
33
+ * @param from - the label to rename.
34
+ * @param to - the new name (an existing name merges the two labels).
35
+ * @param now - clock instant (ms epoch).
36
+ * @returns the rewritten ledger, or a refusal.
37
+ */
38
+ export declare function applyRenameTag(tasks: readonly TaskRecord[], from: string, to: string, now: number): TagEditResult;
39
+ /**
40
+ * Remove one label from every task that carries it. Archived cards are included:
41
+ * the board's label row draws from the whole ledger, so a label left on an
42
+ * archived card would come straight back into the filter.
43
+ * @param tasks - current ledger.
44
+ * @param name - the label to remove.
45
+ * @param now - clock instant (ms epoch).
46
+ * @returns the rewritten ledger.
47
+ */
48
+ export declare function applyDeleteTag(tasks: readonly TaskRecord[], name: string, now: number): TagEditResult;
@@ -15,7 +15,7 @@ import type { TaskHandoverInput } from '../handover.ts';
15
15
  * Editable fields on a task (the update patch surface). `freeze` replaces the
16
16
  * continuation-card snapshot (restamping frozenAt); an explicit null clears it.
17
17
  */
18
- export type TaskUpdatePatch = Partial<Pick<TaskRecord, 'title' | 'description' | 'prompt' | 'workspaceId' | 'mode' | 'permission' | 'model' | 'reuseSession' | 'teamRun' | 'goalRun'>> & {
18
+ export type TaskUpdatePatch = Partial<Pick<TaskRecord, 'title' | 'description' | 'prompt' | 'workspaceId' | 'mode' | 'permission' | 'model' | 'reuseSession' | 'teamRun' | 'goalRun' | 'skipVerification'>> & {
19
19
  freeze?: FreezeSnapshot & {
20
20
  redacted?: boolean;
21
21
  } | null;
@@ -39,8 +39,10 @@ export declare const TASK_CONTENT_FIELDS: readonly ["title", "description", "pro
39
39
  export declare function hasContentPatch(patch: TaskUpdatePatch): boolean;
40
40
  /**
41
41
  * Whether a task's content may still be edited: the task must be on-board
42
- * (not archived) and must never have started executing. Fail-closed: a
43
- * running, settled, or cancelled-before-launch task keeps its content fixed.
42
+ * (not archived) and must never have started executing. Fail-closed: a task
43
+ * with any execution record — running, settled, or cancelled before launch —
44
+ * keeps its content fixed. The run, not the column, is the trigger: a card
45
+ * parked in 'running' by hand has nothing recorded yet and stays editable.
44
46
  */
45
47
  export declare function canEditTaskContent(task: TaskRecord): boolean;
46
48
  /**
@@ -0,0 +1,386 @@
1
+ /**
2
+ * Goal acceptance domain: the board's evaluator-backed certification layer for
3
+ * task executions that run in goal form.
4
+ *
5
+ * The board owns WHEN acceptance runs (the goal's completion gate), the
6
+ * per-cycle budget, the feedback it returns, the settlement rule and the
7
+ * report. The algorithm it runs is the DEFAULT final acceptance of the
8
+ * installed `dsh-llm-verifier` 0.8.4 (MIT), mirrored here rather than imported:
9
+ * that plugin is a third-party plugin, not a dependency of this repository, and
10
+ * a host half may only depend on the official `@deepseek-ai/*` SDK.
11
+ *
12
+ * Mirrored contract, byte-identical where the judge prompt depends on it:
13
+ * the three coding criteria of `DEFAULT_CRITERIA` (`CRITERIA_PRESETS.coding`),
14
+ * the 20-letter A-T scale, the required `<score_A>`/`<score_B>` verdict tags,
15
+ * the untrusted-evidence framing, `EMPTY_WORK_BASELINE` as candidate B, two
16
+ * rounds per criterion with the A/B slots swapped on the odd round, per-round
17
+ * scores mapped back to the caller's slots and averaged per criterion, and the
18
+ * pass rule `winner === 'A' && total >= threshold && every criterion >= threshold`.
19
+ *
20
+ * This module is framework-free (no cordis, no SDK imports) so the whole rule
21
+ * set is unit-testable in isolation; the model call itself lives in the host
22
+ * half (`src/host/verification-runner.ts`).
23
+ */
24
+ /** Schema version of the persisted verification block (per execution record). */
25
+ export declare const VERIFICATION_SCHEMA_VERSION: 1;
26
+ /** Acceptance threshold mirrored from the verifier's `autoVerifyThreshold` default. */
27
+ export declare const VERIFICATION_THRESHOLD = 0.65;
28
+ /** Rounds per criterion: the verifier's `autoVerifyFinalRepeats` default. */
29
+ export declare const VERIFICATION_ROUNDS = 2;
30
+ /**
31
+ * Quality acceptances one goal completion cycle may spend: the first verdict,
32
+ * then one re-verification after the agent repaired the work. A second failure
33
+ * ends the cycle (see {@link MAX_EXCEPTION_ATTEMPTS} for the separate anomaly
34
+ * budget).
35
+ */
36
+ export declare const MAX_QUALITY_ATTEMPTS = 2;
37
+ /**
38
+ * Anomaly budget of one cycle. A timeout, an authentication failure or an
39
+ * unparseable judge answer is not a quality verdict, so it never consumes a
40
+ * quality attempt; it is still bounded, so an unusable judge route can never
41
+ * turn the completion gate into an unbounded retry loop.
42
+ */
43
+ export declare const MAX_EXCEPTION_ATTEMPTS = 2;
44
+ /** The fixed baseline a session acceptance measures itself against. */
45
+ export declare const EMPTY_WORK_BASELINE = "(No useful work or verification was performed.)";
46
+ /** Ground-truth note prepended to every judge prompt. */
47
+ export declare const DEFAULT_GROUND_TRUTH_NOTE = "**IMPORTANT:** Focus on observed tool and terminal output as ground truth. Do NOT trust the agent's self-assessment or claims of success.";
48
+ /** Injected-content guardrail shared by every judge prompt. */
49
+ export declare const UNTRUSTED_EVIDENCE_NOTE: string;
50
+ /** Role sentence for a completed-artifact review of a coding task. */
51
+ export declare const EVALUATOR_ROLE = "You are an expert evaluator of AI coding agents. You will see a task description and two agent trajectories, then evaluate them on ONE specific criterion, stated at the end.";
52
+ /** The 20-point A-T scale, mirrored from the verifier. */
53
+ export declare const GRANULARITY = 20;
54
+ /** One criterion of the coding rubric. */
55
+ export interface VerificationCriterion {
56
+ id: string;
57
+ name: string;
58
+ description: string;
59
+ }
60
+ /** The coding rubric, identical to the verifier's `DEFAULT_CRITERIA`. */
61
+ export declare const CODING_CRITERIA: readonly VerificationCriterion[];
62
+ /** Rating scale text rendered into every judge prompt. */
63
+ export declare const SCALE_DESCRIPTION: string;
64
+ /** A-T letters in scale order (A = best). */
65
+ export declare const LETTERS: readonly string[];
66
+ /**
67
+ * Normalize one score token to an A-T letter.
68
+ * @param token - the raw captured token.
69
+ * @returns the uppercase letter, or undefined when it is not one of A-T.
70
+ */
71
+ export declare function normalizeScoreLetter(token: string): string | undefined;
72
+ /** Numeric value of one A-T letter (A = 20 ... T = 1). */
73
+ export declare function letterValue(letter: string): number;
74
+ /**
75
+ * Read the LAST `<tag> LETTER </tag>` verdict out of one judge answer.
76
+ *
77
+ * The tag contract is the verifier's explicit-tag channel: this deployment's
78
+ * only scoring channel, because the official DSH adapters expose no token
79
+ * logprobs (the verifier's direct top-logprob transport needs a capability the
80
+ * public SDK does not carry). A missing or unusable tag is an exception, never
81
+ * a score: the verdict stays fail-closed.
82
+ * @param text - the raw judge answer.
83
+ * @param tag - the tag name, e.g. `score_A`.
84
+ * @returns the score in 0..1 (A = 1.0, T = 0.0).
85
+ * @throws Error when the answer carries no valid A-T verdict for this tag.
86
+ */
87
+ export declare function extractScore(text: string, tag: string): number;
88
+ /**
89
+ * Render one untrusted content block with deterministic nonce-tagged delimiters.
90
+ * @param tag - block tag.
91
+ * @param token - content-derived delimiter token.
92
+ * @param content - the untrusted content.
93
+ * @returns the wrapped block.
94
+ */
95
+ export declare function renderDelimitedBlock(tag: string, token: string, content: string): string;
96
+ /**
97
+ * Deterministic per-prompt delimiter token (FNV-1a, same construction as the
98
+ * verifier's). Not random: the token must depend on the whole content so that
99
+ * identical inputs render an identical prompt while injected text cannot
100
+ * predict the terminator.
101
+ * @param parts - the content parts.
102
+ * @returns a short base-36 token.
103
+ */
104
+ export declare function evidenceNonce(...parts: readonly string[]): string;
105
+ /**
106
+ * One pairwise judge prompt focused on a single criterion.
107
+ *
108
+ * Everything that does not depend on the criterion comes first and only the
109
+ * criterion varies at the tail, so a prefix-caching backend serves the
110
+ * evidence-heavy body from cache across the criteria of one acceptance.
111
+ * @param problem - the task statement.
112
+ * @param traceA - candidate A's trajectory.
113
+ * @param traceB - candidate B's trajectory.
114
+ * @param criterion - the criterion this call scores.
115
+ * @param groundTruthNote - note prepended to every judge prompt.
116
+ * @param context - optional reference context (the host's own record of what
117
+ * changed on disk), rendered as its own data-only block between the task and
118
+ * the two candidates. Omitted renders nothing, which keeps the prompt
119
+ * byte-identical for a deployment that serves no change service.
120
+ * @returns the rendered prompt.
121
+ */
122
+ export declare function buildAcceptancePrompt(problem: string, traceA: string, traceB: string, criterion: VerificationCriterion, groundTruthNote?: string, context?: string): string;
123
+ /** Where the judge route of one execution came from. */
124
+ export type VerificationRouteSource = 'inherit' | 'explicit';
125
+ /** The resolved judge route of one execution's acceptance. */
126
+ export interface VerificationRoute {
127
+ provider: string;
128
+ model: string;
129
+ reasoningEffort?: string;
130
+ }
131
+ /** One reasoning-effort option an adapter exposes for an exact model route. */
132
+ export interface CatalogReasoningEffort {
133
+ id: string;
134
+ name?: string;
135
+ }
136
+ /** One adapter-discovered model of the host catalog. */
137
+ export interface CatalogModel {
138
+ id: string;
139
+ name?: string;
140
+ reasoning?: {
141
+ efforts: CatalogReasoningEffort[];
142
+ defaultEffort?: string;
143
+ };
144
+ }
145
+ /** One provider route and its models. */
146
+ export interface CatalogGroup {
147
+ id: string;
148
+ name?: string;
149
+ models: CatalogModel[];
150
+ }
151
+ /** The host model catalog the acceptance settings resolve against. */
152
+ export interface ModelCatalogView {
153
+ /** The route an unconfigured session starts at: the host's own configuration. */
154
+ default?: VerificationRoute;
155
+ groups: CatalogGroup[];
156
+ }
157
+ /** The acceptance settings as the configuration holds them. */
158
+ export interface VerificationSettings {
159
+ enabled: boolean;
160
+ /** Qualified provider/model route, or '' to inherit the host default. */
161
+ model: string;
162
+ /** Reasoning effort id, or '' to inherit. */
163
+ reasoningEffort: string;
164
+ }
165
+ /** The acceptance configuration frozen when one execution started. */
166
+ export interface VerificationContract {
167
+ /** Whether acceptance is required for this execution (the switch at start time). */
168
+ enabled: boolean;
169
+ /** Whether the judge model came from the host default or from configuration. */
170
+ modelSource: VerificationRouteSource;
171
+ /** Resolved judge route; absent when the deployment serves no model catalog. */
172
+ route?: VerificationRoute;
173
+ /** The reasoning effort configuration asked for, when it named one. */
174
+ requestedEffort?: string;
175
+ /**
176
+ * Set when an explicitly configured reasoning effort is not supported by the
177
+ * resolved model: the incompatible value is NOT sent, and the acceptance runs
178
+ * on `resolved` (the model's own default when that is defined).
179
+ */
180
+ effortFallback?: {
181
+ requested: string;
182
+ resolved?: string;
183
+ };
184
+ /** Rubric preset. The first version always judges with the coding criteria. */
185
+ preset: 'coding';
186
+ /** Acceptance threshold frozen with the contract. */
187
+ threshold: number;
188
+ }
189
+ /** One criterion's verdict inside an acceptance attempt. */
190
+ export interface VerificationCriterionScore {
191
+ id: string;
192
+ name: string;
193
+ /** Score of the task's own work (0..1). */
194
+ score: number;
195
+ /** Score of the empty-work baseline in the same comparison. */
196
+ baseline: number;
197
+ threshold: number;
198
+ passed: boolean;
199
+ }
200
+ /** Token accounting of one acceptance attempt. */
201
+ export interface VerificationUsage {
202
+ calls: number;
203
+ inputTokens: number;
204
+ outputTokens: number;
205
+ reasoningTokens: number;
206
+ /** At least one call's usage was unknown; the counts are a floor. */
207
+ usageIncomplete?: boolean;
208
+ }
209
+ /** Scope of the evidence one attempt judged. */
210
+ export interface VerificationEvidenceSummary {
211
+ /** Characters handed to the judge after redaction. */
212
+ chars: number;
213
+ /** Characters dropped by the total cap (the newest text is kept). */
214
+ omittedCharacters: number;
215
+ /** Trace entries rendered. */
216
+ entries: number;
217
+ /** Sequence window the evidence was read from. */
218
+ fromSeq?: number;
219
+ toSeq?: number;
220
+ /** Digest of the judged evidence; the pass record is bound to it. */
221
+ hash: string;
222
+ /** Files of host-observed workspace changes rendered into the prompt (0 = none). */
223
+ workspaceFiles?: number;
224
+ }
225
+ /** One recorded acceptance attempt: a quality verdict or an anomaly. */
226
+ export interface VerificationAttempt {
227
+ /** 1-based ordinal within its own stage. */
228
+ index: number;
229
+ /** When the attempt ran (ms epoch). */
230
+ at: number;
231
+ stage: 'quality' | 'exception';
232
+ /** Quality: whether the work passed. A recorded anomaly is never a pass. */
233
+ passed: boolean;
234
+ /** Total score of the task's own work (0 for an anomaly). */
235
+ score: number;
236
+ /** Score of the empty-work baseline. */
237
+ baseline: number;
238
+ criteria: VerificationCriterionScore[];
239
+ /** Bounded, locatable feedback for the agent. */
240
+ findings: string[];
241
+ usage: VerificationUsage;
242
+ evidence: VerificationEvidenceSummary;
243
+ route: VerificationRoute;
244
+ /** Scoring channel that answered. This deployment serves explicit tags only. */
245
+ channel: 'explicit-tag';
246
+ rounds: number;
247
+ /** Anomaly reason; absent on a quality verdict. */
248
+ error?: string;
249
+ }
250
+ /** Persisted acceptance state of one execution. */
251
+ export interface ExecutionVerification {
252
+ contract: VerificationContract;
253
+ attempts: VerificationAttempt[];
254
+ /** True while an acceptance is running, so the board can show 验收中. */
255
+ inFlight?: boolean;
256
+ /**
257
+ * Why this execution may not settle as succeeded without a pass record:
258
+ * `disabled` when the switch was off at start, `skipped` when the CARD opted
259
+ * out of the gate (`TaskRecord.skipVerification`), `goal-unavailable` when
260
+ * the run never became a goal run (so no completion gate could ever fire),
261
+ * and `team-member` for a teammate execution (the Lead's acceptance covers
262
+ * the team's aggregated evidence).
263
+ */
264
+ applicability: 'enforced' | 'disabled' | 'skipped' | 'goal-unavailable' | 'team-member';
265
+ /** Set when the cycle is spent and the execution must fail. */
266
+ failedReason?: string;
267
+ failedAt?: number;
268
+ }
269
+ /** UI/board phase of one execution's acceptance. */
270
+ export type VerificationPhase = 'off' | 'executing' | 'verifying' | 'repairing' | 'passed' | 'failed';
271
+ /** Quality attempts spent by this cycle. */
272
+ export declare function qualityAttempts(verification: ExecutionVerification | undefined): VerificationAttempt[];
273
+ /** Anomaly attempts spent by this cycle. */
274
+ export declare function exceptionAttempts(verification: ExecutionVerification | undefined): VerificationAttempt[];
275
+ /** The quality attempt that passed, when one did. */
276
+ export declare function passedAttempt(verification: ExecutionVerification | undefined): VerificationAttempt | undefined;
277
+ /**
278
+ * Whether the board requires a matching pass record before this execution may
279
+ * settle as succeeded. False when acceptance was off at start, and false for a
280
+ * run that never became a goal run or for a teammate execution — those settle
281
+ * on their own verdict, which is why {@link ExecutionVerification.applicability}
282
+ * is persisted rather than re-derived.
283
+ * @param verification - the execution's persisted acceptance state.
284
+ * @returns true when a pass record is required.
285
+ */
286
+ export declare function verificationRequired(verification: ExecutionVerification | undefined): boolean;
287
+ /** Whether this cycle still has quality budget left. */
288
+ export declare function hasQualityBudget(verification: ExecutionVerification | undefined): boolean;
289
+ /** Whether this cycle still has anomaly budget left. */
290
+ export declare function hasExceptionBudget(verification: ExecutionVerification | undefined): boolean;
291
+ /** Derived board phase of one execution's acceptance. */
292
+ export declare function verificationPhase(verification: ExecutionVerification | undefined): VerificationPhase;
293
+ /**
294
+ * The acceptance rule, mirrored from the verifier's `sessionAccepted`:
295
+ * the work must BEAT the empty-work baseline, reach the total threshold, and
296
+ * reach the threshold on every criterion. A tie or a loss against the baseline
297
+ * fails, so a session indistinguishable from the baseline can never pass.
298
+ * @param score - total score of the task's own work.
299
+ * @param baseline - total score of the empty-work baseline.
300
+ * @param criteria - per-criterion scores of the task's own work.
301
+ * @param threshold - acceptance threshold.
302
+ * @returns true when the work passes.
303
+ */
304
+ export declare function acceptancePassed(score: number, baseline: number, criteria: readonly {
305
+ score: number;
306
+ }[], threshold: number): boolean;
307
+ /**
308
+ * Repair a persisted acceptance block, or drop it.
309
+ *
310
+ * Deliberately fail-soft on the FIELD and fail-closed on the VERDICT: a block
311
+ * that does not parse is dropped (the execution keeps its own record, and the
312
+ * board then treats the execution as unverified), while a block that does parse
313
+ * keeps every recorded attempt verbatim. Dropping a malformed block can only
314
+ * make the board MORE strict, never less.
315
+ * @param value - the persisted value.
316
+ * @returns the repaired block, or undefined when it is unusable.
317
+ */
318
+ export declare function normalizeVerification(value: unknown): ExecutionVerification | undefined;
319
+ /** Totals spanning every attempt of one execution (for the report and the card). */
320
+ export interface VerificationTotals {
321
+ quality: number;
322
+ exceptions: number;
323
+ calls: number;
324
+ inputTokens: number;
325
+ outputTokens: number;
326
+ reasoningTokens: number;
327
+ usageIncomplete: boolean;
328
+ }
329
+ /** Sum the attempts of one execution. */
330
+ export declare function verificationTotals(verification: ExecutionVerification | undefined): VerificationTotals;
331
+ /**
332
+ * The failure feedback one acceptance returns to the fixing agent. It names
333
+ * what failed, with the numbers, the locator lines the judge reported and the
334
+ * remaining budget, so the next round can act on it instead of restating the
335
+ * work.
336
+ * @param attempt - the failed quality attempt.
337
+ * @param remaining - quality attempts still available after this one.
338
+ * @returns the model-facing feedback text.
339
+ */
340
+ export declare function qualityFeedback(attempt: VerificationAttempt, remaining: number): string;
341
+ /**
342
+ * The reason one exhausted acceptance cycle records as the execution's final
343
+ * failure. Unlike {@link qualityFeedback} — which the fixing agent reads while
344
+ * budget remains — this reason is also persisted on the ledger, echoed on every
345
+ * later completion attempt and shown on the card, so it carries the full
346
+ * picture: the scores, the baseline comparison, every failing criterion and the
347
+ * judge's locatable findings, so a later agent (or the user) can act on WHAT to
348
+ * improve, not only on how badly the attempt scored.
349
+ * @param attempt - the failed quality attempt that spent the last budget.
350
+ * @param used - quality attempts spent by the cycle.
351
+ * @param threshold - the contract threshold the work was judged against.
352
+ * @returns the model- and user-facing failure reason.
353
+ */
354
+ export declare function finalFailureReason(attempt: VerificationAttempt, used: number, threshold: number): string;
355
+ /** `0.42` style percentage. */
356
+ export declare function percent(value: number): string;
357
+ /** Split a qualified `provider/model` route; undefined when it is not one. */
358
+ export declare function parseModelRoute(qualified: string | undefined): {
359
+ provider: string;
360
+ model: string;
361
+ } | undefined;
362
+ /**
363
+ * Normalize the raw `session/modelCatalog` reply into the shape the acceptance
364
+ * settings read. Everything is optional in the wire value, so every level is
365
+ * checked: an unreadable catalog degrades to "unknown", never to a crash.
366
+ * @param value - the raw gateway reply.
367
+ * @returns the normalized catalog, or undefined when nothing usable arrived.
368
+ */
369
+ export declare function normalizeCatalog(value: unknown): ModelCatalogView | undefined;
370
+ /** Whether the catalog declares the route at all. */
371
+ export declare function catalogHasRoute(catalog: ModelCatalogView | undefined, provider: string, model: string): boolean;
372
+ /**
373
+ * Resolve the acceptance configuration into the contract one execution freezes.
374
+ *
375
+ * "Inherit host" means the host's own model catalog default, never the card's
376
+ * pinned execution model. An explicitly configured reasoning effort is sent
377
+ * ONLY when the target model's adapter declares it: an unsupported value is
378
+ * dropped instead of being passed through, and the fallback to the target
379
+ * model's own default is recorded so the settings card and the report can show
380
+ * exactly what will be sent.
381
+ * @param settings - the live configuration.
382
+ * @param catalog - the host model catalog, when this cohort serves one.
383
+ * @param threshold - acceptance threshold to freeze.
384
+ * @returns the contract.
385
+ */
386
+ export declare function resolveContract(settings: VerificationSettings, catalog: ModelCatalogView | undefined, threshold?: number): VerificationContract;