@owlmeans/viable-common 0.0.19 → 0.0.20
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.md +2 -2
- package/agent-meta/manifest.json +2 -2
- package/agent-meta/skills/agent-presentation/SKILL.md +1 -1
- package/agent-meta/skills/viable-common/SKILL.md +195 -10
- package/build/ba/consts.d.ts +2 -3
- package/build/ba/consts.d.ts.map +1 -1
- package/build/ba/consts.js +2 -3
- package/build/ba/consts.js.map +1 -1
- package/build/ba/helpers.d.ts +2 -1
- package/build/ba/helpers.d.ts.map +1 -1
- package/build/ba/helpers.js +3 -2
- package/build/ba/helpers.js.map +1 -1
- package/build/ba/types.d.ts +17 -2
- package/build/ba/types.d.ts.map +1 -1
- package/build/connect/consts.d.ts +5 -8
- package/build/connect/consts.d.ts.map +1 -1
- package/build/connect/consts.js +5 -8
- package/build/connect/consts.js.map +1 -1
- package/build/connect/entrypoints.d.ts +1 -43
- package/build/connect/entrypoints.d.ts.map +1 -1
- package/build/connect/entrypoints.js +1 -18
- package/build/connect/entrypoints.js.map +1 -1
- package/build/connect/index.d.ts +1 -0
- package/build/connect/index.d.ts.map +1 -1
- package/build/connect/index.js +1 -0
- package/build/connect/index.js.map +1 -1
- package/build/connect/jobs.d.ts +25 -0
- package/build/connect/jobs.d.ts.map +1 -0
- package/build/connect/jobs.js +29 -0
- package/build/connect/jobs.js.map +1 -0
- package/build/connect/references.d.ts +1 -40
- package/build/connect/references.d.ts.map +1 -1
- package/build/connect/references.js +0 -8
- package/build/connect/references.js.map +1 -1
- package/build/connect/schemas.d.ts +1 -7
- package/build/connect/schemas.d.ts.map +1 -1
- package/build/connect/schemas.js +1 -25
- package/build/connect/schemas.js.map +1 -1
- package/build/connect/types.d.ts +30 -45
- package/build/connect/types.d.ts.map +1 -1
- package/build/design/consts.d.ts +0 -2
- package/build/design/consts.d.ts.map +1 -1
- package/build/design/consts.js +0 -2
- package/build/design/consts.js.map +1 -1
- package/build/design/helpers.d.ts +6 -2
- package/build/design/helpers.d.ts.map +1 -1
- package/build/design/helpers.js +6 -2
- package/build/design/helpers.js.map +1 -1
- package/build/design/types.d.ts +12 -11
- package/build/design/types.d.ts.map +1 -1
- package/build/execution/types.d.ts +11 -0
- package/build/execution/types.d.ts.map +1 -1
- package/build/index.d.ts +1 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +1 -0
- package/build/index.js.map +1 -1
- package/build/planning/consts.d.ts +141 -0
- package/build/planning/consts.d.ts.map +1 -0
- package/build/planning/consts.js +170 -0
- package/build/planning/consts.js.map +1 -0
- package/build/planning/errors.d.ts +64 -0
- package/build/planning/errors.d.ts.map +1 -0
- package/build/planning/errors.js +99 -0
- package/build/planning/errors.js.map +1 -0
- package/build/planning/flows.d.ts +34 -0
- package/build/planning/flows.d.ts.map +1 -0
- package/build/planning/flows.js +174 -0
- package/build/planning/flows.js.map +1 -0
- package/build/planning/helpers.d.ts +54 -0
- package/build/planning/helpers.d.ts.map +1 -0
- package/build/planning/helpers.js +101 -0
- package/build/planning/helpers.js.map +1 -0
- package/build/planning/index.d.ts +7 -0
- package/build/planning/index.d.ts.map +1 -0
- package/build/planning/index.js +6 -0
- package/build/planning/index.js.map +1 -0
- package/build/planning/schemas.d.ts +23 -0
- package/build/planning/schemas.d.ts.map +1 -0
- package/build/planning/schemas.js +65 -0
- package/build/planning/schemas.js.map +1 -0
- package/build/planning/types.d.ts +70 -0
- package/build/planning/types.d.ts.map +1 -0
- package/build/planning/types.js +2 -0
- package/build/planning/types.js.map +1 -0
- package/build/scaffold/schemas.d.ts.map +1 -1
- package/build/scaffold/schemas.js +7 -2
- package/build/scaffold/schemas.js.map +1 -1
- package/build/scaffold/types.d.ts +5 -1
- package/build/scaffold/types.d.ts.map +1 -1
- package/package.json +3 -1
- package/src/ba/consts.ts +2 -3
- package/src/ba/helpers.ts +3 -2
- package/src/ba/types.ts +17 -2
- package/src/connect/consts.ts +5 -8
- package/src/connect/entrypoints.ts +2 -41
- package/src/connect/index.ts +1 -0
- package/src/connect/jobs.ts +40 -0
- package/src/connect/references.ts +1 -22
- package/src/connect/schemas.ts +2 -29
- package/src/connect/types.ts +30 -51
- package/src/design/consts.ts +0 -3
- package/src/design/helpers.ts +6 -2
- package/src/design/types.ts +12 -11
- package/src/execution/types.ts +11 -0
- package/src/index.ts +1 -0
- package/src/planning/consts.ts +182 -0
- package/src/planning/errors.ts +117 -0
- package/src/planning/flows.ts +204 -0
- package/src/planning/helpers.ts +133 -0
- package/src/planning/index.ts +6 -0
- package/src/planning/schemas.ts +70 -0
- package/src/planning/types.ts +75 -0
- package/src/scaffold/schemas.ts +7 -2
- package/src/scaffold/types.ts +10 -1
- package/tests/branding.spec.ts +37 -0
- package/tests/connect-entrypoints.spec.ts +35 -3
- package/tests/design.spec.ts +3 -3
- package/tests/planning.spec.ts +356 -0
package/src/connect/types.ts
CHANGED
|
@@ -86,15 +86,24 @@ export interface ConnectSessionView {
|
|
|
86
86
|
* A derived view of "what the platform is doing for this project right now".
|
|
87
87
|
*
|
|
88
88
|
* Never stored. It is composed per request from the project lock, the slot record, the story
|
|
89
|
-
*
|
|
89
|
+
* card, the latest pipeline run row and the operations queued for the project — the same facts
|
|
90
90
|
* the manager UI reads, arranged for a caller that has one question ("may I stop waiting?") and
|
|
91
91
|
* one follow-up ("what do I call next?").
|
|
92
|
+
*
|
|
93
|
+
* Its `id` is composed and parsed only through `jobIdOf` / `parseJobId`.
|
|
92
94
|
*/
|
|
93
95
|
export interface ConnectJob {
|
|
94
96
|
id: string
|
|
95
97
|
kind: ConnectJobKind
|
|
96
98
|
status: ConnectJobStatus
|
|
99
|
+
/** The project CARD id. */
|
|
97
100
|
projectId: string
|
|
101
|
+
/**
|
|
102
|
+
* The story CARD id — never the story's code.
|
|
103
|
+
*
|
|
104
|
+
* The name is kept because a parent agent reads it: a wire field name is that agent's
|
|
105
|
+
* vocabulary and is never renamed, only re-documented.
|
|
106
|
+
*/
|
|
98
107
|
storyId?: string
|
|
99
108
|
runId?: string
|
|
100
109
|
/** The pipeline step in flight, when a run row says. */
|
|
@@ -137,43 +146,27 @@ export interface ConnectWaitQuery {
|
|
|
137
146
|
wait?: number
|
|
138
147
|
}
|
|
139
148
|
|
|
140
|
-
/** Paging and filtering for the story list a connector reads. */
|
|
141
|
-
export interface ConnectStoryQuery {
|
|
142
|
-
page?: number
|
|
143
|
-
size?: number
|
|
144
|
-
status?: string
|
|
145
|
-
area?: string
|
|
146
|
-
/** Free-text match against the story narrative and its code. */
|
|
147
|
-
q?: string
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
export interface ConnectStoryList {
|
|
151
|
-
items: ConnectStoryItem[]
|
|
152
|
-
page: number
|
|
153
|
-
size: number
|
|
154
|
-
total: number
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
export interface ConnectStoryItem {
|
|
158
|
-
id: string
|
|
159
|
-
code?: string
|
|
160
|
-
story: string
|
|
161
|
-
area?: string
|
|
162
|
-
status: string
|
|
163
|
-
primary: boolean
|
|
164
|
-
warning?: string
|
|
165
|
-
createdAt: string
|
|
166
|
-
}
|
|
167
|
-
|
|
168
149
|
/** What a connector needs to know about a project in one call. */
|
|
169
150
|
export interface ConnectProjectStatus {
|
|
151
|
+
/**
|
|
152
|
+
* The project card, flattened into the names a parent agent already reads.
|
|
153
|
+
*
|
|
154
|
+
* `name` is the card's `title` and `alias` its `code`; the three brief parts are the bodies of
|
|
155
|
+
* the project's `specification`, `vision` and `design-system` specifications. `status` and
|
|
156
|
+
* `intrinsic` are the card's own — a key of the project flow and the intrinsic state it maps to —
|
|
157
|
+
* typed as plain strings because this view crosses a version skew and a newer platform may
|
|
158
|
+
* answer with a status an older connector has never heard of.
|
|
159
|
+
*/
|
|
170
160
|
project: {
|
|
171
161
|
id: string
|
|
172
162
|
name: string
|
|
173
163
|
alias: string
|
|
174
164
|
description?: string
|
|
165
|
+
status: string
|
|
166
|
+
intrinsic: string
|
|
175
167
|
specification?: string
|
|
176
168
|
vision?: string
|
|
169
|
+
designSystem?: string
|
|
177
170
|
}
|
|
178
171
|
slot?: {
|
|
179
172
|
id: string
|
|
@@ -297,12 +290,19 @@ export interface ConnectCreateBody {
|
|
|
297
290
|
target?: ConnectTarget
|
|
298
291
|
}
|
|
299
292
|
|
|
300
|
-
/**
|
|
293
|
+
/**
|
|
294
|
+
* Confirm a drafted project, optionally editing what the analysis produced.
|
|
295
|
+
*
|
|
296
|
+
* The keys are a parent agent's vocabulary and stay as they are: `name` becomes the card's
|
|
297
|
+
* `title`, and each brief part present is written into the project's specification of that
|
|
298
|
+
* category before the confirm transition runs.
|
|
299
|
+
*/
|
|
301
300
|
export interface ConnectConfirmBody {
|
|
302
301
|
name?: string
|
|
303
302
|
description?: string
|
|
304
303
|
specification?: string
|
|
305
304
|
vision?: string
|
|
305
|
+
designSystem?: string
|
|
306
306
|
target?: ConnectTarget
|
|
307
307
|
}
|
|
308
308
|
|
|
@@ -310,10 +310,6 @@ export interface ConnectModifyBody {
|
|
|
310
310
|
prompt: string
|
|
311
311
|
}
|
|
312
312
|
|
|
313
|
-
export interface ConnectStoryBody {
|
|
314
|
-
story: string
|
|
315
|
-
}
|
|
316
|
-
|
|
317
313
|
export interface ConnectPipelineParams {
|
|
318
314
|
id: string
|
|
319
315
|
runId: string
|
|
@@ -419,23 +415,6 @@ export interface ConnectProjectSummary {
|
|
|
419
415
|
alias: string
|
|
420
416
|
}
|
|
421
417
|
|
|
422
|
-
/** A story item returned after creating, editing or fetching one story. */
|
|
423
|
-
export interface ConnectStoryMutation {
|
|
424
|
-
id: string
|
|
425
|
-
code?: string
|
|
426
|
-
story: string
|
|
427
|
-
area?: string
|
|
428
|
-
status: string
|
|
429
|
-
primary: boolean
|
|
430
|
-
warning?: string
|
|
431
|
-
createdAt: string
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
/** The success answer for deleting a story. */
|
|
435
|
-
export interface ConnectStoryDeletion {
|
|
436
|
-
deleted: boolean
|
|
437
|
-
}
|
|
438
|
-
|
|
439
418
|
/** The persistent state of one pipeline run, read by a connector without platform internals. */
|
|
440
419
|
export interface ConnectPipelineState {
|
|
441
420
|
runId: string
|
package/src/design/consts.ts
CHANGED
|
@@ -8,9 +8,6 @@
|
|
|
8
8
|
*/
|
|
9
9
|
export const STORY_DESIGN_VERSION = 1
|
|
10
10
|
|
|
11
|
-
/** The code a scaffold plan is filed under, since it belongs to a project rather than a story. */
|
|
12
|
-
export const SCAFFOLD_CODE = 'scaffold'
|
|
13
|
-
|
|
14
11
|
/** How far a design may drift from the project it was written against before it is stale. */
|
|
15
12
|
export enum DesignStaleness {
|
|
16
13
|
/** Usable as it stands. */
|
package/src/design/helpers.ts
CHANGED
|
@@ -4,15 +4,19 @@ import { DesignStaleness, STORY_DESIGN_VERSION } from './consts.js'
|
|
|
4
4
|
import type { StoryDesign } from './types.js'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* The in-memory aggregate the coders take, derived from the design.
|
|
7
|
+
* The in-memory aggregate the coders take, derived from the design ALONE.
|
|
8
8
|
*
|
|
9
9
|
* Derived rather than stored, and derived HERE rather than at the platform: the aggregate is what
|
|
10
10
|
* every generation helper reads, and a second place that assembles it is a second place that can
|
|
11
11
|
* assemble it differently. The `code` in particular is load-bearing - the scaffold stamps every
|
|
12
12
|
* placeholder it draws with it, so a run keyed by anything else cannot recognise its own
|
|
13
13
|
* reservation.
|
|
14
|
+
*
|
|
15
|
+
* For a context with no card behind it. Where a story card exists, `userStoryOf(card, design)` is
|
|
16
|
+
* the reader: the card wins on the narrative, code, area and actor, which a person may have
|
|
17
|
+
* changed since the design was written.
|
|
14
18
|
*/
|
|
15
|
-
export const
|
|
19
|
+
export const userStoryOfDesign = (design: StoryDesign): UserStory => {
|
|
16
20
|
const componentOf = (name: string): StoryComponent | null => {
|
|
17
21
|
const component = design.components.find(entry => entry.name === name)
|
|
18
22
|
if (component == null) {
|
package/src/design/types.ts
CHANGED
|
@@ -168,24 +168,25 @@ export interface StoryDesign {
|
|
|
168
168
|
provenance: StoryDesignProvenance
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
-
/**
|
|
172
|
-
export interface
|
|
173
|
-
projectId: string
|
|
174
|
-
storyId?: string
|
|
175
|
-
code: string
|
|
176
|
-
kind: string
|
|
177
|
-
payload: unknown
|
|
171
|
+
/** Who wrote a design revision and why — recorded on the transition, never in the design. */
|
|
172
|
+
export interface StoryDesignPutOptions {
|
|
178
173
|
runId?: string
|
|
174
|
+
cause?: string
|
|
179
175
|
}
|
|
180
176
|
|
|
181
177
|
/**
|
|
182
178
|
* How the implementation stage reaches the design, without knowing where it lives.
|
|
183
179
|
*
|
|
184
180
|
* A port rather than a resource for the usual reason: two questions is the whole of what an
|
|
185
|
-
* implementation step needs, and a port that small is satisfiable by a
|
|
186
|
-
* test
|
|
181
|
+
* implementation step needs, and a port that small is satisfiable by a planning facade, a file,
|
|
182
|
+
* or a test. Both methods are addressed by a CARD id — the story card for a story design, the
|
|
183
|
+
* project card for a scaffold plan — and the port decides which specification slot of that card
|
|
184
|
+
* holds the payload. The code a design carries is the target's vocabulary; it never addresses a
|
|
185
|
+
* record.
|
|
187
186
|
*/
|
|
188
187
|
export interface StoryDesignPort {
|
|
189
|
-
|
|
190
|
-
|
|
188
|
+
/** The card's current design and its revision; `null` when none was written or its version differs. */
|
|
189
|
+
current: (cardId: string) => Promise<{ revision: number, design: StoryDesign } | null>
|
|
190
|
+
/** Write a design as the card's next revision and answer the revision number it received. */
|
|
191
|
+
put: (cardId: string, design: StoryDesign, opts?: StoryDesignPutOptions) => Promise<number>
|
|
191
192
|
}
|
package/src/execution/types.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type { PurposeMetadata } from '../agent/types.js'
|
|
|
6
6
|
import type { AgentProject, Entity, UserStory } from '../ba/types.js'
|
|
7
7
|
import type { UXTransition } from '../ux/types.js'
|
|
8
8
|
import type { SeniorityMode } from '../consts.js'
|
|
9
|
+
import type { ViableProjectCard, ViableStoryCard } from '../planning/types.js'
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Model-selection contracts are owned by `@owlmeans/llm-common` — the JSON-safe config
|
|
@@ -26,7 +27,15 @@ export interface ExecutionState extends LlmExecutionState {
|
|
|
26
27
|
slot?: string
|
|
27
28
|
projectId?: string
|
|
28
29
|
entityId?: string
|
|
30
|
+
/** The brief the run reads — assembled from {@link ExecutionState.projectCard} and its specifications. */
|
|
29
31
|
project?: AgentProject
|
|
32
|
+
/**
|
|
33
|
+
* The project card the run acts on, as plain data.
|
|
34
|
+
*
|
|
35
|
+
* Carried beside the brief rather than in place of it: a generator reads the brief, while
|
|
36
|
+
* whatever writes back — a status transition, a specification — needs the card's id and head.
|
|
37
|
+
*/
|
|
38
|
+
projectCard?: ViableProjectCard
|
|
30
39
|
entities?: Entity[]
|
|
31
40
|
/**
|
|
32
41
|
* Which blueprint this run is building against, as an id plus an override patch.
|
|
@@ -51,5 +60,7 @@ export interface TaskExecutionState
|
|
|
51
60
|
extends ExecutionState, Omit<LlmTaskExecutionState, keyof LlmExecutionState> {
|
|
52
61
|
mode?: SeniorityMode
|
|
53
62
|
story?: UserStory
|
|
63
|
+
/** The story card the task develops, as plain data — the aggregate above is derived from it. */
|
|
64
|
+
card?: ViableStoryCard
|
|
54
65
|
transitions?: UXTransition[]
|
|
55
66
|
}
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { CodeScope, CodeStyle } from '@owlmeans/planning'
|
|
2
|
+
import type { CodePolicy } from '@owlmeans/planning'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The OwlMeans Viable vocabulary over `@owlmeans/planning`.
|
|
6
|
+
*
|
|
7
|
+
* A project, a user story and the documents behind them are planning WORKCARDS of the types
|
|
8
|
+
* declared here. Everything generic — the record, the transition, the fold, the store, the protocol
|
|
9
|
+
* tree — belongs to the planning packages; what a Viable project or story IS, which statuses it
|
|
10
|
+
* moves through and which documents it carries, is declared once in this module and read by every
|
|
11
|
+
* runtime that writes one.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/** A Viable project — the card every story, document and platform record of a product hangs under. */
|
|
15
|
+
export const VIABLE_PROJECT_TYPE = 'viable:project'
|
|
16
|
+
/** A user story — the unit of development a person starts. */
|
|
17
|
+
export const VIABLE_STORY_TYPE = 'viable:user-story'
|
|
18
|
+
/** Every document a project or story card carries (specification, vision, design system, plans). */
|
|
19
|
+
export const VIABLE_SPEC_TYPE = 'viable:spec'
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Reserved card types. Declared in full so their code prefix and flow are decided once, and
|
|
23
|
+
* deliberately absent from the project type's `cardTypes`: nothing may create one yet.
|
|
24
|
+
*/
|
|
25
|
+
export const VIABLE_BUG_TYPE = 'viable:bug'
|
|
26
|
+
export const VIABLE_IMPROVEMENT_TYPE = 'viable:improvement'
|
|
27
|
+
export const VIABLE_REQUIREMENT_TYPE = 'viable:requirement'
|
|
28
|
+
|
|
29
|
+
export const VIABLE_PROJECT_FLOW = 'viable:project'
|
|
30
|
+
export const VIABLE_STORY_FLOW = 'viable:user-story'
|
|
31
|
+
/** The one-status flow a document runs — a specification has no lifecycle of its own. */
|
|
32
|
+
export const VIABLE_SPEC_FLOW = 'viable:spec'
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The story flow's status keys.
|
|
36
|
+
*
|
|
37
|
+
* Byte-identical to the strings a story has always carried — the frontmatter of
|
|
38
|
+
* `docs/stories/<code>.md`, the connector's job status mapping, the board's columns, their i18n
|
|
39
|
+
* keys and every end-to-end selector read these exact values. A key is a wire contract and is
|
|
40
|
+
* never renamed.
|
|
41
|
+
*/
|
|
42
|
+
export enum ViableStoryStatus {
|
|
43
|
+
Planned = 'planned',
|
|
44
|
+
InProgress = 'in-progress',
|
|
45
|
+
Completed = 'completed',
|
|
46
|
+
/** Intrinsically PLANNED: a failed story is work still to do, and retrying it is `start`. */
|
|
47
|
+
Failed = 'failed',
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export enum ViableStoryTransition {
|
|
51
|
+
/** `planned | failed → in-progress` — the only move that asks for development. */
|
|
52
|
+
Start = 'start',
|
|
53
|
+
Complete = 'complete',
|
|
54
|
+
Fail = 'fail',
|
|
55
|
+
/** `* → planned` — the manual recovery, and the one move a completed story still accepts. */
|
|
56
|
+
Reset = 'reset',
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export enum ViableProjectStatus {
|
|
60
|
+
/** Created from a prompt, specification drafted, nothing provisioned. */
|
|
61
|
+
Draft = 'draft',
|
|
62
|
+
/** The owner confirmed the brief; initialization is running or has run. */
|
|
63
|
+
Confirmed = 'confirmed',
|
|
64
|
+
/** Initialization finished at least once. */
|
|
65
|
+
Active = 'active',
|
|
66
|
+
Archived = 'archived',
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export enum ViableProjectTransition {
|
|
70
|
+
Confirm = 'confirm',
|
|
71
|
+
Activate = 'activate',
|
|
72
|
+
Archive = 'archive',
|
|
73
|
+
Reopen = 'reopen',
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** The single status a document holds. */
|
|
77
|
+
export enum ViableSpecStatus {
|
|
78
|
+
Current = 'current',
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** The palette key a board renders a status with. Presentation data, carried on the flow. */
|
|
82
|
+
export enum ViableTone {
|
|
83
|
+
Blue = 'blue',
|
|
84
|
+
Yellow = 'yellow',
|
|
85
|
+
Green = 'green',
|
|
86
|
+
Red = 'red',
|
|
87
|
+
Neutral = 'neutral',
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* The specification slots Viable cards carry.
|
|
92
|
+
*
|
|
93
|
+
* Project: `specification`, `vision`, `design-system` (the brief) and `scaffold` (the drawn plan).
|
|
94
|
+
* Story: `design`. The co-located `*.spec/.ux/.ui.md` files of a target are FILES, not slots — that
|
|
95
|
+
* prose already lives inside the `design` payload — so `SpecCategory` is not a slot vocabulary.
|
|
96
|
+
*/
|
|
97
|
+
export enum ViableSpecCategory {
|
|
98
|
+
Specification = 'specification',
|
|
99
|
+
Vision = 'vision',
|
|
100
|
+
DesignSystem = 'design-system',
|
|
101
|
+
Scaffold = 'scaffold',
|
|
102
|
+
Design = 'design',
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** How many revisions of a `design` or `scaffold` document the history must be able to answer. */
|
|
106
|
+
export const VIABLE_DESIGN_REVISIONS_KEPT = 3
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Relationship types between story cards.
|
|
110
|
+
*
|
|
111
|
+
* `follows` is WRITTEN: a connective story follows the flow story it was anchored after, created in
|
|
112
|
+
* the same transition as the card. `shares-widget` and `shares-screen` are DECLARED ONLY — the
|
|
113
|
+
* `scaffold` specification is their single authority, and a second copy as links would be a second
|
|
114
|
+
* answer that can disagree with it.
|
|
115
|
+
*/
|
|
116
|
+
export enum ViableRelationship {
|
|
117
|
+
Follows = 'follows',
|
|
118
|
+
SharesWidget = 'shares-widget',
|
|
119
|
+
SharesScreen = 'shares-screen',
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Where a write came from, carried on `PlanningScope.channel` and recorded on the transition's
|
|
124
|
+
* `actor.channel`.
|
|
125
|
+
*
|
|
126
|
+
* It is never read from the wire: the manager API derives `Connect` from an access-token request
|
|
127
|
+
* and `Web` from everything else; the agent writes as `Agent` or `Pipeline`. Three rules key on it
|
|
128
|
+
* — the balance refusal class (`ConnectOutOfCredits` for `Connect`), re-formatting a narrative
|
|
129
|
+
* (`Web`/`Connect` only), and the develop trigger (a committed `start` by `Web`/`Connect` only).
|
|
130
|
+
*/
|
|
131
|
+
export enum ViableChannel {
|
|
132
|
+
Web = 'web',
|
|
133
|
+
Connect = 'connect',
|
|
134
|
+
Agent = 'agent',
|
|
135
|
+
Pipeline = 'pipeline',
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/** The channels a PERSON writes through. */
|
|
139
|
+
export const VIABLE_USER_CHANNELS: readonly string[] = Object.freeze([
|
|
140
|
+
ViableChannel.Web, ViableChannel.Connect,
|
|
141
|
+
])
|
|
142
|
+
|
|
143
|
+
export const VIABLE_STORY_CODE_PREFIX = 'US-'
|
|
144
|
+
export const VIABLE_BUG_CODE_PREFIX = 'BUG-'
|
|
145
|
+
export const VIABLE_IMPROVEMENT_CODE_PREFIX = 'IMP-'
|
|
146
|
+
export const VIABLE_REQUIREMENT_CODE_PREFIX = 'REQ-'
|
|
147
|
+
export const VIABLE_CARD_CODE_LENGTH = 5
|
|
148
|
+
|
|
149
|
+
/** `US-` + five uppercase characters, unique within the project. The code a target is keyed by. */
|
|
150
|
+
export const VIABLE_STORY_CODE: CodePolicy = Object.freeze({
|
|
151
|
+
prefix: VIABLE_STORY_CODE_PREFIX,
|
|
152
|
+
style: CodeStyle.Random,
|
|
153
|
+
length: VIABLE_CARD_CODE_LENGTH,
|
|
154
|
+
uppercase: true,
|
|
155
|
+
uniqueWithin: CodeScope.Parent,
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* A project's code is its alias — a slug unique within the organization.
|
|
160
|
+
*
|
|
161
|
+
* Minted by the platform's name ladder, which knows about retired aliases and refused hostnames;
|
|
162
|
+
* a code policy only guards uniqueness, so a create always supplies the code.
|
|
163
|
+
*/
|
|
164
|
+
export const VIABLE_PROJECT_CODE: CodePolicy = Object.freeze({
|
|
165
|
+
style: CodeStyle.Slug,
|
|
166
|
+
uniqueWithin: CodeScope.Entity,
|
|
167
|
+
// The alias moves: a rename changes it, and a refused preview certificate walks it to `alias-2`.
|
|
168
|
+
// A story code never moves — the target's files are named after it.
|
|
169
|
+
mutable: true,
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
export const VIABLE_BUG_CODE: CodePolicy = Object.freeze({
|
|
173
|
+
...VIABLE_STORY_CODE, prefix: VIABLE_BUG_CODE_PREFIX,
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
export const VIABLE_IMPROVEMENT_CODE: CodePolicy = Object.freeze({
|
|
177
|
+
...VIABLE_STORY_CODE, prefix: VIABLE_IMPROVEMENT_CODE_PREFIX,
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
export const VIABLE_REQUIREMENT_CODE: CodePolicy = Object.freeze({
|
|
181
|
+
...VIABLE_STORY_CODE, prefix: VIABLE_REQUIREMENT_CODE_PREFIX,
|
|
182
|
+
})
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { ResilientError } from '@owlmeans/error'
|
|
2
|
+
import { ResourceError } from '@owlmeans/resource'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The project and story refusals every process that writes a planning card can raise.
|
|
6
|
+
*
|
|
7
|
+
* Declared HERE rather than by the platform because the viable planning plugin throws them from a
|
|
8
|
+
* process-neutral package, and a refusal class that exists only on one side of a hop cannot be
|
|
9
|
+
* `instanceof`-matched on the other. Type names and markers are wire contracts: the browser
|
|
10
|
+
* phrases a refusal by marker (`viable-project:…`), so neither may change. The bases are declared
|
|
11
|
+
* with them because an error class is unmarshalled by type name with the LAST registration
|
|
12
|
+
* winning — a second declaration of a base anywhere else would replace this one.
|
|
13
|
+
*/
|
|
14
|
+
export class ProjectResourceError extends ResourceError {
|
|
15
|
+
public static override typeName = `ViableProject${ResourceError.typeName}`
|
|
16
|
+
|
|
17
|
+
constructor(message: string = 'error') {
|
|
18
|
+
super(`viable-project:${message}`)
|
|
19
|
+
this.type = ProjectResourceError.typeName
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** No project card with that id in the caller's organization. */
|
|
24
|
+
export class ProjectNotFound extends ProjectResourceError {
|
|
25
|
+
public static override typeName = `NotFound${ProjectResourceError.typeName}`
|
|
26
|
+
|
|
27
|
+
constructor(message: string = 'error') {
|
|
28
|
+
super(`not-found:${message}`)
|
|
29
|
+
this.type = ProjectNotFound.typeName
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** The project exists, and the caller may not act on it. */
|
|
34
|
+
export class ProjectPermissionError extends ProjectResourceError {
|
|
35
|
+
public static override typeName = `Permission${ProjectResourceError.typeName}`
|
|
36
|
+
|
|
37
|
+
constructor(message: string = 'error') {
|
|
38
|
+
super(`permission:${message}`)
|
|
39
|
+
this.type = ProjectPermissionError.typeName
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export class ProjectStoryError extends ProjectResourceError {
|
|
44
|
+
public static override typeName = `Story${ProjectResourceError.typeName}`
|
|
45
|
+
|
|
46
|
+
constructor(message: string = 'error') {
|
|
47
|
+
super(`story:${message}`)
|
|
48
|
+
this.type = ProjectStoryError.typeName
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** No story card with that id or code under the project. */
|
|
53
|
+
export class ProjectStoryNotFound extends ProjectStoryError {
|
|
54
|
+
public static override typeName = `NotFound${ProjectStoryError.typeName}`
|
|
55
|
+
|
|
56
|
+
constructor(message: string = 'error') {
|
|
57
|
+
super(`not-found:${message}`)
|
|
58
|
+
this.type = ProjectStoryNotFound.typeName
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* The story is in a state the requested write does not apply to.
|
|
64
|
+
*
|
|
65
|
+
* `wrong-status` is the marker a completed story's refusal carries — the manager matches the whole
|
|
66
|
+
* `viable-project:story:missconfigured:` prefix, so the reason after it is free to grow.
|
|
67
|
+
*/
|
|
68
|
+
export class ProjectStoryMissconfigured extends ProjectStoryError {
|
|
69
|
+
public static override typeName = `Missconfigured${ProjectStoryError.typeName}`
|
|
70
|
+
|
|
71
|
+
constructor(message: string = 'error') {
|
|
72
|
+
super(`missconfigured:${message}`)
|
|
73
|
+
this.type = ProjectStoryMissconfigured.typeName
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export class ProjectError extends ResilientError {
|
|
78
|
+
public static override typeName = `ViableProject${ResilientError.typeName}`
|
|
79
|
+
|
|
80
|
+
constructor(message: string = 'error') {
|
|
81
|
+
super(ProjectError.typeName, `viable-project:${message}`)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export class ProjectAgentError extends ProjectError {
|
|
86
|
+
public static override typeName = `Agent${ProjectError.typeName}`
|
|
87
|
+
|
|
88
|
+
constructor(message: string = 'error') {
|
|
89
|
+
super(`agent:${message}`)
|
|
90
|
+
this.type = ProjectAgentError.typeName
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* The project's agent is already busy with what was asked for.
|
|
96
|
+
*
|
|
97
|
+
* `story` is the reason a second story start carries: one story of a project is in progress at a
|
|
98
|
+
* time, because a develop run holds the project's sandbox for its whole length.
|
|
99
|
+
*/
|
|
100
|
+
export class ProjectAgentOccupied extends ProjectAgentError {
|
|
101
|
+
public static override typeName = `Occupied${ProjectAgentError.typeName}`
|
|
102
|
+
|
|
103
|
+
constructor(message: string = 'error') {
|
|
104
|
+
super(`occupied:${message}`)
|
|
105
|
+
this.type = ProjectAgentOccupied.typeName
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
ResilientError.registerErrorClass(ProjectResourceError)
|
|
110
|
+
ResilientError.registerErrorClass(ProjectNotFound)
|
|
111
|
+
ResilientError.registerErrorClass(ProjectPermissionError)
|
|
112
|
+
ResilientError.registerErrorClass(ProjectStoryError)
|
|
113
|
+
ResilientError.registerErrorClass(ProjectStoryNotFound)
|
|
114
|
+
ResilientError.registerErrorClass(ProjectStoryMissconfigured)
|
|
115
|
+
ResilientError.registerErrorClass(ProjectError)
|
|
116
|
+
ResilientError.registerErrorClass(ProjectAgentError)
|
|
117
|
+
ResilientError.registerErrorClass(ProjectAgentOccupied)
|