@linxin666/dsh-client-ui-task-board 0.4.5 → 0.4.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.i18n.yaml +2 -2
- package/README.md +34 -18
- package/README.zh.md +34 -18
- package/lib/client.js +2804 -1024
- package/lib/client.js.map +1 -1
- package/lib/index.js +2576 -416
- package/lib/types/client/CardDefaultPresetField.d.ts +35 -0
- package/lib/types/client/TaskBoardSettingsCard.d.ts +61 -0
- package/lib/types/client/board/ReasoningEffortField.d.ts +25 -0
- package/lib/types/client/board/model-options.d.ts +67 -0
- package/lib/types/client/board/preset-label.d.ts +21 -0
- package/lib/types/client/board/preset-roster.d.ts +45 -0
- package/lib/types/client/board/team-run-promotion.d.ts +26 -0
- package/lib/types/client/index.d.ts +4 -5
- package/lib/types/client/locales.d.ts +81 -0
- package/lib/types/client/plugin-card-seat.d.ts +5 -0
- package/lib/types/client/schedule-zone.d.ts +50 -0
- package/lib/types/core/card-defaults.d.ts +78 -0
- package/lib/types/core/controller.d.ts +41 -17
- package/lib/types/core/launch-width.d.ts +31 -0
- package/lib/types/core/poll-cadence.d.ts +31 -0
- package/lib/types/core/reasoning-effort.d.ts +57 -0
- package/lib/types/core/subtask.d.ts +30 -8
- package/lib/types/core/tasks.d.ts +163 -14
- package/lib/types/core/use-cases/task-create.d.ts +10 -5
- package/lib/types/core/use-cases/task-schedule.d.ts +68 -10
- package/lib/types/core/use-cases/task-update.d.ts +1 -1
- package/lib/types/core/verification-budget.d.ts +52 -0
- package/lib/types/core/verification.d.ts +376 -9
- package/lib/types/host/launch-admission.d.ts +72 -0
- package/lib/types/host/verification-gate.d.ts +24 -0
- package/lib/types/host/verification-runner.d.ts +38 -7
- package/lib/types/host-ledger.d.ts +91 -11
- package/lib/types/host-runner.d.ts +111 -13
- package/lib/types/host-service.d.ts +199 -8
- package/lib/types/index.d.ts +141 -0
- package/lib/types/protocol.d.ts +63 -12
- package/package.json +29 -33
- package/src/client/CardDefaultPresetField.tsx +101 -0
- package/src/client/TaskBoardSettingsCard.tsx +288 -17
- package/src/client/board/LinkSubtaskModal.tsx +8 -0
- package/src/client/board/NewTaskModal.tsx +237 -60
- package/src/client/board/ReasoningEffortField.tsx +50 -0
- package/src/client/board/TaskCard.tsx +3 -3
- package/src/client/board/TaskDetail.tsx +261 -24
- package/src/client/board/VerificationReport.tsx +132 -13
- package/src/client/board/model-options.ts +178 -0
- package/src/client/board/preset-label.ts +32 -0
- package/src/client/board/preset-roster.ts +58 -0
- package/src/client/board/status-key.ts +3 -0
- package/src/client/board/team-run-promotion.ts +39 -0
- package/src/client/index.ts +105 -108
- package/src/client/locales.ts +171 -6
- package/src/client/plugin-card-seat.ts +7 -0
- package/src/client/schedule-zone.ts +100 -2
- package/src/client/settings-entry-form.ts +0 -1
- package/src/core/card-defaults.ts +132 -0
- package/src/core/controller.ts +55 -16
- package/src/core/launch-width.ts +38 -0
- package/src/core/poll-cadence.ts +41 -0
- package/src/core/reasoning-effort.ts +92 -0
- package/src/core/store.ts +69 -15
- package/src/core/subtask.ts +48 -13
- package/src/core/tasks.ts +213 -39
- package/src/core/use-cases/task-create.ts +57 -25
- package/src/core/use-cases/task-schedule.ts +190 -25
- package/src/core/use-cases/task-update.ts +9 -4
- package/src/core/verification-budget.ts +115 -0
- package/src/core/verification.ts +785 -17
- package/src/host/agent-tools.ts +127 -29
- package/src/host/launch-admission.ts +140 -0
- package/src/host/verification-gate.ts +172 -16
- package/src/host/verification-runner.ts +207 -40
- package/src/host-ledger.ts +346 -48
- package/src/host-runner.ts +234 -35
- package/src/host-service.ts +539 -52
- package/src/index.ts +250 -7
- package/src/protocol.ts +160 -32
- package/lib/invariant.js +0 -6
- package/lib/types/client/board-card-seat.d.ts +0 -34
- package/lib/types/invariant.d.ts +0 -3
- package/src/client/board-card-seat.ts +0 -102
- package/src/invariant.ts +0 -4
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
*/
|
|
14
14
|
import type { TaskStore } from './store.ts';
|
|
15
15
|
import { type NewTaskInput, type TaskRecord, type TaskStatus } from './tasks.ts';
|
|
16
|
+
import { type SetSchedulePatch } from './use-cases/task-schedule.ts';
|
|
16
17
|
import { type TaskUpdatePatch } from './use-cases/task-update.ts';
|
|
17
18
|
import type { TaskBoardAction, TaskBoardEventPayload, TaskBoardParseDraft, TaskBoardParseRequest, TaskBoardSnapshot } from '../protocol.ts';
|
|
18
19
|
import type { TaskBoardExtensionActionRequest, TaskBoardVisibilityPredicate } from './extension.ts';
|
|
@@ -99,6 +100,17 @@ export interface ExecutionModelOption {
|
|
|
99
100
|
name?: string;
|
|
100
101
|
label?: string;
|
|
101
102
|
provider?: string;
|
|
103
|
+
/**
|
|
104
|
+
* Reasoning metadata the adapter declares for this exact route. An effort
|
|
105
|
+
* picker is offered only while `supported`, and its choices are `efforts` —
|
|
106
|
+
* the ids the target model really accepts, so the UI never offers (or keeps)
|
|
107
|
+
* a level the model would reject. Absent means the deployment published no
|
|
108
|
+
* capability for this model; the card value is then left untouched.
|
|
109
|
+
*/
|
|
110
|
+
reasoning?: {
|
|
111
|
+
supported: boolean;
|
|
112
|
+
efforts?: readonly string[];
|
|
113
|
+
};
|
|
102
114
|
}
|
|
103
115
|
/** The execution-target option sets the UI feeds into the controller. */
|
|
104
116
|
export interface ExecutionOptionsSnapshot {
|
|
@@ -111,7 +123,7 @@ export interface ExecutionOptionsSnapshot {
|
|
|
111
123
|
* (revision/scheduler/power); a full snapshot also carries the deployment
|
|
112
124
|
* constants the UI reads (session default permission, subtask depth).
|
|
113
125
|
*/
|
|
114
|
-
export type HostMirror = Pick<TaskBoardSnapshot, 'revision' | 'scheduler' | 'power' | 'sessionDefaultPermission' | 'maxSubtaskDepth' | 'teamRunAvailable' | 'extensions'>;
|
|
126
|
+
export type HostMirror = Pick<TaskBoardSnapshot, 'revision' | 'scheduler' | 'power' | 'sessionDefaultPermission' | 'maxSubtaskDepth' | 'teamRunAvailable' | 'goalRunEnabled' | 'cardDefaults' | 'extensions'>;
|
|
115
127
|
/** Immutable controller snapshot for UI subscriptions. */
|
|
116
128
|
export interface ControllerSnapshot {
|
|
117
129
|
tasks: readonly TaskRecord[];
|
|
@@ -186,6 +198,19 @@ export declare class BoardController {
|
|
|
186
198
|
isHostBacked(): boolean;
|
|
187
199
|
/** Retry initial migration/state synchronization after an explicit Host error. */
|
|
188
200
|
retryHostSync(): Promise<boolean>;
|
|
201
|
+
/**
|
|
202
|
+
* Re-read the authoritative Host snapshot.
|
|
203
|
+
*
|
|
204
|
+
* The board's volatile deployment configuration — the new-card defaults among
|
|
205
|
+
* it — is republished the moment the settings document is written, but the SSE
|
|
206
|
+
* frame that republish emits carries the value as of BEFORE the write (the
|
|
207
|
+
* loader hands the update to the fiber while the new document is not yet
|
|
208
|
+
* visible to it), so a mirror that followed frames alone would stay one edit
|
|
209
|
+
* behind and the create dialog would prefill from the previous defaults for
|
|
210
|
+
* the rest of the session. The surface that owns the write asks for the
|
|
211
|
+
* snapshot again instead of trusting the frame.
|
|
212
|
+
*/
|
|
213
|
+
refreshHostState(): void;
|
|
189
214
|
/**
|
|
190
215
|
* Show the board. The layout owns which panel the center column renders, so
|
|
191
216
|
* the state flip and the panel selection travel together here; a composition
|
|
@@ -287,19 +312,17 @@ export declare class BoardController {
|
|
|
287
312
|
*/
|
|
288
313
|
deleteTag(name: string): Promise<boolean>;
|
|
289
314
|
/**
|
|
290
|
-
* Update a task's schedule rule.
|
|
291
|
-
*
|
|
292
|
-
*
|
|
293
|
-
*
|
|
315
|
+
* Update a task's schedule rule. An unusable plan (blank or invalid cron, a
|
|
316
|
+
* one-shot with no future instant, a non-positive run cap) is rejected
|
|
317
|
+
* (returns false, state untouched). When the rule ends up enabled the next
|
|
318
|
+
* run instant is computed immediately — a one-shot's next instant IS its
|
|
319
|
+
* planned instant — and a disabled rule carries none. Delegates the domain
|
|
320
|
+
* transition to the schedule use case.
|
|
294
321
|
* @param id - the task to schedule.
|
|
295
322
|
* @param patch - fields to change (absent fields keep their current value).
|
|
296
|
-
* @returns true when applied, false when rejected (
|
|
323
|
+
* @returns true when applied, false when rejected (unknown task / unusable plan).
|
|
297
324
|
*/
|
|
298
|
-
setSchedule(id: string, patch:
|
|
299
|
-
enabled?: boolean;
|
|
300
|
-
cron?: string;
|
|
301
|
-
timeZone?: string | null;
|
|
302
|
-
}): boolean;
|
|
325
|
+
setSchedule(id: string, patch: SetSchedulePatch): boolean;
|
|
303
326
|
/**
|
|
304
327
|
* Legacy pure-controller seam retained for migration-focused tests. The
|
|
305
328
|
* production browser never rolls schedules; the Host ledger owns them.
|
|
@@ -360,12 +383,13 @@ export declare class BoardController {
|
|
|
360
383
|
*/
|
|
361
384
|
private mirrorDepth;
|
|
362
385
|
/**
|
|
363
|
-
* Project a Host snapshot onto the browser's mirror.
|
|
364
|
-
*
|
|
365
|
-
* deployment constants the UI reads
|
|
366
|
-
*
|
|
367
|
-
*
|
|
368
|
-
*
|
|
386
|
+
* Project a Host snapshot onto the browser's mirror. Every snapshot the
|
|
387
|
+
* transport serves is a full document (bootstrap/state/action all answer
|
|
388
|
+
* `TaskBoardHostService.snapshot()`), so the deployment constants the UI reads
|
|
389
|
+
* — the session-default permission the confirmation banner compares against,
|
|
390
|
+
* the subtask depth limit, the platform switches and the extensions a provider
|
|
391
|
+
* published — are taken as published, carried over only where the snapshot
|
|
392
|
+
* itself omits the key.
|
|
369
393
|
*/
|
|
370
394
|
private mirrorOf;
|
|
371
395
|
private refreshRemote;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run-launch admission width: the one bound on how many sessions this board
|
|
3
|
+
* starts at the same time.
|
|
4
|
+
*
|
|
5
|
+
* One board action opens a whole subtree, and a team run hands every member of
|
|
6
|
+
* it to the Lead at once, so without a bound the Host asks DSH for dozens of
|
|
7
|
+
* sessions in a single tick. The repository's own measured guidance caps heavy
|
|
8
|
+
* implementation subagents at three (docs/multi-agent-resources.md) and no
|
|
9
|
+
* runtime mechanism enforced it; this setting is that mechanism.
|
|
10
|
+
*
|
|
11
|
+
* The bounds and the default live here rather than in either half, exactly like
|
|
12
|
+
* the roster cadence: the settings card validates a draft against the same
|
|
13
|
+
* range the Host clamps a hand-edited configuration to, and a programmatic
|
|
14
|
+
* mount that names no width gets the default.
|
|
15
|
+
*
|
|
16
|
+
* @module dsh-task-board/core/launch-width
|
|
17
|
+
*/
|
|
18
|
+
/** Width used when neither the settings document nor the mount names one. */
|
|
19
|
+
export declare const DEFAULT_RUN_LAUNCH_WIDTH = 3;
|
|
20
|
+
/** Narrowest accepted width: one launch at a time. */
|
|
21
|
+
export declare const RUN_LAUNCH_WIDTH_MIN = 1;
|
|
22
|
+
/** Widest accepted width. */
|
|
23
|
+
export declare const RUN_LAUNCH_WIDTH_MAX = 16;
|
|
24
|
+
/**
|
|
25
|
+
* Clamp a configured width into the supported range. A value the schema would
|
|
26
|
+
* refuse (non-finite, below the floor, above the ceiling) still leaves the
|
|
27
|
+
* board launching: an out-of-range setting never stalls a run.
|
|
28
|
+
* @param width - configured width, or undefined for the default.
|
|
29
|
+
* @returns the effective width.
|
|
30
|
+
*/
|
|
31
|
+
export declare function normalizeRunLaunchWidth(width: number | undefined): number;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Roster-poll cadence: the one recurring Host timer the board holds.
|
|
3
|
+
*
|
|
4
|
+
* The cadence is a user setting (seconds), so the bounds and the seconds to
|
|
5
|
+
* milliseconds conversion live here rather than in either half: the settings
|
|
6
|
+
* card validates a draft against the same range the Host clamps a hand-edited
|
|
7
|
+
* configuration to, and a programmatic mount that passes no cadence gets the
|
|
8
|
+
* default.
|
|
9
|
+
*
|
|
10
|
+
* @module dsh-task-board/core/poll-cadence
|
|
11
|
+
*/
|
|
12
|
+
/** Cadence used when neither the settings document nor the mount names one. */
|
|
13
|
+
export declare const DEFAULT_SESSION_POLL_SECONDS = 5;
|
|
14
|
+
/** Shortest accepted cadence: a faster poll only burns CPU on the Host. */
|
|
15
|
+
export declare const SESSION_POLL_MIN_SECONDS = 1;
|
|
16
|
+
/** Longest accepted cadence, five minutes. */
|
|
17
|
+
export declare const SESSION_POLL_MAX_SECONDS = 300;
|
|
18
|
+
/**
|
|
19
|
+
* Clamp a configured cadence into the supported range. A value the schema
|
|
20
|
+
* would refuse (non-finite, below the floor, above the ceiling) still leaves
|
|
21
|
+
* the board polling: an out-of-range setting never disables the timer.
|
|
22
|
+
* @param seconds - configured cadence in seconds, or undefined for the default.
|
|
23
|
+
* @returns the effective cadence in seconds.
|
|
24
|
+
*/
|
|
25
|
+
export declare function normalizeSessionPollSeconds(seconds: number | undefined): number;
|
|
26
|
+
/**
|
|
27
|
+
* The cadence in the milliseconds the Host timer face takes.
|
|
28
|
+
* @param seconds - configured cadence in seconds, or undefined for the default.
|
|
29
|
+
* @returns the effective cadence in milliseconds.
|
|
30
|
+
*/
|
|
31
|
+
export declare function sessionPollMs(seconds: number | undefined): number;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which reasoning effort one execution may actually send.
|
|
3
|
+
*
|
|
4
|
+
* The rule lives here, in one pure place, so the launch path cannot drift from
|
|
5
|
+
* what the picker promises: an effort is sent ONLY for the exact model route
|
|
6
|
+
* whose adapter declares that id. An unsupported value is dropped rather than
|
|
7
|
+
* passed through — the Host validates the selection against the same
|
|
8
|
+
* capability (`resolveCallConfig` rejects an unsupported effort) and the whole
|
|
9
|
+
* model selection would fail with it. An absent effort stays absent: the SDK
|
|
10
|
+
* then materializes the model's own default, which is exactly what "inherit
|
|
11
|
+
* the model" means.
|
|
12
|
+
*
|
|
13
|
+
* A card that pins a bare model id also gets its provider resolved here: the
|
|
14
|
+
* session wire contract requires `provider` (ModelSelection), so the catalog is
|
|
15
|
+
* the only place that can complete the documented `provider/model` or model-id
|
|
16
|
+
* pin.
|
|
17
|
+
*/
|
|
18
|
+
import type { CatalogModel, ModelCatalogView } from './verification.ts';
|
|
19
|
+
/** One execution route an effort resolves against: `provider/model`, or a bare model id. */
|
|
20
|
+
export interface ReasoningRoute {
|
|
21
|
+
provider?: string;
|
|
22
|
+
model: string;
|
|
23
|
+
}
|
|
24
|
+
/** The catalog entry a route names, once the catalog can complete it. */
|
|
25
|
+
export interface DeclaredReasoningRoute {
|
|
26
|
+
provider: string;
|
|
27
|
+
model: string;
|
|
28
|
+
/** The adapter's reasoning metadata; absent when it exposes none. */
|
|
29
|
+
reasoning?: CatalogModel['reasoning'];
|
|
30
|
+
}
|
|
31
|
+
/** What one card's effort resolves to for one route. */
|
|
32
|
+
export interface ReasoningEffortDecision {
|
|
33
|
+
/** The effort to send; absent means "send none". */
|
|
34
|
+
effort?: string;
|
|
35
|
+
/** The card's own value when it will NOT be sent. */
|
|
36
|
+
dropped?: string;
|
|
37
|
+
}
|
|
38
|
+
/** Trim one optional effort: blank text means "not set", like every other pinned target. */
|
|
39
|
+
export declare function normalizeReasoningEffort(value: string | undefined): string | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* Complete one route through the host catalog: a qualified route must match its
|
|
42
|
+
* provider group, and a bare model id matches the first group carrying it —
|
|
43
|
+
* which is the provider the request then names.
|
|
44
|
+
* @param catalog - the host model catalog, when this deployment serves one.
|
|
45
|
+
* @param route - the route as the card pins it.
|
|
46
|
+
* @returns the completed route with its reasoning metadata, or undefined when
|
|
47
|
+
* the catalog declares no such model.
|
|
48
|
+
*/
|
|
49
|
+
export declare function declaredRoute(catalog: ModelCatalogView | undefined, route: ReasoningRoute): DeclaredReasoningRoute | undefined;
|
|
50
|
+
/**
|
|
51
|
+
* Resolve the effort one execution sends.
|
|
52
|
+
* @param requested - the card's stored effort (absent or blank = inherit).
|
|
53
|
+
* @param catalog - the host model catalog, when this deployment serves one.
|
|
54
|
+
* @param route - the route the execution will actually run at.
|
|
55
|
+
* @returns the effort to send, or the dropped value that will not be sent.
|
|
56
|
+
*/
|
|
57
|
+
export declare function resolveReasoningEffort(requested: string | undefined, catalog: ModelCatalogView | undefined, route: ReasoningRoute | undefined): ReasoningEffortDecision;
|
|
@@ -76,11 +76,32 @@ export interface ParentLinkCheck {
|
|
|
76
76
|
export declare function checkParentLink(tasks: readonly TaskRecord[], childId: string, parentId: string | null, maxSubtaskDepth: number, lineage?: LineageIndex): ParentLinkCheck;
|
|
77
77
|
/**
|
|
78
78
|
* The tasks one run request opens executions for: the requested task first,
|
|
79
|
-
* then its on-board descendants within the configured depth.
|
|
80
|
-
*
|
|
81
|
-
* the
|
|
79
|
+
* then its on-board descendants within the configured depth. This is the
|
|
80
|
+
* SHAPE of a cascade — every walk that must see the whole tree (settlement,
|
|
81
|
+
* archive/restore, the running lock) reads it. The run path filters it with
|
|
82
|
+
* {@link joinsCascadeRun}: archived tasks never run, a participant that already
|
|
83
|
+
* has an open execution is skipped by the caller, which cannot start it twice,
|
|
84
|
+
* and a finished descendant is left alone.
|
|
82
85
|
*/
|
|
83
86
|
export declare function cascadeTargets(tasks: readonly TaskRecord[], rootId: string, maxSubtaskDepth: number): TaskRecord[];
|
|
87
|
+
/**
|
|
88
|
+
* Whether a cascade member takes part in a new run.
|
|
89
|
+
*
|
|
90
|
+
* The task the user ran is always a member: the request names that card, and
|
|
91
|
+
* the operator asked for it to run whatever its column says. A descendant does
|
|
92
|
+
* not join once it sits in the `done` column — its work is finished, so running
|
|
93
|
+
* the parent again is a run of the parent, never a second execution of work
|
|
94
|
+
* that is already done. The rule keys on the column alone, so it covers both a
|
|
95
|
+
* subtask that ran and one an operator moved to done by hand, and it holds for
|
|
96
|
+
* every trigger: a manual run, a re-run, and a due occurrence of a schedule.
|
|
97
|
+
* A card whose own schedule is enabled settles back into `todo`, so a scheduled
|
|
98
|
+
* subtask stays a participant; to make a finished one run again, move it back
|
|
99
|
+
* to `todo` or run it on its own.
|
|
100
|
+
* @param task - the candidate member.
|
|
101
|
+
* @param rootId - the task the run request named.
|
|
102
|
+
* @returns false when this member is left alone by the run.
|
|
103
|
+
*/
|
|
104
|
+
export declare function joinsCascadeRun(task: TaskRecord, rootId: string): boolean;
|
|
84
105
|
/** One still-open execution belonging to a cascade run group. */
|
|
85
106
|
export interface OpenCascadeChild {
|
|
86
107
|
taskId: string;
|
|
@@ -114,11 +135,12 @@ export declare function effectiveTaskPermission(task: TaskRecord): TaskRecord['p
|
|
|
114
135
|
/**
|
|
115
136
|
* Resolve the execution targets a (sub)task actually runs with: its own value
|
|
116
137
|
* wins, and an unset target inherits the nearest ancestor up to the root.
|
|
117
|
-
* Workspace, agent preset and
|
|
118
|
-
* handover bundle is a per-card continuation artefact and is never
|
|
119
|
-
* The permission inherits the ancestor's EFFECTIVE binding, and its
|
|
120
|
-
* confirmation travels with it, so a subtask of an already-confirmed
|
|
121
|
-
* card is runnable while a subtask's own unconfirmed binding stays
|
|
138
|
+
* Workspace, agent preset, model and reasoning effort inherit the ancestor's
|
|
139
|
+
* PIN only — a handover bundle is a per-card continuation artefact and is never
|
|
140
|
+
* inherited. The permission inherits the ancestor's EFFECTIVE binding, and its
|
|
141
|
+
* human confirmation travels with it, so a subtask of an already-confirmed
|
|
142
|
+
* elevated card is runnable while a subtask's own unconfirmed binding stays
|
|
143
|
+
* gated.
|
|
122
144
|
*/
|
|
123
145
|
/**
|
|
124
146
|
* The immutable teammate name for one team-mode member. Teammate names are
|
|
@@ -34,8 +34,23 @@ export interface ExecutionRecord {
|
|
|
34
34
|
* Session id of the DSH session that issued the run/rerun action (issue #6
|
|
35
35
|
* audit origin). Client-asserted, not a trust boundary; absent when the run
|
|
36
36
|
* was triggered by cron (source unknown).
|
|
37
|
+
*
|
|
38
|
+
* On an EXTERNAL record (issue #1826) this names the agent that completed the
|
|
39
|
+
* work outside the Host instead, which is what makes the history readable.
|
|
37
40
|
*/
|
|
38
41
|
initiatedBy?: string;
|
|
42
|
+
/**
|
|
43
|
+
* True when this outcome was recorded from outside the Host by
|
|
44
|
+
* `record-external-outcome` rather than observed from a DSH session
|
|
45
|
+
* (issue #1826).
|
|
46
|
+
*
|
|
47
|
+
* The board never manufactures one of these itself: every Host-side path
|
|
48
|
+
* (`run`, `settle`, cascade folding, restart recovery) writes an execution
|
|
49
|
+
* without it, so `external` is the single field separating work this Host ran
|
|
50
|
+
* from work an outside agent reported. Such a record never carries a
|
|
51
|
+
* `sessionId` and never claims a verdict the Host observed.
|
|
52
|
+
*/
|
|
53
|
+
external?: boolean;
|
|
39
54
|
/** Freeze instant captured from the card snapshot when the run opened. */
|
|
40
55
|
frozenAt?: number;
|
|
41
56
|
/** Freeze source session captured from the card snapshot when the run opened. */
|
|
@@ -76,17 +91,69 @@ export declare const EXECUTION_HISTORY_LIMIT = 20;
|
|
|
76
91
|
* cannot start a new run while one is still open.
|
|
77
92
|
*/
|
|
78
93
|
export declare function retainRecentExecutions(executions: readonly ExecutionRecord[]): ExecutionRecord[];
|
|
94
|
+
/**
|
|
95
|
+
* How a rule produces its triggers: a recurring cron rule, or one single
|
|
96
|
+
* planned instant. The distinction is stored rather than inferred so a
|
|
97
|
+
* one-shot is never represented as a date-restricted cron expression.
|
|
98
|
+
*/
|
|
99
|
+
export type ScheduleMode = 'cron' | 'once';
|
|
100
|
+
/**
|
|
101
|
+
* Why a due occurrence produced no run, or why a rule stopped on its own.
|
|
102
|
+
*
|
|
103
|
+
* These are stable codes, not display text: the board renders them through its
|
|
104
|
+
* locale dictionary, so the ledger never carries a translated string.
|
|
105
|
+
*/
|
|
106
|
+
export type ScheduleStopReason =
|
|
107
|
+
/** The single planned instant produced its run. */
|
|
108
|
+
'fired'
|
|
109
|
+
/** The recurring rule reached its run budget. */
|
|
110
|
+
| 'limit'
|
|
111
|
+
/** The plan has no reachable instant any more (an impossible cron). */
|
|
112
|
+
| 'no-target'
|
|
113
|
+
/** The instant passed while the board was not running through it. */
|
|
114
|
+
| 'missed'
|
|
115
|
+
/** The task already had an open execution, so this occurrence was skipped. */
|
|
116
|
+
| 'busy'
|
|
117
|
+
/** An above-default permission was still unconfirmed, so this occurrence was skipped. */
|
|
118
|
+
| 'permission'
|
|
119
|
+
/**
|
|
120
|
+
* A scheduled launch failed before any session existed, so the occurrence
|
|
121
|
+
* created no execution and its run was refunded rather than spent.
|
|
122
|
+
*/
|
|
123
|
+
| 'launch-failed';
|
|
124
|
+
/** Every stop reason this build understands; the repair and wire gates share it. */
|
|
125
|
+
export declare const SCHEDULE_STOP_REASONS: readonly ScheduleStopReason[];
|
|
79
126
|
/**
|
|
80
127
|
* A scheduled-run rule attached to a task. The Host scheduler triggers the
|
|
81
128
|
* task when `nextRunAt` is due and persists the rule in the Host ledger.
|
|
129
|
+
*
|
|
130
|
+
* A rule is either `cron` (the historical shape: a 5-field expression with an
|
|
131
|
+
* explicit IANA zone, optionally capped by `maxRuns`) or `once` (one planned
|
|
132
|
+
* instant, `at`, with an implicit budget of one run). Both modes count the
|
|
133
|
+
* executions the scheduler actually started in `runCount`; a rule that reaches
|
|
134
|
+
* its budget stops itself in the ledger (`enabled: false` + `endedReason`)
|
|
135
|
+
* instead of relying on the execution agent to disable it.
|
|
82
136
|
*/
|
|
83
137
|
export interface ScheduleRule {
|
|
84
138
|
/** Whether the schedule is armed. */
|
|
85
139
|
enabled: boolean;
|
|
86
|
-
/** 5-field cron expression: `分 时 日 月 周`. */
|
|
87
|
-
cron: string;
|
|
88
140
|
/**
|
|
89
|
-
*
|
|
141
|
+
* Which kind of plan this rule carries. A rule loaded from a ledger written
|
|
142
|
+
* before the field existed normalizes to `cron` (its `cron` is the plan).
|
|
143
|
+
*/
|
|
144
|
+
mode: ScheduleMode;
|
|
145
|
+
/**
|
|
146
|
+
* 5-field cron expression: `分 时 日 月 周`. Present on a `cron` rule and
|
|
147
|
+
* absent on a `once` rule.
|
|
148
|
+
*/
|
|
149
|
+
cron?: string;
|
|
150
|
+
/**
|
|
151
|
+
* The instant a `once` rule executes (ms epoch). Kept after the run so the
|
|
152
|
+
* detail view can still show the planned time once the rule has ended.
|
|
153
|
+
*/
|
|
154
|
+
at?: number;
|
|
155
|
+
/**
|
|
156
|
+
* IANA zone the wall clock is read in (issue #1722). Absent means the
|
|
90
157
|
* Host process zone, which is what a rule written before zones were
|
|
91
158
|
* persisted keeps using; the Host stamps its own zone at ledger migration so
|
|
92
159
|
* a later `TZ` change cannot silently move an existing rule.
|
|
@@ -96,7 +163,51 @@ export interface ScheduleRule {
|
|
|
96
163
|
nextRunAt: number | undefined;
|
|
97
164
|
/** Instant of the latest scheduled trigger (ms epoch). */
|
|
98
165
|
lastTriggeredAt: number | undefined;
|
|
166
|
+
/**
|
|
167
|
+
* Scheduled executions the Host has created under this rule. This is the
|
|
168
|
+
* run budget's counter: it counts executions that were successfully opened
|
|
169
|
+
* (whatever their later outcome), never completions, and a manual run never
|
|
170
|
+
* touches it. A skipped occurrence (busy / permission / missed / no target)
|
|
171
|
+
* creates no execution and therefore consumes nothing.
|
|
172
|
+
*/
|
|
173
|
+
runCount: number;
|
|
174
|
+
/**
|
|
175
|
+
* Maximum scheduled executions for a `cron` rule; absent means unlimited
|
|
176
|
+
* (the historical behavior). A `once` rule has an implicit budget of one and
|
|
177
|
+
* stores no `maxRuns`.
|
|
178
|
+
*/
|
|
179
|
+
maxRuns?: number;
|
|
180
|
+
/** Instant the rule stopped itself (ms epoch); absent while it may still fire. */
|
|
181
|
+
endedAt?: number;
|
|
182
|
+
/** Why the rule stopped itself; present with `endedAt`. */
|
|
183
|
+
endedReason?: ScheduleStopReason;
|
|
184
|
+
/** Instant of the latest occurrence that produced no run. */
|
|
185
|
+
skippedAt?: number;
|
|
186
|
+
/** Why that occurrence produced no run; present with `skippedAt`. */
|
|
187
|
+
skippedReason?: ScheduleStopReason;
|
|
99
188
|
}
|
|
189
|
+
/**
|
|
190
|
+
* The rule's total run budget: one for a one-shot, the stored cap for a
|
|
191
|
+
* recurring rule, and undefined when the rule is unlimited.
|
|
192
|
+
* @param rule - the schedule rule.
|
|
193
|
+
* @returns the budget, or undefined for an uncapped rule.
|
|
194
|
+
*/
|
|
195
|
+
export declare function scheduleRunBudget(rule: ScheduleRule): number | undefined;
|
|
196
|
+
/**
|
|
197
|
+
* Whether a rule has no runs left. The scheduler refuses to open another
|
|
198
|
+
* execution for an exhausted rule, which is what makes the budget terminal
|
|
199
|
+
* regardless of restarts or repeated timer fires.
|
|
200
|
+
* @param rule - the schedule rule.
|
|
201
|
+
* @returns true when the run budget is spent.
|
|
202
|
+
*/
|
|
203
|
+
export declare function scheduleExhausted(rule: ScheduleRule): boolean;
|
|
204
|
+
/**
|
|
205
|
+
* The instant a rule plans to fire next, for display, whatever its mode: the
|
|
206
|
+
* planned `at` of a one-shot, or the stored `nextRunAt` of a recurring rule.
|
|
207
|
+
* @param rule - the schedule rule.
|
|
208
|
+
* @returns the planned instant, or undefined when the rule carries none.
|
|
209
|
+
*/
|
|
210
|
+
export declare function schedulePlannedAt(rule: ScheduleRule): number | undefined;
|
|
100
211
|
/**
|
|
101
212
|
* Frozen context snapshot carried by a continuation card (issue #4): the
|
|
102
213
|
* goal/progress/next text (already sanitized by the freeze gates) plus the
|
|
@@ -214,6 +325,15 @@ export interface TaskRecord {
|
|
|
214
325
|
* absent falls back to the host default (agent-default-model).
|
|
215
326
|
*/
|
|
216
327
|
model?: string;
|
|
328
|
+
/**
|
|
329
|
+
* Reasoning effort pinned for that execution route (an adapter-owned id such
|
|
330
|
+
* as "high"). Absent (or blank) means INHERIT: the session runs at the
|
|
331
|
+
* model's own default level, exactly as a card written before the field
|
|
332
|
+
* existed does. The launch sends the value only when the target model's
|
|
333
|
+
* adapter declares that exact id, so switching a card to a model without
|
|
334
|
+
* that level never pushes an invalid selection (see core/reasoning-effort.ts).
|
|
335
|
+
*/
|
|
336
|
+
reasoningEffort?: string;
|
|
217
337
|
/**
|
|
218
338
|
* Whether later executions continue in the previous execution's session
|
|
219
339
|
* (issue #1419) instead of minting a fresh conversation per run. Absent or
|
|
@@ -236,9 +356,11 @@ export interface TaskRecord {
|
|
|
236
356
|
* armed with the composed execution prompt as its objective. The session then
|
|
237
357
|
* keeps working automatic continuation rounds until the agent marks the goal
|
|
238
358
|
* complete, and this board settles the execution on the goal's own end
|
|
239
|
-
* instead of at the first turn end. Absent means
|
|
240
|
-
* by default, so only an explicit `
|
|
241
|
-
*
|
|
359
|
+
* instead of at the first turn end. Absent means OFF — the option is
|
|
360
|
+
* unchecked by default, so only an explicit `true` joins the goal run and
|
|
361
|
+
* every card that never touched it (including every card written before the
|
|
362
|
+
* field existed) runs one plain turn. A session whose `/goal` command is
|
|
363
|
+
* refused still runs the prompt.
|
|
242
364
|
*/
|
|
243
365
|
goalRun?: boolean;
|
|
244
366
|
/**
|
|
@@ -333,13 +455,23 @@ export interface NewTaskInput {
|
|
|
333
455
|
permission?: TaskPermission;
|
|
334
456
|
/** Optional pinned model for the execution session; absent = host default. */
|
|
335
457
|
model?: string;
|
|
458
|
+
/** Optional reasoning effort for that model route; empty/absent = the model's own default. */
|
|
459
|
+
reasoningEffort?: string;
|
|
460
|
+
/**
|
|
461
|
+
* Opt in to the deployment's new-card defaults: a target this input leaves
|
|
462
|
+
* out is filled from the configured default (agent preset, permission, model
|
|
463
|
+
* and the level bound to that model). Absent means the create stores exactly
|
|
464
|
+
* what it was given, which is what the extension provider's own create path
|
|
465
|
+
* and the legacy import rely on.
|
|
466
|
+
*/
|
|
467
|
+
applyCardDefaults?: boolean;
|
|
336
468
|
/** Reuse the previous execution's session for later runs (issue #1419). */
|
|
337
469
|
reuseSession?: boolean;
|
|
338
470
|
/** Run the subtree as an Agent Team (Team Lead session plus one teammate per direct subtask). */
|
|
339
471
|
teamRun?: boolean;
|
|
340
472
|
/**
|
|
341
|
-
* Start the execution with dsh's built-in `/goal`. Absent
|
|
342
|
-
*
|
|
473
|
+
* Start the execution with dsh's built-in `/goal`. Absent means the default
|
|
474
|
+
* (one plain turn); only an explicit true joins the goal run.
|
|
343
475
|
*/
|
|
344
476
|
goalRun?: boolean;
|
|
345
477
|
/**
|
|
@@ -348,15 +480,21 @@ export interface NewTaskInput {
|
|
|
348
480
|
*/
|
|
349
481
|
skipVerification?: boolean;
|
|
350
482
|
/**
|
|
351
|
-
* Optional
|
|
352
|
-
* dialog): an enable flag, a 5-field cron
|
|
353
|
-
*
|
|
354
|
-
*
|
|
483
|
+
* Optional scheduling rule requested at creation time (the new-task
|
|
484
|
+
* dialog): an enable flag, the kind of plan (a recurring 5-field cron
|
|
485
|
+
* expression, or one planned instant for a one-shot), an optional run cap,
|
|
486
|
+
* and the IANA zone its wall clock is read in (absent means the Host zone).
|
|
487
|
+
* The create use case arms it only when enabled and the plan is valid.
|
|
355
488
|
*/
|
|
356
489
|
schedule?: {
|
|
357
490
|
enabled: boolean;
|
|
358
|
-
|
|
491
|
+
mode?: ScheduleMode;
|
|
492
|
+
cron?: string;
|
|
493
|
+
/** Planned instant of a one-shot rule (ms epoch). */
|
|
494
|
+
at?: number;
|
|
359
495
|
timeZone?: string;
|
|
496
|
+
/** Run cap of a recurring rule; absent means unlimited. */
|
|
497
|
+
maxRuns?: number;
|
|
360
498
|
};
|
|
361
499
|
/**
|
|
362
500
|
* Optional frozen context snapshot (goal/progress/next, sanitized by the
|
|
@@ -448,7 +586,8 @@ export declare function withStatus(task: TaskRecord, status: TaskStatus, now: nu
|
|
|
448
586
|
* Merge a schedule patch into a task's schedule rule (creating it when
|
|
449
587
|
* absent), with a fresh updatedAt. Keys present in the patch overwrite the
|
|
450
588
|
* current value — including explicit `undefined`, which clears a field (used
|
|
451
|
-
* to disarm `nextRunAt`); absent keys keep
|
|
589
|
+
* to disarm `nextRunAt` or to drop an ended/skip record); absent keys keep
|
|
590
|
+
* their current value.
|
|
452
591
|
*/
|
|
453
592
|
export declare function withSchedule(task: TaskRecord, patch: Partial<ScheduleRule>, now: number): TaskRecord;
|
|
454
593
|
/**
|
|
@@ -461,6 +600,16 @@ export declare function startExecution(task: TaskRecord, now: number, executionI
|
|
|
461
600
|
task: TaskRecord;
|
|
462
601
|
execution: ExecutionRecord;
|
|
463
602
|
};
|
|
603
|
+
/**
|
|
604
|
+
* The column a settled outcome puts a card in. The ONE derivation shared by
|
|
605
|
+
* every settlement path (issue #1826): a Host-run execution and an outcome an
|
|
606
|
+
* outside agent reported both land in the same column from the same rule, so
|
|
607
|
+
* the column never becomes a second, independent piece of state.
|
|
608
|
+
@param task - the card being settled.
|
|
609
|
+
@param outcome - the settled outcome.
|
|
610
|
+
@returns the status the card shows afterwards.
|
|
611
|
+
*/
|
|
612
|
+
export declare function settledStatus(task: TaskRecord, outcome: ExecutionOutcome): TaskStatus;
|
|
464
613
|
/**
|
|
465
614
|
* Settle a running execution: record the outcome and move the task into the
|
|
466
615
|
* matching column. No-op (returns the input task) when the execution is not
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type CardDefaults } from '../card-defaults.ts';
|
|
1
2
|
import { type NewTaskInput, type TaskRecord } from '../tasks.ts';
|
|
2
3
|
/** Result of a create transition: the new task (when accepted) + the next ledger. */
|
|
3
4
|
export interface CreateTaskResult {
|
|
@@ -13,15 +14,19 @@ export interface CreateTaskResult {
|
|
|
13
14
|
* appended ledger, or the unchanged ledger when the title is blank or the
|
|
14
15
|
* requested parent link is refused.
|
|
15
16
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
17
|
+
* The execution targets resolve through {@link resolveCardTargets}: what the
|
|
18
|
+
* caller sent wins, then the parent's own pins, then - only when the caller
|
|
19
|
+
* opted in with `applyCardDefaults` - the deployment's configured new-card
|
|
20
|
+
* defaults. Without the flag the resolution sees no defaults at all, which is
|
|
21
|
+
* exactly the inline parent inheritance this path has always applied. The
|
|
22
|
+
* workspace is not part of that resolution: a subtask still takes the parent's
|
|
23
|
+
* workspace, and the defaults never name one.
|
|
20
24
|
* @param tasks - current ledger.
|
|
21
25
|
* @param input - raw user input (title/description/prompt + optional schedule/parent).
|
|
22
26
|
* @param now - clock instant (ms epoch).
|
|
23
27
|
* @param id - minted task id.
|
|
24
28
|
* @param maxSubtaskDepth - deployment subtask depth limit.
|
|
25
29
|
* @param hostTimeZone - zone a rule that stores no zone of its own follows.
|
|
30
|
+
* @param cardDefaults - the deployment's new-card defaults, read live at creation.
|
|
26
31
|
*/
|
|
27
|
-
export declare function applyCreateTask(tasks: readonly TaskRecord[], input: NewTaskInput, now: number, id: string, maxSubtaskDepth?: number, hostTimeZone?: string): CreateTaskResult;
|
|
32
|
+
export declare function applyCreateTask(tasks: readonly TaskRecord[], input: NewTaskInput, now: number, id: string, maxSubtaskDepth?: number, hostTimeZone?: string, cardDefaults?: CardDefaults): CreateTaskResult;
|