@owlmeans/planning 0.1.18-rc.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.
Files changed (139) hide show
  1. package/README.md +169 -0
  2. package/agent-meta/manifest.json +16 -0
  3. package/agent-meta/skills/planning/SKILL.md +248 -0
  4. package/build/consts.d.ts +126 -0
  5. package/build/consts.d.ts.map +1 -0
  6. package/build/consts.js +129 -0
  7. package/build/consts.js.map +1 -0
  8. package/build/entrypoints.d.ts +14 -0
  9. package/build/entrypoints.d.ts.map +1 -0
  10. package/build/entrypoints.js +69 -0
  11. package/build/entrypoints.js.map +1 -0
  12. package/build/errors.d.ts +94 -0
  13. package/build/errors.d.ts.map +1 -0
  14. package/build/errors.js +169 -0
  15. package/build/errors.js.map +1 -0
  16. package/build/helpers/apply.d.ts +27 -0
  17. package/build/helpers/apply.d.ts.map +1 -0
  18. package/build/helpers/apply.js +162 -0
  19. package/build/helpers/apply.js.map +1 -0
  20. package/build/helpers/card.d.ts +17 -0
  21. package/build/helpers/card.d.ts.map +1 -0
  22. package/build/helpers/card.js +31 -0
  23. package/build/helpers/card.js.map +1 -0
  24. package/build/helpers/changes.d.ts +51 -0
  25. package/build/helpers/changes.d.ts.map +1 -0
  26. package/build/helpers/changes.js +277 -0
  27. package/build/helpers/changes.js.map +1 -0
  28. package/build/helpers/code.d.ts +24 -0
  29. package/build/helpers/code.d.ts.map +1 -0
  30. package/build/helpers/code.js +47 -0
  31. package/build/helpers/code.js.map +1 -0
  32. package/build/helpers/index.d.ts +9 -0
  33. package/build/helpers/index.d.ts.map +1 -0
  34. package/build/helpers/index.js +9 -0
  35. package/build/helpers/index.js.map +1 -0
  36. package/build/helpers/query.d.ts +39 -0
  37. package/build/helpers/query.d.ts.map +1 -0
  38. package/build/helpers/query.js +293 -0
  39. package/build/helpers/query.js.map +1 -0
  40. package/build/helpers/specification.d.ts +21 -0
  41. package/build/helpers/specification.d.ts.map +1 -0
  42. package/build/helpers/specification.js +48 -0
  43. package/build/helpers/specification.js.map +1 -0
  44. package/build/helpers/status.d.ts +44 -0
  45. package/build/helpers/status.d.ts.map +1 -0
  46. package/build/helpers/status.js +78 -0
  47. package/build/helpers/status.js.map +1 -0
  48. package/build/helpers/validate.d.ts +30 -0
  49. package/build/helpers/validate.d.ts.map +1 -0
  50. package/build/helpers/validate.js +93 -0
  51. package/build/helpers/validate.js.map +1 -0
  52. package/build/i18n/be.json +51 -0
  53. package/build/i18n/de.json +51 -0
  54. package/build/i18n/en.json +51 -0
  55. package/build/i18n/es.json +51 -0
  56. package/build/i18n/pl.json +51 -0
  57. package/build/i18n/ru.json +51 -0
  58. package/build/i18n/uk.json +51 -0
  59. package/build/i18n.d.ts +2 -0
  60. package/build/i18n.d.ts.map +1 -0
  61. package/build/i18n.js +19 -0
  62. package/build/i18n.js.map +1 -0
  63. package/build/index.d.ts +10 -0
  64. package/build/index.d.ts.map +1 -0
  65. package/build/index.js +9 -0
  66. package/build/index.js.map +1 -0
  67. package/build/models/index.d.ts +7 -0
  68. package/build/models/index.d.ts.map +1 -0
  69. package/build/models/index.js +19 -0
  70. package/build/models/index.js.map +1 -0
  71. package/build/models/project.d.ts +4 -0
  72. package/build/models/project.d.ts.map +1 -0
  73. package/build/models/project.js +17 -0
  74. package/build/models/project.js.map +1 -0
  75. package/build/models/specification.d.ts +4 -0
  76. package/build/models/specification.d.ts.map +1 -0
  77. package/build/models/specification.js +15 -0
  78. package/build/models/specification.js.map +1 -0
  79. package/build/models/workcard.d.ts +14 -0
  80. package/build/models/workcard.d.ts.map +1 -0
  81. package/build/models/workcard.js +103 -0
  82. package/build/models/workcard.js.map +1 -0
  83. package/build/queue/index.d.ts +25 -0
  84. package/build/queue/index.d.ts.map +1 -0
  85. package/build/queue/index.js +14 -0
  86. package/build/queue/index.js.map +1 -0
  87. package/build/registry.d.ts +10 -0
  88. package/build/registry.d.ts.map +1 -0
  89. package/build/registry.js +75 -0
  90. package/build/registry.js.map +1 -0
  91. package/build/schemas.d.ts +56 -0
  92. package/build/schemas.d.ts.map +1 -0
  93. package/build/schemas.js +578 -0
  94. package/build/schemas.js.map +1 -0
  95. package/build/types.d.ts +785 -0
  96. package/build/types.d.ts.map +1 -0
  97. package/build/types.js +2 -0
  98. package/build/types.js.map +1 -0
  99. package/package.json +58 -0
  100. package/src/consts.ts +136 -0
  101. package/src/entrypoints.ts +127 -0
  102. package/src/errors.ts +207 -0
  103. package/src/helpers/apply.ts +183 -0
  104. package/src/helpers/card.ts +42 -0
  105. package/src/helpers/changes.ts +333 -0
  106. package/src/helpers/code.ts +66 -0
  107. package/src/helpers/index.ts +8 -0
  108. package/src/helpers/query.ts +345 -0
  109. package/src/helpers/specification.ts +65 -0
  110. package/src/helpers/status.ts +117 -0
  111. package/src/helpers/validate.ts +107 -0
  112. package/src/i18n/be.json +51 -0
  113. package/src/i18n/de.json +51 -0
  114. package/src/i18n/en.json +51 -0
  115. package/src/i18n/es.json +51 -0
  116. package/src/i18n/pl.json +51 -0
  117. package/src/i18n/ru.json +51 -0
  118. package/src/i18n/uk.json +51 -0
  119. package/src/i18n.ts +21 -0
  120. package/src/index.ts +9 -0
  121. package/src/models/index.ts +21 -0
  122. package/src/models/project.ts +24 -0
  123. package/src/models/specification.ts +21 -0
  124. package/src/models/workcard.ts +138 -0
  125. package/src/queue/index.ts +31 -0
  126. package/src/registry.ts +90 -0
  127. package/src/schemas.ts +654 -0
  128. package/src/types.ts +837 -0
  129. package/tests/apply.spec.ts +176 -0
  130. package/tests/code.spec.ts +40 -0
  131. package/tests/entrypoints.spec.ts +57 -0
  132. package/tests/fixtures.ts +124 -0
  133. package/tests/i18n.spec.ts +30 -0
  134. package/tests/models.spec.ts +133 -0
  135. package/tests/query.spec.ts +90 -0
  136. package/tests/schemas.spec.ts +74 -0
  137. package/tests/status.spec.ts +75 -0
  138. package/tests/tsconfig.json +17 -0
  139. package/tsconfig.json +15 -0
@@ -0,0 +1,162 @@
1
+ import { IntrinsicStatus, TransitionAction } from '../consts.js';
2
+ import { PlanningError } from '../errors.js';
3
+ /** Never written by a transition's `changes`: the fold takes them from the transition itself. */
4
+ const IDENTITY_KEYS = new Set(['id', 'kind', 'type', 'entityId', 'seq', 'head', 'createdAt']);
5
+ /** Cannot be cleared: a record without them is not a record. */
6
+ const REQUIRED_KEYS = new Set([
7
+ ...IDENTITY_KEYS, 'title', 'parents', 'status', 'intrinsic', 'flows', 'labels', 'fields',
8
+ ]);
9
+ /** Merged shallowly into the card's own map rather than replacing it. */
10
+ const MERGED_KEYS = new Set(['fields', 'flows']);
11
+ const clean = (record) => Object.fromEntries(Object.entries(record).filter(([, value]) => value !== undefined));
12
+ const outOfOrder = (card, transition) => new PlanningError(`fold:out-of-order:${transition.card}:${card?.seq ?? 0}:${transition.seq}`);
13
+ const unsetOn = (record, paths) => {
14
+ for (const path of paths ?? []) {
15
+ const dot = path.indexOf('.');
16
+ if (dot > 0) {
17
+ const head = path.slice(0, dot);
18
+ const map = record[head];
19
+ if (MERGED_KEYS.has(head) && map != null && typeof map === 'object') {
20
+ delete map[path.slice(dot + 1)];
21
+ }
22
+ continue;
23
+ }
24
+ if (!REQUIRED_KEYS.has(path)) {
25
+ delete record[path];
26
+ }
27
+ }
28
+ };
29
+ const writeChanges = (record, changes) => {
30
+ for (const [key, value] of Object.entries(changes)) {
31
+ if (value === undefined || IDENTITY_KEYS.has(key)) {
32
+ continue;
33
+ }
34
+ if (MERGED_KEYS.has(key)) {
35
+ const merged = { ...(record[key] ?? {}) };
36
+ for (const [entry, entryValue] of Object.entries(value ?? {})) {
37
+ if (entryValue === null) {
38
+ delete merged[entry];
39
+ }
40
+ else if (entryValue !== undefined) {
41
+ merged[entry] = entryValue;
42
+ }
43
+ }
44
+ record[key] = merged;
45
+ continue;
46
+ }
47
+ if (value === null) {
48
+ if (!REQUIRED_KEYS.has(key)) {
49
+ delete record[key];
50
+ }
51
+ continue;
52
+ }
53
+ record[key] = value;
54
+ }
55
+ };
56
+ /**
57
+ * THE fold: the card after one transition. Pure, total, no I/O — every store (memory, Mongo, a
58
+ * client mirror) folds with this and nothing else, so one log always means one card.
59
+ *
60
+ * - An already-applied transition (`seq <= card.seq`) returns the card unchanged: re-folding is
61
+ * safe.
62
+ * - Anything but the next seq (`card.seq + 1`, or 1 for a create with no card) is refused with
63
+ * `PlanningError('fold:out-of-order')`.
64
+ * - `create` builds the whole record from `changes` plus the transition's identity; `delete`
65
+ * answers `null`; `link`/`unlink` only move `seq`/`head`/`updatedAt` (the edges are
66
+ * {@link applyRelationship}'s); `update`/`transit` write `changes` — `fields` and `flows` merge,
67
+ * everything else replaces — and clear `unset`.
68
+ * - Every result has `seq = transition.seq`, `head = max(head, seq)`, `updatedAt = transition.at`.
69
+ *
70
+ * @throws {PlanningError} `planning:fold:out-of-order:…`
71
+ */
72
+ export const applyTransition = (card, transition) => {
73
+ if (card != null && transition.seq <= card.seq) {
74
+ return card;
75
+ }
76
+ if (card == null) {
77
+ if (transition.action === TransitionAction.Delete) {
78
+ return null;
79
+ }
80
+ if (transition.action !== TransitionAction.Create || transition.seq !== 1) {
81
+ throw outOfOrder(card, transition);
82
+ }
83
+ }
84
+ else if (transition.seq !== card.seq + 1) {
85
+ throw outOfOrder(card, transition);
86
+ }
87
+ if (transition.action === TransitionAction.Delete) {
88
+ return null;
89
+ }
90
+ const head = Math.max(card?.head ?? card?.seq ?? 0, transition.seq);
91
+ const changes = structuredClone(transition.changes ?? {});
92
+ if (transition.action === TransitionAction.Create) {
93
+ const record = {
94
+ parents: [], labels: [], fields: {}, flows: {}, status: '', intrinsic: IntrinsicStatus.Planned,
95
+ };
96
+ writeChanges(record, changes);
97
+ unsetOn(record, transition.unset);
98
+ return clean({
99
+ ...record,
100
+ id: transition.card,
101
+ kind: transition.kind,
102
+ type: transition.type,
103
+ entityId: transition.entityId,
104
+ seq: transition.seq,
105
+ head,
106
+ createdAt: transition.at,
107
+ updatedAt: transition.at,
108
+ });
109
+ }
110
+ const record = structuredClone(card);
111
+ if (transition.action === TransitionAction.Update || transition.action === TransitionAction.Transit) {
112
+ writeChanges(record, changes);
113
+ unsetOn(record, transition.unset);
114
+ }
115
+ record.seq = transition.seq;
116
+ record.head = head;
117
+ record.updatedAt = transition.at;
118
+ return clean(record);
119
+ };
120
+ const edgeOf = (transition, draft) => clean({
121
+ entityId: transition.entityId,
122
+ type: draft.type,
123
+ from: draft.from ?? transition.card,
124
+ to: draft.to,
125
+ project: transition.project,
126
+ fields: draft.fields == null ? undefined : structuredClone(draft.fields),
127
+ createdAt: transition.at,
128
+ transition: transition.id,
129
+ });
130
+ const sameEdge = (left, right) => left.entityId === right.entityId && left.from === right.from && left.to === right.to && left.type === right.type;
131
+ /**
132
+ * The relationships after one transition. Pure and total, like {@link applyTransition}.
133
+ *
134
+ * `create` adds its `links`, `link` adds its `link`, `unlink` removes the matching edge, and a
135
+ * `delete` removes every edge touching the card. An edge that already exists is kept as it is, so
136
+ * re-folding adds nothing. Every other action answers the list unchanged. Always a new array.
137
+ */
138
+ export const applyRelationship = (links, transition) => {
139
+ const add = (drafts) => drafts.reduce((result, draft) => {
140
+ const edge = edgeOf(transition, draft);
141
+ return result.some(existing => sameEdge(existing, edge)) ? result : [...result, edge];
142
+ }, [...links]);
143
+ switch (transition.action) {
144
+ case TransitionAction.Create:
145
+ return add(transition.links ?? []);
146
+ case TransitionAction.Link:
147
+ return add(transition.link == null ? [] : [transition.link]);
148
+ case TransitionAction.Unlink: {
149
+ if (transition.link == null) {
150
+ return [...links];
151
+ }
152
+ const edge = edgeOf(transition, transition.link);
153
+ return links.filter(existing => !sameEdge(existing, edge));
154
+ }
155
+ case TransitionAction.Delete:
156
+ return links.filter(existing => existing.entityId !== transition.entityId
157
+ || (existing.from !== transition.card && existing.to !== transition.card));
158
+ default:
159
+ return [...links];
160
+ }
161
+ };
162
+ //# sourceMappingURL=apply.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apply.js","sourceRoot":"","sources":["../../src/helpers/apply.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { Card, Project, Specification, Workcard, WorkcardDraft } from '../types.js';
2
+ export declare const isProject: (card?: Workcard | null) => card is Project;
3
+ export declare const isCard: (card?: Workcard | null) => card is Card;
4
+ export declare const isSpecification: (card?: Workcard | null) => card is Specification;
5
+ /** `parents` with `parent` first and no repeats — the invariant every record keeps. */
6
+ export declare const normalizeParents: (parent?: string | null, parents?: string[] | null) => string[];
7
+ /** A draft with the collections every record carries filled in. */
8
+ export declare const cardDefaults: (draft: WorkcardDraft) => WorkcardDraft & Required<Pick<WorkcardDraft, 'parents' | 'labels' | 'fields'>>;
9
+ /** A transition was allocated for the card and has not been folded yet. */
10
+ export declare const isPending: (card: Pick<Workcard, 'seq' | 'head'>) => boolean;
11
+ export declare const parentOf: (card: Workcard) => string | undefined;
12
+ /**
13
+ * The project a card belongs to: a project is its own; a card under a project is that project's;
14
+ * anything deeper is its parent's project, which needs the parent to answer.
15
+ */
16
+ export declare const projectOf: (card: Workcard, parent?: Workcard | null) => string | undefined;
17
+ //# sourceMappingURL=card.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"card.d.ts","sourceRoot":"","sources":["../../src/helpers/card.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAExF,eAAO,MAAM,SAAS,UAAW,QAAQ,GAAG,IAAI,KAAG,IAAI,IAAI,OAA8C,CAAA;AAEzG,eAAO,MAAM,MAAM,UAAW,QAAQ,GAAG,IAAI,KAAG,IAAI,IAAI,IAAwC,CAAA;AAEhG,eAAO,MAAM,eAAe,UAAW,QAAQ,GAAG,IAAI,KAAG,IAAI,IAAI,aACtB,CAAA;AAE3C,uFAAuF;AACvF,eAAO,MAAM,gBAAgB,YAAa,MAAM,GAAG,IAAI,YAAY,MAAM,EAAE,GAAG,IAAI,KAAG,MAAM,EAE/D,CAAA;AAE5B,mEAAmE;AACnE,eAAO,MAAM,YAAY,UAAW,aAAa,KAAG,aAAa,GAAG,QAAQ,CAAC,IAAI,CAAC,aAAa,EAAE,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC,CAK/H,CAAA;AAEF,2EAA2E;AAC3E,eAAO,MAAM,SAAS,SAAU,IAAI,CAAC,QAAQ,EAAE,KAAK,GAAG,MAAM,CAAC,KAAG,OAA6C,CAAA;AAE9G,eAAO,MAAM,QAAQ,SAAU,QAAQ,KAAG,MAAM,GAAG,SAA2C,CAAA;AAE9F;;;GAGG;AACH,eAAO,MAAM,SAAS,SAAU,QAAQ,WAAW,QAAQ,GAAG,IAAI,KAAG,MAAM,GAAG,SAS7E,CAAA"}
@@ -0,0 +1,31 @@
1
+ import { WorkcardKind } from '../consts.js';
2
+ export const isProject = (card) => card?.kind === WorkcardKind.Project;
3
+ export const isCard = (card) => card?.kind === WorkcardKind.Card;
4
+ export const isSpecification = (card) => card?.kind === WorkcardKind.Specification;
5
+ /** `parents` with `parent` first and no repeats — the invariant every record keeps. */
6
+ export const normalizeParents = (parent, parents) => [...new Set([...(parent != null && parent !== '' ? [parent] : []), ...(parents ?? [])])]
7
+ .filter(id => id !== '');
8
+ /** A draft with the collections every record carries filled in. */
9
+ export const cardDefaults = (draft) => ({
10
+ ...draft,
11
+ parents: normalizeParents(draft.parent, draft.parents),
12
+ labels: [...new Set(draft.labels ?? [])],
13
+ fields: draft.fields ?? {},
14
+ });
15
+ /** A transition was allocated for the card and has not been folded yet. */
16
+ export const isPending = (card) => (card.head ?? card.seq) > card.seq;
17
+ export const parentOf = (card) => card.parent ?? card.parents[0];
18
+ /**
19
+ * The project a card belongs to: a project is its own; a card under a project is that project's;
20
+ * anything deeper is its parent's project, which needs the parent to answer.
21
+ */
22
+ export const projectOf = (card, parent) => {
23
+ if (isProject(card)) {
24
+ return card.id;
25
+ }
26
+ if (parent != null) {
27
+ return isProject(parent) ? parent.id : parent.parent;
28
+ }
29
+ return card.parent;
30
+ };
31
+ //# sourceMappingURL=card.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"card.js","sourceRoot":"","sources":["../../src/helpers/card.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAG3C,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,IAAsB,EAAmB,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,YAAY,CAAC,OAAO,CAAA;AAEzG,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,IAAsB,EAAgB,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,YAAY,CAAC,IAAI,CAAA;AAEhG,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,IAAsB,EAAyB,EAAE,CAC/E,IAAI,EAAE,IAAI,KAAK,YAAY,CAAC,aAAa,CAAA;AAE3C,uFAAuF;AACvF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,MAAsB,EAAE,OAAyB,EAAY,EAAE,CAC9F,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,IAAI,IAAI,IAAI,MAAM,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;KACrF,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAA;AAE5B,mEAAmE;AACnE,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,KAAoB,EAAkF,EAAE,CAAC,CAAC;IACrI,GAAG,KAAK;IACR,OAAO,EAAE,gBAAgB,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC;IACtD,MAAM,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;IACxC,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,EAAE;CAC3B,CAAC,CAAA;AAEF,2EAA2E;AAC3E,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,IAAoC,EAAW,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAA;AAE9G,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,IAAc,EAAsB,EAAE,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;AAE9F;;;GAGG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,IAAc,EAAE,MAAwB,EAAsB,EAAE;IACxF,IAAI,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;QACpB,OAAO,IAAI,CAAC,EAAE,CAAA;IAChB,CAAC;IACD,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;QACnB,OAAO,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAA;IACtD,CAAC;IAED,OAAO,IAAI,CAAC,MAAM,CAAA;AACpB,CAAC,CAAA"}
@@ -0,0 +1,51 @@
1
+ import type { AnyTypeSchema, PlanningSchemaRegistry, SpecificationSlot, TransitionExecution, Workcard, WorkcardChanges } from '../types.js';
2
+ type FlowLookup = Pick<PlanningSchemaRegistry, 'flow'>;
3
+ export interface ChangeSet {
4
+ changes: WorkcardChanges;
5
+ unset: string[];
6
+ /** Transit only: the flow that moved, and the move. */
7
+ flow?: string;
8
+ from?: string;
9
+ to?: string;
10
+ }
11
+ /** Structural equality over JSON values. */
12
+ export declare const sameValue: (left: unknown, right: unknown) => boolean;
13
+ /** A shallow merge that drops keys patched to `null`. */
14
+ export declare const mergeFields: (base?: Record<string, unknown> | null, patch?: Record<string, unknown> | null) => Record<string, unknown>;
15
+ /** A copy of the record with the paths (`key`, `fields.key`, `flows.id`) removed. */
16
+ export declare const applyUnset: <T extends object>(record: T, unset?: string[]) => T;
17
+ /**
18
+ * Refuse an execution that writes what only the transition, the flow or the executor may write.
19
+ *
20
+ * `status`/`intrinsic`/`flows`/`closedAt` move only through `transit` (a create's draft may name
21
+ * the initial status); `code` is fixed once minted unless the type's policy says `mutable`;
22
+ * `category` is fixed; `revision`/`bodyChars` are computed.
23
+ *
24
+ * @throws {PlanningError} `planning:immutable:<field>`
25
+ */
26
+ export declare const assertMutable: (exec: TransitionExecution, type: AnyTypeSchema) => void;
27
+ /**
28
+ * The `changes`/`unset` a transition records (plan step 9).
29
+ *
30
+ * - `create`: the whole initial record from the draft (overlaid by `exec.changes`) — `parents`
31
+ * normalized, every flow at its initial status (the draft's `status` for the primary one),
32
+ * `status`/`intrinsic` mirrored, `closedAt` when it starts closed; a specification gets its
33
+ * format, `bodyChars` and revision 1 when the slot is revisioned.
34
+ * - `update`: only what differs; `null` or `exec.unset` clears a field that has a value; a moved
35
+ * `parent` replaces the old one in `parents`; a revisioned document whose content changed gets
36
+ * `revision + 1`. An update that changes nothing is empty ({@link isEmptyChange}).
37
+ * - `transit`: `flows[flow] = rule.to`, `status` when the flow is primary, `intrinsic` when it
38
+ * moves, `closedAt` set on entering closed and cleared on leaving it — plus the caller's own
39
+ * changes, diffed as in an update.
40
+ * - `link`, `unlink`, `delete`: nothing.
41
+ *
42
+ * @throws {IllegalTransition} a transit the flow does not offer from the current status
43
+ * @throws {PlanningError} `malformed:*` for an execution missing what its action needs
44
+ */
45
+ export declare const computeChanges: (card: Workcard | null | undefined, exec: TransitionExecution, type: AnyTypeSchema, registry: FlowLookup, at: string, opts?: {
46
+ slot?: SpecificationSlot | null;
47
+ }) => ChangeSet;
48
+ /** Nothing to write: no changed value and nothing to clear. */
49
+ export declare const isEmptyChange: (set: Pick<ChangeSet, 'changes' | 'unset'>) => boolean;
50
+ export {};
51
+ //# sourceMappingURL=changes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"changes.d.ts","sourceRoot":"","sources":["../../src/helpers/changes.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,aAAa,EAAE,sBAAsB,EAAiB,iBAAiB,EAAE,mBAAmB,EAC5F,QAAQ,EAAE,eAAe,EAC1B,MAAM,aAAa,CAAA;AAKpB,KAAK,UAAU,GAAG,IAAI,CAAC,sBAAsB,EAAE,MAAM,CAAC,CAAA;AAEtD,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,eAAe,CAAA;IACxB,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,uDAAuD;IACvD,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,EAAE,CAAC,EAAE,MAAM,CAAA;CACZ;AAgBD,4CAA4C;AAC5C,eAAO,MAAM,SAAS,SAAU,OAAO,SAAS,OAAO,KAAG,OAczD,CAAA;AAKD,yDAAyD;AACzD,eAAO,MAAM,WAAW,UACf,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,UAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,KAC5E,MAAM,CAAC,MAAM,EAAE,OAAO,CACuC,CAAA;AAEhE,qFAAqF;AACrF,eAAO,MAAM,UAAU,GAAI,CAAC,SAAS,MAAM,UAAU,CAAC,UAAU,MAAM,EAAE,KAAG,CAe1E,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,aAAa,SAAU,mBAAmB,QAAQ,aAAa,KAAG,IA0B9E,CAAA;AAsID;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,cAAc,SACnB,QAAQ,GAAG,IAAI,GAAG,SAAS,QAC3B,mBAAmB,QACnB,aAAa,YACT,UAAU,MAChB,MAAM,SACH;IAAE,IAAI,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAA;CAAE,KACzC,SAsDF,CAAA;AAED,+DAA+D;AAC/D,eAAO,MAAM,aAAa,QAAS,IAAI,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,KAAG,OAEW,CAAA"}
@@ -0,0 +1,277 @@
1
+ import { IntrinsicStatus, SpecificationFormat, TransitionAction, WorkcardKind } from '../consts.js';
2
+ import { IllegalTransition, PlanningError } from '../errors.js';
3
+ import { normalizeParents } from './card.js';
4
+ import { bodyCharsOf, nextRevision } from './specification.js';
5
+ import { initialFlowsOf, initialStatusOf, primaryFlowOf, resolveIntrinsic, ruleOf } from './status.js';
6
+ /** Never in a caller's changes: the transition itself carries them. */
7
+ const IDENTITY_KEYS = ['id', 'kind', 'type', 'entityId', 'seq', 'head', 'createdAt'];
8
+ /** Move only through `transit` (or a create's draft). */
9
+ const FLOW_KEYS = ['status', 'intrinsic', 'flows', 'closedAt'];
10
+ /** Computed by the executor, never supplied. */
11
+ const DERIVED_KEYS = ['revision', 'bodyChars'];
12
+ /** Cannot be cleared. */
13
+ const REQUIRED_KEYS = ['title', 'parents', 'labels', 'fields', 'category', 'format'];
14
+ /** Changing one of these produces a new revision of a revisioned document. */
15
+ const CONTENT_KEYS = ['body', 'ref', 'format', 'version'];
16
+ const isPlainObject = (value) => value != null && typeof value === 'object' && !Array.isArray(value);
17
+ /** Structural equality over JSON values. */
18
+ export const sameValue = (left, right) => {
19
+ if (left === right) {
20
+ return true;
21
+ }
22
+ if (Array.isArray(left) && Array.isArray(right)) {
23
+ return left.length === right.length && left.every((entry, index) => sameValue(entry, right[index]));
24
+ }
25
+ if (isPlainObject(left) && isPlainObject(right)) {
26
+ const keys = Object.keys(left).filter(key => left[key] !== undefined);
27
+ const other = Object.keys(right).filter(key => right[key] !== undefined);
28
+ return keys.length === other.length && keys.every(key => sameValue(left[key], right[key]));
29
+ }
30
+ return false;
31
+ };
32
+ const clean = (record) => Object.fromEntries(Object.entries(record).filter(([, value]) => value !== undefined));
33
+ /** A shallow merge that drops keys patched to `null`. */
34
+ export const mergeFields = (base, patch) => Object.fromEntries(Object.entries({ ...(base ?? {}), ...(patch ?? {}) })
35
+ .filter(([, value]) => value !== null && value !== undefined));
36
+ /** A copy of the record with the paths (`key`, `fields.key`, `flows.id`) removed. */
37
+ export const applyUnset = (record, unset) => {
38
+ const copy = structuredClone(record);
39
+ for (const path of unset ?? []) {
40
+ const [head, ...rest] = path.split('.');
41
+ if (rest.length > 0) {
42
+ const map = copy[head];
43
+ if (isPlainObject(map)) {
44
+ delete map[rest.join('.')];
45
+ }
46
+ }
47
+ else {
48
+ delete copy[head];
49
+ }
50
+ }
51
+ return copy;
52
+ };
53
+ /**
54
+ * Refuse an execution that writes what only the transition, the flow or the executor may write.
55
+ *
56
+ * `status`/`intrinsic`/`flows`/`closedAt` move only through `transit` (a create's draft may name
57
+ * the initial status); `code` is fixed once minted unless the type's policy says `mutable`;
58
+ * `category` is fixed; `revision`/`bodyChars` are computed.
59
+ *
60
+ * @throws {PlanningError} `planning:immutable:<field>`
61
+ */
62
+ export const assertMutable = (exec, type) => {
63
+ const create = exec.action === TransitionAction.Create;
64
+ const codeFixed = type.code != null && type.code.mutable !== true;
65
+ const refuse = (key) => {
66
+ throw new PlanningError(`immutable:${FLOW_KEYS.includes(key) ? 'status' : key}`);
67
+ };
68
+ for (const [key, value] of Object.entries(exec.changes ?? {})) {
69
+ if (value === undefined) {
70
+ continue;
71
+ }
72
+ if (IDENTITY_KEYS.includes(key) || DERIVED_KEYS.includes(key)) {
73
+ refuse(key);
74
+ }
75
+ if (!create && (FLOW_KEYS.includes(key) || key === 'category' || (key === 'code' && codeFixed))) {
76
+ refuse(key);
77
+ }
78
+ }
79
+ for (const path of exec.unset ?? []) {
80
+ const head = path.split('.')[0];
81
+ if (IDENTITY_KEYS.includes(path) || DERIVED_KEYS.includes(path) || REQUIRED_KEYS.includes(path)
82
+ || FLOW_KEYS.includes(head) || (path === 'code' && codeFixed)) {
83
+ refuse(path);
84
+ }
85
+ }
86
+ };
87
+ const reach = (record, path) => path.split('.')
88
+ .reduce((value, step) => isPlainObject(value) ? value[step] : undefined, record);
89
+ /** Only what differs from the card; `null` becomes an unset of a field that has a value. */
90
+ const diffInto = (card, changes, skip, set) => {
91
+ const out = set.changes;
92
+ const current = card;
93
+ for (const [key, value] of Object.entries(changes ?? {})) {
94
+ if (value === undefined || IDENTITY_KEYS.includes(key) || skip.includes(key)) {
95
+ continue;
96
+ }
97
+ if (key === 'fields' || key === 'flows') {
98
+ const own = (current[key] ?? {});
99
+ const patch = {};
100
+ for (const [entry, entryValue] of Object.entries(value ?? {})) {
101
+ if (entryValue === undefined) {
102
+ continue;
103
+ }
104
+ if (entryValue === null) {
105
+ if (own[entry] !== undefined) {
106
+ set.unset.push(`${key}.${entry}`);
107
+ }
108
+ }
109
+ else if (!sameValue(own[entry], entryValue)) {
110
+ patch[entry] = entryValue;
111
+ }
112
+ }
113
+ if (Object.keys(patch).length > 0) {
114
+ out[key] = patch;
115
+ }
116
+ continue;
117
+ }
118
+ if (value === null) {
119
+ if (current[key] != null) {
120
+ set.unset.push(key);
121
+ }
122
+ continue;
123
+ }
124
+ if (!sameValue(current[key], value)) {
125
+ out[key] = value;
126
+ }
127
+ }
128
+ };
129
+ const unsetInto = (card, unset, set) => {
130
+ for (const path of unset ?? []) {
131
+ if (reach(card, path) !== undefined && !set.unset.includes(path)) {
132
+ set.unset.push(path);
133
+ }
134
+ }
135
+ };
136
+ /** A moved primary parent replaces the old one in `parents`. */
137
+ const reparent = (card, set) => {
138
+ const out = set.changes;
139
+ const moved = out.parent !== undefined || set.unset.includes('parent');
140
+ if (!moved || out.parents !== undefined) {
141
+ return;
142
+ }
143
+ const parents = normalizeParents(out.parent, card.parents.filter(parent => parent !== card.parent));
144
+ if (!sameValue(parents, card.parents)) {
145
+ out.parents = parents;
146
+ }
147
+ };
148
+ const reviseInto = (card, slot, set) => {
149
+ if (card.kind !== WorkcardKind.Specification) {
150
+ return;
151
+ }
152
+ const out = set.changes;
153
+ if (out.body !== undefined) {
154
+ out.bodyChars = bodyCharsOf(out.body);
155
+ }
156
+ else if (set.unset.includes('body') && !set.unset.includes('bodyChars')) {
157
+ set.unset.push('bodyChars');
158
+ }
159
+ const revised = CONTENT_KEYS.some(key => out[key] !== undefined || set.unset.includes(key));
160
+ if (revised) {
161
+ const revision = nextRevision(card, slot);
162
+ if (revision != null) {
163
+ out.revision = revision;
164
+ }
165
+ }
166
+ };
167
+ const createOf = (exec, type, registry, at, slot) => {
168
+ if (typeof exec.card === 'string') {
169
+ throw new PlanningError('malformed:create-without-draft');
170
+ }
171
+ const draft = exec.card;
172
+ const overlay = Object.fromEntries(Object.entries(exec.changes ?? {})
173
+ .filter(([key]) => !FLOW_KEYS.includes(key) && !IDENTITY_KEYS.includes(key) && !DERIVED_KEYS.includes(key)));
174
+ const parent = overlay.parent ?? draft.parent;
175
+ const flows = initialFlowsOf(type, registry, draft.status ?? exec.changes?.status);
176
+ const intrinsic = resolveIntrinsic(type, flows, registry);
177
+ const record = {
178
+ title: draft.title,
179
+ description: draft.description,
180
+ code: draft.code,
181
+ order: draft.order,
182
+ createdBy: draft.createdBy,
183
+ ...overlay,
184
+ labels: [...new Set(overlay.labels ?? draft.labels ?? [])],
185
+ parent,
186
+ parents: normalizeParents(parent, overlay.parents ?? draft.parents),
187
+ fields: mergeFields(draft.fields, overlay.fields),
188
+ flows,
189
+ status: flows[primaryFlowOf(type)],
190
+ intrinsic,
191
+ closedAt: intrinsic === IntrinsicStatus.Closed ? at : undefined,
192
+ };
193
+ if (draft.kind === WorkcardKind.Specification) {
194
+ const body = overlay.body ?? draft.body;
195
+ Object.assign(record, {
196
+ category: overlay.category ?? draft.category ?? slot?.category,
197
+ format: overlay.format ?? draft.format ?? slot?.format ?? SpecificationFormat.Markdown,
198
+ body,
199
+ ref: overlay.ref ?? draft.ref,
200
+ version: overlay.version ?? draft.version ?? slot?.version,
201
+ bodyChars: bodyCharsOf(body),
202
+ revision: nextRevision(null, slot),
203
+ });
204
+ }
205
+ return { changes: clean(record), unset: [] };
206
+ };
207
+ /**
208
+ * The `changes`/`unset` a transition records (plan step 9).
209
+ *
210
+ * - `create`: the whole initial record from the draft (overlaid by `exec.changes`) — `parents`
211
+ * normalized, every flow at its initial status (the draft's `status` for the primary one),
212
+ * `status`/`intrinsic` mirrored, `closedAt` when it starts closed; a specification gets its
213
+ * format, `bodyChars` and revision 1 when the slot is revisioned.
214
+ * - `update`: only what differs; `null` or `exec.unset` clears a field that has a value; a moved
215
+ * `parent` replaces the old one in `parents`; a revisioned document whose content changed gets
216
+ * `revision + 1`. An update that changes nothing is empty ({@link isEmptyChange}).
217
+ * - `transit`: `flows[flow] = rule.to`, `status` when the flow is primary, `intrinsic` when it
218
+ * moves, `closedAt` set on entering closed and cleared on leaving it — plus the caller's own
219
+ * changes, diffed as in an update.
220
+ * - `link`, `unlink`, `delete`: nothing.
221
+ *
222
+ * @throws {IllegalTransition} a transit the flow does not offer from the current status
223
+ * @throws {PlanningError} `malformed:*` for an execution missing what its action needs
224
+ */
225
+ export const computeChanges = (card, exec, type, registry, at, opts) => {
226
+ if (exec.action === TransitionAction.Create) {
227
+ return createOf(exec, type, registry, at, opts?.slot);
228
+ }
229
+ const set = { changes: {}, unset: [] };
230
+ if (exec.action !== TransitionAction.Update && exec.action !== TransitionAction.Transit) {
231
+ return set;
232
+ }
233
+ if (card == null) {
234
+ throw new PlanningError(`malformed:${exec.action}-without-card`);
235
+ }
236
+ if (exec.action === TransitionAction.Update) {
237
+ diffInto(card, exec.changes, [], set);
238
+ unsetInto(card, exec.unset, set);
239
+ reparent(card, set);
240
+ reviseInto(card, opts?.slot, set);
241
+ return set;
242
+ }
243
+ if (exec.transition == null) {
244
+ throw new PlanningError('malformed:transit-without-transition');
245
+ }
246
+ const primary = primaryFlowOf(type);
247
+ const flowId = exec.flow ?? primary;
248
+ const flow = registry.flow(flowId);
249
+ const from = card.flows[flowId] ?? (flowId === primary ? card.status : initialStatusOf(flow));
250
+ const rule = ruleOf(flow, exec.transition, from);
251
+ if (rule == null) {
252
+ throw new IllegalTransition(`${flowId}:${exec.transition}:${from}`);
253
+ }
254
+ diffInto(card, exec.changes, FLOW_KEYS, set);
255
+ unsetInto(card, exec.unset?.filter(path => !FLOW_KEYS.includes(path.split('.')[0])), set);
256
+ reparent(card, set);
257
+ reviseInto(card, opts?.slot, set);
258
+ const flows = { ...card.flows, [flowId]: rule.to };
259
+ set.changes.flows = { [flowId]: rule.to };
260
+ if (flowId === primary) {
261
+ set.changes.status = rule.to;
262
+ }
263
+ const intrinsic = resolveIntrinsic(type, flows, registry);
264
+ if (intrinsic !== card.intrinsic) {
265
+ set.changes.intrinsic = intrinsic;
266
+ }
267
+ if (intrinsic === IntrinsicStatus.Closed && card.intrinsic !== IntrinsicStatus.Closed) {
268
+ set.changes.closedAt = at;
269
+ }
270
+ else if (intrinsic !== IntrinsicStatus.Closed && card.closedAt != null) {
271
+ set.unset.push('closedAt');
272
+ }
273
+ return { ...set, flow: flowId, from, to: rule.to };
274
+ };
275
+ /** Nothing to write: no changed value and nothing to clear. */
276
+ export const isEmptyChange = (set) => set.unset.length === 0 && Object.entries(set.changes).every(([, value]) => value === undefined || (isPlainObject(value) && Object.keys(value).length === 0));
277
+ //# sourceMappingURL=changes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"changes.js","sourceRoot":"","sources":["../../src/helpers/changes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import type { CodePolicy, WorkcardDraft } from '../types.js';
2
+ export interface MintCodeOptions {
3
+ /** Slug style: the text the slug is derived from (a title). A word slug when omitted. */
4
+ seed?: string;
5
+ /** Sequential style: how many codes the scope already holds. */
6
+ count?: number;
7
+ }
8
+ /** `Some Title!` → `some-title`. */
9
+ export declare const slugOf: (text: string, max?: number) => string;
10
+ /**
11
+ * Mint a code under a policy, asking `taken` for each candidate.
12
+ *
13
+ * `random` draws `prefix + Base58(length)` (upper-cased when asked) afresh per attempt; `slug`
14
+ * walks `base`, `base-2`, `base-3` from the seed (a word slug without one); `sequential` counts on
15
+ * from `opts.count`, zero-padded to `length`. After `attempts` taken candidates it refuses.
16
+ *
17
+ * @throws {CodeTaken}
18
+ */
19
+ export declare const mintCode: (policy: CodePolicy, taken: (code: string) => boolean | Promise<boolean>, attempts?: number, opts?: MintCodeOptions) => Promise<string>;
20
+ /** Where a draft's code must be unique: its parent, or the whole entity. */
21
+ export declare const codeScopeOf: (policy: CodePolicy, draft: Pick<WorkcardDraft, 'parent'>) => {
22
+ parent?: string;
23
+ };
24
+ //# sourceMappingURL=code.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code.d.ts","sourceRoot":"","sources":["../../src/helpers/code.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAE5D,MAAM,WAAW,eAAe;IAC9B,yFAAyF;IACzF,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,gEAAgE;IAChE,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,oCAAoC;AACpC,eAAO,MAAM,MAAM,SAAU,MAAM,QAAO,MAAM,KAAc,MAG1B,CAAA;AAmBpC;;;;;;;;GAQG;AACH,eAAO,MAAM,QAAQ,WACX,UAAU,SACX,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,aACzC,MAAM,SACT,eAAe,KACrB,OAAO,CAAC,MAAM,CAYhB,CAAA;AAED,4EAA4E;AAC5E,eAAO,MAAM,WAAW,WAAY,UAAU,SAAS,IAAI,CAAC,aAAa,EAAE,QAAQ,CAAC,KAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAC9B,CAAA"}