create-flowdular 0.2.4 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -0
- package/agent-template/.agents/skills/agent-tool-design/SKILL.md +203 -0
- package/agent-template/.agents/skills/auth-security-review/SKILL.md +90 -0
- package/agent-template/.agents/skills/auto-review/SKILL.md +103 -0
- package/agent-template/.agents/skills/bug-hunt/SKILL.md +104 -0
- package/agent-template/.agents/skills/business-agent-design/SKILL.md +182 -0
- package/agent-template/.agents/skills/cli-extension/SKILL.md +108 -0
- package/agent-template/.agents/skills/core-extend/SKILL.md +99 -0
- package/agent-template/.agents/skills/database-adapter/SKILL.md +198 -0
- package/agent-template/.agents/skills/database-adapter/references/first-run-and-matrix.md +105 -0
- package/agent-template/.agents/skills/migration-authoring/SKILL.md +161 -0
- package/agent-template/.agents/skills/module-new/SKILL.md +171 -0
- package/agent-template/.agents/skills/module-update/SKILL.md +91 -0
- package/agent-template/.agents/skills/perf-audit/SKILL.md +98 -0
- package/agent-template/.agents/skills/release-eject-pr/SKILL.md +107 -0
- package/agent-template/.agents/skills/spec-approval/SKILL.md +106 -0
- package/agent-template/.agents/skills/test-hardening/SKILL.md +79 -0
- package/agent-template/.agents/skills/translations-i18n/SKILL.md +78 -0
- package/agent-template/.agents/skills/ux-design/SKILL.md +92 -0
- package/agent-template/.agents/skills/variables/SKILL.md +156 -0
- package/agent-template/.agents/skills/workflow-development/SKILL.md +192 -0
- package/agent-template/.ai/README.md +62 -0
- package/agent-template/.ai/agents/README.md +27 -0
- package/agent-template/.ai/agents/module-executor.md +36 -0
- package/agent-template/.ai/agents/reviewer.md +23 -0
- package/agent-template/.ai/agents/sandbox/agentic-engineer.md +31 -0
- package/agent-template/.ai/agents/sandbox/backend-engineer.md +36 -0
- package/agent-template/.ai/agents/sandbox/business-manager.md +23 -0
- package/agent-template/.ai/agents/sandbox/frontend-engineer.md +27 -0
- package/agent-template/.ai/agents/sandbox/ux-designer.md +23 -0
- package/agent-template/.ai/agents/spec-author.md +29 -0
- package/agent-template/.ai/blueprints/add-migration/README.md +5 -0
- package/agent-template/.ai/blueprints/add-migration/allowed-paths.yaml +23 -0
- package/agent-template/.ai/blueprints/add-migration/blueprint.json +14 -0
- package/agent-template/.ai/blueprints/add-migration/examples/invalid/input-destructive.json +6 -0
- package/agent-template/.ai/blueprints/add-migration/examples/invalid/plan-unnumbered-file.json +9 -0
- package/agent-template/.ai/blueprints/add-migration/examples/valid/input.json +6 -0
- package/agent-template/.ai/blueprints/add-migration/examples/valid/plan.json +9 -0
- package/agent-template/.ai/blueprints/add-migration/gates.yaml +30 -0
- package/agent-template/.ai/blueprints/add-migration/input.schema.json +23 -0
- package/agent-template/.ai/blueprints/add-migration/plan.schema.json +54 -0
- package/agent-template/.ai/blueprints/add-migration/required-files.yaml +18 -0
- package/agent-template/.ai/blueprints/add-migration/spec-requirements.yaml +13 -0
- package/agent-template/.ai/blueprints/add-migration/steps.yaml +62 -0
- package/agent-template/.ai/blueprints/author-spec/README.md +5 -0
- package/agent-template/.ai/blueprints/author-spec/allowed-paths.yaml +7 -0
- package/agent-template/.ai/blueprints/author-spec/blueprint.json +14 -0
- package/agent-template/.ai/blueprints/author-spec/examples/invalid/input-missing-outcome.json +5 -0
- package/agent-template/.ai/blueprints/author-spec/examples/valid/input.json +6 -0
- package/agent-template/.ai/blueprints/author-spec/gates.yaml +13 -0
- package/agent-template/.ai/blueprints/author-spec/input.schema.json +20 -0
- package/agent-template/.ai/blueprints/author-spec/plan.schema.json +14 -0
- package/agent-template/.ai/blueprints/author-spec/required-files.yaml +6 -0
- package/agent-template/.ai/blueprints/author-spec/spec-requirements.yaml +35 -0
- package/agent-template/.ai/blueprints/author-spec/steps.yaml +28 -0
- package/agent-template/.ai/blueprints/author-spec/templates/module.yaml +45 -0
- package/agent-template/.ai/blueprints/bug-fix/README.md +5 -0
- package/agent-template/.ai/blueprints/bug-fix/allowed-paths.yaml +29 -0
- package/agent-template/.ai/blueprints/bug-fix/blueprint.json +14 -0
- package/agent-template/.ai/blueprints/bug-fix/examples/invalid/input-no-symptom.json +4 -0
- package/agent-template/.ai/blueprints/bug-fix/examples/invalid/plan-no-test.json +8 -0
- package/agent-template/.ai/blueprints/bug-fix/examples/valid/input.json +6 -0
- package/agent-template/.ai/blueprints/bug-fix/examples/valid/plan.json +8 -0
- package/agent-template/.ai/blueprints/bug-fix/gates.yaml +30 -0
- package/agent-template/.ai/blueprints/bug-fix/input.schema.json +25 -0
- package/agent-template/.ai/blueprints/bug-fix/plan.schema.json +53 -0
- package/agent-template/.ai/blueprints/bug-fix/required-files.yaml +7 -0
- package/agent-template/.ai/blueprints/bug-fix/spec-requirements.yaml +7 -0
- package/agent-template/.ai/blueprints/bug-fix/steps.yaml +51 -0
- package/agent-template/.ai/blueprints/core-extend/README.md +5 -0
- package/agent-template/.ai/blueprints/core-extend/allowed-paths.yaml +49 -0
- package/agent-template/.ai/blueprints/core-extend/blueprint.json +14 -0
- package/agent-template/.ai/blueprints/core-extend/examples/invalid/input-unknown-package.json +5 -0
- package/agent-template/.ai/blueprints/core-extend/examples/invalid/plan-missing-gates.json +7 -0
- package/agent-template/.ai/blueprints/core-extend/examples/valid/input.json +6 -0
- package/agent-template/.ai/blueprints/core-extend/examples/valid/plan.json +10 -0
- package/agent-template/.ai/blueprints/core-extend/gates.yaml +16 -0
- package/agent-template/.ai/blueprints/core-extend/input.schema.json +54 -0
- package/agent-template/.ai/blueprints/core-extend/plan.schema.json +39 -0
- package/agent-template/.ai/blueprints/core-extend/required-files.yaml +36 -0
- package/agent-template/.ai/blueprints/core-extend/spec-requirements.yaml +17 -0
- package/agent-template/.ai/blueprints/core-extend/steps.yaml +54 -0
- package/agent-template/.ai/blueprints/edit-module/README.md +9 -0
- package/agent-template/.ai/blueprints/edit-module/allowed-paths.yaml +27 -0
- package/agent-template/.ai/blueprints/edit-module/blueprint.json +20 -0
- package/agent-template/.ai/blueprints/edit-module/examples/invalid/input-unknown-change.json +5 -0
- package/agent-template/.ai/blueprints/edit-module/examples/invalid/plan-touches-platform.json +15 -0
- package/agent-template/.ai/blueprints/edit-module/examples/valid/input.json +5 -0
- package/agent-template/.ai/blueprints/edit-module/examples/valid/plan.json +25 -0
- package/agent-template/.ai/blueprints/edit-module/gates.yaml +30 -0
- package/agent-template/.ai/blueprints/edit-module/input.schema.json +31 -0
- package/agent-template/.ai/blueprints/edit-module/plan.schema.json +65 -0
- package/agent-template/.ai/blueprints/edit-module/required-files.yaml +80 -0
- package/agent-template/.ai/blueprints/edit-module/spec-requirements.yaml +15 -0
- package/agent-template/.ai/blueprints/edit-module/steps.yaml +115 -0
- package/agent-template/.ai/blueprints/new-module/README.md +7 -0
- package/agent-template/.ai/blueprints/new-module/allowed-paths.yaml +27 -0
- package/agent-template/.ai/blueprints/new-module/blueprint.json +20 -0
- package/agent-template/.ai/blueprints/new-module/examples/invalid/input-spec-outside-modules.json +4 -0
- package/agent-template/.ai/blueprints/new-module/examples/invalid/plan-unknown-gate.json +8 -0
- package/agent-template/.ai/blueprints/new-module/examples/valid/input.json +5 -0
- package/agent-template/.ai/blueprints/new-module/examples/valid/plan.json +22 -0
- package/agent-template/.ai/blueprints/new-module/gates.yaml +30 -0
- package/agent-template/.ai/blueprints/new-module/input.schema.json +21 -0
- package/agent-template/.ai/blueprints/new-module/plan.schema.json +58 -0
- package/agent-template/.ai/blueprints/new-module/required-files.yaml +73 -0
- package/agent-template/.ai/blueprints/new-module/spec-requirements.yaml +30 -0
- package/agent-template/.ai/blueprints/new-module/steps.yaml +138 -0
- package/agent-template/.ai/blueprints/release/README.md +5 -0
- package/agent-template/.ai/blueprints/release/allowed-paths.yaml +19 -0
- package/agent-template/.ai/blueprints/release/blueprint.json +14 -0
- package/agent-template/.ai/blueprints/release/examples/invalid/input-bad-version.json +4 -0
- package/agent-template/.ai/blueprints/release/examples/invalid/plan-bad-branch.json +7 -0
- package/agent-template/.ai/blueprints/release/examples/valid/input.json +5 -0
- package/agent-template/.ai/blueprints/release/examples/valid/plan.json +20 -0
- package/agent-template/.ai/blueprints/release/gates.yaml +20 -0
- package/agent-template/.ai/blueprints/release/input.schema.json +24 -0
- package/agent-template/.ai/blueprints/release/plan.schema.json +46 -0
- package/agent-template/.ai/blueprints/release/required-files.yaml +19 -0
- package/agent-template/.ai/blueprints/release/spec-requirements.yaml +8 -0
- package/agent-template/.ai/blueprints/release/steps.yaml +47 -0
- package/agent-template/.ai/blueprints/security-review/README.md +5 -0
- package/agent-template/.ai/blueprints/security-review/allowed-paths.yaml +6 -0
- package/agent-template/.ai/blueprints/security-review/blueprint.json +14 -0
- package/agent-template/.ai/blueprints/security-review/examples/invalid/input-unknown-kind.json +4 -0
- package/agent-template/.ai/blueprints/security-review/examples/invalid/plan-finding-without-scenario.json +14 -0
- package/agent-template/.ai/blueprints/security-review/examples/valid/input.json +4 -0
- package/agent-template/.ai/blueprints/security-review/examples/valid/plan.json +19 -0
- package/agent-template/.ai/blueprints/security-review/gates.yaml +22 -0
- package/agent-template/.ai/blueprints/security-review/input.schema.json +20 -0
- package/agent-template/.ai/blueprints/security-review/plan.schema.json +65 -0
- package/agent-template/.ai/blueprints/security-review/required-files.yaml +6 -0
- package/agent-template/.ai/blueprints/security-review/spec-requirements.yaml +9 -0
- package/agent-template/.ai/blueprints/security-review/steps.yaml +38 -0
- package/agent-template/.ai/examples/README.md +8 -0
- package/agent-template/.ai/examples/bad/client-imports-server/README.md +20 -0
- package/agent-template/.ai/examples/bad/client-imports-server/api.ts +12 -0
- package/agent-template/.ai/examples/bad/missing-acl/README.md +23 -0
- package/agent-template/.ai/examples/bad/missing-acl/endpoints.ts +12 -0
- package/agent-template/.ai/examples/bad/tenant-from-body/README.md +19 -0
- package/agent-template/.ai/examples/bad/tenant-from-body/endpoints.ts +33 -0
- package/agent-template/.ai/examples/client-contribution/CustomerListView.tsrx +34 -0
- package/agent-template/.ai/examples/client-contribution/README.md +11 -0
- package/agent-template/.ai/examples/client-contribution/contribution.tsrx +48 -0
- package/agent-template/.ai/examples/client-contribution/index.ts +20 -0
- package/agent-template/.ai/examples/client-contribution/permissions.ts +8 -0
- package/agent-template/.ai/examples/customer-cli-extension/README.md +14 -0
- package/agent-template/.ai/examples/customer-cli-extension/commands.json +17 -0
- package/agent-template/.ai/examples/customer-cli-extension/index.ts +36 -0
- package/agent-template/.ai/examples/module-create/task-packet.json +11 -0
- package/agent-template/.ai/guides/application-development.md +97 -0
- package/agent-template/.ai/policies/capabilities.yaml +164 -0
- package/agent-template/.ai/policies/model-routing.yaml +72 -0
- package/agent-template/.ai/policies/path-ownership.yaml +65 -0
- package/agent-template/.ai/policies/task-budgets.yaml +37 -0
- package/agent-template/.ai/references/catalog/LICENSE +21 -0
- package/agent-template/.ai/references/catalog/migrations/0001_catalog_core.down.sql +2 -0
- package/agent-template/.ai/references/catalog/migrations/0001_catalog_core.up.sql +21 -0
- package/agent-template/.ai/references/catalog/migrations/0002_catalog_history.down.sql +3 -0
- package/agent-template/.ai/references/catalog/migrations/0002_catalog_history.up.sql +20 -0
- package/agent-template/.ai/references/catalog/migrations/0003_catalog_history_service_actors.down.sql +3 -0
- package/agent-template/.ai/references/catalog/migrations/0003_catalog_history_service_actors.up.sql +36 -0
- package/agent-template/.ai/references/catalog/migrations/0004_catalog_idempotency_ledger.down.sql +3 -0
- package/agent-template/.ai/references/catalog/migrations/0004_catalog_idempotency_ledger.up.sql +19 -0
- package/agent-template/.ai/references/catalog/migrations/README.md +3 -0
- package/agent-template/.ai/references/catalog/module.json +27 -0
- package/agent-template/.ai/references/catalog/package.json +49 -0
- package/agent-template/.ai/references/catalog/spec/module.yaml +86 -0
- package/agent-template/.ai/references/catalog/src/acl/permissions.ts +6 -0
- package/agent-template/.ai/references/catalog/src/agent/tools.ts +164 -0
- package/agent-template/.ai/references/catalog/src/api/endpoints.ts +243 -0
- package/agent-template/.ai/references/catalog/src/client/CatalogHistoryDrawer.tsrx +123 -0
- package/agent-template/.ai/references/catalog/src/client/CatalogItemForm.tsrx +190 -0
- package/agent-template/.ai/references/catalog/src/client/CatalogView.tsrx +473 -0
- package/agent-template/.ai/references/catalog/src/client/api.ts +111 -0
- package/agent-template/.ai/references/catalog/src/client/contribution.tsrx +61 -0
- package/agent-template/.ai/references/catalog/src/client/index.ts +18 -0
- package/agent-template/.ai/references/catalog/src/client/navigation-copy.ts +9 -0
- package/agent-template/.ai/references/catalog/src/client/state.ts +24 -0
- package/agent-template/.ai/references/catalog/src/domain/types.ts +32 -0
- package/agent-template/.ai/references/catalog/src/domain/variables.ts +111 -0
- package/agent-template/.ai/references/catalog/src/index.ts +31 -0
- package/agent-template/.ai/references/catalog/src/platform.ts +35 -0
- package/agent-template/.ai/references/catalog/src/server/index.ts +4 -0
- package/agent-template/.ai/references/catalog/src/server/runtime.ts +86 -0
- package/agent-template/.ai/references/catalog/src/services/catalog-service.ts +306 -0
- package/agent-template/.ai/references/catalog/src/services/database-repository.ts +440 -0
- package/agent-template/.ai/references/catalog/src/services/index.ts +4 -0
- package/agent-template/.ai/references/catalog/src/services/migration.ts +171 -0
- package/agent-template/.ai/references/catalog/src/services/repository.ts +36 -0
- package/agent-template/.ai/references/catalog/src/services/target-idempotency.ts +59 -0
- package/agent-template/.ai/references/catalog/tests/agent-tools.test.ts +277 -0
- package/agent-template/.ai/references/catalog/tests/endpoints.test.ts +320 -0
- package/agent-template/.ai/references/catalog/tests/idempotency.test.ts +297 -0
- package/agent-template/.ai/references/catalog/tests/migrations.test.ts +149 -0
- package/agent-template/.ai/references/catalog/tests/module.test.ts +271 -0
- package/agent-template/.ai/references/catalog/tests/support/database.ts +76 -0
- package/agent-template/.ai/references/catalog/translations/en.json +101 -0
- package/agent-template/.ai/references/catalog/translations/pl.json +101 -0
- package/agent-template/.ai/references/catalog/tsconfig.json +15 -0
- package/agent-template/.ai/references/catalog/vitest.config.ts +16 -0
- package/agent-template/.ai/references/catalog.provenance.json +55 -0
- package/agent-template/.ai/rules/flowdular.md +86 -0
- package/agent-template/.ai/skills/README.md +36 -0
- package/agent-template/.ai/skills/agent-tool-design/SKILL.md +209 -0
- package/agent-template/.ai/skills/auth-security-review/SKILL.md +96 -0
- package/agent-template/.ai/skills/auto-review/SKILL.md +112 -0
- package/agent-template/.ai/skills/bug-hunt/SKILL.md +110 -0
- package/agent-template/.ai/skills/business-agent-design/SKILL.md +188 -0
- package/agent-template/.ai/skills/cli-extension/SKILL.md +114 -0
- package/agent-template/.ai/skills/core-extend/SKILL.md +104 -0
- package/agent-template/.ai/skills/database-adapter/SKILL.md +204 -0
- package/agent-template/.ai/skills/database-adapter/references/first-run-and-matrix.md +105 -0
- package/agent-template/.ai/skills/migration-authoring/SKILL.md +167 -0
- package/agent-template/.ai/skills/module-new/SKILL.md +180 -0
- package/agent-template/.ai/skills/module-update/SKILL.md +100 -0
- package/agent-template/.ai/skills/perf-audit/SKILL.md +105 -0
- package/agent-template/.ai/skills/release-eject-pr/SKILL.md +113 -0
- package/agent-template/.ai/skills/spec-approval/SKILL.md +112 -0
- package/agent-template/.ai/skills/test-hardening/SKILL.md +86 -0
- package/agent-template/.ai/skills/translations-i18n/SKILL.md +85 -0
- package/agent-template/.ai/skills/ux-design/SKILL.md +97 -0
- package/agent-template/.ai/skills/variables/SKILL.md +164 -0
- package/agent-template/.ai/skills/workflow-development/SKILL.md +199 -0
- package/agent-template/.claude/skills/agent-tool-design/SKILL.md +203 -0
- package/agent-template/.claude/skills/auth-security-review/SKILL.md +90 -0
- package/agent-template/.claude/skills/auto-review/SKILL.md +103 -0
- package/agent-template/.claude/skills/bug-hunt/SKILL.md +104 -0
- package/agent-template/.claude/skills/business-agent-design/SKILL.md +182 -0
- package/agent-template/.claude/skills/cli-extension/SKILL.md +108 -0
- package/agent-template/.claude/skills/core-extend/SKILL.md +99 -0
- package/agent-template/.claude/skills/database-adapter/SKILL.md +198 -0
- package/agent-template/.claude/skills/database-adapter/references/first-run-and-matrix.md +105 -0
- package/agent-template/.claude/skills/migration-authoring/SKILL.md +161 -0
- package/agent-template/.claude/skills/module-new/SKILL.md +171 -0
- package/agent-template/.claude/skills/module-update/SKILL.md +91 -0
- package/agent-template/.claude/skills/perf-audit/SKILL.md +98 -0
- package/agent-template/.claude/skills/release-eject-pr/SKILL.md +107 -0
- package/agent-template/.claude/skills/spec-approval/SKILL.md +106 -0
- package/agent-template/.claude/skills/test-hardening/SKILL.md +79 -0
- package/agent-template/.claude/skills/translations-i18n/SKILL.md +78 -0
- package/agent-template/.claude/skills/ux-design/SKILL.md +92 -0
- package/agent-template/.claude/skills/variables/SKILL.md +156 -0
- package/agent-template/.claude/skills/workflow-development/SKILL.md +192 -0
- package/agent-template/AGENTS.md +77 -0
- package/agent-template/CLAUDE.md +77 -0
- package/agent-template/docs/adr/0001-development-reload.md +16 -0
- package/agent-template/docs/adr/0002-durable-agent-execution.md +21 -0
- package/agent-template/docs/adr/0003-module-settings.md +22 -0
- package/agent-template/docs/adr/0004-enterprise-access-and-audit.md +36 -0
- package/agent-template/docs/adr/0005-sandbox-runtime-and-coding-agents.md +81 -0
- package/agent-template/docs/adr/0006-agentic-workflows.md +1702 -0
- package/agent-template/docs/adr/0007-module-owned-agents.md +429 -0
- package/agent-template/docs/adr/0008-database-adapter-contract.md +90 -0
- package/agent-template/docs/agent-contract.md +45 -0
- package/agent-template/docs/configuration.md +122 -0
- package/agent-template/docs/database-adapters.md +346 -0
- package/agent-template/docs/design-system.md +217 -0
- package/agent-template/docs/modules.md +146 -0
- package/agent-template/platform/scripts/build.mjs +38 -0
- package/agent-template/rulesync.jsonc +11 -0
- package/dist/bin.js +3 -1
- package/package.json +3 -2
- package/template/default/.prettierignore +9 -0
- package/template/default/README.md +12 -0
- package/template/default/flowdular.json +3 -3
- package/template/default/package.json +6 -2
- package/template/default/platform/octane.config.ts +17 -6
- package/template/default/platform/package.json +2 -1
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Flowdular contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
CREATE TABLE IF NOT EXISTS catalog_items (
|
|
2
|
+
id TEXT PRIMARY KEY,
|
|
3
|
+
tenant_id TEXT NOT NULL,
|
|
4
|
+
sku TEXT NOT NULL,
|
|
5
|
+
sku_normalized TEXT NOT NULL,
|
|
6
|
+
name TEXT NOT NULL,
|
|
7
|
+
kind TEXT NOT NULL CHECK (kind IN ('product', 'service')),
|
|
8
|
+
unit TEXT NOT NULL,
|
|
9
|
+
base_price_minor BIGINT NOT NULL CHECK (base_price_minor >= 0),
|
|
10
|
+
currency TEXT NOT NULL,
|
|
11
|
+
status TEXT NOT NULL CHECK (status IN ('active', 'archived')),
|
|
12
|
+
created_at BIGINT NOT NULL,
|
|
13
|
+
UNIQUE (tenant_id, sku_normalized)
|
|
14
|
+
);
|
|
15
|
+
CREATE INDEX IF NOT EXISTS catalog_items_tenant_sku_idx
|
|
16
|
+
ON catalog_items (tenant_id, sku_normalized, id);
|
|
17
|
+
ALTER TABLE catalog_items ENABLE ROW LEVEL SECURITY;
|
|
18
|
+
ALTER TABLE catalog_items FORCE ROW LEVEL SECURITY;
|
|
19
|
+
CREATE POLICY catalog_items_tenant_policy ON catalog_items
|
|
20
|
+
USING (tenant_id = current_setting('coreloom.tenant_id', true))
|
|
21
|
+
WITH CHECK (tenant_id = current_setting('coreloom.tenant_id', true));
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
CREATE TABLE IF NOT EXISTS catalog_items_history (
|
|
2
|
+
id TEXT PRIMARY KEY,
|
|
3
|
+
tenant_id TEXT NOT NULL,
|
|
4
|
+
record_id TEXT NOT NULL,
|
|
5
|
+
version BIGINT NOT NULL CHECK (version >= 1),
|
|
6
|
+
action TEXT NOT NULL CHECK (length(action) BETWEEN 1 AND 32),
|
|
7
|
+
actor_kind TEXT NOT NULL CHECK (actor_kind IN ('user', 'agent')),
|
|
8
|
+
actor_id TEXT NOT NULL CHECK (length(actor_id) BETWEEN 1 AND 128),
|
|
9
|
+
actor_label TEXT NOT NULL CHECK (length(actor_label) BETWEEN 1 AND 160),
|
|
10
|
+
run_id TEXT CHECK (run_id IS NULL OR length(run_id) BETWEEN 1 AND 128),
|
|
11
|
+
changes_json TEXT NOT NULL,
|
|
12
|
+
occurred_at BIGINT NOT NULL
|
|
13
|
+
);
|
|
14
|
+
CREATE UNIQUE INDEX IF NOT EXISTS catalog_items_history_tenant_record_version_idx
|
|
15
|
+
ON catalog_items_history (tenant_id, record_id, version DESC);
|
|
16
|
+
ALTER TABLE catalog_items_history ENABLE ROW LEVEL SECURITY;
|
|
17
|
+
ALTER TABLE catalog_items_history FORCE ROW LEVEL SECURITY;
|
|
18
|
+
CREATE POLICY catalog_items_history_tenant_policy ON catalog_items_history
|
|
19
|
+
USING (tenant_id = current_setting('coreloom.tenant_id', true))
|
|
20
|
+
WITH CHECK (tenant_id = current_setting('coreloom.tenant_id', true));
|
package/agent-template/.ai/references/catalog/migrations/0003_catalog_history_service_actors.up.sql
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
CREATE TABLE IF NOT EXISTS catalog_items_history_v2 (
|
|
2
|
+
id TEXT PRIMARY KEY,
|
|
3
|
+
tenant_id TEXT NOT NULL,
|
|
4
|
+
record_id TEXT NOT NULL,
|
|
5
|
+
version BIGINT NOT NULL CHECK (version >= 1),
|
|
6
|
+
action TEXT NOT NULL CHECK (length(action) BETWEEN 1 AND 32),
|
|
7
|
+
actor_kind TEXT NOT NULL CHECK (actor_kind IN ('user', 'agent', 'service')),
|
|
8
|
+
actor_id TEXT NOT NULL CHECK (length(actor_id) BETWEEN 1 AND 128),
|
|
9
|
+
actor_label TEXT NOT NULL CHECK (length(actor_label) BETWEEN 1 AND 160),
|
|
10
|
+
run_id TEXT CHECK (run_id IS NULL OR length(run_id) BETWEEN 1 AND 128),
|
|
11
|
+
configured_by_json TEXT CHECK (configured_by_json IS NULL OR configured_by_json::jsonb IS NOT NULL),
|
|
12
|
+
changes_json TEXT NOT NULL,
|
|
13
|
+
occurred_at BIGINT NOT NULL,
|
|
14
|
+
CHECK (
|
|
15
|
+
(actor_kind = 'agent' AND run_id IS NOT NULL)
|
|
16
|
+
OR (actor_kind IN ('user', 'service') AND run_id IS NULL)
|
|
17
|
+
),
|
|
18
|
+
CHECK (
|
|
19
|
+
(actor_kind = 'service' AND configured_by_json IS NOT NULL)
|
|
20
|
+
OR (actor_kind IN ('user', 'agent') AND configured_by_json IS NULL)
|
|
21
|
+
)
|
|
22
|
+
);
|
|
23
|
+
CREATE UNIQUE INDEX IF NOT EXISTS catalog_items_history_v2_tenant_record_version_idx
|
|
24
|
+
ON catalog_items_history_v2 (tenant_id, record_id, version DESC);
|
|
25
|
+
INSERT INTO catalog_items_history_v2
|
|
26
|
+
(id, tenant_id, record_id, version, action, actor_kind, actor_id,
|
|
27
|
+
actor_label, run_id, configured_by_json, changes_json, occurred_at)
|
|
28
|
+
SELECT id, tenant_id, record_id, version, action, actor_kind, actor_id,
|
|
29
|
+
actor_label, run_id, NULL, changes_json, occurred_at
|
|
30
|
+
FROM catalog_items_history
|
|
31
|
+
ON CONFLICT DO NOTHING;
|
|
32
|
+
ALTER TABLE catalog_items_history_v2 ENABLE ROW LEVEL SECURITY;
|
|
33
|
+
ALTER TABLE catalog_items_history_v2 FORCE ROW LEVEL SECURITY;
|
|
34
|
+
CREATE POLICY catalog_items_history_v2_tenant_policy ON catalog_items_history_v2
|
|
35
|
+
USING (tenant_id = current_setting('coreloom.tenant_id', true))
|
|
36
|
+
WITH CHECK (tenant_id = current_setting('coreloom.tenant_id', true));
|
package/agent-template/.ai/references/catalog/migrations/0004_catalog_idempotency_ledger.up.sql
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
CREATE TABLE IF NOT EXISTS catalog_idempotency_ledger (
|
|
2
|
+
id TEXT PRIMARY KEY,
|
|
3
|
+
tenant_id TEXT NOT NULL,
|
|
4
|
+
idempotency_key TEXT NOT NULL CHECK (length(idempotency_key) BETWEEN 8 AND 128),
|
|
5
|
+
operation_id TEXT NOT NULL CHECK (length(operation_id) BETWEEN 3 AND 160),
|
|
6
|
+
input_digest TEXT NOT NULL CHECK (length(input_digest) = 71),
|
|
7
|
+
outcome TEXT NOT NULL CHECK (outcome = 'succeeded'),
|
|
8
|
+
result_json TEXT NOT NULL CHECK (result_json::jsonb IS NOT NULL),
|
|
9
|
+
result_digest TEXT NOT NULL CHECK (length(result_digest) = 71),
|
|
10
|
+
created_at BIGINT NOT NULL,
|
|
11
|
+
UNIQUE (tenant_id, idempotency_key)
|
|
12
|
+
);
|
|
13
|
+
CREATE INDEX IF NOT EXISTS catalog_idempotency_ledger_tenant_operation_idx
|
|
14
|
+
ON catalog_idempotency_ledger (tenant_id, operation_id, created_at, id);
|
|
15
|
+
ALTER TABLE catalog_idempotency_ledger ENABLE ROW LEVEL SECURITY;
|
|
16
|
+
ALTER TABLE catalog_idempotency_ledger FORCE ROW LEVEL SECURITY;
|
|
17
|
+
CREATE POLICY catalog_idempotency_ledger_tenant_policy ON catalog_idempotency_ledger
|
|
18
|
+
USING (tenant_id = current_setting('coreloom.tenant_id', true))
|
|
19
|
+
WITH CHECK (tenant_id = current_setting('coreloom.tenant_id', true));
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../../packages/contracts/schemas/module.schema.json",
|
|
3
|
+
"schemaVersion": 1,
|
|
4
|
+
"id": "catalog.core",
|
|
5
|
+
"package": "@flowdular/module-catalog",
|
|
6
|
+
"version": "0.6.1",
|
|
7
|
+
"profile": "full",
|
|
8
|
+
"capabilities": ["api", "database", "client", "translations"],
|
|
9
|
+
"platform": {
|
|
10
|
+
"server": true,
|
|
11
|
+
"client": true
|
|
12
|
+
},
|
|
13
|
+
"dependencies": [
|
|
14
|
+
{
|
|
15
|
+
"id": "system.core",
|
|
16
|
+
"range": "0.5.0"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"id": "auth.core",
|
|
20
|
+
"range": "0.10.0"
|
|
21
|
+
}
|
|
22
|
+
],
|
|
23
|
+
"tenancy": "required",
|
|
24
|
+
"locales": ["en", "pl"],
|
|
25
|
+
"stability": "experimental",
|
|
26
|
+
"platformApi": "0.1.0"
|
|
27
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@flowdular/module-catalog",
|
|
3
|
+
"version": "0.6.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"exports": {
|
|
6
|
+
".": "./src/index.ts",
|
|
7
|
+
"./client": "./src/client/index.ts",
|
|
8
|
+
"./server": "./src/server/index.ts",
|
|
9
|
+
"./platform": "./src/platform.ts",
|
|
10
|
+
"./module.json": "./module.json"
|
|
11
|
+
},
|
|
12
|
+
"scripts": {
|
|
13
|
+
"typecheck": "tsrx-tsc --noEmit -p tsconfig.json",
|
|
14
|
+
"test": "vitest run"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"octane": "0.1.51",
|
|
18
|
+
"segment-state": "0.2.0",
|
|
19
|
+
"@flowdular/sdk": "0.1.0"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@tsrx/typescript-plugin": "0.3.120",
|
|
23
|
+
"@types/node": "24.13.3",
|
|
24
|
+
"typescript": "5.9.3",
|
|
25
|
+
"vitest": "4.1.10"
|
|
26
|
+
},
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"access": "public"
|
|
30
|
+
},
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "git+https://github.com/Flowdular/official-modules.git",
|
|
34
|
+
"directory": "modules/catalog"
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"src",
|
|
38
|
+
"schemas",
|
|
39
|
+
"dist",
|
|
40
|
+
"bin",
|
|
41
|
+
"public",
|
|
42
|
+
"module.json",
|
|
43
|
+
"migrations",
|
|
44
|
+
"translations",
|
|
45
|
+
"spec",
|
|
46
|
+
"README.md",
|
|
47
|
+
"LICENSE"
|
|
48
|
+
]
|
|
49
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
schemaVersion: 1
|
|
2
|
+
id: catalog.core
|
|
3
|
+
specVersion: 0.6.1
|
|
4
|
+
status: approved
|
|
5
|
+
name: Product Catalog Core
|
|
6
|
+
description: Provides tenant-scoped products and services with stable SKUs, units, prices, currencies, and lifecycle state.
|
|
7
|
+
profile: full
|
|
8
|
+
capabilities:
|
|
9
|
+
- api
|
|
10
|
+
- database
|
|
11
|
+
- client
|
|
12
|
+
- translations
|
|
13
|
+
dependencies:
|
|
14
|
+
- id: system.core
|
|
15
|
+
range: 0.5.0
|
|
16
|
+
- id: auth.core
|
|
17
|
+
range: 0.10.0
|
|
18
|
+
tenancy: required
|
|
19
|
+
locales:
|
|
20
|
+
- en
|
|
21
|
+
- pl
|
|
22
|
+
invariants:
|
|
23
|
+
- Persistence runs on the shared asynchronous database contract. The module receives a leased PostgreSQL handle from platform composition, never a driver or a connection string, and declares explicit PostgreSQL SQL for every statement and migration.
|
|
24
|
+
- PostgreSQL item, history, and idempotency ledger tables enable and force row-level security with USING and WITH CHECK policies bound to transaction-local coreloom.tenant_id, and the runtime role holds neither SUPERUSER nor BYPASSRLS. Migrations use a separate lease.
|
|
25
|
+
- Every catalog item is owned by exactly one tenant and every query uses the trusted tenant identifier.
|
|
26
|
+
- SKU is unique inside a tenant and is never used as tenancy authority.
|
|
27
|
+
- Monetary values are stored as integer minor units with an explicit ISO currency code.
|
|
28
|
+
- Item kind is product or service and status is active or archived.
|
|
29
|
+
- Background workflow actions preserve their service actor and the configuring user in record history.
|
|
30
|
+
- One tenant-scoped durable target ledger is shared by mutating agent tools and workflow actions; each entry binds an idempotency key to the exact tool identifier or versioned workflow action identifier, canonical input digest, and first persisted result in the same transaction as the catalog mutation.
|
|
31
|
+
- Replaying the same idempotency key for the same operation and canonical input returns the original result without another catalog item or history row, while reuse for another operation or input fails with a stable conflict.
|
|
32
|
+
- Idempotency ledger entries remain after a catalog item is deleted, and audit metadata records identifiers, input digests, and outcomes without raw tool input, credentials, secrets, or result payloads.
|
|
33
|
+
permissions:
|
|
34
|
+
- id: catalog.items.read
|
|
35
|
+
description: Read products and services in the active tenant.
|
|
36
|
+
- id: catalog.items.manage
|
|
37
|
+
description: Create and update products and services in the active tenant.
|
|
38
|
+
dataOwnership:
|
|
39
|
+
- catalog.core owns SKU, item identity, kind, unit, base price, currency, and lifecycle status.
|
|
40
|
+
- catalog.core owns the idempotency ledger for its mutating agent tools and workflow actions; callers supply the key but do not maintain a second target ledger.
|
|
41
|
+
- Sales and purchasing modules reference catalog item identifiers and snapshot commercial terms when required by their specs.
|
|
42
|
+
acceptanceScenarios:
|
|
43
|
+
- id: CATALOG-LIST
|
|
44
|
+
given: Tenant-scoped products and services exist.
|
|
45
|
+
when: An authorized principal lists catalog items.
|
|
46
|
+
then: Only items owned by the active tenant are returned in deterministic SKU order.
|
|
47
|
+
- id: CATALOG-CREATE
|
|
48
|
+
given: An authorized principal supplies a unique SKU and valid product or service data.
|
|
49
|
+
when: The catalog item is created.
|
|
50
|
+
then: A tenant-owned active item is persisted with integer minor-unit pricing.
|
|
51
|
+
- id: CATALOG-DUPLICATE
|
|
52
|
+
given: An item already uses a SKU in the active tenant.
|
|
53
|
+
when: Another item is created with the same normalized SKU.
|
|
54
|
+
then: The server returns a stable conflict error and leaves existing data unchanged.
|
|
55
|
+
- id: CATALOG-DENY
|
|
56
|
+
given: A principal is unauthenticated or lacks the required catalog permission.
|
|
57
|
+
when: The principal reads or mutates catalog data.
|
|
58
|
+
then: The server denies the operation before repository access.
|
|
59
|
+
- id: CATALOG-AGENT-TOOL
|
|
60
|
+
given: An agent run holds catalog.items.manage in its permission snapshot and the tool catalog.item.create in its grants.
|
|
61
|
+
when: The agent invokes the tool with a valid item, and a run without the manage scope invokes the same tool.
|
|
62
|
+
then: The scoped run creates a tenant-owned catalog item from the run tenant and the harness denies the unscoped run before any write.
|
|
63
|
+
- id: CATALOG-LIFECYCLE-HISTORY
|
|
64
|
+
given: A catalog item is active in the current tenant.
|
|
65
|
+
when: An authorized principal edits it, archives it, restores it, or deletes it after archiving.
|
|
66
|
+
then: Each accepted transition has an append-only tenant-scoped revision with the user or agent actor, and the item history endpoint returns only that tenant's revisions.
|
|
67
|
+
- id: CATALOG-WORKFLOW-ACTIONS
|
|
68
|
+
given: A workflow revision selects a versioned catalog read or create action and carries the matching permission snapshot.
|
|
69
|
+
when: The action capability validates and executes the node with an idempotency key and service actor.
|
|
70
|
+
then: The action exposes exact input and output schemas, refuses a missing permission before work, cooperates with cancellation, and attributes a created item to the service and its configuring user.
|
|
71
|
+
- id: CATALOG-IDEMPOTENCY-REPLAY
|
|
72
|
+
given: A mutating catalog tool or workflow action has committed a catalog mutation and its target-ledger result for an idempotency key.
|
|
73
|
+
when: The caller repeats the exact operation with the same canonical input and key, including after losing the first response.
|
|
74
|
+
then: The module returns the original persisted result and creates no second catalog item or history row.
|
|
75
|
+
- id: CATALOG-IDEMPOTENCY-CONFLICT
|
|
76
|
+
given: A tenant-scoped idempotency key is already bound to an exact catalog tool identifier or versioned workflow action identifier and canonical input digest.
|
|
77
|
+
when: A caller reuses the key for a different operation or canonical input.
|
|
78
|
+
then: The module returns a stable conflict before any catalog item, history, or ledger write.
|
|
79
|
+
- id: CATALOG-POSTGRESQL-TENANT-BOUNDARY
|
|
80
|
+
given: catalog.core runs on PostgreSQL and two tenants own catalog data.
|
|
81
|
+
when: A runtime transaction bound to one tenant reads or writes items, history, or ledger rows.
|
|
82
|
+
then: Only that tenant's rows are visible or mutable, a transaction without a tenant is refused, and the forced row-level security policy rejects a row carrying another tenant identifier.
|
|
83
|
+
- id: CATALOG-IDEMPOTENCY-RECOVERY
|
|
84
|
+
given: A catalog item has been committed atomically with its idempotency result, or the item is later deleted through its lifecycle operation.
|
|
85
|
+
when: Recovery replays the mutating tool or workflow action with the same key.
|
|
86
|
+
then: The retained ledger returns the original result without another mutation, and audit evidence contains no raw input, credentials, secrets, or result payload.
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { defineApiAgentTool } from '@flowdular/sdk/harness/tool-adapters';
|
|
2
|
+
import {
|
|
3
|
+
AgentHarnessError,
|
|
4
|
+
type AgentTool,
|
|
5
|
+
type AgentToolContext,
|
|
6
|
+
} from '@flowdular/sdk/harness/runtime';
|
|
7
|
+
import { agentActor, type Actor } from '@flowdular/sdk/kernel';
|
|
8
|
+
import { CATALOG_PERMISSIONS } from '../acl/permissions.ts';
|
|
9
|
+
import type { CatalogItemKind } from '../domain/types.ts';
|
|
10
|
+
import type { CatalogRuntime } from '../server/runtime.ts';
|
|
11
|
+
import { CatalogServiceError } from '../services/catalog-service.ts';
|
|
12
|
+
|
|
13
|
+
const MAX_TOOL_ROWS = 200;
|
|
14
|
+
const CREATE_OPERATION = 'catalog.item.create@1';
|
|
15
|
+
|
|
16
|
+
const CATALOG_ITEM_OUTPUT_SCHEMA = {
|
|
17
|
+
type: 'object',
|
|
18
|
+
additionalProperties: false,
|
|
19
|
+
required: [
|
|
20
|
+
'id',
|
|
21
|
+
'tenantId',
|
|
22
|
+
'sku',
|
|
23
|
+
'name',
|
|
24
|
+
'kind',
|
|
25
|
+
'unit',
|
|
26
|
+
'basePriceMinor',
|
|
27
|
+
'currency',
|
|
28
|
+
'status',
|
|
29
|
+
'createdAt',
|
|
30
|
+
],
|
|
31
|
+
properties: {
|
|
32
|
+
id: { type: 'string' },
|
|
33
|
+
tenantId: { type: 'string' },
|
|
34
|
+
sku: { type: 'string' },
|
|
35
|
+
name: { type: 'string' },
|
|
36
|
+
kind: { type: 'string', enum: ['product', 'service'] },
|
|
37
|
+
unit: { type: 'string' },
|
|
38
|
+
basePriceMinor: { type: 'integer' },
|
|
39
|
+
currency: { type: 'string' },
|
|
40
|
+
status: { type: 'string', enum: ['active', 'archived'] },
|
|
41
|
+
createdAt: { type: 'integer' },
|
|
42
|
+
},
|
|
43
|
+
} as const;
|
|
44
|
+
|
|
45
|
+
function actionActor(context: AgentToolContext): Actor {
|
|
46
|
+
return context.actor ?? agentActor(context);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function normalized(value: unknown): string {
|
|
50
|
+
return typeof value === 'string'
|
|
51
|
+
? value.trim().toLocaleLowerCase('en-US')
|
|
52
|
+
: '';
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function idempotencyKey(context: AgentToolContext): string {
|
|
56
|
+
if (!context.idempotencyKey) {
|
|
57
|
+
throw new AgentHarnessError(
|
|
58
|
+
'TOOL_IDEMPOTENCY_KEY_REQUIRED',
|
|
59
|
+
'The catalog create tool requires a durable idempotency key.',
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
return context.idempotencyKey;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/* Tools call the catalog service and take the tenant and the actor from the
|
|
66
|
+
run context, never from input; the service revalidates so a tool cannot
|
|
67
|
+
bypass the endpoint's rules, every write is attributed to the run that made
|
|
68
|
+
it, and list output is capped so one call cannot flood the run window. */
|
|
69
|
+
export function catalogAgentTools(
|
|
70
|
+
runtime: CatalogRuntime,
|
|
71
|
+
): readonly AgentTool[] {
|
|
72
|
+
return [
|
|
73
|
+
defineApiAgentTool({
|
|
74
|
+
id: 'catalog.item.list',
|
|
75
|
+
endpointId: 'catalog.items.list',
|
|
76
|
+
contractVersion: 1,
|
|
77
|
+
description:
|
|
78
|
+
'List products and services of the active tenant, optionally filtered by a free-text query.',
|
|
79
|
+
requiredPermissions: [CATALOG_PERMISSIONS.read],
|
|
80
|
+
risk: 'read',
|
|
81
|
+
idempotency: 'required',
|
|
82
|
+
cancellation: 'cooperative',
|
|
83
|
+
inputSchema: {
|
|
84
|
+
type: 'object',
|
|
85
|
+
additionalProperties: false,
|
|
86
|
+
properties: { query: { type: 'string', maxLength: 120 } },
|
|
87
|
+
},
|
|
88
|
+
outputSchema: { type: 'array', items: CATALOG_ITEM_OUTPUT_SCHEMA },
|
|
89
|
+
execute: async (input, context) => {
|
|
90
|
+
context.signal.throwIfAborted();
|
|
91
|
+
const query = normalized(
|
|
92
|
+
(input as Record<string, unknown> | null)?.query,
|
|
93
|
+
);
|
|
94
|
+
return (await (await runtime.service()).list(context.tenantId))
|
|
95
|
+
.filter(
|
|
96
|
+
(item) =>
|
|
97
|
+
query === '' ||
|
|
98
|
+
item.id.toLocaleLowerCase('en-US') === query ||
|
|
99
|
+
item.sku.toLocaleLowerCase('en-US').includes(query) ||
|
|
100
|
+
item.name.toLocaleLowerCase('en-US').includes(query),
|
|
101
|
+
)
|
|
102
|
+
.slice(0, MAX_TOOL_ROWS);
|
|
103
|
+
},
|
|
104
|
+
}),
|
|
105
|
+
defineApiAgentTool({
|
|
106
|
+
id: 'catalog.item.create',
|
|
107
|
+
endpointId: 'catalog.items.create',
|
|
108
|
+
contractVersion: 1,
|
|
109
|
+
description: 'Create a product or service owned by the active tenant.',
|
|
110
|
+
requiredPermissions: [CATALOG_PERMISSIONS.manage],
|
|
111
|
+
risk: 'workspace-write',
|
|
112
|
+
idempotency: 'required',
|
|
113
|
+
idempotencyProtection: 'target-ledger',
|
|
114
|
+
cancellation: 'cooperative',
|
|
115
|
+
inputSchema: {
|
|
116
|
+
type: 'object',
|
|
117
|
+
additionalProperties: false,
|
|
118
|
+
required: ['sku', 'name', 'kind', 'unit', 'basePriceMinor', 'currency'],
|
|
119
|
+
properties: {
|
|
120
|
+
sku: { type: 'string', maxLength: 64 },
|
|
121
|
+
name: { type: 'string', maxLength: 160 },
|
|
122
|
+
kind: { type: 'string', enum: ['product', 'service'] },
|
|
123
|
+
unit: { type: 'string', maxLength: 24 },
|
|
124
|
+
basePriceMinor: { type: 'integer' },
|
|
125
|
+
currency: { type: 'string', maxLength: 3 },
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
outputSchema: CATALOG_ITEM_OUTPUT_SCHEMA,
|
|
129
|
+
execute: async (input, context) => {
|
|
130
|
+
context.signal.throwIfAborted();
|
|
131
|
+
const value = (input ?? {}) as Record<string, unknown>;
|
|
132
|
+
try {
|
|
133
|
+
return (await runtime.service()).createIdempotent(
|
|
134
|
+
context.tenantId,
|
|
135
|
+
{
|
|
136
|
+
sku: String(value.sku ?? ''),
|
|
137
|
+
name: String(value.name ?? ''),
|
|
138
|
+
kind: value.kind as CatalogItemKind,
|
|
139
|
+
unit: String(value.unit ?? ''),
|
|
140
|
+
basePriceMinor:
|
|
141
|
+
typeof value.basePriceMinor === 'number'
|
|
142
|
+
? value.basePriceMinor
|
|
143
|
+
: Number.NaN,
|
|
144
|
+
currency: String(value.currency ?? ''),
|
|
145
|
+
},
|
|
146
|
+
actionActor(context),
|
|
147
|
+
{
|
|
148
|
+
key: idempotencyKey(context),
|
|
149
|
+
operationId: CREATE_OPERATION,
|
|
150
|
+
},
|
|
151
|
+
);
|
|
152
|
+
} catch (error) {
|
|
153
|
+
if (
|
|
154
|
+
error instanceof CatalogServiceError &&
|
|
155
|
+
error.code === 'CATALOG_IDEMPOTENCY_CONFLICT'
|
|
156
|
+
) {
|
|
157
|
+
throw new AgentHarnessError(error.code, error.message);
|
|
158
|
+
}
|
|
159
|
+
throw error;
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
}),
|
|
163
|
+
];
|
|
164
|
+
}
|