@adobe/data 0.9.37 → 0.9.40
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/AGENTS.md +160 -0
- package/dist/ecs/database/observe-select-deep.d.ts +23 -0
- package/dist/ecs/database/observe-select-deep.js +15 -0
- package/dist/ecs/database/observe-select-deep.js.map +1 -0
- package/dist/ecs/database/observe-select-deep.type-test.js +111 -0
- package/dist/ecs/database/observe-select-deep.type-test.js.map +1 -0
- package/dist/ecs/persistence-service/create-storage-persistence-service.js +4 -3
- package/dist/ecs/persistence-service/create-storage-persistence-service.js.map +1 -1
- package/dist/ecs/persistence-service/create-storage-persistence-service.test.js +52 -0
- package/dist/ecs/persistence-service/create-storage-persistence-service.test.js.map +1 -0
- package/dist/service/agentic-service/action.d.ts +4 -8
- package/dist/service/agentic-service/create.d.ts +1 -5
- package/dist/service/agentic-service/create.js +1 -1
- package/dist/service/agentic-service/create.js.map +1 -1
- package/dist/service/agentic-service/create.test.js +1 -1
- package/dist/service/agentic-service/create.test.js.map +1 -1
- package/dist/service/agentic-service/create.type-test.js +0 -23
- package/dist/service/agentic-service/create.type-test.js.map +1 -1
- package/dist/service/agentic-service/link.d.ts +15 -0
- package/dist/service/agentic-service/link.js +3 -0
- package/dist/service/agentic-service/link.js.map +1 -0
- package/dist/service/async-data-service/is-valid.d.ts +3 -1
- package/dist/service/async-data-service/is-valid.type-test.d.ts +1 -0
- package/dist/service/async-data-service/is-valid.type-test.js +3 -0
- package/dist/service/async-data-service/is-valid.type-test.js.map +1 -0
- package/dist/service/dynamic-service/semantic-service.d.ts +19 -0
- package/dist/service/dynamic-service/semantic-service.js +2 -0
- package/dist/service/dynamic-service/semantic-service.js.map +1 -0
- package/dist/service/semantic-service/semantic-service.d.ts +19 -0
- package/dist/service/semantic-service/semantic-service.js +2 -0
- package/dist/service/semantic-service/semantic-service.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -1
- package/references/data-lit/README.md +18 -0
- package/references/data-lit/package.json +35 -0
- package/references/data-lit/src/decorators/apply-decorator.ts +26 -0
- package/references/data-lit/src/decorators/apply-service-decorators.ts +15 -0
- package/references/data-lit/src/decorators/index.ts +4 -0
- package/references/data-lit/src/decorators/require-service.ts +20 -0
- package/references/data-lit/src/elements/application-element.ts +42 -0
- package/references/data-lit/src/elements/application-host.ts +43 -0
- package/references/data-lit/src/elements/database-element.ts +42 -0
- package/references/data-lit/src/elements/index.ts +5 -0
- package/references/data-lit/src/functions/index.ts +3 -0
- package/references/data-lit/src/functions/iterate-self-and-ancestors.ts +23 -0
- package/references/data-lit/src/hooks/attach-decorator.ts +32 -0
- package/references/data-lit/src/hooks/component/component.ts +12 -0
- package/references/data-lit/src/hooks/component/stack.ts +19 -0
- package/references/data-lit/src/hooks/index.ts +21 -0
- package/references/data-lit/src/hooks/use-connected.ts +41 -0
- package/references/data-lit/src/hooks/use-debounce.ts +26 -0
- package/references/data-lit/src/hooks/use-drag-observe.ts +59 -0
- package/references/data-lit/src/hooks/use-drag-transaction.ts +46 -0
- package/references/data-lit/src/hooks/use-draggable.ts +112 -0
- package/references/data-lit/src/hooks/use-effect.ts +19 -0
- package/references/data-lit/src/hooks/use-element.ts +83 -0
- package/references/data-lit/src/hooks/use-memo.ts +16 -0
- package/references/data-lit/src/hooks/use-observable-values.ts +10 -0
- package/references/data-lit/src/hooks/use-observable.ts +15 -0
- package/references/data-lit/src/hooks/use-ref.ts +8 -0
- package/references/data-lit/src/hooks/use-resize-observer.ts +31 -0
- package/references/data-lit/src/hooks/use-state.ts +19 -0
- package/references/data-lit/src/hooks/use-updated.ts +56 -0
- package/references/data-lit/src/hooks/use-window-event.ts +16 -0
- package/references/data-lit/src/hooks/with-hooks.ts +22 -0
- package/references/data-lit/src/index.ts +6 -0
- package/references/data-lit/tsconfig.json +11 -0
- package/references/data-lit-tictactoe/package.json +22 -0
- package/references/data-lit-tictactoe/src/elements/tictactoe-app/tictactoe-app.css.ts +11 -0
- package/references/data-lit-tictactoe/src/elements/tictactoe-app/tictactoe-app.ts +22 -0
- package/references/data-lit-tictactoe/src/elements/tictactoe-board/tictactoe-board-presentation.ts +13 -0
- package/references/data-lit-tictactoe/src/elements/tictactoe-board/tictactoe-board.css.ts +17 -0
- package/references/data-lit-tictactoe/src/elements/tictactoe-board/tictactoe-board.ts +18 -0
- package/references/data-lit-tictactoe/src/elements/tictactoe-cell/tictactoe-cell-presentation.ts +22 -0
- package/references/data-lit-tictactoe/src/elements/tictactoe-cell/tictactoe-cell.css.ts +31 -0
- package/references/data-lit-tictactoe/src/elements/tictactoe-cell/tictactoe-cell.ts +41 -0
- package/references/data-lit-tictactoe/src/elements/tictactoe-hud/tictactoe-hud-presentation.ts +16 -0
- package/references/data-lit-tictactoe/src/elements/tictactoe-hud/tictactoe-hud.css.ts +18 -0
- package/references/data-lit-tictactoe/src/elements/tictactoe-hud/tictactoe-hud.ts +44 -0
- package/references/data-lit-tictactoe/src/main.ts +9 -0
- package/references/data-lit-tictactoe/src/state/agent-plugin.ts +117 -0
- package/references/data-lit-tictactoe/src/state/tictactoe-plugin.ts +56 -0
- package/references/data-lit-tictactoe/src/tictactoe-element.ts +10 -0
- package/references/data-lit-tictactoe/src/types/board-cell.ts +5 -0
- package/references/data-lit-tictactoe/src/types/board-state/board-state.ts +7 -0
- package/references/data-lit-tictactoe/src/types/board-state/create-initial-board.ts +5 -0
- package/references/data-lit-tictactoe/src/types/board-state/current-player.ts +13 -0
- package/references/data-lit-tictactoe/src/types/board-state/derive-status.ts +12 -0
- package/references/data-lit-tictactoe/src/types/board-state/get-cell.ts +7 -0
- package/references/data-lit-tictactoe/src/types/board-state/get-move-count.ts +6 -0
- package/references/data-lit-tictactoe/src/types/board-state/get-winner.ts +14 -0
- package/references/data-lit-tictactoe/src/types/board-state/get-winning-line.ts +25 -0
- package/references/data-lit-tictactoe/src/types/board-state/is-board-full.ts +5 -0
- package/references/data-lit-tictactoe/src/types/board-state/is-cell-playable.ts +13 -0
- package/references/data-lit-tictactoe/src/types/board-state/is-cell-winning.ts +9 -0
- package/references/data-lit-tictactoe/src/types/board-state/is-game-over.ts +8 -0
- package/references/data-lit-tictactoe/src/types/board-state/public.ts +15 -0
- package/references/data-lit-tictactoe/src/types/board-state/schema.ts +10 -0
- package/references/data-lit-tictactoe/src/types/board-state/set-board-cell.ts +13 -0
- package/references/data-lit-tictactoe/src/types/game-status.ts +3 -0
- package/references/data-lit-tictactoe/src/types/move-reject-reason.ts +7 -0
- package/references/data-lit-tictactoe/src/types/play-move-args/can-play-move.ts +33 -0
- package/references/data-lit-tictactoe/src/types/play-move-args/play-move-args.ts +4 -0
- package/references/data-lit-tictactoe/src/types/play-move-args/public.ts +3 -0
- package/references/data-lit-tictactoe/src/types/player-mark/player-mark.ts +7 -0
- package/references/data-lit-tictactoe/src/types/player-mark/public.ts +3 -0
- package/references/data-lit-tictactoe/src/types/player-mark/schema.ts +9 -0
- package/references/data-lit-tictactoe/src/types/winning-line.ts +3 -0
- package/references/data-lit-tictactoe/tsconfig.json +16 -0
- package/references/data-lit-todo/package.json +30 -0
- package/references/data-lit-todo/src/elements/todo-list/todo-list-presentation.ts +22 -0
- package/references/data-lit-todo/src/elements/todo-list/todo-list.css.ts +12 -0
- package/references/data-lit-todo/src/elements/todo-list/todo-list.ts +45 -0
- package/references/data-lit-todo/src/elements/todo-row/index.ts +2 -0
- package/references/data-lit-todo/src/elements/todo-row/todo-row-presentation.ts +68 -0
- package/references/data-lit-todo/src/elements/todo-row/todo-row.css.ts +49 -0
- package/references/data-lit-todo/src/elements/todo-row/todo-row.ts +46 -0
- package/references/data-lit-todo/src/elements/todo-toolbar/index.ts +2 -0
- package/references/data-lit-todo/src/elements/todo-toolbar/todo-toolbar-presentation.ts +55 -0
- package/references/data-lit-todo/src/elements/todo-toolbar/todo-toolbar.css.ts +34 -0
- package/references/data-lit-todo/src/elements/todo-toolbar/todo-toolbar.ts +62 -0
- package/references/data-lit-todo/src/elements/todo-undo-redo/index.ts +3 -0
- package/references/data-lit-todo/src/elements/todo-undo-redo/todo-undo-redo-presentation.ts +41 -0
- package/references/data-lit-todo/src/elements/todo-undo-redo/todo-undo-redo.css.ts +12 -0
- package/references/data-lit-todo/src/elements/todo-undo-redo/todo-undo-redo.ts +37 -0
- package/references/data-lit-todo/src/index.ts +9 -0
- package/references/data-lit-todo/src/main.ts +29 -0
- package/references/data-lit-todo/src/sample-types.ts +14 -0
- package/references/data-lit-todo/src/services/dependent-state-service/create-dependent-state-service.ts +8 -0
- package/references/data-lit-todo/src/services/dependent-state-service/dependent-state/all-todos.ts +5 -0
- package/references/data-lit-todo/src/services/dependent-state-service/dependent-state/complete-todos.ts +5 -0
- package/references/data-lit-todo/src/services/dependent-state-service/dependent-state/incomplete-todos.ts +5 -0
- package/references/data-lit-todo/src/services/dependent-state-service/dependent-state/index.ts +4 -0
- package/references/data-lit-todo/src/services/dependent-state-service/dependent-state-service.ts +4 -0
- package/references/data-lit-todo/src/services/main-service/create-main-service.ts +53 -0
- package/references/data-lit-todo/src/services/main-service/todo-main-service.ts +20 -0
- package/references/data-lit-todo/src/services/state-service/create-todo-database.ts +16 -0
- package/references/data-lit-todo/src/services/state-service/create-todo-store.ts +28 -0
- package/references/data-lit-todo/src/services/state-service/todo-state-service.ts +9 -0
- package/references/data-lit-todo/src/services/state-service/transactions/create-bulk-todos.ts +12 -0
- package/references/data-lit-todo/src/services/state-service/transactions/create-todo.test.ts +17 -0
- package/references/data-lit-todo/src/services/state-service/transactions/create-todo.ts +15 -0
- package/references/data-lit-todo/src/services/state-service/transactions/delete-all-todos.ts +18 -0
- package/references/data-lit-todo/src/services/state-service/transactions/delete-todo.test.ts +25 -0
- package/references/data-lit-todo/src/services/state-service/transactions/delete-todo.ts +11 -0
- package/references/data-lit-todo/src/services/state-service/transactions/drag-todo.ts +19 -0
- package/references/data-lit-todo/src/services/state-service/transactions/index.ts +8 -0
- package/references/data-lit-todo/src/services/state-service/transactions/reorder-todos.ts +13 -0
- package/references/data-lit-todo/src/services/state-service/transactions/toggle-complete.test.ts +78 -0
- package/references/data-lit-todo/src/services/state-service/transactions/toggle-complete.ts +15 -0
- package/references/data-lit-todo/src/todo-element.ts +6 -0
- package/references/data-lit-todo/src/todo-host.ts +29 -0
- package/references/data-lit-todo/src/todo-main-element.ts +40 -0
- package/references/data-lit-todo/src/todo-sample.ts +21 -0
- package/references/data-lit-todo/tsconfig.json +10 -0
- package/references/data-react/README.md +47 -0
- package/references/data-react/package.json +36 -0
- package/references/data-react/src/context/database-context.tsx +41 -0
- package/references/data-react/src/hooks/index.ts +5 -0
- package/references/data-react/src/hooks/use-database.ts +13 -0
- package/references/data-react/src/hooks/use-observable-values.ts +15 -0
- package/references/data-react/src/hooks/use-observable.ts +14 -0
- package/references/data-react/src/index.ts +7 -0
- package/references/data-react/tsconfig.json +12 -0
- package/references/data-react-hello/package.json +25 -0
- package/references/data-react-hello/src/app.tsx +13 -0
- package/references/data-react-hello/src/components/counter/counter-presentation.tsx +13 -0
- package/references/data-react-hello/src/components/counter/counter.tsx +26 -0
- package/references/data-react-hello/src/main.tsx +9 -0
- package/references/data-react-hello/src/state/counter-plugin.ts +14 -0
- package/references/data-react-hello/src/state/use-counter-database.ts +6 -0
- package/references/data-react-hello/tsconfig.json +16 -0
- package/references/data-react-pixie/package.json +28 -0
- package/references/data-react-pixie/src/app.tsx +21 -0
- package/references/data-react-pixie/src/components/filter-selector/filter-selector-presentation.tsx +40 -0
- package/references/data-react-pixie/src/components/filter-selector/filter-selector.tsx +22 -0
- package/references/data-react-pixie/src/components/pixie-scene/pixie-filters.ts +24 -0
- package/references/data-react-pixie/src/components/pixie-scene/pixie-scene-presentation.tsx +18 -0
- package/references/data-react-pixie/src/components/pixie-scene/pixie-scene.tsx +26 -0
- package/references/data-react-pixie/src/components/pixie-scene/pixie-tick.tsx +12 -0
- package/references/data-react-pixie/src/components/sprite/sprite-presentation.tsx +39 -0
- package/references/data-react-pixie/src/components/sprite/sprite.tsx +37 -0
- package/references/data-react-pixie/src/components/sprite/use-sprite-texture.ts +24 -0
- package/references/data-react-pixie/src/main.tsx +14 -0
- package/references/data-react-pixie/src/state/pixie-plugin.ts +97 -0
- package/references/data-react-pixie/src/state/use-pixie-database.ts +6 -0
- package/references/data-react-pixie/src/types/filter-type.ts +3 -0
- package/references/data-react-pixie/src/types/sprite-type/bunny.png +0 -0
- package/references/data-react-pixie/src/types/sprite-type/fox.png +0 -0
- package/references/data-react-pixie/src/types/sprite-type/image.ts +14 -0
- package/references/data-react-pixie/src/types/sprite-type/public.ts +4 -0
- package/references/data-react-pixie/src/types/sprite-type/schema.ts +5 -0
- package/references/data-react-pixie/src/types/sprite-type/sprite-type.ts +7 -0
- package/references/data-react-pixie/src/vite-env.d.ts +6 -0
- package/references/data-react-pixie/tsconfig.json +16 -0
- package/dist/LICENSE +0 -21
- package/dist/README.md +0 -296
- package/dist/package.json +0 -183
- package/dist/service/agentic-service/create-from-config.d.ts +0 -45
- package/dist/service/agentic-service/create-from-config.js +0 -85
- package/dist/service/agentic-service/create-from-config.js.map +0 -1
- package/dist/service/agentic-service/create.interface-first-spike.type-test.js +0 -119
- package/dist/service/agentic-service/create.interface-first-spike.type-test.js.map +0 -1
- package/dist/service/agentic-service/index.d.ts +0 -1
- package/dist/service/agentic-service/index.js +0 -3
- package/dist/service/agentic-service/index.js.map +0 -1
- package/dist/service/dynamic-service/create.interface-first-spike.type-test.js +0 -118
- package/dist/service/dynamic-service/create.interface-first-spike.type-test.js.map +0 -1
- /package/dist/{service/agentic-service/create.interface-first-spike.type-test.d.ts → ecs/database/observe-select-deep.type-test.d.ts} +0 -0
- /package/dist/{service/dynamic-service/create.interface-first-spike.type-test.d.ts → ecs/persistence-service/create-storage-persistence-service.test.d.ts} +0 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// © 2026 Adobe. MIT License. See /LICENSE for details.
|
|
2
|
+
|
|
3
|
+
import { css } from "lit";
|
|
4
|
+
|
|
5
|
+
export const styles = css`
|
|
6
|
+
.hud {
|
|
7
|
+
padding: 0.5rem 1rem;
|
|
8
|
+
font-family: system-ui, sans-serif;
|
|
9
|
+
display: flex;
|
|
10
|
+
align-items: center;
|
|
11
|
+
gap: 0.5rem;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.hud button {
|
|
15
|
+
padding: 0.25rem 0.75rem;
|
|
16
|
+
cursor: pointer;
|
|
17
|
+
}
|
|
18
|
+
`;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// © 2026 Adobe. MIT License. See /LICENSE for details.
|
|
2
|
+
|
|
3
|
+
import { customElement } from "lit/decorators.js";
|
|
4
|
+
import { useObservableValues } from "@adobe/data-lit";
|
|
5
|
+
import { BoardState } from "../../types/board-state/board-state.js";
|
|
6
|
+
import { TictactoeElement } from "../../tictactoe-element.js";
|
|
7
|
+
import { styles } from "./tictactoe-hud.css.js";
|
|
8
|
+
import * as presentation from "./tictactoe-hud-presentation.js";
|
|
9
|
+
|
|
10
|
+
export const tagName = "tictactoe-hud";
|
|
11
|
+
|
|
12
|
+
@customElement(tagName)
|
|
13
|
+
export class TictactoeHud extends TictactoeElement {
|
|
14
|
+
static styles = styles;
|
|
15
|
+
|
|
16
|
+
render() {
|
|
17
|
+
const values = useObservableValues(
|
|
18
|
+
() => ({
|
|
19
|
+
board: this.service.observe.resources.board,
|
|
20
|
+
firstPlayer: this.service.observe.resources.firstPlayer,
|
|
21
|
+
}),
|
|
22
|
+
[],
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
const board = values?.board ?? " ";
|
|
26
|
+
const firstPlayer = values?.firstPlayer ?? "X";
|
|
27
|
+
|
|
28
|
+
const currentPlayer = BoardState.currentPlayer(board, firstPlayer);
|
|
29
|
+
const status = BoardState.deriveStatus(board);
|
|
30
|
+
const winner = BoardState.getWinner(board);
|
|
31
|
+
|
|
32
|
+
const statusText =
|
|
33
|
+
status === "won" && winner !== null
|
|
34
|
+
? `Winner: ${winner}`
|
|
35
|
+
: status === "draw"
|
|
36
|
+
? "Draw"
|
|
37
|
+
: `Current Player: ${currentPlayer}`;
|
|
38
|
+
|
|
39
|
+
return presentation.render({
|
|
40
|
+
statusText,
|
|
41
|
+
restartGame: () => this.service.transactions.restartGame(),
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// © 2026 Adobe. MIT License. See /LICENSE for details.
|
|
2
|
+
|
|
3
|
+
import { Database } from "@adobe/data/ecs";
|
|
4
|
+
import { Observe } from "@adobe/data/observe";
|
|
5
|
+
import { AgenticService } from "@adobe/data/service";
|
|
6
|
+
import { BoardState } from "../types/board-state/board-state";
|
|
7
|
+
import type { PlayerMark } from "../types/player-mark/player-mark";
|
|
8
|
+
import { tictactoePlugin } from "./tictactoe-plugin";
|
|
9
|
+
import type { TictactoeDatabase } from "./tictactoe-plugin";
|
|
10
|
+
|
|
11
|
+
const roleDescription = (mark: PlayerMark): string =>
|
|
12
|
+
`You are playing as ${mark} in tic-tac-toe. Play to the best of your ability.`;
|
|
13
|
+
|
|
14
|
+
const createTictactoeAgentService = (
|
|
15
|
+
db: TictactoeDatabase,
|
|
16
|
+
agentMark: PlayerMark,
|
|
17
|
+
): AgenticService => {
|
|
18
|
+
const board = db.observe.resources.board;
|
|
19
|
+
const isGameOver = Observe.withFilter(board, BoardState.isGameOver);
|
|
20
|
+
const currentPlayer = Observe.withFilter(
|
|
21
|
+
board,
|
|
22
|
+
(nextBoard) =>
|
|
23
|
+
BoardState.currentPlayer(nextBoard, db.resources.firstPlayer),
|
|
24
|
+
);
|
|
25
|
+
const yourTurn = Observe.withMap(
|
|
26
|
+
Observe.fromProperties({ isGameOver, currentPlayer }),
|
|
27
|
+
({ isGameOver: over, currentPlayer: cur }) => !over && cur === agentMark,
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
return AgenticService.create({
|
|
31
|
+
interface: {
|
|
32
|
+
role: {
|
|
33
|
+
type: "state",
|
|
34
|
+
schema: { type: "string" as const },
|
|
35
|
+
description: "Your role and objective",
|
|
36
|
+
},
|
|
37
|
+
board: {
|
|
38
|
+
type: "state",
|
|
39
|
+
schema: BoardState.schema,
|
|
40
|
+
description: "Board state",
|
|
41
|
+
},
|
|
42
|
+
yourTurn: {
|
|
43
|
+
type: "state",
|
|
44
|
+
schema: { type: "boolean" as const },
|
|
45
|
+
description: "True when it is your turn to play",
|
|
46
|
+
},
|
|
47
|
+
resetGame: {
|
|
48
|
+
type: "action",
|
|
49
|
+
description: "Reset the game after completion",
|
|
50
|
+
parameters: [],
|
|
51
|
+
},
|
|
52
|
+
winner: {
|
|
53
|
+
type: "state",
|
|
54
|
+
schema: {
|
|
55
|
+
type: "string" as const,
|
|
56
|
+
enum: ["X", "O", "cat", null],
|
|
57
|
+
},
|
|
58
|
+
description: "Winner mark when game over",
|
|
59
|
+
},
|
|
60
|
+
playMove: {
|
|
61
|
+
type: "action",
|
|
62
|
+
description: `Play a ${agentMark} move on the board`,
|
|
63
|
+
parameters: [
|
|
64
|
+
{
|
|
65
|
+
title: "index",
|
|
66
|
+
type: "integer" as const,
|
|
67
|
+
minimum: 0,
|
|
68
|
+
maximum: 8,
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
implementation: {
|
|
74
|
+
role: Observe.fromConstant(roleDescription(agentMark)),
|
|
75
|
+
board,
|
|
76
|
+
yourTurn,
|
|
77
|
+
winner: Observe.withFilter(board, BoardState.getWinner),
|
|
78
|
+
resetGame: async () => {
|
|
79
|
+
db.transactions.restartGame();
|
|
80
|
+
},
|
|
81
|
+
playMove: async (index: number) => {
|
|
82
|
+
db.transactions.playMove({ index });
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
conditional: {
|
|
86
|
+
resetGame: isGameOver,
|
|
87
|
+
playMove: yourTurn,
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const tictactoeLinkDescriptions = { x: "Play as X", o: "Play as O" } as const;
|
|
93
|
+
|
|
94
|
+
const createTictactoeRootAgentService = (
|
|
95
|
+
db: TictactoeDatabase,
|
|
96
|
+
): AgenticService => {
|
|
97
|
+
const root = AgenticService.create({
|
|
98
|
+
interface: {
|
|
99
|
+
x: { type: "link", description: tictactoeLinkDescriptions.x },
|
|
100
|
+
o: { type: "link", description: tictactoeLinkDescriptions.o },
|
|
101
|
+
},
|
|
102
|
+
implementation: {
|
|
103
|
+
x: createTictactoeAgentService(db, "X"),
|
|
104
|
+
o: createTictactoeAgentService(db, "O"),
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
return { ...root, linkDescriptions: tictactoeLinkDescriptions } as AgenticService;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
export const agentPlugin = Database.Plugin.create({
|
|
111
|
+
extends: tictactoePlugin,
|
|
112
|
+
services: {
|
|
113
|
+
agent: (db): AgenticService => createTictactoeRootAgentService(db),
|
|
114
|
+
agentX: (db): AgenticService => createTictactoeAgentService(db, "X"),
|
|
115
|
+
agentO: (db): AgenticService => createTictactoeAgentService(db, "O"),
|
|
116
|
+
},
|
|
117
|
+
});
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// © 2026 Adobe. MIT License. See /LICENSE for details.
|
|
2
|
+
|
|
3
|
+
import { Database } from "@adobe/data/ecs";
|
|
4
|
+
import { Observe } from "@adobe/data/observe";
|
|
5
|
+
import { BoardState } from "../types/board-state/board-state";
|
|
6
|
+
import type { PlayerMark } from "../types/player-mark/player-mark";
|
|
7
|
+
import { PlayMoveArgs } from "../types/play-move-args/play-move-args";
|
|
8
|
+
|
|
9
|
+
export const tictactoePlugin = Database.Plugin.create({
|
|
10
|
+
resources: {
|
|
11
|
+
board: { default: BoardState.createInitialBoard() },
|
|
12
|
+
firstPlayer: { default: "X" as PlayerMark },
|
|
13
|
+
},
|
|
14
|
+
computed: {
|
|
15
|
+
currentPlayer: (db) =>
|
|
16
|
+
Observe.withFilter(db.observe.resources.board, (board) =>
|
|
17
|
+
BoardState.currentPlayer(board, db.resources.firstPlayer),
|
|
18
|
+
),
|
|
19
|
+
moveCount: (db) =>
|
|
20
|
+
Observe.withFilter(db.observe.resources.board, BoardState.getMoveCount),
|
|
21
|
+
status: (db) =>
|
|
22
|
+
Observe.withFilter(db.observe.resources.board, BoardState.deriveStatus),
|
|
23
|
+
winningLine: (db) =>
|
|
24
|
+
Observe.withFilter(db.observe.resources.board, BoardState.getWinningLine),
|
|
25
|
+
winner: (db) =>
|
|
26
|
+
Observe.withFilter(db.observe.resources.board, BoardState.getWinner),
|
|
27
|
+
isGameOver: (db) =>
|
|
28
|
+
Observe.withFilter(db.observe.resources.board, BoardState.isGameOver),
|
|
29
|
+
},
|
|
30
|
+
transactions: {
|
|
31
|
+
restartGame: (t) => {
|
|
32
|
+
t.resources.firstPlayer =
|
|
33
|
+
t.resources.firstPlayer === "X" ? "O" : "X";
|
|
34
|
+
t.resources.board = BoardState.createInitialBoard();
|
|
35
|
+
},
|
|
36
|
+
playMove: (t, { index }: PlayMoveArgs) => {
|
|
37
|
+
const validation = PlayMoveArgs.canPlayMove({
|
|
38
|
+
board: t.resources.board,
|
|
39
|
+
index,
|
|
40
|
+
});
|
|
41
|
+
if (!validation.ok) return;
|
|
42
|
+
const mark = BoardState.currentPlayer(
|
|
43
|
+
t.resources.board,
|
|
44
|
+
t.resources.firstPlayer,
|
|
45
|
+
);
|
|
46
|
+
const nextBoard = BoardState.setBoardCell({
|
|
47
|
+
board: t.resources.board,
|
|
48
|
+
index,
|
|
49
|
+
mark,
|
|
50
|
+
});
|
|
51
|
+
t.resources.board = nextBoard;
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
export type TictactoeDatabase = Database.FromPlugin<typeof tictactoePlugin>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// © 2026 Adobe. MIT License. See /LICENSE for details.
|
|
2
|
+
|
|
3
|
+
import { DatabaseElement } from "@adobe/data-lit";
|
|
4
|
+
import { agentPlugin } from "./state/agent-plugin.js";
|
|
5
|
+
|
|
6
|
+
export class TictactoeElement extends DatabaseElement<typeof agentPlugin> {
|
|
7
|
+
get plugin() {
|
|
8
|
+
return agentPlugin;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// © 2026 Adobe. MIT License. See /LICENSE for details.
|
|
2
|
+
|
|
3
|
+
import type { BoardState } from "./board-state";
|
|
4
|
+
import type { PlayerMark } from "../player-mark/player-mark";
|
|
5
|
+
|
|
6
|
+
export const currentPlayer = (
|
|
7
|
+
board: BoardState,
|
|
8
|
+
firstPlayer: PlayerMark,
|
|
9
|
+
): PlayerMark => {
|
|
10
|
+
const xCount = (board.match(/X/g) ?? []).length;
|
|
11
|
+
const oCount = (board.match(/O/g) ?? []).length;
|
|
12
|
+
return xCount === oCount ? firstPlayer : firstPlayer === "X" ? "O" : "X";
|
|
13
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// © 2026 Adobe. MIT License. See /LICENSE for details.
|
|
2
|
+
|
|
3
|
+
import type { BoardState } from "./board-state";
|
|
4
|
+
import type { GameStatus } from "../game-status";
|
|
5
|
+
import { getWinningLine } from "./get-winning-line";
|
|
6
|
+
import { isBoardFull } from "./is-board-full";
|
|
7
|
+
|
|
8
|
+
export const deriveStatus = (board: BoardState): GameStatus => {
|
|
9
|
+
if (getWinningLine(board)) return "won";
|
|
10
|
+
if (isBoardFull(board)) return "draw";
|
|
11
|
+
return (board.match(/[XO]/g) ?? []).length > 0 ? "in_progress" : "idle";
|
|
12
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// © 2026 Adobe. MIT License. See /LICENSE for details.
|
|
2
|
+
|
|
3
|
+
import type { BoardState } from "./board-state";
|
|
4
|
+
import type { BoardCell } from "../board-cell";
|
|
5
|
+
|
|
6
|
+
export const getCell = (board: BoardState, index: number): BoardCell =>
|
|
7
|
+
(board[index] as BoardCell) ?? " ";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// © 2026 Adobe. MIT License. See /LICENSE for details.
|
|
2
|
+
|
|
3
|
+
import type { BoardState } from "./board-state";
|
|
4
|
+
import type { PlayerMark } from "../player-mark/player-mark";
|
|
5
|
+
import { getWinningLine } from "./get-winning-line";
|
|
6
|
+
import { isBoardFull } from "./is-board-full";
|
|
7
|
+
|
|
8
|
+
export const getWinner = (
|
|
9
|
+
board: BoardState,
|
|
10
|
+
): PlayerMark | "cat" | null => {
|
|
11
|
+
const line = getWinningLine(board);
|
|
12
|
+
if (line) return board[line[0]] as PlayerMark;
|
|
13
|
+
return isBoardFull(board) ? "cat" : null;
|
|
14
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// © 2026 Adobe. MIT License. See /LICENSE for details.
|
|
2
|
+
|
|
3
|
+
import type { BoardState } from "./board-state";
|
|
4
|
+
import type { WinningLine } from "../winning-line";
|
|
5
|
+
|
|
6
|
+
const LINES: readonly WinningLine[] = [
|
|
7
|
+
[0, 1, 2],
|
|
8
|
+
[3, 4, 5],
|
|
9
|
+
[6, 7, 8],
|
|
10
|
+
[0, 3, 6],
|
|
11
|
+
[1, 4, 7],
|
|
12
|
+
[2, 5, 8],
|
|
13
|
+
[0, 4, 8],
|
|
14
|
+
[2, 4, 6],
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
export const getWinningLine = (board: BoardState): WinningLine | null => {
|
|
18
|
+
for (const [a, b, c] of LINES) {
|
|
19
|
+
const mark = board[a];
|
|
20
|
+
if (mark !== " " && mark === board[b] && mark === board[c]) {
|
|
21
|
+
return [a, b, c];
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return null;
|
|
25
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// © 2026 Adobe. MIT License. See /LICENSE for details.
|
|
2
|
+
|
|
3
|
+
import type { BoardState } from "./board-state";
|
|
4
|
+
import { deriveStatus } from "./derive-status";
|
|
5
|
+
import { getCell } from "./get-cell";
|
|
6
|
+
|
|
7
|
+
export const isCellPlayable = (board: BoardState, index: number): boolean => {
|
|
8
|
+
const status = deriveStatus(board);
|
|
9
|
+
const cell = getCell(board, index);
|
|
10
|
+
return (
|
|
11
|
+
(status === "in_progress" || status === "idle") && cell === " "
|
|
12
|
+
);
|
|
13
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// © 2026 Adobe. MIT License. See /LICENSE for details.
|
|
2
|
+
|
|
3
|
+
import type { BoardState } from "./board-state";
|
|
4
|
+
import { getWinningLine } from "./get-winning-line";
|
|
5
|
+
|
|
6
|
+
export const isCellWinning = (board: BoardState, index: number): boolean => {
|
|
7
|
+
const line = getWinningLine(board);
|
|
8
|
+
return line !== null && line.includes(index);
|
|
9
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// © 2026 Adobe. MIT License. See /LICENSE for details.
|
|
2
|
+
|
|
3
|
+
import type { BoardState } from "./board-state";
|
|
4
|
+
import { getWinningLine } from "./get-winning-line";
|
|
5
|
+
import { isBoardFull } from "./is-board-full";
|
|
6
|
+
|
|
7
|
+
export const isGameOver = (board: BoardState): boolean =>
|
|
8
|
+
getWinningLine(board) !== null || isBoardFull(board);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// © 2026 Adobe. MIT License. See /LICENSE for details.
|
|
2
|
+
|
|
3
|
+
export { schema } from "./schema";
|
|
4
|
+
export { createInitialBoard } from "./create-initial-board";
|
|
5
|
+
export { currentPlayer } from "./current-player";
|
|
6
|
+
export { deriveStatus } from "./derive-status";
|
|
7
|
+
export { getCell } from "./get-cell";
|
|
8
|
+
export { getWinningLine } from "./get-winning-line";
|
|
9
|
+
export { isCellPlayable } from "./is-cell-playable";
|
|
10
|
+
export { isCellWinning } from "./is-cell-winning";
|
|
11
|
+
export { getWinner } from "./get-winner";
|
|
12
|
+
export { getMoveCount } from "./get-move-count";
|
|
13
|
+
export { isBoardFull } from "./is-board-full";
|
|
14
|
+
export { isGameOver } from "./is-game-over";
|
|
15
|
+
export { setBoardCell } from "./set-board-cell";
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// © 2026 Adobe. MIT License. See /LICENSE for details.
|
|
2
|
+
|
|
3
|
+
import { Schema } from "@adobe/data/schema";
|
|
4
|
+
|
|
5
|
+
export const schema = {
|
|
6
|
+
type: "string",
|
|
7
|
+
description: "Tic-Tac-Toe board top left to bottom right",
|
|
8
|
+
minLength: 9,
|
|
9
|
+
maxLength: 9,
|
|
10
|
+
} as const satisfies Schema;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// © 2026 Adobe. MIT License. See /LICENSE for details.
|
|
2
|
+
|
|
3
|
+
import type { BoardState } from "./board-state";
|
|
4
|
+
import type { PlayerMark } from "../player-mark/player-mark";
|
|
5
|
+
|
|
6
|
+
export const setBoardCell = (args: {
|
|
7
|
+
board: BoardState;
|
|
8
|
+
index: number;
|
|
9
|
+
mark: PlayerMark;
|
|
10
|
+
}): BoardState => {
|
|
11
|
+
const { board, index, mark } = args;
|
|
12
|
+
return board.slice(0, index) + mark + board.slice(index + 1);
|
|
13
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// © 2026 Adobe. MIT License. See /LICENSE for details.
|
|
2
|
+
|
|
3
|
+
import { BoardState } from "../board-state/board-state";
|
|
4
|
+
import type { MoveRejectReason } from "../move-reject-reason";
|
|
5
|
+
|
|
6
|
+
export type CanPlayMoveArgs = {
|
|
7
|
+
readonly board: BoardState;
|
|
8
|
+
readonly index: number;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type CanPlayMoveResult =
|
|
12
|
+
| { readonly ok: true }
|
|
13
|
+
| { readonly ok: false; readonly reason: MoveRejectReason };
|
|
14
|
+
|
|
15
|
+
export const canPlayMove = ({
|
|
16
|
+
board,
|
|
17
|
+
index,
|
|
18
|
+
}: CanPlayMoveArgs): CanPlayMoveResult => {
|
|
19
|
+
if (!Number.isInteger(index) || index < 0 || index > 8) {
|
|
20
|
+
return { ok: false, reason: "index_out_of_bounds" };
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const status = BoardState.deriveStatus(board);
|
|
24
|
+
if (status === "won" || status === "draw") {
|
|
25
|
+
return { ok: false, reason: "game_over" };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (board[index] !== " ") {
|
|
29
|
+
return { ok: false, reason: "cell_occupied" };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return { ok: true };
|
|
33
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"useDefineForClassFields": false,
|
|
5
|
+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
"moduleResolution": "bundler",
|
|
9
|
+
"resolveJsonModule": true,
|
|
10
|
+
"isolatedModules": true,
|
|
11
|
+
"noEmit": true,
|
|
12
|
+
"experimentalDecorators": true,
|
|
13
|
+
"strict": true
|
|
14
|
+
},
|
|
15
|
+
"include": ["src"]
|
|
16
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "data-lit-todo",
|
|
3
|
+
"version": "0.9.38",
|
|
4
|
+
"description": "Todo sample app demonstrating @adobe/data with Lit",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"private": true,
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "vite build",
|
|
9
|
+
"dev": "vite",
|
|
10
|
+
"publish-public": "true"
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"@adobe/data": "workspace:*",
|
|
14
|
+
"@adobe/data-lit": "workspace:*",
|
|
15
|
+
"@spectrum-web-components/action-button": "^1.7.0",
|
|
16
|
+
"@spectrum-web-components/action-group": "^1.7.0",
|
|
17
|
+
"@spectrum-web-components/button": "^1.7.0",
|
|
18
|
+
"@spectrum-web-components/card": "^1.7.0",
|
|
19
|
+
"@spectrum-web-components/checkbox": "^1.7.0",
|
|
20
|
+
"@spectrum-web-components/icons-workflow": "^1.7.0",
|
|
21
|
+
"@spectrum-web-components/styles": "^1.7.0",
|
|
22
|
+
"@spectrum-web-components/theme": "^1.7.0",
|
|
23
|
+
"lit": "^3.3.1"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"typescript": "^5.8.3",
|
|
27
|
+
"vite": "^6.4.0",
|
|
28
|
+
"vitest": "^1.6.0"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// © 2026 Adobe. MIT License. See /LICENSE for details.
|
|
2
|
+
import type { Entity } from "@adobe/data/ecs";
|
|
3
|
+
import { html } from 'lit';
|
|
4
|
+
import { repeat } from 'lit/directives/repeat.js';
|
|
5
|
+
import '@spectrum-web-components/action-button/sp-action-button.js';
|
|
6
|
+
import '../todo-row/todo-row.js';
|
|
7
|
+
|
|
8
|
+
type RenderArgs = {
|
|
9
|
+
todos: readonly Entity[];
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export function render(args: RenderArgs) {
|
|
13
|
+
return html`
|
|
14
|
+
<div class="todo-list">
|
|
15
|
+
${repeat(
|
|
16
|
+
args.todos,
|
|
17
|
+
todo => todo,
|
|
18
|
+
(todo, index) => html` <data-todo-row .entity=${todo} .index=${index}></data-todo-row> `
|
|
19
|
+
)}
|
|
20
|
+
</div>
|
|
21
|
+
`;
|
|
22
|
+
}
|