@zhchxiao123/dsh-devflow 0.2.0 → 0.4.0-dev.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.js +97 -14
- package/lib/types/index.d.ts +19 -2
- package/lib/types/index.js +1 -1
- package/lib/types/journal.d.ts +14 -2
- package/lib/types/journal.js +36 -4
- package/lib/types/stages.d.ts +42 -7
- package/lib/types/stages.js +61 -10
- package/lib/types/types.d.ts +83 -1
- package/package.json +9 -9
package/lib/index.js
CHANGED
|
@@ -28,6 +28,31 @@ function isCardLocation(value) {
|
|
|
28
28
|
return value === "blocked" || isDevStage(value);
|
|
29
29
|
}
|
|
30
30
|
/**
|
|
31
|
+
* The service classes, in ascending order of what they skip.
|
|
32
|
+
*
|
|
33
|
+
* Closed vocabulary rather than a plugin `Config` field, on the same grounds as
|
|
34
|
+
* {@link DEV_STAGES}: the board, both language documents, and the agent's
|
|
35
|
+
* prompts all reference these names, and a deployment-defined class would make
|
|
36
|
+
* every one of those references local. Letting a deployment mint its own
|
|
37
|
+
* shorter class is also precisely the failure mode this vocabulary exists to
|
|
38
|
+
* prevent — see the service-class Agent Note.
|
|
39
|
+
*/
|
|
40
|
+
const SERVICE_CLASSES = [
|
|
41
|
+
"standard",
|
|
42
|
+
"express",
|
|
43
|
+
"emergency"
|
|
44
|
+
];
|
|
45
|
+
/** The class of a card that declares none, on disk and in memory. */
|
|
46
|
+
const DEFAULT_SERVICE_CLASS = "standard";
|
|
47
|
+
/**
|
|
48
|
+
* Narrow an unknown value to a service class.
|
|
49
|
+
* @param value - the candidate value.
|
|
50
|
+
* @returns `true` when `value` is one of {@link SERVICE_CLASSES}.
|
|
51
|
+
*/
|
|
52
|
+
function isServiceClass(value) {
|
|
53
|
+
return typeof value === "string" && SERVICE_CLASSES.includes(value);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
31
56
|
* Brand a raw string as a {@link DevflowCardId}. The id equals the card's
|
|
32
57
|
* directory name; construction lives here because this package owns the brand.
|
|
33
58
|
* @param value - the card directory name.
|
|
@@ -45,12 +70,17 @@ function DevflowCardId(value) {
|
|
|
45
70
|
* is. Without the second, design rework happens on a card labelled
|
|
46
71
|
* `developing`, and the board stops answering the one question it exists to
|
|
47
72
|
* answer.
|
|
73
|
+
*
|
|
74
|
+
* `developing` reaches `designing` for the same reason, from the stage that
|
|
75
|
+
* finds such faults most often. Its absence left `developing → reviewing →
|
|
76
|
+
* designing` as the only route back, which records a review that never
|
|
77
|
+
* happened in the authoritative journal to reach the stage owning the fault.
|
|
48
78
|
*/
|
|
49
79
|
const FLOW = {
|
|
50
80
|
draft: ["designing"],
|
|
51
81
|
designing: ["ready"],
|
|
52
82
|
ready: ["developing"],
|
|
53
|
-
developing: ["reviewing"],
|
|
83
|
+
developing: ["reviewing", "designing"],
|
|
54
84
|
reviewing: [
|
|
55
85
|
"testing",
|
|
56
86
|
"developing",
|
|
@@ -64,32 +94,61 @@ const FLOW = {
|
|
|
64
94
|
done: []
|
|
65
95
|
};
|
|
66
96
|
/**
|
|
97
|
+
* Edges each service class adds to {@link FLOW}, and the only place a class
|
|
98
|
+
* differs from another. Stated as additions rather than as one whole graph per
|
|
99
|
+
* class so "every class is a superset of `standard`" is a property of the code
|
|
100
|
+
* instead of a convention: a class cannot remove an edge, and therefore cannot
|
|
101
|
+
* make a journal that replays today stop replaying.
|
|
102
|
+
*/
|
|
103
|
+
const CLASS_EXTRA = {
|
|
104
|
+
standard: {},
|
|
105
|
+
express: {
|
|
106
|
+
draft: ["developing"],
|
|
107
|
+
reviewing: ["done"]
|
|
108
|
+
},
|
|
109
|
+
emergency: {
|
|
110
|
+
draft: ["developing"],
|
|
111
|
+
developing: ["done"]
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
/**
|
|
67
115
|
* Whether one stage move is a legal edge of the state machine.
|
|
68
116
|
*
|
|
69
117
|
* Main flow follows the pipeline order; `reviewing` and `testing` may rework
|
|
70
|
-
* to `developing
|
|
71
|
-
*
|
|
118
|
+
* to `developing` or `designing` and `developing` may rework to `designing`;
|
|
119
|
+
* any non-terminal location may enter `blocked`; a blocked card may only
|
|
120
|
+
* recover to the exact stage it interrupted. A card's service class adds the
|
|
121
|
+
* shortcuts in {@link CLASS_EXTRA} and takes nothing away.
|
|
122
|
+
*
|
|
123
|
+
* `blocked` legality does not vary by class: a shortcut is about which stages
|
|
124
|
+
* a card may skip, not about how it pauses.
|
|
72
125
|
* @param from - the card's current location.
|
|
73
126
|
* @param to - the requested target location.
|
|
74
|
-
* @param
|
|
127
|
+
* @param card - the moving card's own context; omitted reads as a `standard`
|
|
128
|
+
* card that is not blocked.
|
|
75
129
|
* @returns `true` when the move is a legal edge.
|
|
76
130
|
*/
|
|
77
|
-
function isLegalTransition(from, to,
|
|
131
|
+
function isLegalTransition(from, to, card) {
|
|
78
132
|
if (from === to) return false;
|
|
79
|
-
if (from === "blocked") return to === blockedFrom;
|
|
133
|
+
if (from === "blocked") return to === card?.blockedFrom;
|
|
80
134
|
if (to === "blocked") return from !== "done";
|
|
81
|
-
|
|
135
|
+
if (FLOW[from].includes(to)) return true;
|
|
136
|
+
return (CLASS_EXTRA[card?.serviceClass ?? "standard"][from] ?? []).includes(to);
|
|
82
137
|
}
|
|
83
138
|
/**
|
|
84
139
|
* Whether a legal edge moves the card backwards (a rework). Rework edges
|
|
85
|
-
* require a recorded `reason` so the next holder knows what to fix
|
|
140
|
+
* require a recorded `reason` so the next holder knows what to fix — on
|
|
141
|
+
* `developing -> designing` that reason is what implementing the design
|
|
142
|
+
* revealed about it, which is the whole point of routing the card back rather
|
|
143
|
+
* than redesigning in place.
|
|
86
144
|
* @param from - the departing location.
|
|
87
145
|
* @param to - the target location.
|
|
88
146
|
* @returns `true` for a move from `reviewing` or `testing` back to
|
|
89
|
-
* `developing` or `designing`.
|
|
147
|
+
* `developing` or `designing`, and for `developing` back to `designing`.
|
|
90
148
|
*/
|
|
91
149
|
function isReworkEdge(from, to) {
|
|
92
|
-
|
|
150
|
+
if (to === "designing") return from === "developing" || from === "reviewing" || from === "testing";
|
|
151
|
+
return to === "developing" && (from === "reviewing" || from === "testing");
|
|
93
152
|
}
|
|
94
153
|
//#endregion
|
|
95
154
|
//#region packages/devflow/src/journal.ts
|
|
@@ -122,7 +181,8 @@ function decodeJournalEntry(value) {
|
|
|
122
181
|
at: entry.at,
|
|
123
182
|
type: "created",
|
|
124
183
|
by: decodeActor(entry.by),
|
|
125
|
-
...decodeOptionalCardId(entry, "parent")
|
|
184
|
+
...decodeOptionalCardId(entry, "parent"),
|
|
185
|
+
...decodeOptionalServiceClass(entry)
|
|
126
186
|
};
|
|
127
187
|
case "transition":
|
|
128
188
|
if (!isCardLocation(entry.from)) throw new Error("transition field \"from\" must be a stage or \"blocked\"");
|
|
@@ -149,6 +209,15 @@ function decodeJournalEntry(value) {
|
|
|
149
209
|
...entry.by !== void 0 ? { by: decodeActor(entry.by) } : {},
|
|
150
210
|
...decodeOptionalString(entry, "kind")
|
|
151
211
|
};
|
|
212
|
+
case "abandoned":
|
|
213
|
+
if (typeof entry.reason !== "string" || entry.reason.trim().length === 0) throw new Error("abandoned field \"reason\" must be a non-empty string; a card leaving the board without one loses the decision");
|
|
214
|
+
return {
|
|
215
|
+
rev,
|
|
216
|
+
at: entry.at,
|
|
217
|
+
type: "abandoned",
|
|
218
|
+
by: decodeActor(entry.by),
|
|
219
|
+
reason: entry.reason
|
|
220
|
+
};
|
|
152
221
|
case "claim-expired":
|
|
153
222
|
if (entry.previousOwner === void 0) throw new Error("claim-expired field \"previousOwner\" is required");
|
|
154
223
|
return {
|
|
@@ -158,7 +227,7 @@ function decodeJournalEntry(value) {
|
|
|
158
227
|
previousOwner: decodeActor(entry.previousOwner),
|
|
159
228
|
by: decodeActor(entry.by)
|
|
160
229
|
};
|
|
161
|
-
default: throw new Error(`journal entry field "type" must be created, transition, artifact, or claim-expired (got ${JSON.stringify(entry.type)})`);
|
|
230
|
+
default: throw new Error(`journal entry field "type" must be created, transition, artifact, abandoned, or claim-expired (got ${JSON.stringify(entry.type)})`);
|
|
162
231
|
}
|
|
163
232
|
}
|
|
164
233
|
/**
|
|
@@ -167,7 +236,8 @@ function decodeJournalEntry(value) {
|
|
|
167
236
|
* Validates the structural invariants of the durable stream: revisions are the
|
|
168
237
|
* contiguous sequence 1..n, the first entry is `created`, every transition
|
|
169
238
|
* departs from the current location, a move to `blocked` remembers its origin,
|
|
170
|
-
*
|
|
239
|
+
* the matching recovery returns exactly there, and nothing follows an
|
|
240
|
+
* `abandoned` entry.
|
|
171
241
|
* @param entries - decoded entries in file order.
|
|
172
242
|
* @returns the folded card state.
|
|
173
243
|
* @throws {Error} naming the first violated invariant and its entry revision.
|
|
@@ -177,6 +247,7 @@ function foldJournal(entries) {
|
|
|
177
247
|
const state = {
|
|
178
248
|
stage: "draft",
|
|
179
249
|
revision: 0,
|
|
250
|
+
serviceClass: DEFAULT_SERVICE_CLASS,
|
|
180
251
|
artifacts: []
|
|
181
252
|
};
|
|
182
253
|
for (const [index, entry] of entries.entries()) {
|
|
@@ -184,9 +255,11 @@ function foldJournal(entries) {
|
|
|
184
255
|
if (index === 0) {
|
|
185
256
|
if (entry.type !== "created") throw new Error("journal entry 1 must be \"created\"");
|
|
186
257
|
if (entry.parent !== void 0) state.parent = entry.parent;
|
|
258
|
+
if (entry.serviceClass !== void 0) state.serviceClass = entry.serviceClass;
|
|
187
259
|
state.revision = entry.rev;
|
|
188
260
|
continue;
|
|
189
261
|
}
|
|
262
|
+
if (state.abandoned === true) throw new Error(`journal entry rev ${entry.rev} follows an abandoned card; abandoning is terminal`);
|
|
190
263
|
switch (entry.type) {
|
|
191
264
|
case "created": throw new Error(`journal entry rev ${entry.rev} repeats "created"`);
|
|
192
265
|
case "transition":
|
|
@@ -204,6 +277,10 @@ function foldJournal(entries) {
|
|
|
204
277
|
state.artifacts.push(entry.path);
|
|
205
278
|
state.revision = entry.rev;
|
|
206
279
|
break;
|
|
280
|
+
case "abandoned":
|
|
281
|
+
state.abandoned = true;
|
|
282
|
+
state.revision = entry.rev;
|
|
283
|
+
break;
|
|
207
284
|
case "claim-expired": state.revision = entry.rev;
|
|
208
285
|
}
|
|
209
286
|
}
|
|
@@ -271,6 +348,12 @@ function decodeActor(value) {
|
|
|
271
348
|
default: throw new Error(`actor field "kind" must be human, agent, or command (got ${JSON.stringify(actor.kind)})`);
|
|
272
349
|
}
|
|
273
350
|
}
|
|
351
|
+
function decodeOptionalServiceClass(record) {
|
|
352
|
+
const value = record.serviceClass;
|
|
353
|
+
if (value === void 0) return {};
|
|
354
|
+
if (!isServiceClass(value)) throw new Error(`created field "serviceClass" must be one of ${SERVICE_CLASSES.join(", ")} when present`);
|
|
355
|
+
return { serviceClass: value };
|
|
356
|
+
}
|
|
274
357
|
function decodeOptionalCardId(record, key) {
|
|
275
358
|
const value = record[key];
|
|
276
359
|
if (value === void 0) return {};
|
|
@@ -458,6 +541,6 @@ function rootOfCwd(cwd) {
|
|
|
458
541
|
return cwd === void 0 ? void 0 : join(cwd, ".devflow");
|
|
459
542
|
}
|
|
460
543
|
//#endregion
|
|
461
|
-
export { ARTIFACT_RECORD_SCHEMA, ARTIFACT_TRANSITION_INSPECTION_SCHEMA, DEV_STAGES, DevflowCardId, DevflowStore, DevflowStore as default, decodeJournalEntry, foldArtifactRecords, foldJournal, isCardLocation, isDevStage, isLegalTransition, isReworkEdge };
|
|
544
|
+
export { ARTIFACT_RECORD_SCHEMA, ARTIFACT_TRANSITION_INSPECTION_SCHEMA, DEFAULT_SERVICE_CLASS, DEV_STAGES, DevflowCardId, DevflowStore, DevflowStore as default, SERVICE_CLASSES, decodeJournalEntry, foldArtifactRecords, foldJournal, isCardLocation, isDevStage, isLegalTransition, isReworkEdge, isServiceClass };
|
|
462
545
|
|
|
463
546
|
//# sourceMappingURL=index.js.map
|
package/lib/types/index.d.ts
CHANGED
|
@@ -7,9 +7,10 @@
|
|
|
7
7
|
* @module @zhchxiao123/dsh-devflow
|
|
8
8
|
*/
|
|
9
9
|
import { Context, Service } from '@deepseek-ai/cordis';
|
|
10
|
-
import type { ArtifactRequest, ArtifactResult, CardFilter, ClaimHolder, ClaimOptions, ClaimResult, CreateRequest, CreateResult, CreateSpec, DevActor, DevCard, DevCardDetail, DevflowCardId, DevflowJournalEntry, TransitionRequest, TransitionResult, TransitionSpec } from './types.ts';
|
|
10
|
+
import type { AbandonRequest, AbandonResult, ArtifactRequest, ArtifactResult, CardFilter, ClaimHolder, ClaimOptions, ClaimResult, CreateRequest, CreateResult, CreateSpec, DevActor, DevCard, DevCardDetail, DevflowCardId, DevflowJournalEntry, TransitionRequest, TransitionResult, TransitionSpec } from './types.ts';
|
|
11
11
|
export type * from './types.ts';
|
|
12
|
-
export { DEV_STAGES, DevflowCardId, isCardLocation, isDevStage, isLegalTransition, isReworkEdge } from './stages.ts';
|
|
12
|
+
export { DEFAULT_SERVICE_CLASS, DEV_STAGES, DevflowCardId, SERVICE_CLASSES, isCardLocation, isDevStage, isLegalTransition, isReworkEdge, isServiceClass } from './stages.ts';
|
|
13
|
+
export type { TransitionContext } from './stages.ts';
|
|
13
14
|
export { decodeJournalEntry, foldArtifactRecords, foldJournal } from './journal.ts';
|
|
14
15
|
export type { JournalFoldState } from './journal.ts';
|
|
15
16
|
/** JSON Schema for the Definition-owned artifact registration record. */
|
|
@@ -237,6 +238,22 @@ export declare abstract class DevflowStore extends Service {
|
|
|
237
238
|
* @returns the outcome carrying the registered record; domain rejections resolve with `ok: false`.
|
|
238
239
|
*/
|
|
239
240
|
abstract attachArtifact(request: ArtifactRequest): Promise<ArtifactResult>;
|
|
241
|
+
/**
|
|
242
|
+
* Record that a card's work stops and take it off the active board.
|
|
243
|
+
*
|
|
244
|
+
* The journal append is the commit point; the card's directory then joins
|
|
245
|
+
* the archive. A crash between the two leaves an abandoned card under
|
|
246
|
+
* `tasks/`, so {@link list} must exclude it by its folded state rather than
|
|
247
|
+
* by where its directory sits.
|
|
248
|
+
*
|
|
249
|
+
* The reason is required — a card that disappears without one loses the
|
|
250
|
+
* decision it exists to record — and a `done` card is refused: a delivered
|
|
251
|
+
* outcome is settled by {@link archiveDone}, not overwritten by a decision
|
|
252
|
+
* not to deliver it.
|
|
253
|
+
* @param request - card, expected revision, actor, and the reason.
|
|
254
|
+
* @returns the outcome; domain rejections resolve with `ok: false`.
|
|
255
|
+
*/
|
|
256
|
+
abstract abandon(request: AbandonRequest): Promise<AbandonResult>;
|
|
240
257
|
/**
|
|
241
258
|
* Move every `done` card of one root out of the active set into that root's
|
|
242
259
|
* archive, keyed by the month of its last journal entry. Archived cards
|
package/lib/types/index.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
import { join } from 'node:path';
|
|
10
10
|
import { Service } from '@deepseek-ai/cordis';
|
|
11
11
|
import { DEV_STAGES } from "./stages.js";
|
|
12
|
-
export { DEV_STAGES, DevflowCardId, isCardLocation, isDevStage, isLegalTransition, isReworkEdge } from "./stages.js";
|
|
12
|
+
export { DEFAULT_SERVICE_CLASS, DEV_STAGES, DevflowCardId, SERVICE_CLASSES, isCardLocation, isDevStage, isLegalTransition, isReworkEdge, isServiceClass } from "./stages.js";
|
|
13
13
|
export { decodeJournalEntry, foldArtifactRecords, foldJournal } from "./journal.js";
|
|
14
14
|
/** JSON Schema for the Definition-owned artifact registration record. */
|
|
15
15
|
export const ARTIFACT_RECORD_SCHEMA = {
|
package/lib/types/journal.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* @module @zhchxiao123/dsh-devflow/src/journal
|
|
7
7
|
*/
|
|
8
8
|
import { DevflowCardId } from './stages.ts';
|
|
9
|
-
import type { ArtifactRecord, CardLocation, DevStage, DevflowJournalEntry } from './types.ts';
|
|
9
|
+
import type { ArtifactRecord, CardLocation, DevStage, DevflowJournalEntry, ServiceClass } from './types.ts';
|
|
10
10
|
/** Card state derived by {@link foldJournal}; the read-side authority. */
|
|
11
11
|
export interface JournalFoldState {
|
|
12
12
|
/** Current location after the last entry. */
|
|
@@ -17,6 +17,17 @@ export interface JournalFoldState {
|
|
|
17
17
|
blockedFrom?: DevStage;
|
|
18
18
|
/** The card this one decomposes, from the `created` entry; absent for a top-level card. */
|
|
19
19
|
parent?: DevflowCardId;
|
|
20
|
+
/**
|
|
21
|
+
* The card's service class, from the `created` entry. Always set: an entry
|
|
22
|
+
* that states none is a {@link DEFAULT_SERVICE_CLASS} card, so no read-side
|
|
23
|
+
* consumer branches on absence.
|
|
24
|
+
*/
|
|
25
|
+
serviceClass: ServiceClass;
|
|
26
|
+
/**
|
|
27
|
+
* Set once the card was abandoned. Terminal: no entry may follow, and the
|
|
28
|
+
* card is off the active board even while its directory awaits archiving.
|
|
29
|
+
*/
|
|
30
|
+
abandoned?: true;
|
|
20
31
|
/** Artifact paths in registration order. */
|
|
21
32
|
artifacts: string[];
|
|
22
33
|
}
|
|
@@ -37,7 +48,8 @@ export declare function decodeJournalEntry(value: unknown): DevflowJournalEntry;
|
|
|
37
48
|
* Validates the structural invariants of the durable stream: revisions are the
|
|
38
49
|
* contiguous sequence 1..n, the first entry is `created`, every transition
|
|
39
50
|
* departs from the current location, a move to `blocked` remembers its origin,
|
|
40
|
-
*
|
|
51
|
+
* the matching recovery returns exactly there, and nothing follows an
|
|
52
|
+
* `abandoned` entry.
|
|
41
53
|
* @param entries - decoded entries in file order.
|
|
42
54
|
* @returns the folded card state.
|
|
43
55
|
* @throws {Error} naming the first violated invariant and its entry revision.
|
package/lib/types/journal.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* entries through this module so every consumer derives identical state.
|
|
6
6
|
* @module @zhchxiao123/dsh-devflow/src/journal
|
|
7
7
|
*/
|
|
8
|
-
import { DEV_STAGES, DevflowCardId, isCardLocation, isDevStage } from "./stages.js";
|
|
8
|
+
import { DEFAULT_SERVICE_CLASS, DEV_STAGES, DevflowCardId, SERVICE_CLASSES, isCardLocation, isDevStage, isServiceClass } from "./stages.js";
|
|
9
9
|
/**
|
|
10
10
|
* Decode one parsed journal value into a {@link DevflowJournalEntry}.
|
|
11
11
|
*
|
|
@@ -36,6 +36,7 @@ export function decodeJournalEntry(value) {
|
|
|
36
36
|
type: 'created',
|
|
37
37
|
by: decodeActor(entry.by),
|
|
38
38
|
...decodeOptionalCardId(entry, 'parent'),
|
|
39
|
+
...decodeOptionalServiceClass(entry),
|
|
39
40
|
};
|
|
40
41
|
case 'transition': {
|
|
41
42
|
if (!isCardLocation(entry.from))
|
|
@@ -70,6 +71,18 @@ export function decodeJournalEntry(value) {
|
|
|
70
71
|
...decodeOptionalString(entry, 'kind'),
|
|
71
72
|
};
|
|
72
73
|
}
|
|
74
|
+
case 'abandoned': {
|
|
75
|
+
if (typeof entry.reason !== 'string' || entry.reason.trim().length === 0) {
|
|
76
|
+
throw new Error('abandoned field "reason" must be a non-empty string; a card leaving the board without one loses the decision');
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
rev,
|
|
80
|
+
at: entry.at,
|
|
81
|
+
type: 'abandoned',
|
|
82
|
+
by: decodeActor(entry.by),
|
|
83
|
+
reason: entry.reason,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
73
86
|
case 'claim-expired': {
|
|
74
87
|
if (entry.previousOwner === undefined) {
|
|
75
88
|
throw new Error('claim-expired field "previousOwner" is required');
|
|
@@ -83,7 +96,7 @@ export function decodeJournalEntry(value) {
|
|
|
83
96
|
};
|
|
84
97
|
}
|
|
85
98
|
default:
|
|
86
|
-
throw new Error(`journal entry field "type" must be created, transition, artifact, or claim-expired (got ${JSON.stringify(entry.type)})`);
|
|
99
|
+
throw new Error(`journal entry field "type" must be created, transition, artifact, abandoned, or claim-expired (got ${JSON.stringify(entry.type)})`);
|
|
87
100
|
}
|
|
88
101
|
}
|
|
89
102
|
/**
|
|
@@ -92,7 +105,8 @@ export function decodeJournalEntry(value) {
|
|
|
92
105
|
* Validates the structural invariants of the durable stream: revisions are the
|
|
93
106
|
* contiguous sequence 1..n, the first entry is `created`, every transition
|
|
94
107
|
* departs from the current location, a move to `blocked` remembers its origin,
|
|
95
|
-
*
|
|
108
|
+
* the matching recovery returns exactly there, and nothing follows an
|
|
109
|
+
* `abandoned` entry.
|
|
96
110
|
* @param entries - decoded entries in file order.
|
|
97
111
|
* @returns the folded card state.
|
|
98
112
|
* @throws {Error} naming the first violated invariant and its entry revision.
|
|
@@ -100,7 +114,7 @@ export function decodeJournalEntry(value) {
|
|
|
100
114
|
export function foldJournal(entries) {
|
|
101
115
|
if (entries.length === 0)
|
|
102
116
|
throw new Error('journal is empty; every card starts with a "created" entry');
|
|
103
|
-
const state = { stage: 'draft', revision: 0, artifacts: [] };
|
|
117
|
+
const state = { stage: 'draft', revision: 0, serviceClass: DEFAULT_SERVICE_CLASS, artifacts: [] };
|
|
104
118
|
for (const [index, entry] of entries.entries()) {
|
|
105
119
|
if (entry.rev !== index + 1) {
|
|
106
120
|
throw new Error(`journal entry ${index + 1} carries rev ${entry.rev}; revisions must be contiguous from 1`);
|
|
@@ -110,9 +124,14 @@ export function foldJournal(entries) {
|
|
|
110
124
|
throw new Error('journal entry 1 must be "created"');
|
|
111
125
|
if (entry.parent !== undefined)
|
|
112
126
|
state.parent = entry.parent;
|
|
127
|
+
if (entry.serviceClass !== undefined)
|
|
128
|
+
state.serviceClass = entry.serviceClass;
|
|
113
129
|
state.revision = entry.rev;
|
|
114
130
|
continue;
|
|
115
131
|
}
|
|
132
|
+
if (state.abandoned === true) {
|
|
133
|
+
throw new Error(`journal entry rev ${entry.rev} follows an abandoned card; abandoning is terminal`);
|
|
134
|
+
}
|
|
116
135
|
switch (entry.type) {
|
|
117
136
|
case 'created':
|
|
118
137
|
throw new Error(`journal entry rev ${entry.rev} repeats "created"`);
|
|
@@ -142,6 +161,10 @@ export function foldJournal(entries) {
|
|
|
142
161
|
state.artifacts.push(entry.path);
|
|
143
162
|
state.revision = entry.rev;
|
|
144
163
|
break;
|
|
164
|
+
case 'abandoned':
|
|
165
|
+
state.abandoned = true;
|
|
166
|
+
state.revision = entry.rev;
|
|
167
|
+
break;
|
|
145
168
|
case 'claim-expired':
|
|
146
169
|
state.revision = entry.rev;
|
|
147
170
|
break;
|
|
@@ -215,6 +238,15 @@ function decodeActor(value) {
|
|
|
215
238
|
throw new Error(`actor field "kind" must be human, agent, or command (got ${JSON.stringify(actor.kind)})`);
|
|
216
239
|
}
|
|
217
240
|
}
|
|
241
|
+
function decodeOptionalServiceClass(record) {
|
|
242
|
+
const value = record.serviceClass;
|
|
243
|
+
if (value === undefined)
|
|
244
|
+
return {};
|
|
245
|
+
if (!isServiceClass(value)) {
|
|
246
|
+
throw new Error(`created field "serviceClass" must be one of ${SERVICE_CLASSES.join(', ')} when present`);
|
|
247
|
+
}
|
|
248
|
+
return { serviceClass: value };
|
|
249
|
+
}
|
|
218
250
|
function decodeOptionalCardId(record, key) {
|
|
219
251
|
const value = record[key];
|
|
220
252
|
if (value === undefined)
|
package/lib/types/stages.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* @module @zhchxiao123/dsh-devflow/src/stages
|
|
6
6
|
*/
|
|
7
7
|
import type { Branded } from '@deepseek-ai/dsh-brand';
|
|
8
|
-
import type { CardLocation, DevStage } from './types.ts';
|
|
8
|
+
import type { CardLocation, DevStage, ServiceClass } from './types.ts';
|
|
9
9
|
/** Opaque id of one task card; equals the card's directory name and never changes. */
|
|
10
10
|
export type DevflowCardId = Branded<'DevflowCardId'>;
|
|
11
11
|
/** The pipeline stages in flow order; `blocked` is a bypass, not a member. */
|
|
@@ -22,6 +22,25 @@ export declare function isDevStage(value: unknown): value is DevStage;
|
|
|
22
22
|
* @returns `true` when `value` is a stage or the `blocked` bypass.
|
|
23
23
|
*/
|
|
24
24
|
export declare function isCardLocation(value: unknown): value is CardLocation;
|
|
25
|
+
/**
|
|
26
|
+
* The service classes, in ascending order of what they skip.
|
|
27
|
+
*
|
|
28
|
+
* Closed vocabulary rather than a plugin `Config` field, on the same grounds as
|
|
29
|
+
* {@link DEV_STAGES}: the board, both language documents, and the agent's
|
|
30
|
+
* prompts all reference these names, and a deployment-defined class would make
|
|
31
|
+
* every one of those references local. Letting a deployment mint its own
|
|
32
|
+
* shorter class is also precisely the failure mode this vocabulary exists to
|
|
33
|
+
* prevent — see the service-class Agent Note.
|
|
34
|
+
*/
|
|
35
|
+
export declare const SERVICE_CLASSES: readonly ["standard", "express", "emergency"];
|
|
36
|
+
/** The class of a card that declares none, on disk and in memory. */
|
|
37
|
+
export declare const DEFAULT_SERVICE_CLASS: ServiceClass;
|
|
38
|
+
/**
|
|
39
|
+
* Narrow an unknown value to a service class.
|
|
40
|
+
* @param value - the candidate value.
|
|
41
|
+
* @returns `true` when `value` is one of {@link SERVICE_CLASSES}.
|
|
42
|
+
*/
|
|
43
|
+
export declare function isServiceClass(value: unknown): value is ServiceClass;
|
|
25
44
|
/**
|
|
26
45
|
* Brand a raw string as a {@link DevflowCardId}. The id equals the card's
|
|
27
46
|
* directory name; construction lives here because this package owns the brand.
|
|
@@ -29,25 +48,41 @@ export declare function isCardLocation(value: unknown): value is CardLocation;
|
|
|
29
48
|
* @returns the branded id.
|
|
30
49
|
*/
|
|
31
50
|
export declare function DevflowCardId(value: string): DevflowCardId;
|
|
51
|
+
/** A card's own contribution to edge legality; {@link DevCard} satisfies it. */
|
|
52
|
+
export interface TransitionContext {
|
|
53
|
+
/** The remembered origin stage while the card sits at `blocked`. */
|
|
54
|
+
blockedFrom?: DevStage;
|
|
55
|
+
/** The card's service class; omitted is {@link DEFAULT_SERVICE_CLASS}. */
|
|
56
|
+
serviceClass?: ServiceClass;
|
|
57
|
+
}
|
|
32
58
|
/**
|
|
33
59
|
* Whether one stage move is a legal edge of the state machine.
|
|
34
60
|
*
|
|
35
61
|
* Main flow follows the pipeline order; `reviewing` and `testing` may rework
|
|
36
|
-
* to `developing
|
|
37
|
-
*
|
|
62
|
+
* to `developing` or `designing` and `developing` may rework to `designing`;
|
|
63
|
+
* any non-terminal location may enter `blocked`; a blocked card may only
|
|
64
|
+
* recover to the exact stage it interrupted. A card's service class adds the
|
|
65
|
+
* shortcuts in {@link CLASS_EXTRA} and takes nothing away.
|
|
66
|
+
*
|
|
67
|
+
* `blocked` legality does not vary by class: a shortcut is about which stages
|
|
68
|
+
* a card may skip, not about how it pauses.
|
|
38
69
|
* @param from - the card's current location.
|
|
39
70
|
* @param to - the requested target location.
|
|
40
|
-
* @param
|
|
71
|
+
* @param card - the moving card's own context; omitted reads as a `standard`
|
|
72
|
+
* card that is not blocked.
|
|
41
73
|
* @returns `true` when the move is a legal edge.
|
|
42
74
|
*/
|
|
43
|
-
export declare function isLegalTransition(from: CardLocation, to: CardLocation,
|
|
75
|
+
export declare function isLegalTransition(from: CardLocation, to: CardLocation, card?: TransitionContext): boolean;
|
|
44
76
|
/**
|
|
45
77
|
* Whether a legal edge moves the card backwards (a rework). Rework edges
|
|
46
|
-
* require a recorded `reason` so the next holder knows what to fix
|
|
78
|
+
* require a recorded `reason` so the next holder knows what to fix — on
|
|
79
|
+
* `developing -> designing` that reason is what implementing the design
|
|
80
|
+
* revealed about it, which is the whole point of routing the card back rather
|
|
81
|
+
* than redesigning in place.
|
|
47
82
|
* @param from - the departing location.
|
|
48
83
|
* @param to - the target location.
|
|
49
84
|
* @returns `true` for a move from `reviewing` or `testing` back to
|
|
50
|
-
* `developing` or `designing`.
|
|
85
|
+
* `developing` or `designing`, and for `developing` back to `designing`.
|
|
51
86
|
*/
|
|
52
87
|
export declare function isReworkEdge(from: CardLocation, to: CardLocation): boolean;
|
|
53
88
|
//# sourceMappingURL=stages.d.ts.map
|
package/lib/types/stages.js
CHANGED
|
@@ -30,6 +30,27 @@ export function isDevStage(value) {
|
|
|
30
30
|
export function isCardLocation(value) {
|
|
31
31
|
return value === 'blocked' || isDevStage(value);
|
|
32
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* The service classes, in ascending order of what they skip.
|
|
35
|
+
*
|
|
36
|
+
* Closed vocabulary rather than a plugin `Config` field, on the same grounds as
|
|
37
|
+
* {@link DEV_STAGES}: the board, both language documents, and the agent's
|
|
38
|
+
* prompts all reference these names, and a deployment-defined class would make
|
|
39
|
+
* every one of those references local. Letting a deployment mint its own
|
|
40
|
+
* shorter class is also precisely the failure mode this vocabulary exists to
|
|
41
|
+
* prevent — see the service-class Agent Note.
|
|
42
|
+
*/
|
|
43
|
+
export const SERVICE_CLASSES = ['standard', 'express', 'emergency'];
|
|
44
|
+
/** The class of a card that declares none, on disk and in memory. */
|
|
45
|
+
export const DEFAULT_SERVICE_CLASS = 'standard';
|
|
46
|
+
/**
|
|
47
|
+
* Narrow an unknown value to a service class.
|
|
48
|
+
* @param value - the candidate value.
|
|
49
|
+
* @returns `true` when `value` is one of {@link SERVICE_CLASSES}.
|
|
50
|
+
*/
|
|
51
|
+
export function isServiceClass(value) {
|
|
52
|
+
return typeof value === 'string' && SERVICE_CLASSES.includes(value);
|
|
53
|
+
}
|
|
33
54
|
/**
|
|
34
55
|
* Brand a raw string as a {@link DevflowCardId}. The id equals the card's
|
|
35
56
|
* directory name; construction lives here because this package owns the brand.
|
|
@@ -48,45 +69,75 @@ export function DevflowCardId(value) {
|
|
|
48
69
|
* is. Without the second, design rework happens on a card labelled
|
|
49
70
|
* `developing`, and the board stops answering the one question it exists to
|
|
50
71
|
* answer.
|
|
72
|
+
*
|
|
73
|
+
* `developing` reaches `designing` for the same reason, from the stage that
|
|
74
|
+
* finds such faults most often. Its absence left `developing → reviewing →
|
|
75
|
+
* designing` as the only route back, which records a review that never
|
|
76
|
+
* happened in the authoritative journal to reach the stage owning the fault.
|
|
51
77
|
*/
|
|
52
78
|
const FLOW = {
|
|
53
79
|
draft: ['designing'],
|
|
54
80
|
designing: ['ready'],
|
|
55
81
|
ready: ['developing'],
|
|
56
|
-
developing: ['reviewing'],
|
|
82
|
+
developing: ['reviewing', 'designing'],
|
|
57
83
|
reviewing: ['testing', 'developing', 'designing'],
|
|
58
84
|
testing: ['done', 'developing', 'designing'],
|
|
59
85
|
done: [],
|
|
60
86
|
};
|
|
87
|
+
/**
|
|
88
|
+
* Edges each service class adds to {@link FLOW}, and the only place a class
|
|
89
|
+
* differs from another. Stated as additions rather than as one whole graph per
|
|
90
|
+
* class so "every class is a superset of `standard`" is a property of the code
|
|
91
|
+
* instead of a convention: a class cannot remove an edge, and therefore cannot
|
|
92
|
+
* make a journal that replays today stop replaying.
|
|
93
|
+
*/
|
|
94
|
+
const CLASS_EXTRA = {
|
|
95
|
+
standard: {},
|
|
96
|
+
express: { draft: ['developing'], reviewing: ['done'] },
|
|
97
|
+
emergency: { draft: ['developing'], developing: ['done'] },
|
|
98
|
+
};
|
|
61
99
|
/**
|
|
62
100
|
* Whether one stage move is a legal edge of the state machine.
|
|
63
101
|
*
|
|
64
102
|
* Main flow follows the pipeline order; `reviewing` and `testing` may rework
|
|
65
|
-
* to `developing
|
|
66
|
-
*
|
|
103
|
+
* to `developing` or `designing` and `developing` may rework to `designing`;
|
|
104
|
+
* any non-terminal location may enter `blocked`; a blocked card may only
|
|
105
|
+
* recover to the exact stage it interrupted. A card's service class adds the
|
|
106
|
+
* shortcuts in {@link CLASS_EXTRA} and takes nothing away.
|
|
107
|
+
*
|
|
108
|
+
* `blocked` legality does not vary by class: a shortcut is about which stages
|
|
109
|
+
* a card may skip, not about how it pauses.
|
|
67
110
|
* @param from - the card's current location.
|
|
68
111
|
* @param to - the requested target location.
|
|
69
|
-
* @param
|
|
112
|
+
* @param card - the moving card's own context; omitted reads as a `standard`
|
|
113
|
+
* card that is not blocked.
|
|
70
114
|
* @returns `true` when the move is a legal edge.
|
|
71
115
|
*/
|
|
72
|
-
export function isLegalTransition(from, to,
|
|
116
|
+
export function isLegalTransition(from, to, card) {
|
|
73
117
|
if (from === to)
|
|
74
118
|
return false;
|
|
75
119
|
if (from === 'blocked')
|
|
76
|
-
return to === blockedFrom;
|
|
120
|
+
return to === card?.blockedFrom;
|
|
77
121
|
if (to === 'blocked')
|
|
78
122
|
return from !== 'done';
|
|
79
|
-
|
|
123
|
+
if (FLOW[from].includes(to))
|
|
124
|
+
return true;
|
|
125
|
+
return (CLASS_EXTRA[card?.serviceClass ?? DEFAULT_SERVICE_CLASS][from] ?? []).includes(to);
|
|
80
126
|
}
|
|
81
127
|
/**
|
|
82
128
|
* Whether a legal edge moves the card backwards (a rework). Rework edges
|
|
83
|
-
* require a recorded `reason` so the next holder knows what to fix
|
|
129
|
+
* require a recorded `reason` so the next holder knows what to fix — on
|
|
130
|
+
* `developing -> designing` that reason is what implementing the design
|
|
131
|
+
* revealed about it, which is the whole point of routing the card back rather
|
|
132
|
+
* than redesigning in place.
|
|
84
133
|
* @param from - the departing location.
|
|
85
134
|
* @param to - the target location.
|
|
86
135
|
* @returns `true` for a move from `reviewing` or `testing` back to
|
|
87
|
-
* `developing` or `designing`.
|
|
136
|
+
* `developing` or `designing`, and for `developing` back to `designing`.
|
|
88
137
|
*/
|
|
89
138
|
export function isReworkEdge(from, to) {
|
|
90
|
-
|
|
139
|
+
if (to === 'designing')
|
|
140
|
+
return from === 'developing' || from === 'reviewing' || from === 'testing';
|
|
141
|
+
return to === 'developing' && (from === 'reviewing' || from === 'testing');
|
|
91
142
|
}
|
|
92
143
|
//# sourceMappingURL=stages.js.map
|
package/lib/types/types.d.ts
CHANGED
|
@@ -47,6 +47,20 @@ declare module '@deepseek-ai/cordis' {
|
|
|
47
47
|
export type DevStage = 'draft' | 'designing' | 'ready' | 'developing' | 'reviewing' | 'testing' | 'done';
|
|
48
48
|
/** Where a card currently sits: a pipeline stage, or the `blocked` bypass. */
|
|
49
49
|
export type CardLocation = DevStage | 'blocked';
|
|
50
|
+
/**
|
|
51
|
+
* The closed set of service classes a card is created under, each selecting
|
|
52
|
+
* which edges of the pipeline that card may take. Every class is a superset of
|
|
53
|
+
* `standard`, so a class only ever adds a shortcut.
|
|
54
|
+
*
|
|
55
|
+
* - `standard` — the full pipeline; the class of a card that declares none.
|
|
56
|
+
* - `express` — reaches `developing` from `draft` and `done` from
|
|
57
|
+
* `reviewing`, skipping design, readiness, and independent verification.
|
|
58
|
+
* Peer review stays: it is the control worth keeping on cheap work.
|
|
59
|
+
* - `emergency` — reaches `developing` from `draft` and `done` from
|
|
60
|
+
* `developing`. It gives up review too, and the follow-up is an ordinary
|
|
61
|
+
* card rather than an obligation encoded in the state machine.
|
|
62
|
+
*/
|
|
63
|
+
export type ServiceClass = 'standard' | 'express' | 'emergency';
|
|
50
64
|
/** Who performed a journal action; `command` marks the human-command intervention plane. */
|
|
51
65
|
export type DevActor = {
|
|
52
66
|
kind: 'human';
|
|
@@ -66,6 +80,12 @@ export interface JournalCreated {
|
|
|
66
80
|
by: DevActor;
|
|
67
81
|
/** The card this one decomposes, fixed here at creation and never changed. */
|
|
68
82
|
parent?: DevflowCardId;
|
|
83
|
+
/**
|
|
84
|
+
* The card's service class, fixed here at creation and never changed.
|
|
85
|
+
* Omitted is `standard`, so a journal written before classes existed reads
|
|
86
|
+
* as one and a `standard` card's first entry keeps its original bytes.
|
|
87
|
+
*/
|
|
88
|
+
serviceClass?: ServiceClass;
|
|
69
89
|
}
|
|
70
90
|
/**
|
|
71
91
|
* One recorded gate verdict on a committed transition: which actor allowed the
|
|
@@ -115,6 +135,23 @@ export interface JournalArtifact {
|
|
|
115
135
|
*/
|
|
116
136
|
kind?: string;
|
|
117
137
|
}
|
|
138
|
+
/**
|
|
139
|
+
* The decision to stop: this card will never be finished. Terminal — no entry
|
|
140
|
+
* may follow it — and the card leaves the active board rather than occupying
|
|
141
|
+
* a stage nobody is working in.
|
|
142
|
+
*/
|
|
143
|
+
export interface JournalAbandoned {
|
|
144
|
+
rev: number;
|
|
145
|
+
at: string;
|
|
146
|
+
type: 'abandoned';
|
|
147
|
+
by: DevActor;
|
|
148
|
+
/**
|
|
149
|
+
* Why the work stopped. Required, unlike a transition's reason: a transition
|
|
150
|
+
* leaves the card visible and explicable from where it sits, while this
|
|
151
|
+
* removes it from the board, so the reason is all that is left of it.
|
|
152
|
+
*/
|
|
153
|
+
reason: string;
|
|
154
|
+
}
|
|
118
155
|
/** Takeover of a stale lease: the previous holder's heartbeat lapsed. */
|
|
119
156
|
export interface JournalClaimExpired {
|
|
120
157
|
rev: number;
|
|
@@ -124,7 +161,7 @@ export interface JournalClaimExpired {
|
|
|
124
161
|
by: DevActor;
|
|
125
162
|
}
|
|
126
163
|
/** The journal entry union; the discriminant is `type`. */
|
|
127
|
-
export type DevflowJournalEntry = JournalCreated | JournalTransition | JournalArtifact | JournalClaimExpired;
|
|
164
|
+
export type DevflowJournalEntry = JournalCreated | JournalTransition | JournalArtifact | JournalAbandoned | JournalClaimExpired;
|
|
128
165
|
/**
|
|
129
166
|
* Read-side value of one artifact registration: the journal entry's facts
|
|
130
167
|
* without its envelope. Registrations are immutable — the newest record of one
|
|
@@ -158,6 +195,16 @@ export interface DevCard {
|
|
|
158
195
|
* exists, so a card carrying `parent` is never itself a parent.
|
|
159
196
|
*/
|
|
160
197
|
parent?: DevflowCardId;
|
|
198
|
+
/**
|
|
199
|
+
* The card's service class, selecting which pipeline edges it may take.
|
|
200
|
+
* Always present: a card whose journal states none is `standard`.
|
|
201
|
+
*/
|
|
202
|
+
serviceClass: ServiceClass;
|
|
203
|
+
/**
|
|
204
|
+
* Set once the card was abandoned: the work stopped and will not resume.
|
|
205
|
+
* Such a card is off the active board, so `list` never reports one.
|
|
206
|
+
*/
|
|
207
|
+
abandoned?: true;
|
|
161
208
|
/** Markdown body of the card file below its frontmatter. */
|
|
162
209
|
body: string;
|
|
163
210
|
/** Display path of the card file. */
|
|
@@ -215,6 +262,12 @@ export interface CreateRequest {
|
|
|
215
262
|
* must be an active top-level card of the same root — only one level exists.
|
|
216
263
|
*/
|
|
217
264
|
parent?: DevflowCardId;
|
|
265
|
+
/**
|
|
266
|
+
* Which pipeline edges the card may take, fixed here and never changed —
|
|
267
|
+
* escalating live work means a new card, not a mutated one. Omitted is
|
|
268
|
+
* `standard`, the full pipeline.
|
|
269
|
+
*/
|
|
270
|
+
serviceClass?: ServiceClass;
|
|
218
271
|
/** Devflow root receiving the card; omitted uses the implementation's default root. */
|
|
219
272
|
root?: string;
|
|
220
273
|
}
|
|
@@ -307,6 +360,35 @@ export type TransitionResult = {
|
|
|
307
360
|
code: TransitionRejectionCode;
|
|
308
361
|
message: string;
|
|
309
362
|
};
|
|
363
|
+
/** Caller view of one abandonment: the decision that this card stops here. */
|
|
364
|
+
export interface AbandonRequest {
|
|
365
|
+
id: DevflowCardId;
|
|
366
|
+
/** Optimistic-concurrency token: the `stageRevision` the caller last observed. */
|
|
367
|
+
expectedRevision: number;
|
|
368
|
+
by: DevActor;
|
|
369
|
+
/** Why the work stopped; blank is rejected rather than recorded as nothing. */
|
|
370
|
+
reason: string;
|
|
371
|
+
/** Devflow root holding the card; omitted uses the implementation's default root. */
|
|
372
|
+
root?: string;
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Stable rejection codes of {@link AbandonResult}. `already-done` names the one
|
|
376
|
+
* card that must not be abandoned: a delivered outcome is not a decision to
|
|
377
|
+
* stop, and `archiveDone` is what settles it.
|
|
378
|
+
*/
|
|
379
|
+
export type AbandonRejectionCode = 'empty-reason' | 'already-done' | 'revision-mismatch' | 'write-contended';
|
|
380
|
+
/**
|
|
381
|
+
* Outcome of one abandonment. Domain rejections resolve with a stable code;
|
|
382
|
+
* only infrastructure failures reject the promise.
|
|
383
|
+
*/
|
|
384
|
+
export type AbandonResult = {
|
|
385
|
+
ok: true;
|
|
386
|
+
card: DevCard;
|
|
387
|
+
} | {
|
|
388
|
+
ok: false;
|
|
389
|
+
code: AbandonRejectionCode;
|
|
390
|
+
message: string;
|
|
391
|
+
};
|
|
310
392
|
/** Fields shared by both {@link ArtifactRequest} forms. */
|
|
311
393
|
interface ArtifactRequestBase {
|
|
312
394
|
id: DevflowCardId;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhchxiao123/dsh-devflow",
|
|
3
3
|
"description": "Service Definition for the ctx.devflow task-card capability seam of the DeepSeek Harness",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.4.0-dev.0",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -46,16 +46,16 @@
|
|
|
46
46
|
"zod": "^4.4.3"
|
|
47
47
|
},
|
|
48
48
|
"peerDependencies": {
|
|
49
|
-
"@deepseek-ai/cordis": "4.0.
|
|
50
|
-
"@deepseek-ai/dsh-brand": "0.1.
|
|
51
|
-
"@deepseek-ai/dsh-invariants": "0.1.
|
|
49
|
+
"@deepseek-ai/cordis": "4.0.2",
|
|
50
|
+
"@deepseek-ai/dsh-brand": "0.1.2-alpha.3",
|
|
51
|
+
"@deepseek-ai/dsh-invariants": "0.1.2-alpha.3"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
|
-
"@deepseek-ai/cordis": "4.0.
|
|
55
|
-
"@deepseek-ai/dsh-brand": "0.1.
|
|
56
|
-
"@deepseek-ai/dsh-invariants": "0.1.
|
|
57
|
-
"@deepseek-ai/dsh-session": "0.1.
|
|
58
|
-
"@deepseek-ai/dsh-session-persistence": "0.1.
|
|
54
|
+
"@deepseek-ai/cordis": "4.0.2",
|
|
55
|
+
"@deepseek-ai/dsh-brand": "0.1.2-alpha.3",
|
|
56
|
+
"@deepseek-ai/dsh-invariants": "0.1.2-alpha.3",
|
|
57
|
+
"@deepseek-ai/dsh-session": "0.1.2-alpha.3",
|
|
58
|
+
"@deepseek-ai/dsh-session-persistence": "0.1.2-alpha.3"
|
|
59
59
|
},
|
|
60
60
|
"scripts": {}
|
|
61
61
|
}
|