@adobe/data-ai 0.9.89 → 0.9.91
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/.claude/rules/README.md +22 -16
- package/.claude/rules/element.md +1 -1
- package/.claude/rules/features/data/index.md +1 -1
- package/.claude/rules/features/data/state.md +2 -2
- package/.claude/rules/features/index.md +56 -39
- package/.claude/rules/features/services/index.md +31 -18
- package/.claude/rules/features/{ecs → services/main-service}/actions.md +2 -2
- package/.claude/rules/features/{ecs → services/main-service}/archetypes.md +1 -1
- package/.claude/rules/features/{ecs → services/main-service}/components.md +2 -2
- package/.claude/rules/features/{ecs → services/main-service}/computed.md +1 -1
- package/.claude/rules/features/{ecs → services/main-service}/conformance.md +3 -3
- package/.claude/rules/features/{ecs → services/main-service}/index.md +10 -8
- package/.claude/rules/features/{ecs → services/main-service}/indexes.md +1 -1
- package/.claude/rules/features/{ecs → services/main-service}/resources.md +2 -2
- package/.claude/rules/features/{ecs → services/main-service}/services.md +1 -1
- package/.claude/rules/features/{ecs → services/main-service}/systems.md +8 -4
- package/.claude/rules/features/{ecs → services/main-service}/transactions.md +3 -3
- package/.claude/rules/features/ui/binding-element.md +2 -2
- package/.claude/rules/features/ui/index.md +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +1 -1
- package/bin/cli.mjs +51 -3
- package/package.json +4 -5
- package/skills/build-actions/SKILL.md +4 -4
- package/skills/build-app-entry/SKILL.md +1 -1
- package/skills/build-computed/SKILL.md +3 -3
- package/skills/build-core-database/SKILL.md +3 -3
- package/skills/build-data/SKILL.md +1 -1
- package/skills/build-game/SKILL.md +1 -1
- package/skills/build-indexes/SKILL.md +3 -3
- package/skills/build-service-database/SKILL.md +3 -3
- package/skills/build-services/SKILL.md +2 -2
- package/skills/build-systems/SKILL.md +8 -5
- package/skills/build-transactions/SKILL.md +4 -3
- package/skills/build-ui/SKILL.md +1 -1
- package/skills/meta-build/SKILL.md +1 -0
- package/skills/review/SKILL.md +1 -0
- /package/.claude/rules/{cohesion.md → global/cohesion.md} +0 -0
- /package/.claude/rules/{function-references.md → global/function-references.md} +0 -0
- /package/.claude/rules/{namespace.md → global/namespace.md} +0 -0
- /package/.claude/rules/{react.md → global/react.md} +0 -0
- /package/.claude/rules/{type-casts.md → global/type-casts.md} +0 -0
package/.claude/rules/README.md
CHANGED
|
@@ -13,30 +13,36 @@ folder's own `index.md` holds just enough to understand that folder; each
|
|
|
13
13
|
child gets its own file (recursing wherever the source tree does):
|
|
14
14
|
|
|
15
15
|
```
|
|
16
|
+
global/ # always-on conventions — deliberately repo-wide globs
|
|
17
|
+
namespace.md cohesion.md type-casts.md function-references.md react.md
|
|
16
18
|
features/
|
|
17
|
-
index.md # the feature layering as a whole (ui →
|
|
19
|
+
index.md # the feature layering as a whole (ui → services → data)
|
|
18
20
|
data/
|
|
19
21
|
index.md # data-type namespaces (foundation)
|
|
20
22
|
state.md # the State aggregate: pure transforms & derivations
|
|
21
|
-
services/
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
services/
|
|
24
|
+
index.md # the services layer: main-service + capability contracts
|
|
25
|
+
main-service/ # the feature service (ECS implementation)
|
|
26
|
+
index.md # the service + its layered database plugins
|
|
27
|
+
components.md resources.md archetypes.md
|
|
28
|
+
computed.md indexes.md transactions.md services.md actions.md
|
|
29
|
+
systems.md conformance.md
|
|
27
30
|
ui/index.md # UI (points to element / presentation / lazy-element file rules)
|
|
28
31
|
```
|
|
29
32
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
`
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
The `global/` rules (`namespace.md`, `cohesion.md`, `type-casts.md`,
|
|
34
|
+
`function-references.md`, `react.md`) are **intentionally repo-wide** — their
|
|
35
|
+
`paths:` globs (`**/*.ts` etc.) apply everywhere, by design, so the folder name
|
|
36
|
+
makes that explicit. Alongside `features/`, the remaining rules-root `.md` files
|
|
37
|
+
hold the other **cross-cutting** patterns the feature rules reference —
|
|
38
|
+
`data-modelling.md`, `archetypes.md` (row iteration), `plugin-modelling.md`, and
|
|
39
|
+
the UI file rules (`element.md`, `lazy-element.md`, `presentation.md`). They live
|
|
40
|
+
here so the bundle is self-contained; this repo symlinks them into its own
|
|
41
|
+
`.claude/rules/` (as it does `features/`).
|
|
36
42
|
|
|
37
43
|
Each rule's `paths:` glob is scoped to `**/features/*/<layer>/…`, so these
|
|
38
44
|
rules apply only once an application opts into the feature-folder pattern
|
|
39
45
|
(source organized under `features/<name>/`). Editing
|
|
40
|
-
`features/<name>/
|
|
41
|
-
`
|
|
42
|
-
at creation and at every later edit.
|
|
46
|
+
`features/<name>/services/main-service/core-database/components.ts` pulls in both
|
|
47
|
+
`main-service/index.md` (the layer overview) and `main-service/components.md`
|
|
48
|
+
(the specifics) — at creation and at every later edit.
|
package/.claude/rules/element.md
CHANGED
|
@@ -124,7 +124,7 @@ Lit-only: `static styles = styles` from a sibling `*.css.ts`. `@property`
|
|
|
124
124
|
exists *only* for locator inputs — never for state, never for derived
|
|
125
125
|
values, never for parent-forwarded flags. The `P` in `DatabaseElement<P>` (and
|
|
126
126
|
the `get plugin()` it returns) is the surface the element *consumes* — never the
|
|
127
|
-
varying topmost-layer name (see `features/
|
|
127
|
+
varying topmost-layer name (see `features/services/main-service/index.md`): `typeof
|
|
128
128
|
FeatureDatabase.plugin` for a self-contained feature. **Exception:** an element
|
|
129
129
|
meant to be *extended* — injected with various databases that build on this
|
|
130
130
|
feature (a peer app that adds an agent, a p2p/presence build) — types on the
|
|
@@ -11,7 +11,7 @@ communication over the wire — no functions, no handles, just plain data.
|
|
|
11
11
|
It depends on nothing but `@adobe/data` and other `data/` declarations, and
|
|
12
12
|
needs no knowledge of anything built on top of it.
|
|
13
13
|
|
|
14
|
-
Each data type is its own namespace folder (see `namespace.md`), holding
|
|
14
|
+
Each data type is its own namespace folder (see `global/namespace.md`), holding
|
|
15
15
|
its schema, its derived type, and its pure synchronous helpers together:
|
|
16
16
|
|
|
17
17
|
```
|
|
@@ -43,8 +43,8 @@ export * as State from "./public.js";
|
|
|
43
43
|
- Each transform has a sibling `*.test.ts`; performance is irrelevant here,
|
|
44
44
|
correctness is everything. Keep its cases in a sibling `<transform>.cases.ts`
|
|
45
45
|
typed `ConformanceCase<Args>[]` (the shared `conformance-case.ts` type) —
|
|
46
|
-
spec-owned truth the matching
|
|
47
|
-
`
|
|
46
|
+
spec-owned truth the matching main-service conformance test imports unchanged (see
|
|
47
|
+
`services/main-service/conformance.md`). Author `before`/`after` as full `State`
|
|
48
48
|
(`{ ...State.create(), …overrides }`); the generic-slice signature lets them
|
|
49
49
|
flow through. Tolerant full-`State` equality is the shared
|
|
50
50
|
`expect-state-matches.ts`, alongside the cases here.
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
paths:
|
|
3
3
|
- '**/features/*/data/**/*.ts'
|
|
4
4
|
- '**/features/*/services/**/*.ts'
|
|
5
|
-
- '**/features/*/ecs/**/*.ts'
|
|
6
5
|
- '**/features/*/ui/**/*.ts'
|
|
7
6
|
---
|
|
8
7
|
|
|
@@ -14,34 +13,39 @@ trust, and an **efficient implementation** proven equivalent to it.
|
|
|
14
13
|
- **`data/` is the specification.** The whole feature modelled as one immutable
|
|
15
14
|
`State` with pure transformations over it — correct by construction, fully
|
|
16
15
|
unit-tested, performance irrelevant. This is the source of truth.
|
|
17
|
-
- **`
|
|
18
|
-
mutation efficiency
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
- **`services/main-service/` is the implementation.** The same model physically
|
|
17
|
+
arranged for mutation efficiency — a reactive Entity-Component-System, an
|
|
18
|
+
implementation detail behind the service. Its reads and writes wrap the
|
|
19
|
+
`data/` functions where practical; where they must be hand-optimized, unit
|
|
20
|
+
tests verify they still agree with the `data/` precedent.
|
|
21
21
|
|
|
22
|
-
Because the optimized `
|
|
23
|
-
it can be generated and kept honest by AI rules, with the conformance
|
|
24
|
-
the safety net. Net result: write a slow-but-verifiable app, then
|
|
25
|
-
one that provably behaves the same.
|
|
22
|
+
Because the optimized `main-service` is largely mechanical given the `data/`
|
|
23
|
+
spec, it can be generated and kept honest by AI rules, with the conformance
|
|
24
|
+
tests as the safety net. Net result: write a slow-but-verifiable app, then
|
|
25
|
+
derive a fast one that provably behaves the same.
|
|
26
26
|
|
|
27
|
-
## The
|
|
27
|
+
## The layers
|
|
28
28
|
|
|
29
|
-
`ui →
|
|
29
|
+
`ui → services → data` — higher imports lower, never the reverse. `data/`
|
|
30
30
|
depends on nothing but `@adobe/data` and other `data/` declarations. A feature
|
|
31
31
|
creates only the layers it uses.
|
|
32
32
|
|
|
33
33
|
| Layer | Role |
|
|
34
34
|
|-------|------|
|
|
35
35
|
| `data/` | The spec: `State`, pure transforms & derivations, entity sub-types. Pure, tested. |
|
|
36
|
-
| `services/` |
|
|
37
|
-
| `
|
|
36
|
+
| `services/main-service/` | The implementation: the ECS materialisation + reactive reads/writes. The **sole entrypoint** — the only service the `ui/` binds to. |
|
|
37
|
+
| `services/<name>-service/` | Async capability contracts (ports to the outside world). Reached only *through* `main-service` (its actions/services wire them in), never by the UI. Optional. |
|
|
38
38
|
| `ui/` | Presentation. |
|
|
39
39
|
|
|
40
|
+
`services/` holds two kinds of service: the one `main-service/` (ECS-backed
|
|
41
|
+
state, its own subtree of rules) and any async capability contracts. The UI, and
|
|
42
|
+
every external consumer, sees only `main-service`.
|
|
43
|
+
|
|
40
44
|
## One app, many features
|
|
41
45
|
|
|
42
46
|
An application is a set of **features**, each its own `features/<name>/` folder
|
|
43
|
-
with the same
|
|
44
|
-
|
|
47
|
+
with the same layers. One base feature (`features/main/`) is the host; the rest
|
|
48
|
+
are peers that load lazily.
|
|
45
49
|
|
|
46
50
|
**Keep each feature small; grow by adding features, not by bloating one.** A
|
|
47
51
|
feature is meant to fit in the head — a handful of files per layer. When a
|
|
@@ -53,16 +57,17 @@ its own peer feature rather than let one feature's folders balloon.
|
|
|
53
57
|
base must not depend on its children — with one sanctioned exception below.
|
|
54
58
|
- **The base `imports` every peer's *schema* plugin** —
|
|
55
59
|
`Database.Plugin.create({ imports })`, not `extends`. `imports` merges the
|
|
56
|
-
peer's `core-database` (components / resources /
|
|
57
|
-
store at runtime **without** pulling its types or
|
|
58
|
-
or bundle (`extends` would do both, and cost
|
|
59
|
-
every feature's schema — data coexists,
|
|
60
|
-
stays decoupled. Import the peer's
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
60
|
+
peer's `services/main-service/core-database` (components / resources /
|
|
61
|
+
archetypes) into the shared store at runtime **without** pulling its types or
|
|
62
|
+
behavior into the base's type or bundle (`extends` would do both, and cost
|
|
63
|
+
quadratically). So one store knows every feature's schema — data coexists,
|
|
64
|
+
persists, and syncs — while the base stays decoupled. Import the peer's
|
|
65
|
+
`services/main-service/core-database.ts` plugin (schema only) — under its
|
|
66
|
+
feature-qualified name `<Peer>CoreDatabase` (see the cross-feature naming rule
|
|
67
|
+
in `services/main-service/index.md`): its indexes, transactions, computed,
|
|
68
|
+
services, and UI stay out until the feature loads. A column two features share
|
|
69
|
+
(e.g. `name`) lives in `data/` and is referenced by identity, so
|
|
70
|
+
`combinePlugins` dedupes it.
|
|
66
71
|
- **Peers load lazily by being used.** `DatabaseElement`, on connect, walks up to
|
|
67
72
|
the nearest ancestor database and `extend`s it with its own plugin — so the
|
|
68
73
|
first time a feature element renders, its full plugin (indexes, transactions,
|
|
@@ -71,25 +76,37 @@ its own peer feature rather than let one feature's folders balloon.
|
|
|
71
76
|
load is genuinely on-demand.
|
|
72
77
|
- **The base reaches a child only through a lazy element wrapper** — a tiny
|
|
73
78
|
`Foo()` that `void import()`s the child element. That dynamic import is the one
|
|
74
|
-
allowed core→child seam; the heavy element and its service
|
|
79
|
+
allowed core→child seam; the heavy element and its main-service stay in the
|
|
75
80
|
child's own chunk.
|
|
76
81
|
|
|
77
82
|
## Spec and implementation, kept honest
|
|
78
83
|
|
|
79
|
-
The tie between `data/` (spec) and `
|
|
80
|
-
one property —
|
|
81
|
-
|
|
84
|
+
The tie between `data/` (spec) and `main-service` (implementation) is
|
|
85
|
+
**conformance**, one property —
|
|
86
|
+
`toState(apply(fromState(before), args)) ≡ transform(before, args)`: each
|
|
87
|
+
main-service mutation, seeded and read back through a test-only store↔`State`
|
|
82
88
|
projection, equals the pure `data/` transform it stands for. The projection and
|
|
83
|
-
its runner live in `
|
|
84
|
-
`{ before, args, after }`
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
below.
|
|
89
|
+
its runner live in `services/main-service/conformance/` (see
|
|
90
|
+
`services/main-service/conformance.md`); the shared `{ before, args, after }`
|
|
91
|
+
cases are spec-owned (`data/state/<transform>.cases.ts`), so conforming the
|
|
92
|
+
implementation is "substitute the implementation, reuse the expectations." This
|
|
93
|
+
lets `main-service` be largely mechanical and agent-generated, with the spec as
|
|
94
|
+
oracle. *How* to author each layer lives in the per-folder rules below.
|
|
95
|
+
|
|
96
|
+
## Reference implementations
|
|
97
|
+
|
|
98
|
+
Working samples ship inside `@adobe/data` at
|
|
99
|
+
`node_modules/@adobe/data/references/<sample>/src/` — read them for concrete,
|
|
100
|
+
current examples of this structure. `data-lit-todo` is the most complete
|
|
101
|
+
(multi-feature, capability services, indexes, conformance tests);
|
|
102
|
+
`data-lit-tictactoe` is the minimal turn-based reference.
|
|
89
103
|
|
|
90
104
|
## Per-layer detail
|
|
91
105
|
|
|
92
|
-
See the rules under each folder: `data/`, `services
|
|
93
|
-
resources, archetypes, computed, indexes, transactions
|
|
94
|
-
|
|
95
|
-
|
|
106
|
+
See the rules under each folder: `data/`, `services/` — the `main-service/`
|
|
107
|
+
subtree (components, resources, archetypes, computed, indexes, transactions,
|
|
108
|
+
systems, conformance) and capability-contract services — and `ui/`.
|
|
109
|
+
Always-on conventions live in `global/` (`namespace.md`, `cohesion.md`,
|
|
110
|
+
`type-casts.md`, `function-references.md`, `react.md` — deliberately repo-wide);
|
|
111
|
+
other cross-cutting patterns at the rules root — `data-modelling.md`,
|
|
112
|
+
`archetypes.md` (row iteration).
|
|
@@ -3,32 +3,45 @@ paths:
|
|
|
3
3
|
- '**/features/*/services/**/*.ts'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# services/ —
|
|
6
|
+
# services/ — the feature's services
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
is the boundary between pure feature code and the outside world, which is
|
|
10
|
-
why its members are async — enabling cross-process portability and lazy
|
|
11
|
-
loading (`AsyncDataService.createLazy`).
|
|
8
|
+
Everything a feature exposes as a service lives here. Two kinds:
|
|
12
9
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
- **`main-service/`** — the one entrypoint. The ECS-backed reactive state
|
|
11
|
+
service (materialisation + reads/writes over it); the only service the `ui/`
|
|
12
|
+
and external consumers bind to. It has its own subtree of rules
|
|
13
|
+
(`main-service/index.md` and the layer files under it). Every feature with
|
|
14
|
+
state has exactly one.
|
|
15
|
+
- **`<name>-service/`** — async **capability contracts**: ports to the outside
|
|
16
|
+
world (processing, persistence, observation, generation). Reached only
|
|
17
|
+
*through* `main-service` (its service/action layers wire them in), never by the
|
|
18
|
+
UI. A feature has zero or more.
|
|
16
19
|
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
The rest of this rule governs the capability contracts; `main-service` follows
|
|
21
|
+
its own subtree.
|
|
22
|
+
|
|
23
|
+
## Capability contracts
|
|
24
|
+
|
|
25
|
+
Each is a namespace folder (`global/namespace.md`); the export and folder both carry the
|
|
26
|
+
`-service` suffix. A service is the boundary between pure feature code and the
|
|
27
|
+
outside world, which is why its members are async — enabling cross-process
|
|
28
|
+
portability and lazy loading (`AsyncDataService.createLazy`).
|
|
29
|
+
|
|
30
|
+
- The contract is an `interface` — the only place `interface` is used in the
|
|
31
|
+
codebase — validated immediately with
|
|
19
32
|
`Assert<AsyncDataService.IsValid<typeof MyService>>`.
|
|
20
33
|
- Members are async only: `void | Promise<T> | AsyncGenerator<T> | Observe<T>`.
|
|
21
34
|
- Provide `create*` factories.
|
|
22
35
|
|
|
23
36
|
## Where the I/O types live
|
|
24
37
|
|
|
25
|
-
Most input/output types belong to a single service — declare them **on
|
|
26
|
-
|
|
27
|
-
|
|
38
|
+
Most input/output types belong to a single service — declare them **on that
|
|
39
|
+
service's namespace** (`MyService.SomeInput`) and expose them only when something
|
|
40
|
+
external actually references them; not everything does.
|
|
28
41
|
|
|
29
|
-
A **service type** may be non-serializable (callbacks, function
|
|
30
|
-
|
|
31
|
-
|
|
42
|
+
A **service type** may be non-serializable (callbacks, function signatures) —
|
|
43
|
+
that's what distinguishes it from a `data/` type. If an I/O value is a plain
|
|
44
|
+
serializable value, prefer a `data/` type instead.
|
|
32
45
|
|
|
33
|
-
A non-service type sits *directly* in `services/` **only** when it is
|
|
34
|
-
|
|
46
|
+
A non-service type sits *directly* in `services/` **only** when it is genuinely
|
|
47
|
+
shared across more than one service — rare, but it happens.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
paths:
|
|
3
|
-
- '**/features/*/
|
|
3
|
+
- '**/features/*/services/main-service/**/actions/**/*.ts'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
#
|
|
6
|
+
# services/main-service/actions/ — async orchestration
|
|
7
7
|
|
|
8
8
|
One action per file: a function taking the **whole database** as its first
|
|
9
9
|
argument and pure `data/` args. Actions orchestrate anything *outside* a
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
paths:
|
|
3
|
-
- '**/features/*/
|
|
3
|
+
- '**/features/*/services/main-service/**/core-database/components.ts'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# core-database/components.ts — the feature's components
|
|
@@ -28,7 +28,7 @@ export const components = Database.components({
|
|
|
28
28
|
- A component name may differ from the type it stores (`position` of a `Vec3`,
|
|
29
29
|
`mark` of a `PlayerMark`) — the field name describes the role, the schema the
|
|
30
30
|
shape.
|
|
31
|
-
- **Scope = which group it sits in** (see `
|
|
31
|
+
- **Scope = which group it sits in** (see `services/main-service/index.md` for the four scopes and
|
|
32
32
|
their flags). `document` is the common case; hover a scope key for its
|
|
33
33
|
meaning. Never write `nonShared` / `nonPersistent` by hand — the group applies
|
|
34
34
|
them.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
paths:
|
|
3
|
-
- '**/features/*/
|
|
3
|
+
- '**/features/*/services/main-service/**/conformance/**/*.ts'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
#
|
|
6
|
+
# services/main-service/conformance/ — spec↔implementation projection (test-only)
|
|
7
7
|
|
|
8
8
|
The bridge that keeps the ecs implementation honest against the `data/` spec.
|
|
9
9
|
**Test-only**: imported solely by `*.test.ts` and in no facet barrel, so it never
|
|
@@ -19,7 +19,7 @@ The property, per `{ before, args, after }` case:
|
|
|
19
19
|
|
|
20
20
|
Conformance test-support splits by concern along the layer boundary:
|
|
21
21
|
|
|
22
|
-
- **Store-side, here in `
|
|
22
|
+
- **Store-side, here in `services/main-service/conformance/`:**
|
|
23
23
|
- `from-state.ts` → `fromState(store: CoreDatabase.Store, state: State): void`
|
|
24
24
|
seeds the store (clear tail→head → insert entities → set resources) to a `State`.
|
|
25
25
|
- `to-state.ts` → `toState(store): State` reads the store back — each kind via
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
paths:
|
|
3
|
-
- '**/features/*/
|
|
3
|
+
- '**/features/*/services/main-service/**/*.ts'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
#
|
|
6
|
+
# services/main-service/ — the feature service (ECS implementation)
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
`main-service/` is the feature's single entrypoint service (see `../index.md`),
|
|
9
|
+
implemented as a reactive Entity-Component-System — an implementation detail
|
|
10
|
+
behind the service. Everything ECS-specific lives here: the schema that stores `data/` types as
|
|
9
11
|
entity state (`core-database/`), the derived and mutating logic over it
|
|
10
12
|
(`indexes/`, `transactions/`, `computed/`), the database-bound service factories
|
|
11
13
|
(`services/`), the async orchestrators (`actions/`), and the layered plugins
|
|
@@ -23,7 +25,7 @@ one `core-database/` folder: `core-database.ts` plus one file per facet the
|
|
|
23
25
|
feature uses (all three facets are optional on `Database.Plugin.create`):
|
|
24
26
|
|
|
25
27
|
```
|
|
26
|
-
|
|
28
|
+
core-database/
|
|
27
29
|
core-database.ts # Database.Plugin.create({ components?, resources?, archetypes? }) → CoreDatabase
|
|
28
30
|
components.ts # export const components = Database.components({ … })
|
|
29
31
|
resources.ts # export const resources = Database.resources({ … })
|
|
@@ -97,7 +99,7 @@ facet folder it adds. **Name each layer for the facet it adds — never for the
|
|
|
97
99
|
feature or app.** A feature creates only the layers it uses:
|
|
98
100
|
|
|
99
101
|
```
|
|
100
|
-
|
|
102
|
+
main-service/
|
|
101
103
|
core-database/ # the schema (above)
|
|
102
104
|
index-database/ # extends core; indexes/
|
|
103
105
|
transaction-database/ # extends index; transactions/
|
|
@@ -107,7 +109,7 @@ ecs/
|
|
|
107
109
|
```
|
|
108
110
|
|
|
109
111
|
Each exports a namespace mirroring the plugin — the composed object is a
|
|
110
|
-
`Database` (the `@adobe/data` term) even though the folder is `
|
|
112
|
+
`Database` (the `@adobe/data` term) even though the folder is `services/main-service/`:
|
|
111
113
|
|
|
112
114
|
```ts
|
|
113
115
|
export type IndexDatabase = Database.Plugin.ToDatabase<typeof indexDatabasePlugin>;
|
|
@@ -120,12 +122,12 @@ export namespace IndexDatabase {
|
|
|
120
122
|
### The assembled database — `FeatureDatabase`
|
|
121
123
|
|
|
122
124
|
*Which* layer is topmost varies with the facets a feature uses (computed /
|
|
123
|
-
service / action / system). Consumers — `ui/`, the app entry, `
|
|
125
|
+
service / action / system). Consumers — `ui/`, the app entry, `services/main-service/conformance/`
|
|
124
126
|
— need the *whole* feature database but must not name that layer, or adding or
|
|
125
127
|
dropping a layer rewrites them all. Alias it once:
|
|
126
128
|
|
|
127
129
|
```ts
|
|
128
|
-
//
|
|
130
|
+
// services/main-service/feature-database.ts
|
|
129
131
|
export { SystemDatabase as FeatureDatabase } from "./system-database/system-database.js";
|
|
130
132
|
```
|
|
131
133
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
paths:
|
|
3
|
-
- '**/features/*/
|
|
3
|
+
- '**/features/*/services/main-service/**/core-database/resources.ts'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# core-database/resources.ts — the feature's resources
|
|
@@ -21,7 +21,7 @@ export const resources = Database.resources({
|
|
|
21
21
|
|
|
22
22
|
- Give each resource a `default` — spread the data-type's schema and add one, or
|
|
23
23
|
bind a `data/` / primitive schema that already carries a sensible default.
|
|
24
|
-
- **Scope = which group it sits in** (see `
|
|
24
|
+
- **Scope = which group it sits in** (see `services/main-service/index.md`). A per-device
|
|
25
25
|
preference is `settings` (durable, `nonShared`); a synced-but-unsaved value is
|
|
26
26
|
`presence`; a saved shared value is `document`.
|
|
27
27
|
- Because there is only ever one instance, linear-memory packing buys nothing —
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
paths:
|
|
3
|
-
- '**/features/*/
|
|
3
|
+
- '**/features/*/services/main-service/**/systems/**/*.ts'
|
|
4
4
|
- '**/systems/*.ts'
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -32,6 +32,8 @@ import { Database, scheduler } from "@adobe/data/ecs";
|
|
|
32
32
|
import { Motion } from "../../data/motion/motion.js";
|
|
33
33
|
|
|
34
34
|
const plugin = Database.Plugin.create({
|
|
35
|
+
// combine scheduler with the CURRENT TOP layer — ComputedDatabase here, but
|
|
36
|
+
// ActionDatabase / ServiceDatabase if the feature built those (systems come last).
|
|
35
37
|
extends: Database.Plugin.combine(ComputedDatabase.plugin, scheduler),
|
|
36
38
|
systems: {
|
|
37
39
|
control: { create: (db) => () => { /* input → ship; db.transactions.fireBullet() */ } },
|
|
@@ -119,15 +121,17 @@ with no rAF and no rendering attached.
|
|
|
119
121
|
|
|
120
122
|
## Layer
|
|
121
123
|
|
|
122
|
-
`system-database.ts` extends the
|
|
123
|
-
|
|
124
|
+
`system-database.ts` extends the feature's **current top** main-service layer (`ActionDatabase` /
|
|
125
|
+
`ServiceDatabase` / `ComputedDatabase` — whichever it built; systems come last in the pipeline, so
|
|
126
|
+
they must sit atop any service/action layers, not a hardcoded `ComputedDatabase`), combined with
|
|
127
|
+
`scheduler`, and declares the `systems` map **inline** (see above —
|
|
124
128
|
this is the one facet not split one-per-file, because `create`'s `db` is only typed
|
|
125
129
|
inline and standalone declarations break name inference). A `systems/` folder is
|
|
126
130
|
optional: it holds extracted per-frame body helpers (`(db) => () => void`) only when
|
|
127
131
|
an inline body grows too large — the schedule and registration still live inline in
|
|
128
132
|
`system-database.ts`. The headless conformance test drives one frame via
|
|
129
133
|
`db.system.order` / `db.system.functions` and compares to the `data/` `step` oracle,
|
|
130
|
-
**reusing the feature projection** (`
|
|
134
|
+
**reusing the feature projection** (`services/main-service/conformance.md`); it lives at
|
|
131
135
|
`system-database/tick-loop.test.ts`. Test **selection/detection** logic (which
|
|
132
136
|
entities collide, which pair resolves) separately, with seeded edge-case geometries
|
|
133
137
|
— it's a system concern, not a transaction, and where subtle bugs hide.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
paths:
|
|
3
|
-
- '**/features/*/
|
|
3
|
+
- '**/features/*/services/main-service/**/transactions/**/*.ts'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# database/transactions/ — atomic mutations
|
|
@@ -32,7 +32,7 @@ export const playMove = (t: CoreDatabase.Store, { index }: PlayMoveArgs) => {
|
|
|
32
32
|
result — read the touched slice, call the `data/` transform, write the diff.
|
|
33
33
|
- **Conform every transaction to its `data/` transform** in its sibling
|
|
34
34
|
`*.test.ts`, via `expectConforms` over the spec's shared cases (see
|
|
35
|
-
`
|
|
35
|
+
`services/main-service/conformance.md`): seed `fromState(before)`, dispatch, assert `toState ≡
|
|
36
36
|
after`, covering every branch and edge case. A transaction taking **entity
|
|
37
37
|
ids** resolves them from the seeded store in the `apply` closure; one with no
|
|
38
38
|
`data/` analogue (`setBounds`, `setInput`) gets a direct resource assertion.
|
|
@@ -41,5 +41,5 @@ export const playMove = (t: CoreDatabase.Store, { index }: PlayMoveArgs) => {
|
|
|
41
41
|
transactions (`readShip`, `readBoard` — a `(t) => value` function) may live
|
|
42
42
|
beside them in `transactions/`, but keep it **out of the barrel**, or it gets
|
|
43
43
|
registered as a dispatchable transaction. (These are related helpers, so they
|
|
44
|
-
belong here, not in a separate folder — `cohesion.md`'s peer-level caution
|
|
44
|
+
belong here, not in a separate folder — `global/cohesion.md`'s peer-level caution
|
|
45
45
|
doesn't apply.)
|
|
@@ -32,7 +32,7 @@ Presentation files (`*-presentation.ts`), CSS files (`*.css.ts`), tests (`*.test
|
|
|
32
32
|
A binding element is a thin wire between a service and a presentation. The class body contains:
|
|
33
33
|
|
|
34
34
|
1. Optional static `styles` property definition
|
|
35
|
-
2. Zero or more `@property` declarations (
|
|
35
|
+
2. Zero or more `@property` declarations (allowed below).
|
|
36
36
|
3. One `render()` method whose body is: one `useObservableValues(...)` call, another lifecycle hook call (in rare cases), a null-guard, and
|
|
37
37
|
`return presentation.render({ ...values, ...callbacks })`.
|
|
38
38
|
|
|
@@ -40,7 +40,7 @@ No other members. No `@state`. No private handler fields. No lifecycle methods (
|
|
|
40
40
|
`disconnectedCallback`) except on app-entrypoint classes where the lifecycle concern is app-boot shaped but cannot be expressed as a hook
|
|
41
41
|
(see `.claude/rules/hooks.md` for hook-first lifecycle).
|
|
42
42
|
|
|
43
|
-
## `@property`
|
|
43
|
+
## `@property` allowlist
|
|
44
44
|
|
|
45
45
|
The allowed set depends on **class role**:
|
|
46
46
|
|
|
@@ -5,7 +5,7 @@ paths:
|
|
|
5
5
|
|
|
6
6
|
# ui/ — user interface
|
|
7
7
|
|
|
8
|
-
The top layer: UI that binds the `
|
|
8
|
+
The top layer: UI that binds the `services/main-service/` database to what the user sees. It
|
|
9
9
|
owns no business logic — it subscribes to state, hands it to a pure
|
|
10
10
|
presentation, and wires actions back to transactions.
|
|
11
11
|
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
AI architecture skills + rules for building applications with
|
|
4
4
|
[`@adobe/data`](https://www.npmjs.com/package/@adobe/data) — a layered,
|
|
5
|
-
spec-first feature structure (`data →
|
|
5
|
+
spec-first feature structure (`data → services → ui`) kept honest by conformance
|
|
6
6
|
tests. Versioned in lockstep with the library: `@adobe/data-ai@x.y.z` targets
|
|
7
7
|
`@adobe/data@x.y.z`.
|
|
8
8
|
|
package/bin/cli.mjs
CHANGED
|
@@ -50,8 +50,8 @@ function notice(extra) {
|
|
|
50
50
|
|
|
51
51
|
The files in this folder are installed and managed by the \`${PKG_NAME}\`
|
|
52
52
|
package. This entire directory is **deleted and rebuilt** on every
|
|
53
|
-
\`npx ${PKG_NAME} install\`, so any local edit here is silently discarded on
|
|
54
|
-
next reinstall or version upgrade.
|
|
53
|
+
\`npx ${PKG_NAME}@${VERSION} install\`, so any local edit here is silently discarded on
|
|
54
|
+
the next reinstall or version upgrade.
|
|
55
55
|
|
|
56
56
|
To change them, edit upstream in the \`${PKG_NAME}\` package and publish a new
|
|
57
57
|
version, then reinstall — do not modify these files in place.
|
|
@@ -66,10 +66,21 @@ function writeMeta(bundleDir, noticeBody, extraMeta) {
|
|
|
66
66
|
);
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
+
// Skills that author/evolve the bundle itself (the self-improvement loop and its
|
|
70
|
+
// rule review). They mutate or critique the managed files, so they belong only to
|
|
71
|
+
// the source repo — never a consumer install, where those files are read-only
|
|
72
|
+
// managed copies. Both also carry `disable-model-invocation: true`.
|
|
73
|
+
const MAINTAINER_ONLY = new Set(["meta-build", "review"]);
|
|
74
|
+
|
|
69
75
|
function discoverSkills() {
|
|
70
76
|
if (!existsSync(skillsSrc)) return [];
|
|
71
77
|
return readdirSync(skillsSrc, { withFileTypes: true })
|
|
72
|
-
.filter(
|
|
78
|
+
.filter(
|
|
79
|
+
(d) =>
|
|
80
|
+
d.isDirectory() &&
|
|
81
|
+
!MAINTAINER_ONLY.has(d.name) &&
|
|
82
|
+
existsSync(join(skillsSrc, d.name, "SKILL.md")),
|
|
83
|
+
)
|
|
73
84
|
.map((d) => d.name)
|
|
74
85
|
.sort();
|
|
75
86
|
}
|
|
@@ -111,6 +122,41 @@ function installRules(base) {
|
|
|
111
122
|
return bundleDir;
|
|
112
123
|
}
|
|
113
124
|
|
|
125
|
+
// A single managed rule (namespaced by its `adobe-data-ai-` filename prefix) telling
|
|
126
|
+
// an agent to (re)install the bundle when the skills are absent — pinned to THIS
|
|
127
|
+
// reviewed version, never `@latest`, so a drifted or compromised release cannot execute
|
|
128
|
+
// during install. Rewritten with the matching version on every install. It sits beside
|
|
129
|
+
// (not inside) the wiped bundle dir, so it survives and is simply overwritten.
|
|
130
|
+
function installBootstrap(base) {
|
|
131
|
+
const file = join(base, ".claude", "rules", `${BUNDLE}-bootstrap.md`);
|
|
132
|
+
mkdirSync(dirname(file), { recursive: true });
|
|
133
|
+
writeFileSync(
|
|
134
|
+
file,
|
|
135
|
+
`---
|
|
136
|
+
paths:
|
|
137
|
+
- '**/features/*/data/**/*.ts'
|
|
138
|
+
- '**/features/*/services/**/*.ts'
|
|
139
|
+
- '**/features/*/ui/**/*.ts'
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
# ${PKG_NAME} skills — ensure installed
|
|
143
|
+
|
|
144
|
+
Before using an \`@adobe/data\` build workflow, confirm the skills are present: look for
|
|
145
|
+
a skill named \`build-feature\` (or \`build-application\`). If it is missing, install the
|
|
146
|
+
pinned, reviewed bundle, then re-check:
|
|
147
|
+
|
|
148
|
+
\`\`\`sh
|
|
149
|
+
npx ${PKG_NAME}@${VERSION} install
|
|
150
|
+
\`\`\`
|
|
151
|
+
|
|
152
|
+
Pin the version to the reviewed bundle (never \`@latest\`) so a compromised or drifted
|
|
153
|
+
release cannot execute during install. This file is regenerated with the matching
|
|
154
|
+
version on every install. Package: <https://www.npmjs.com/package/${PKG_NAME}>
|
|
155
|
+
`,
|
|
156
|
+
);
|
|
157
|
+
return file;
|
|
158
|
+
}
|
|
159
|
+
|
|
114
160
|
function parseArgs(argv) {
|
|
115
161
|
const positional = [];
|
|
116
162
|
const flags = new Set();
|
|
@@ -176,11 +222,13 @@ function main() {
|
|
|
176
222
|
const base = flags.has("global") ? homedir() : dir ? resolve(dir) : process.cwd();
|
|
177
223
|
const skillsDir = installSkills(base, skills);
|
|
178
224
|
const rulesDir = installRules(base);
|
|
225
|
+
const bootstrapFile = installBootstrap(base);
|
|
179
226
|
const ruleCount = countRules(rulesSrc);
|
|
180
227
|
|
|
181
228
|
process.stdout.write(`Installed ${PKG_NAME} v${VERSION}\n`);
|
|
182
229
|
process.stdout.write(` ${skills.length} skills → ${skillsDir}\n`);
|
|
183
230
|
process.stdout.write(` ${ruleCount} rules → ${rulesDir}\n`);
|
|
231
|
+
process.stdout.write(` bootstrap → ${bootstrapFile}\n`);
|
|
184
232
|
}
|
|
185
233
|
|
|
186
234
|
main();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe/data-ai",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.91",
|
|
4
4
|
"description": "Cross-agent architecture skills for @adobe/data — installable as a Claude Code plugin or copied into any Agent-Skills-compatible agent (Cursor, Codex).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -29,18 +29,17 @@
|
|
|
29
29
|
"skills"
|
|
30
30
|
],
|
|
31
31
|
"peerDependencies": {
|
|
32
|
-
"@adobe/data": "0.9.
|
|
32
|
+
"@adobe/data": "0.9.91"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"typescript": "^5.8.3",
|
|
36
36
|
"vitest": "^1.6.0",
|
|
37
|
-
"@adobe/data": "0.9.
|
|
37
|
+
"@adobe/data": "0.9.91"
|
|
38
38
|
},
|
|
39
39
|
"license": "MIT",
|
|
40
40
|
"scripts": {
|
|
41
41
|
"build": "cp ../../LICENSE .",
|
|
42
42
|
"typecheck": "true",
|
|
43
|
-
"test": "vitest --run --passWithNoTests"
|
|
44
|
-
"publish-public": "pnpm build && pnpm publish --no-git-checks --access public"
|
|
43
|
+
"test": "vitest --run --passWithNoTests"
|
|
45
44
|
}
|
|
46
45
|
}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: build-actions
|
|
3
|
-
description: Build a feature's
|
|
3
|
+
description: Build a feature's action-database — async orchestration over services and transactions. If the feature has async flows or side effects outside of the main store.
|
|
4
4
|
input: feature
|
|
5
5
|
output: feature
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
Skip if this feature doesn't contain or require actions.
|
|
9
9
|
|
|
10
|
-
Create `
|
|
10
|
+
Create `services/main-service/action-database/`: `action-database.ts` (extends `ServiceDatabase`, adds `actions`
|
|
11
11
|
from `./actions/index.js`) plus an `actions/` folder — one async orchestrator per file. An action
|
|
12
12
|
takes `db: ServiceDatabase`, awaits `services/` ports, then commits **exactly one** transaction.
|
|
13
13
|
|
|
14
|
-
The top
|
|
14
|
+
The top main-service layer; comes after `service-database`.
|
|
15
15
|
|
|
16
|
-
The how is in the auto-loading `features/
|
|
16
|
+
The how is in the auto-loading `features/services/main-service/actions.md` rule.
|
|
@@ -10,6 +10,6 @@ output: app
|
|
|
10
10
|
- The base reaches a peer only through a lazy element wrapper (dynamic import), so peers
|
|
11
11
|
load on demand.
|
|
12
12
|
- The entry point creates the live database from `FeatureDatabase.plugin` (the base
|
|
13
|
-
feature's assembled database — see `features/
|
|
13
|
+
feature's assembled database — see `features/services/main-service/index.md`) and mounts the root UI.
|
|
14
14
|
|
|
15
15
|
See `features/index.md` (one-app-many-features) for the wiring rules.
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: build-computed
|
|
3
|
-
description: Build a feature's
|
|
3
|
+
description: Build a feature's computed-database — derived observable values.
|
|
4
4
|
input: feature
|
|
5
5
|
output: feature
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
Skip if this feature doesn't contain or require computed values.
|
|
9
9
|
|
|
10
|
-
Create `
|
|
10
|
+
Create `services/main-service/computed-database/`: `computed-database.ts` (extends the previous layer, adds
|
|
11
11
|
`computed` from `./computed/index.js`) plus a `computed/` folder — one `cached` derived value
|
|
12
12
|
per file + barrel. Derivation logic lives in `data/`; a computed only wires a db observable to it.
|
|
13
13
|
|
|
14
14
|
Comes after `transaction-database`.
|
|
15
15
|
|
|
16
|
-
The how is in the auto-loading `features/
|
|
16
|
+
The how is in the auto-loading `features/services/main-service/computed.md` rule.
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: build-core-database
|
|
3
|
-
description: Build a feature's
|
|
3
|
+
description: Build a feature's schema — the core-database (components, resources, archetypes). The first main-service layer.
|
|
4
4
|
input: feature
|
|
5
5
|
output: feature
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
Create `
|
|
8
|
+
Create `services/main-service/core-database/` — `core-database.ts` plus one single-export file per facet
|
|
9
9
|
the feature actually uses (`components`, `resources`, `archetypes` are each optional on
|
|
10
10
|
`Database.Plugin.create`). Create only the facet files you need; omit the rest rather than
|
|
11
11
|
shipping empty `Database.components({})` boilerplate. A feature with **no entities** (a
|
|
@@ -20,5 +20,5 @@ The schema root; comes after `data/` (and `services/`). Bind each schema from it
|
|
|
20
20
|
type — don't author shapes here. Components use JSON schemas; resources use the
|
|
21
21
|
`{ default }` convention (a schemaless aggregate binds via `{ default: State.create() }`).
|
|
22
22
|
|
|
23
|
-
The how is in the auto-loading `features/
|
|
23
|
+
The how is in the auto-loading `features/services/main-service/index.md` + `components.md` / `resources.md` /
|
|
24
24
|
`archetypes.md` rules.
|
|
@@ -19,4 +19,4 @@ The schema is the single source of truth; the type derives from it (`Schema.ToTy
|
|
|
19
19
|
Helpers are pure and unit-tested. Run this first — every other layer imports `data/`.
|
|
20
20
|
|
|
21
21
|
The how is in the auto-loading rules: `features/data/index.md`, `features/data/state.md`, and
|
|
22
|
-
`namespace.md`.
|
|
22
|
+
`global/namespace.md`.
|
|
@@ -16,6 +16,6 @@ transactions = moves/spawns, computed = score/status/winner, ui = view + input.
|
|
|
16
16
|
- **Real-time** adds the `build-systems` phase: a per-frame tick loop (movement,
|
|
17
17
|
collision, lifetime) driven by the scheduler, over many entities in distinct
|
|
18
18
|
archetypes. Systems must stay O(1) per touched entity — never project the whole
|
|
19
|
-
`State` into/out of the store each frame (see `features/
|
|
19
|
+
`State` into/out of the store each frame (see `features/services/main-service/systems.md`).
|
|
20
20
|
This is where components, archetypes, indexes, and systems all carry real
|
|
21
21
|
weight.
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: build-indexes
|
|
3
|
-
description: Build a feature's
|
|
3
|
+
description: Build a feature's index-database — component/archetype indexes for O(1) lookup. As needed.
|
|
4
4
|
input: feature
|
|
5
5
|
output: feature
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
Skip if this feature doesn't contain or require indexes.
|
|
9
9
|
|
|
10
|
-
Create `
|
|
10
|
+
Create `services/main-service/index-database/`: `index-database.ts` (extends `CoreDatabase`, adds the `indexes`
|
|
11
11
|
facet from `./indexes/index.js`) plus an `indexes/` folder — one index per file + an `index.ts`
|
|
12
12
|
barrel.
|
|
13
13
|
|
|
14
14
|
Only if the feature needs indexed lookups. Comes after `core-database`.
|
|
15
15
|
|
|
16
|
-
The how is in the auto-loading `features/
|
|
16
|
+
The how is in the auto-loading `features/services/main-service/indexes.md` rule.
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: build-service-database
|
|
3
|
-
description: Build a feature's
|
|
3
|
+
description: Build a feature's service-database — db-bound service factories. If the feature exposes services.
|
|
4
4
|
input: feature
|
|
5
5
|
output: feature
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
Create `
|
|
8
|
+
Create `services/main-service/service-database/`: `service-database.ts` (extends the previous layer, registers the
|
|
9
9
|
`services` facet). Two forms:
|
|
10
10
|
|
|
11
11
|
- db-bound factories `create<Name>Service(db, …)` in `service-database/services/` (one per file + barrel), for services that read `db.observe.*` / call `db.transactions.*`; or
|
|
@@ -13,4 +13,4 @@ Create `ecs/service-database/`: `service-database.ts` (extends the previous laye
|
|
|
13
13
|
|
|
14
14
|
Comes after `computed-database`.
|
|
15
15
|
|
|
16
|
-
The how is in the auto-loading `features/
|
|
16
|
+
The how is in the auto-loading `features/services/main-service/services.md` rule.
|
|
@@ -11,6 +11,6 @@ Create the feature's `services/` layer: one `<name>-service/` namespace folder p
|
|
|
11
11
|
contract — an `interface` (validated with `AsyncDataService.IsValid`), async-only members,
|
|
12
12
|
and `create*` factories.
|
|
13
13
|
|
|
14
|
-
Only if the feature talks to the outside world. Comes after `data/`, before `
|
|
14
|
+
Only if the feature talks to the outside world. Comes after `data/`, before `services/main-service/`.
|
|
15
15
|
|
|
16
|
-
The how is in the auto-loading `features/services/index.md` rule (and `namespace.md`).
|
|
16
|
+
The how is in the auto-loading `features/services/index.md` rule (and `global/namespace.md`).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: build-systems
|
|
3
|
-
description: Build a feature's
|
|
3
|
+
description: Build a feature's system-database — the real-time tick loop (systems the scheduler runs each frame). For real-time features only.
|
|
4
4
|
input: feature
|
|
5
5
|
output: feature
|
|
6
6
|
---
|
|
@@ -8,9 +8,12 @@ output: feature
|
|
|
8
8
|
Skip if this feature doesn't contain or require systems.
|
|
9
9
|
Most games that use a canvas will use systems but most applications will not.
|
|
10
10
|
|
|
11
|
-
Create `
|
|
12
|
-
Database.Plugin.combine(
|
|
13
|
-
|
|
11
|
+
Create `services/main-service/system-database/system-database.ts`: `Database.Plugin.create({ extends:
|
|
12
|
+
Database.Plugin.combine(<currentTop>.plugin, scheduler), systems })` — combine `scheduler` with the
|
|
13
|
+
feature's **current top** main-service layer (`ActionDatabase` / `ServiceDatabase` / `ComputedDatabase`,
|
|
14
|
+
whichever it built), never a hardcoded `ComputedDatabase`, so systems *and* any services/actions
|
|
15
|
+
compose into the one `FeatureDatabase`. The `systems`
|
|
16
|
+
map is declared **inline** (see `features/services/main-service/systems.md` — inline is required for `db` to be
|
|
14
17
|
typed and for system-name inference; a `systems/` folder is optional, only for extracted
|
|
15
18
|
per-frame body helpers).
|
|
16
19
|
|
|
@@ -21,4 +24,4 @@ per-frame body helpers).
|
|
|
21
24
|
combining `scheduler` (rAF), gated by the `schedulerState` resource.
|
|
22
25
|
|
|
23
26
|
**Only for real-time features** (games, sims) — turn-based features skip this phase entirely.
|
|
24
|
-
Comes after `build-computed`. The how is in the auto-loading `features/
|
|
27
|
+
Comes after `build-computed`. The how is in the auto-loading `features/services/main-service/systems.md` rule.
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: build-transactions
|
|
3
|
-
description: Build a feature's
|
|
3
|
+
description: Build a feature's transaction-database — atomic mutations over the store.
|
|
4
4
|
input: feature
|
|
5
5
|
output: feature
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
Create `
|
|
8
|
+
Create `services/main-service/transaction-database/`: `transaction-database.ts` (extends the
|
|
9
|
+
preceding layer — `IndexDatabase` if the feature built indexes, else `CoreDatabase` — adds
|
|
9
10
|
`transactions` from `./transactions/index.js`) plus a `transactions/` folder — one mutation per
|
|
10
11
|
file + barrel. Type the store param `CoreDatabase.Store` (entities/resources/archetypes) or
|
|
11
12
|
`IndexDatabase.Store` (reads an index).
|
|
12
13
|
|
|
13
14
|
Comes after `index-database` (or `core-database` if no indexes).
|
|
14
15
|
|
|
15
|
-
The how is in the auto-loading `features/
|
|
16
|
+
The how is in the auto-loading `features/services/main-service/transactions.md` rule.
|
package/skills/build-ui/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: build-ui
|
|
3
|
-
description: Build a feature's ui/ layer — presentation bound to the
|
|
3
|
+
description: Build a feature's ui/ layer — presentation bound to the main-service database. The final, top layer.
|
|
4
4
|
input: feature
|
|
5
5
|
output: feature
|
|
6
6
|
---
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: meta-build
|
|
3
|
+
disable-model-invocation: true
|
|
3
4
|
description: Iteratively build an application or game phase-by-phase in clean subagents, reviewing each phase and refining the build-* skills / rules until each is optimal, then summarizing.
|
|
4
5
|
input: a prompt describing the application or game to build
|
|
5
6
|
options:
|
package/skills/review/SKILL.md
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: review
|
|
3
|
+
disable-model-invocation: true
|
|
3
4
|
description: Review built feature/application output against the @adobe/data feature rules; report whether it is optimal and where any fix belongs. Read-only.
|
|
4
5
|
input: a path to built output (a layer, a feature, or a whole app)
|
|
5
6
|
output: a review — OPTIMAL, or a list of issues each tagged code | skill | rule
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|