@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,47 @@
1
+ import { createIdOfLength, generateWordSlug, IdStyle, nextSlugCandidate } from '@owlmeans/basic-ids';
2
+ import { CODE_MAX, CODE_MINT_ATTEMPTS, CodeScope, CodeStyle, DEFAULT_CODE_LENGTH } from '../consts.js';
3
+ import { CodeTaken } from '../errors.js';
4
+ /** `Some Title!` → `some-title`. */
5
+ export const slugOf = (text, max = CODE_MAX) => text
6
+ .normalize('NFKD').replace(/[̀-ͯ]/g, '')
7
+ .toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '')
8
+ .slice(0, max).replace(/-+$/g, '');
9
+ const candidateOf = (policy, attempt, base, opts) => {
10
+ const prefix = policy.prefix ?? '';
11
+ switch (policy.style) {
12
+ case CodeStyle.Slug:
13
+ return `${prefix}${nextSlugCandidate(base, attempt + 1)}`;
14
+ case CodeStyle.Sequential: {
15
+ const number = `${(opts?.count ?? 0) + attempt + 1}`;
16
+ return `${prefix}${policy.length != null ? number.padStart(policy.length, '0') : number}`;
17
+ }
18
+ case CodeStyle.Random:
19
+ default: {
20
+ const random = createIdOfLength(policy.length ?? DEFAULT_CODE_LENGTH, IdStyle.Base58);
21
+ return `${prefix}${policy.uppercase === true ? random.toUpperCase() : random}`;
22
+ }
23
+ }
24
+ };
25
+ /**
26
+ * Mint a code under a policy, asking `taken` for each candidate.
27
+ *
28
+ * `random` draws `prefix + Base58(length)` (upper-cased when asked) afresh per attempt; `slug`
29
+ * walks `base`, `base-2`, `base-3` from the seed (a word slug without one); `sequential` counts on
30
+ * from `opts.count`, zero-padded to `length`. After `attempts` taken candidates it refuses.
31
+ *
32
+ * @throws {CodeTaken}
33
+ */
34
+ export const mintCode = async (policy, taken, attempts = CODE_MINT_ATTEMPTS, opts) => {
35
+ const seeded = opts?.seed != null ? slugOf(opts.seed, CODE_MAX - (policy.prefix?.length ?? 0) - 4) : '';
36
+ const base = policy.style === CodeStyle.Slug ? (seeded !== '' ? seeded : generateWordSlug()) : '';
37
+ for (let attempt = 0; attempt < attempts; ++attempt) {
38
+ const candidate = candidateOf(policy, attempt, base, opts);
39
+ if (!await taken(candidate)) {
40
+ return candidate;
41
+ }
42
+ }
43
+ throw new CodeTaken(`${policy.style}:${policy.prefix ?? ''}:${attempts}`);
44
+ };
45
+ /** Where a draft's code must be unique: its parent, or the whole entity. */
46
+ export const codeScopeOf = (policy, draft) => policy.uniqueWithin === CodeScope.Parent ? { parent: draft.parent } : {};
47
+ //# sourceMappingURL=code.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code.js","sourceRoot":"","sources":["../../src/helpers/code.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export * from './apply.js';
2
+ export * from './card.js';
3
+ export * from './changes.js';
4
+ export * from './code.js';
5
+ export * from './query.js';
6
+ export * from './specification.js';
7
+ export * from './status.js';
8
+ export * from './validate.js';
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/helpers/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA;AACzB,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA;AACzB,cAAc,YAAY,CAAA;AAC1B,cAAc,oBAAoB,CAAA;AAClC,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA"}
@@ -0,0 +1,9 @@
1
+ export * from './apply.js';
2
+ export * from './card.js';
3
+ export * from './changes.js';
4
+ export * from './code.js';
5
+ export * from './query.js';
6
+ export * from './specification.js';
7
+ export * from './status.js';
8
+ export * from './validate.js';
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/helpers/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA;AACzB,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA;AACzB,cAAc,YAAY,CAAA;AAC1B,cAAc,oBAAoB,CAAA;AAClC,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA"}
@@ -0,0 +1,39 @@
1
+ import type { Criteria, ListOptions, ResourceRecord, Sort } from '@owlmeans/resource';
2
+ import type { PlanningScope, RelationshipQuery, RelationshipQueryWire, RelationshipWhere, Specification, SpecificationQuery, SpecificationQueryWire, SummaryQuery, SummaryQueryWire, SummaryView, TransitionQuery, TransitionQueryWire, TransitionWhere, Workcard, WorkcardQuery, WorkcardQueryWire } from '../types.js';
3
+ type Scope = Pick<PlanningScope, 'entityId'>;
4
+ /**
5
+ * `WorkcardQuery` → `Criteria<Workcard>` — the ONE translation every store answers, so a query
6
+ * means the same thing in memory, in Mongo and in a client mirror.
7
+ *
8
+ * `entityId` always comes from the scope (a query that forgot it would be a cross-tenant read);
9
+ * `undefined` values are omitted. Paging and sorting are {@link listOptionsOf}'s.
10
+ */
11
+ export declare const criteriaOf: (query?: WorkcardQuery | null, scope?: Scope) => Criteria<Workcard>;
12
+ /** Paging and sorting out of a query. `size: 0` (no limit) survives. */
13
+ export declare const listOptionsOf: <T extends ResourceRecord>(query?: ListOptions<T> | null) => ListOptions<T>;
14
+ /** The criteria over a parent's specifications. */
15
+ export declare const specCriteriaOf: (parent: string, query?: SpecificationQuery | null, scope?: Scope) => Criteria<Specification>;
16
+ export declare const linkWhereOf: (query: RelationshipQuery | null | undefined, scope: Scope) => RelationshipWhere;
17
+ export declare const transitionWhereOf: (query: TransitionQuery | null | undefined, scope: Scope) => TransitionWhere;
18
+ /** Counts of DIRECT children (`card.parent`) per parent, by intrinsic state. No key for a parent with none. */
19
+ export declare const summaryOf: (cards: Workcard[], parents: string[]) => SummaryView;
20
+ /** A list as one query value: comma-joined, or JSON when an element itself holds a comma. */
21
+ export declare const encodeList: (value?: string | readonly string[] | null) => string | undefined;
22
+ /** Every entry of a list query value, whatever shape the transport left it in. */
23
+ export declare const decodeList: (value: unknown, key?: string) => string[] | undefined;
24
+ /** `[{ field: 'order' }, { field: 'updatedAt', order: 'desc' }]` ⇄ `order,-updatedAt`. */
25
+ export declare const encodeSort: <T>(sort?: Sort<T>[] | null) => string | undefined;
26
+ export declare const decodeSort: <T>(value: unknown) => Sort<T>[] | undefined;
27
+ export declare const encodeWorkcardQuery: (query?: WorkcardQuery | null) => WorkcardQueryWire;
28
+ /** @throws {PlanningError} `malformed:query:<key>` for a value that does not decode */
29
+ export declare const decodeWorkcardQuery: (wire?: WorkcardQueryWire | WorkcardQuery | null) => WorkcardQuery;
30
+ export declare const encodeSummaryQuery: (query: SummaryQuery) => SummaryQueryWire;
31
+ export declare const decodeSummaryQuery: (wire?: SummaryQueryWire | SummaryQuery | null) => SummaryQuery;
32
+ export declare const encodeTransitionQuery: (query?: TransitionQuery | null) => TransitionQueryWire;
33
+ export declare const decodeTransitionQuery: (wire?: TransitionQueryWire | TransitionQuery | null) => TransitionQuery;
34
+ export declare const encodeSpecificationQuery: (query?: SpecificationQuery | null) => SpecificationQueryWire;
35
+ export declare const decodeSpecificationQuery: (wire?: SpecificationQueryWire | SpecificationQuery | null) => SpecificationQuery;
36
+ export declare const encodeRelationshipQuery: (query?: RelationshipQuery | null) => RelationshipQueryWire;
37
+ export declare const decodeRelationshipQuery: (wire?: RelationshipQueryWire | RelationshipQuery | null) => RelationshipQuery;
38
+ export {};
39
+ //# sourceMappingURL=query.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/helpers/query.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAA;AAGrF,OAAO,KAAK,EACiB,aAAa,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,iBAAiB,EACrG,aAAa,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,YAAY,EAAE,gBAAgB,EAAE,WAAW,EACtG,eAAe,EAAE,mBAAmB,EAAE,eAAe,EAAE,QAAQ,EAAE,aAAa,EAAE,iBAAiB,EAClG,MAAM,aAAa,CAAA;AAEpB,KAAK,KAAK,GAAG,IAAI,CAAC,aAAa,EAAE,UAAU,CAAC,CAAA;AAQ5C;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,WAAY,aAAa,GAAG,IAAI,UAAU,KAAK,KAAG,QAAQ,CAAC,QAAQ,CAiCzF,CAAA;AAED,wEAAwE;AACxE,eAAO,MAAM,aAAa,GAAI,CAAC,SAAS,cAAc,UAAU,WAAW,CAAC,CAAC,CAAC,GAAG,IAAI,KAAG,WAAW,CAAC,CAAC,CAInG,CAAA;AAEF,mDAAmD;AACnD,eAAO,MAAM,cAAc,WACjB,MAAM,UAAU,kBAAkB,GAAG,IAAI,UAAU,KAAK,KAC/D,QAAQ,CAAC,aAAa,CAKI,CAAA;AAE7B,eAAO,MAAM,WAAW,UAAW,iBAAiB,GAAG,IAAI,GAAG,SAAS,SAAS,KAAK,KAAG,iBAKtF,CAAA;AAEF,eAAO,MAAM,iBAAiB,UAAW,eAAe,GAAG,IAAI,GAAG,SAAS,SAAS,KAAK,KAAG,eAO1F,CAAA;AAMF,+GAA+G;AAC/G,eAAO,MAAM,SAAS,UAAW,QAAQ,EAAE,WAAW,MAAM,EAAE,KAAG,WAWhE,CAAA;AAID,6FAA6F;AAC7F,eAAO,MAAM,UAAU,WAAY,MAAM,GAAG,SAAS,MAAM,EAAE,GAAG,IAAI,KAAG,MAAM,GAAG,SAc/E,CAAA;AAED,kFAAkF;AAClF,eAAO,MAAM,UAAU,UAAW,OAAO,QAAO,MAAM,KAAY,MAAM,EAAE,GAAG,SAwB5E,CAAA;AA0CD,0FAA0F;AAC1F,eAAO,MAAM,UAAU,GAAI,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,KAAG,MAAM,GAAG,SAGI,CAAA;AAErE,eAAO,MAAM,UAAU,GAAI,CAAC,SAAS,OAAO,KAAG,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,SAmB1D,CAAA;AAiBD,eAAO,MAAM,mBAAmB,WAAY,aAAa,GAAG,IAAI,KAAG,iBAgBjE,CAAA;AAEF,uFAAuF;AACvF,eAAO,MAAM,mBAAmB,UAAW,iBAAiB,GAAG,aAAa,GAAG,IAAI,KAAG,aAmBrF,CAAA;AAED,eAAO,MAAM,kBAAkB,UAAW,YAAY,KAAG,gBAIvD,CAAA;AAEF,eAAO,MAAM,kBAAkB,UAAW,gBAAgB,GAAG,YAAY,GAAG,IAAI,KAAG,YAOlF,CAAA;AAED,eAAO,MAAM,qBAAqB,WAAY,eAAe,GAAG,IAAI,KAAG,mBAOrE,CAAA;AAEF,eAAO,MAAM,qBAAqB,UAAW,mBAAmB,GAAG,eAAe,GAAG,IAAI,KAAG,eAU3F,CAAA;AAED,eAAO,MAAM,wBAAwB,WAAY,kBAAkB,GAAG,IAAI,KAAG,sBAI3E,CAAA;AAEF,eAAO,MAAM,wBAAwB,UAAW,sBAAsB,GAAG,kBAAkB,GAAG,IAAI,KAAG,kBAOpG,CAAA;AAED,eAAO,MAAM,uBAAuB,WAAY,iBAAiB,GAAG,IAAI,KAAG,qBAKzE,CAAA;AAEF,eAAO,MAAM,uBAAuB,UAAW,qBAAqB,GAAG,iBAAiB,GAAG,IAAI,KAAG,iBAQjG,CAAA"}
@@ -0,0 +1,293 @@
1
+ import { IntrinsicStatus, WorkcardKind } from '../consts.js';
2
+ import { PlanningError } from '../errors.js';
3
+ const clean = (record) => Object.fromEntries(Object.entries(record).filter(([, value]) => value !== undefined));
4
+ /** `%`, `_` and `\` are wildcards/escapes to `$ilike`; a search text means them literally. */
5
+ const escapeLike = (text) => text.replace(/[\\%_]/g, char => `\\${char}`);
6
+ /**
7
+ * `WorkcardQuery` → `Criteria<Workcard>` — the ONE translation every store answers, so a query
8
+ * means the same thing in memory, in Mongo and in a client mirror.
9
+ *
10
+ * `entityId` always comes from the scope (a query that forgot it would be a cross-tenant read);
11
+ * `undefined` values are omitted. Paging and sorting are {@link listOptionsOf}'s.
12
+ */
13
+ export const criteriaOf = (query, scope) => {
14
+ const where = {
15
+ entityId: scope?.entityId,
16
+ kind: query?.kind,
17
+ type: query?.type,
18
+ status: query?.status,
19
+ intrinsic: query?.intrinsic,
20
+ code: query?.code,
21
+ parent: query?.parent,
22
+ parents: query?.within != null ? { $contains: query.within } : undefined,
23
+ labels: query?.labels != null ? { $overlaps: query.labels } : undefined,
24
+ id: query?.ids != null ? { $in: query.ids } : undefined,
25
+ category: query?.category,
26
+ updatedAt: query?.updatedSince != null ? { $gte: query.updatedSince } : undefined,
27
+ };
28
+ if (query?.flow != null) {
29
+ where[`flows.${query.flow.id}`] = query.flow.status;
30
+ }
31
+ for (const [key, value] of Object.entries(query?.fields ?? {})) {
32
+ if (value !== undefined) {
33
+ where[`fields.${key}`] = value;
34
+ }
35
+ }
36
+ if (query?.q != null && query.q !== '') {
37
+ const like = `%${escapeLike(query.q)}%`;
38
+ where.$or = [
39
+ { title: { $ilike: like } },
40
+ { description: { $ilike: like } },
41
+ { code: { $startsWith: query.q } },
42
+ ];
43
+ }
44
+ return clean(where);
45
+ };
46
+ /** Paging and sorting out of a query. `size: 0` (no limit) survives. */
47
+ export const listOptionsOf = (query) => clean({
48
+ page: query?.page,
49
+ size: query?.size,
50
+ sort: query?.sort,
51
+ });
52
+ /** The criteria over a parent's specifications. */
53
+ export const specCriteriaOf = (parent, query, scope) => clean({
54
+ entityId: scope?.entityId,
55
+ kind: WorkcardKind.Specification,
56
+ parent,
57
+ category: query?.category,
58
+ });
59
+ export const linkWhereOf = (query, scope) => clean({
60
+ entityId: scope.entityId,
61
+ from: query?.from,
62
+ to: query?.to,
63
+ type: query?.type,
64
+ });
65
+ export const transitionWhereOf = (query, scope) => clean({
66
+ entityId: scope.entityId,
67
+ card: query?.card,
68
+ project: query?.project,
69
+ sinceSeq: query?.sinceSeq,
70
+ action: query?.action,
71
+ state: query?.state,
72
+ });
73
+ const emptyCounts = () => ({
74
+ total: 0, [IntrinsicStatus.Planned]: 0, [IntrinsicStatus.InProgress]: 0, [IntrinsicStatus.Closed]: 0,
75
+ });
76
+ /** Counts of DIRECT children (`card.parent`) per parent, by intrinsic state. No key for a parent with none. */
77
+ export const summaryOf = (cards, parents) => cards.reduce((view, card) => {
78
+ if (card.parent == null || !parents.includes(card.parent)) {
79
+ return view;
80
+ }
81
+ const counts = view[card.parent] ?? emptyCounts();
82
+ counts.total += 1;
83
+ counts[card.intrinsic] = (counts[card.intrinsic] ?? 0) + 1;
84
+ view[card.parent] = counts;
85
+ return view;
86
+ }, {});
87
+ // ─── Wire encoding ───────────────────────────────────────────────────────────────────────────────
88
+ /** A list as one query value: comma-joined, or JSON when an element itself holds a comma. */
89
+ export const encodeList = (value) => {
90
+ if (value == null) {
91
+ return undefined;
92
+ }
93
+ if (typeof value === 'string') {
94
+ return encodeList([value]);
95
+ }
96
+ if (value.length === 0) {
97
+ return undefined;
98
+ }
99
+ return value.some(entry => entry.includes(',') || entry.startsWith('['))
100
+ ? JSON.stringify(value)
101
+ : value.join(',');
102
+ };
103
+ /** Every entry of a list query value, whatever shape the transport left it in. */
104
+ export const decodeList = (value, key = 'list') => {
105
+ if (value == null || value === '') {
106
+ return undefined;
107
+ }
108
+ if (Array.isArray(value)) {
109
+ const entries = value.filter(entry => entry != null && entry !== '').map(entry => `${entry}`);
110
+ return entries.length > 0 ? entries : undefined;
111
+ }
112
+ if (typeof value !== 'string') {
113
+ return [`${value}`];
114
+ }
115
+ if (value.startsWith('[')) {
116
+ const parsed = (() => {
117
+ try {
118
+ return JSON.parse(value);
119
+ }
120
+ catch {
121
+ throw new PlanningError(`malformed:query:${key}`);
122
+ }
123
+ })();
124
+ return Array.isArray(parsed) ? parsed.map(entry => `${entry}`) : undefined;
125
+ }
126
+ const entries = value.split(',').map(entry => entry.trim()).filter(entry => entry !== '');
127
+ return entries.length > 0 ? entries : undefined;
128
+ };
129
+ /** A list decoded to a bare value when it holds one — the same criteria either way. */
130
+ const decodeOneOrMany = (value, key) => {
131
+ const entries = decodeList(value, key);
132
+ return entries == null ? undefined : entries.length === 1 ? entries[0] : entries;
133
+ };
134
+ const encodeJson = (value) => value == null ? undefined : JSON.stringify(value);
135
+ const decodeJson = (value, key) => {
136
+ if (value == null || value === '') {
137
+ return undefined;
138
+ }
139
+ if (typeof value !== 'string') {
140
+ return value;
141
+ }
142
+ try {
143
+ return JSON.parse(value);
144
+ }
145
+ catch {
146
+ throw new PlanningError(`malformed:query:${key}`);
147
+ }
148
+ };
149
+ const decodeNumber = (value, key) => {
150
+ if (value == null || value === '') {
151
+ return undefined;
152
+ }
153
+ const number = typeof value === 'number' ? value : Number(value);
154
+ if (Number.isNaN(number)) {
155
+ throw new PlanningError(`malformed:query:${key}`);
156
+ }
157
+ return number;
158
+ };
159
+ const decodeBoolean = (value) => value == null || value === '' ? undefined : value === true || value === 'true' || value === '1';
160
+ const decodeText = (value) => value == null || value === '' ? undefined : `${Array.isArray(value) ? value[0] : value}`;
161
+ /** `[{ field: 'order' }, { field: 'updatedAt', order: 'desc' }]` ⇄ `order,-updatedAt`. */
162
+ export const encodeSort = (sort) => sort == null || sort.length === 0 ? undefined : sort.map(entry => typeof entry === 'string'
163
+ ? entry
164
+ : `${entry.order === 'desc' ? '-' : ''}${entry.field}`).join(',');
165
+ export const decodeSort = (value) => {
166
+ if (value == null || value === '') {
167
+ return undefined;
168
+ }
169
+ const entries = Array.isArray(value) ? value : typeof value === 'string' ? value.split(',') : [value];
170
+ const sort = entries.flatMap((entry) => {
171
+ if (typeof entry !== 'string') {
172
+ return entry != null && typeof entry === 'object' && 'field' in entry ? [entry] : [];
173
+ }
174
+ const field = entry.trim();
175
+ if (field === '' || field === '-') {
176
+ return [];
177
+ }
178
+ return field.startsWith('-')
179
+ ? [{ field: field.slice(1), order: 'desc' }]
180
+ : [field];
181
+ });
182
+ return sort.length > 0 ? sort : undefined;
183
+ };
184
+ const encodeListOptions = (query) => clean({
185
+ page: query?.page,
186
+ size: query?.size,
187
+ sort: encodeSort(query?.sort),
188
+ });
189
+ const decodeListOptions = (wire) => clean({
190
+ page: decodeNumber(wire.page, 'page'),
191
+ size: decodeNumber(wire.size, 'size'),
192
+ sort: decodeSort(wire.sort),
193
+ });
194
+ const asRecord = (wire) => wire != null && typeof wire === 'object' ? wire : {};
195
+ export const encodeWorkcardQuery = (query) => clean({
196
+ ...encodeListOptions(query),
197
+ kind: encodeList(query?.kind),
198
+ type: encodeList(query?.type),
199
+ parent: query?.parent,
200
+ within: query?.within,
201
+ status: encodeList(query?.status),
202
+ intrinsic: encodeList(query?.intrinsic),
203
+ flow: encodeJson(query?.flow),
204
+ labels: encodeList(query?.labels),
205
+ code: encodeList(query?.code),
206
+ ids: encodeList(query?.ids),
207
+ fields: query?.fields != null && Object.keys(query.fields).length > 0 ? encodeJson(query.fields) : undefined,
208
+ q: query?.q,
209
+ category: encodeList(query?.category),
210
+ updatedSince: query?.updatedSince,
211
+ });
212
+ /** @throws {PlanningError} `malformed:query:<key>` for a value that does not decode */
213
+ export const decodeWorkcardQuery = (wire) => {
214
+ const value = asRecord(wire);
215
+ return clean({
216
+ ...decodeListOptions(value),
217
+ kind: decodeOneOrMany(value.kind, 'kind'),
218
+ type: decodeOneOrMany(value.type, 'type'),
219
+ parent: decodeText(value.parent),
220
+ within: decodeText(value.within),
221
+ status: decodeOneOrMany(value.status, 'status'),
222
+ intrinsic: decodeOneOrMany(value.intrinsic, 'intrinsic'),
223
+ flow: decodeJson(value.flow, 'flow'),
224
+ labels: decodeList(value.labels, 'labels'),
225
+ code: decodeOneOrMany(value.code, 'code'),
226
+ ids: decodeList(value.ids, 'ids'),
227
+ fields: decodeJson(value.fields, 'fields'),
228
+ q: decodeText(value.q),
229
+ category: decodeOneOrMany(value.category, 'category'),
230
+ updatedSince: decodeText(value.updatedSince),
231
+ });
232
+ };
233
+ export const encodeSummaryQuery = (query) => clean({
234
+ parents: encodeList(query.parents) ?? '',
235
+ kind: query.kind,
236
+ type: encodeList(query.type),
237
+ });
238
+ export const decodeSummaryQuery = (wire) => {
239
+ const value = asRecord(wire);
240
+ return clean({
241
+ parents: decodeList(value.parents, 'parents') ?? [],
242
+ kind: decodeText(value.kind),
243
+ type: decodeOneOrMany(value.type, 'type'),
244
+ });
245
+ };
246
+ export const encodeTransitionQuery = (query) => clean({
247
+ ...encodeListOptions(query),
248
+ card: query?.card,
249
+ project: query?.project,
250
+ sinceSeq: query?.sinceSeq,
251
+ action: encodeList(query?.action),
252
+ state: query?.state,
253
+ });
254
+ export const decodeTransitionQuery = (wire) => {
255
+ const value = asRecord(wire);
256
+ return clean({
257
+ ...decodeListOptions(value),
258
+ card: decodeText(value.card),
259
+ project: decodeText(value.project),
260
+ sinceSeq: decodeNumber(value.sinceSeq, 'sinceSeq'),
261
+ action: decodeOneOrMany(value.action, 'action'),
262
+ state: decodeText(value.state),
263
+ });
264
+ };
265
+ export const encodeSpecificationQuery = (query) => clean({
266
+ ...encodeListOptions(query),
267
+ category: encodeList(query?.category),
268
+ all: query?.all,
269
+ });
270
+ export const decodeSpecificationQuery = (wire) => {
271
+ const value = asRecord(wire);
272
+ return clean({
273
+ ...decodeListOptions(value),
274
+ category: decodeOneOrMany(value.category, 'category'),
275
+ all: decodeBoolean(value.all),
276
+ });
277
+ };
278
+ export const encodeRelationshipQuery = (query) => clean({
279
+ ...encodeListOptions(query),
280
+ from: encodeList(query?.from),
281
+ to: encodeList(query?.to),
282
+ type: encodeList(query?.type),
283
+ });
284
+ export const decodeRelationshipQuery = (wire) => {
285
+ const value = asRecord(wire);
286
+ return clean({
287
+ ...decodeListOptions(value),
288
+ from: decodeOneOrMany(value.from, 'from'),
289
+ to: decodeOneOrMany(value.to, 'to'),
290
+ type: decodeOneOrMany(value.type, 'type'),
291
+ });
292
+ };
293
+ //# sourceMappingURL=query.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.js","sourceRoot":"","sources":["../../src/helpers/query.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import type { AnyTypeSchema, PlanningSchemaRegistry, Specification, SpecificationSlot, Workcard } from '../types.js';
2
+ /** The slot a parent type declares for a category. */
3
+ export declare const slotOf: (type: AnyTypeSchema, category: string) => SpecificationSlot | undefined;
4
+ export declare const isRevisioned: (slot?: SpecificationSlot | null) => boolean;
5
+ export declare const bodyCharsOf: (body?: string | null) => number | undefined;
6
+ /** The revision a write lands as: 1 for a new document, current + 1 after, none when unrevisioned. */
7
+ export declare const nextRevision: (current: Pick<Specification, 'revision'> | null | undefined, slot?: SpecificationSlot | null) => number | undefined;
8
+ /**
9
+ * The current document of a category among a parent's specifications: the highest revision, then
10
+ * the most recently updated. `null` when the category has none.
11
+ */
12
+ export declare const currentSpecification: (specs: Workcard[], category: string) => Specification | null;
13
+ /**
14
+ * The specification type a new document of a slot is created with: the slot's own `type`, else
15
+ * the only registered specification type, else the one sharing the parent type's prefix
16
+ * (`viable:project` → `viable:spec`).
17
+ *
18
+ * @throws {UnknownWorkcardType} when none or several candidates remain
19
+ */
20
+ export declare const specificationTypeOf: (registry: Pick<PlanningSchemaRegistry, 'types'>, parentType: string, slot?: SpecificationSlot | null) => string;
21
+ //# sourceMappingURL=specification.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"specification.d.ts","sourceRoot":"","sources":["../../src/helpers/specification.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,aAAa,EAAE,sBAAsB,EAAE,aAAa,EAAE,iBAAiB,EAAE,QAAQ,EAClF,MAAM,aAAa,CAAA;AAEpB,sDAAsD;AACtD,eAAO,MAAM,MAAM,SAAU,aAAa,YAAY,MAAM,KAAG,iBAAiB,GAAG,SACrB,CAAA;AAE9D,eAAO,MAAM,YAAY,UAAW,iBAAiB,GAAG,IAAI,KAAG,OAAoC,CAAA;AAEnG,eAAO,MAAM,WAAW,UAAW,MAAM,GAAG,IAAI,KAAG,MAAM,GAAG,SAAmD,CAAA;AAE/G,sGAAsG;AACtG,eAAO,MAAM,YAAY,YACd,IAAI,CAAC,aAAa,EAAE,UAAU,CAAC,GAAG,IAAI,GAAG,SAAS,SAAS,iBAAiB,GAAG,IAAI,KAC3F,MAAM,GAAG,SAA0E,CAAA;AAEtF;;;GAGG;AACH,eAAO,MAAM,oBAAoB,UACxB,QAAQ,EAAE,YAAY,MAAM,KAClC,aAAa,GAAG,IAYT,CAAA;AAIV;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,aACpB,IAAI,CAAC,sBAAsB,EAAE,OAAO,CAAC,cAAc,MAAM,SAAS,iBAAiB,GAAG,IAAI,KACnG,MAcF,CAAA"}
@@ -0,0 +1,48 @@
1
+ import { WorkcardKind } from '../consts.js';
2
+ import { UnknownWorkcardType } from '../errors.js';
3
+ /** The slot a parent type declares for a category. */
4
+ export const slotOf = (type, category) => type.specifications.find(slot => slot.category === category);
5
+ export const isRevisioned = (slot) => slot?.revisioned === true;
6
+ export const bodyCharsOf = (body) => body == null ? undefined : body.length;
7
+ /** The revision a write lands as: 1 for a new document, current + 1 after, none when unrevisioned. */
8
+ export const nextRevision = (current, slot) => isRevisioned(slot) ? (current?.revision ?? 0) + 1 : undefined;
9
+ /**
10
+ * The current document of a category among a parent's specifications: the highest revision, then
11
+ * the most recently updated. `null` when the category has none.
12
+ */
13
+ export const currentSpecification = (specs, category) => specs
14
+ .filter((spec) => spec.kind === WorkcardKind.Specification
15
+ && spec.category === category)
16
+ .reduce((best, spec) => {
17
+ if (best == null) {
18
+ return spec;
19
+ }
20
+ const byRevision = (spec.revision ?? 0) - (best.revision ?? 0);
21
+ if (byRevision !== 0) {
22
+ return byRevision > 0 ? spec : best;
23
+ }
24
+ return (spec.updatedAt ?? spec.createdAt) > (best.updatedAt ?? best.createdAt) ? spec : best;
25
+ }, null);
26
+ const prefixOf = (type) => type.includes(':') ? type.slice(0, type.lastIndexOf(':')) : '';
27
+ /**
28
+ * The specification type a new document of a slot is created with: the slot's own `type`, else
29
+ * the only registered specification type, else the one sharing the parent type's prefix
30
+ * (`viable:project` → `viable:spec`).
31
+ *
32
+ * @throws {UnknownWorkcardType} when none or several candidates remain
33
+ */
34
+ export const specificationTypeOf = (registry, parentType, slot) => {
35
+ if (slot?.type != null) {
36
+ return slot.type;
37
+ }
38
+ const candidates = registry.types().filter(type => type.kind === WorkcardKind.Specification);
39
+ if (candidates.length === 1) {
40
+ return candidates[0].type;
41
+ }
42
+ const prefixed = candidates.filter(type => prefixOf(type.type) === prefixOf(parentType));
43
+ if (prefixed.length === 1) {
44
+ return prefixed[0].type;
45
+ }
46
+ throw new UnknownWorkcardType(`specification:${parentType}:${slot?.category ?? ''}`);
47
+ };
48
+ //# sourceMappingURL=specification.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"specification.js","sourceRoot":"","sources":["../../src/helpers/specification.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ import { IntrinsicStatus } from '../consts.js';
2
+ import type { AnyTypeSchema, PlanningSchemaRegistry, StatusDefinition, StatusFlowSchema, StatusTransitionRule } from '../types.js';
3
+ type FlowLookup = Pick<PlanningSchemaRegistry, 'flow'>;
4
+ /** The primary flow id of a type — `flows[0]`. @throws {UnknownStatusFlow} when it declares none */
5
+ export declare const primaryFlowOf: (type: AnyTypeSchema) => string;
6
+ export declare const flowIdsOf: (type: AnyTypeSchema) => string[];
7
+ export declare const statusDefinitionOf: (flow: StatusFlowSchema, status: string) => StatusDefinition | undefined;
8
+ /** The intrinsic state a status maps onto, or `undefined` for a status the flow does not declare. */
9
+ export declare const intrinsicOf: (flow: StatusFlowSchema, status: string) => IntrinsicStatus | undefined;
10
+ /** The status marked `initial`, else the first one. @throws {PlanningError} for a flow with none */
11
+ export declare const initialStatusOf: (flow: StatusFlowSchema) => string;
12
+ export declare const isTerminal: (flow: StatusFlowSchema, status: string) => boolean;
13
+ /**
14
+ * The rule a named transition follows from a status.
15
+ *
16
+ * A name may be declared several times with different `from` sets; the rule naming the status
17
+ * explicitly wins, and a `'*'` rule of that name answers only when none does.
18
+ */
19
+ export declare const ruleOf: (flow: StatusFlowSchema, transition: string, from: string) => StatusTransitionRule | undefined;
20
+ export declare const canTransit: (flow: StatusFlowSchema, transition: string, from: string) => boolean;
21
+ /**
22
+ * Every transition available from a status, one rule per name (the one `ruleOf` would pick), in
23
+ * declaration order. `explicit: true` keeps only the rules offered to a person.
24
+ */
25
+ export declare const transitionsFrom: (flow: StatusFlowSchema, status: string, opts?: {
26
+ explicit?: boolean;
27
+ }) => StatusTransitionRule[];
28
+ /**
29
+ * A new card's status per flow: every flow's initial status, with the primary one overridden by
30
+ * `status` when the draft names one.
31
+ *
32
+ * @throws {UnknownStatusFlow}
33
+ */
34
+ export declare const initialFlowsOf: (type: AnyTypeSchema, registry: FlowLookup, status?: string) => Record<string, string>;
35
+ /**
36
+ * The card's intrinsic state over its flows. {@link IntrinsicPolicy.Primary} reads the primary
37
+ * flow; {@link IntrinsicPolicy.All} takes the least advanced flow. A status the flow does not
38
+ * declare reads as planned.
39
+ *
40
+ * @throws {UnknownStatusFlow}
41
+ */
42
+ export declare const resolveIntrinsic: (type: AnyTypeSchema, flows: Record<string, string>, registry: FlowLookup) => IntrinsicStatus;
43
+ export {};
44
+ //# sourceMappingURL=status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/helpers/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgD,eAAe,EAAE,MAAM,cAAc,CAAA;AAE5F,OAAO,KAAK,EACV,aAAa,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,oBAAoB,EAChG,MAAM,aAAa,CAAA;AAEpB,KAAK,UAAU,GAAG,IAAI,CAAC,sBAAsB,EAAE,MAAM,CAAC,CAAA;AAEtD,oGAAoG;AACpG,eAAO,MAAM,aAAa,SAAU,aAAa,KAAG,MAOnD,CAAA;AAED,eAAO,MAAM,SAAS,SAAU,aAAa,KAAG,MAAM,EAAqB,CAAA;AAE3E,eAAO,MAAM,kBAAkB,SAAU,gBAAgB,UAAU,MAAM,KAAG,gBAAgB,GAAG,SAClC,CAAA;AAE7D,qGAAqG;AACrG,eAAO,MAAM,WAAW,SAAU,gBAAgB,UAAU,MAAM,KAAG,eAAe,GAAG,SAC1C,CAAA;AAE7C,oGAAoG;AACpG,eAAO,MAAM,eAAe,SAAU,gBAAgB,KAAG,MAOxD,CAAA;AAED,eAAO,MAAM,UAAU,SAAU,gBAAgB,UAAU,MAAM,KAAG,OACf,CAAA;AAKrD;;;;;GAKG;AACH,eAAO,MAAM,MAAM,SACX,gBAAgB,cAAc,MAAM,QAAQ,MAAM,KACvD,oBAAoB,GAAG,SAKzB,CAAA;AAED,eAAO,MAAM,UAAU,SAAU,gBAAgB,cAAc,MAAM,QAAQ,MAAM,KAAG,OAC9C,CAAA;AAExC;;;GAGG;AACH,eAAO,MAAM,eAAe,SACpB,gBAAgB,UAAU,MAAM,SAAS;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,KACpE,oBAAoB,EAMtB,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,cAAc,SACnB,aAAa,YAAY,UAAU,WAAW,MAAM,KACzD,MAAM,CAAC,MAAM,EAAE,MAAM,CAMvB,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,SACrB,aAAa,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,YAAY,UAAU,KACvE,eAgBF,CAAA"}