openxiangda-skill-kit 2.0.0-alpha.91 → 2.0.0-alpha.92

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openxiangda-skill-kit",
3
- "version": "2.0.0-alpha.91",
3
+ "version": "2.0.0-alpha.92",
4
4
  "description": "Validation and deterministic packaging for OpenXiangda 2.0 AI skills.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -17,7 +17,7 @@
17
17
  "README.md"
18
18
  ],
19
19
  "dependencies": {
20
- "openxiangda-devkit-core": "2.0.0-alpha.72"
20
+ "openxiangda-devkit-core": "2.0.0-alpha.73"
21
21
  },
22
22
  "devDependencies": {
23
23
  "tsx": "4.23.12",
@@ -38,10 +38,18 @@ For an AI-native client, start the workspace protocol through the same pinned ex
38
38
  pnpm exec openxiangda --mcp-stdio --cwd <workspace>
39
39
  ```
40
40
 
41
- Read `openxiangda://workspace/contracts` or call `contract_describe`. When AppSpec is enabled, read `openxiangda://workspace/appspec` or call `appspec_context`; treat it as advisory context, never as deployment authority. Require `aiCatalog` and `aiCatalogDigest` to match the normal compiler output. Never create an application MCP server, Catalog file, preview store or AI authorization path.
41
+ Read `openxiangda://workspace/contracts` or call `contract_describe`. For first-time menu authoring, copy `data.adminNavigationAuthoring.suggestion.expression` once into `frontend.admin.navigation` with its listed `openxiangda/config` imports, then edit that application-owned declaration; never treat the proposal as runtime discovery. When AppSpec is enabled, read `openxiangda://workspace/appspec` or call `appspec_context`; treat it as advisory context, never as deployment authority. Require `aiCatalog` and `aiCatalogDigest` to match the normal compiler output. Never create an application MCP server, Catalog file, preview store or AI authorization path.
42
42
 
43
43
  The browser uses the current logged-in user's complete application-role union. The platform is authoritative for capabilities, fields, rows and RLS. A declared Perspective is only a read projection over that union: it may narrow pages, rows and readable fields, but never create/update/delete, workflow or custom-action authorization. Omitted Perspective means the complete union. Application code does not replace the authenticated identity, persist a platform token, construct an authorization result or keep a second permission state.
44
44
 
45
+ Applications own one explicit typed admin navigation declaration. The compiler
46
+ owns page/route generation, but it never turns every generated resource or
47
+ Workflow into a menu item; the Shell renders only declared navigation and then
48
+ filters it by authorization. Keep page existence, route reachability and menu
49
+ visibility separate. Use resource mutation ownership and per-operation
50
+ generated surface flags, and give only self-contained `standalone` Workflow
51
+ launch pages a menu entry.
52
+
45
53
  Read only the references needed for the current change, except the mandatory discovery and Data/authorization rules above:
46
54
 
47
55
  - [Discovery](references/discovery.md)
@@ -243,6 +243,10 @@ contract:
243
243
  and may protect a mutation of another resource;
244
244
  - `record-assert` locks one exact record and checks declared field values or
245
245
  declared field-to-field comparisons;
246
+ - `databaseNowAssertion('publishAt', 'lte')` compares a declared `datetime`
247
+ field with the single PostgreSQL transaction time. Do not pass `Date.now()`,
248
+ an offset, a SQL function or a fallback timestamp; a successful idempotent
249
+ replay returns the original `evaluatedAt` without re-evaluating the guard;
246
250
  - `increment` targets one declared integer field and must have a matching
247
251
  same-resource, same-record `record-assert` guard;
248
252
  - never send SQL, table names, expressions, old guards without `errorCode`, or
@@ -62,6 +62,16 @@ also granted only to the intended roles. They are owned and exported by the
62
62
  generated field policy, so do not repeat them in `authz.capabilities`.
63
63
  `authz.capabilities` contains only explicit `backend` or `ui` capabilities.
64
64
 
65
+ Declare mutation ownership on the same resource with
66
+ `mutationOwner: 'native' | 'action' | 'readonly' | 'workflow'`. Native defaults
67
+ to generated list/detail/create/update/delete. Other owners default to readable
68
+ list/detail only and must use their named action or Workflow boundary for
69
+ mutation. Use `generated: { list, detail, create, update, delete }` to narrow
70
+ the generated page/operation surface. The compiler rejects Native mutation
71
+ pages, AI operations or role grants on a non-Native owner, and rejects
72
+ create/update when no writable business field exists. Do not grant a resource
73
+ create/update/delete capability to make an action-owned record editable.
74
+
65
75
  Declare optional work Perspectives once at the application root. A Perspective
66
76
  references existing role codes; the compiler derives its readable capability
67
77
  projection, so never hand-author `capabilityCodes` or duplicate row filters:
@@ -99,6 +109,40 @@ generated UI and platform field policies.
99
109
 
100
110
  Field types are semantic, not PostgreSQL storage aliases. Use the catalog in the generated `AGENTS.md`: for example `text.short`, `number.integer`, `user.single`, `department.multiple`, `resource-ref.single`, `file`, `address` and `subtable`. The compiler alone chooses storage columns and constraints. Reference fields store JSON display values. For `resource-ref.*`, `resourceCode`, `value`, `label`, optional `description` and optional `snapshot` are convenient historical display data only: the target resource remains authoritative, the platform does not create a foreign key or refresh/check the stored JSON, and business actions that need current target state must query it by `resourceCode` plus `value`. A resource source `labelField` must point to `text.short` or `text.long`; a `serial-number` field can be listed in `searchFields`, `descriptionFields` or `snapshotFields`, but it is not a display label. File limits exist only under `file`; `maxCount` owns the single/multiple bound and `maxSizeMb` owns the per-file size bound. There is no `file.multiple` key.
101
111
 
112
+ Numeric bounds belong on the field declaration and are enforced by the
113
+ platform for every write path. They are inclusive, and only valid on
114
+ `number.integer` or `number.decimal`:
115
+
116
+ ```ts
117
+ { code: 'capacity', type: 'number.integer', label: '容量', required: true, min: 0, max: 10000 }
118
+ ```
119
+
120
+ Cross-field rules belong on the resource, not in a generated form callback.
121
+ Only bounded same-record field comparisons are supported; declare multiple
122
+ invariants when all must hold:
123
+
124
+ ```ts
125
+ {
126
+ code: 'sessions',
127
+ name: '场次',
128
+ fields: [
129
+ { code: 'startAt', type: 'datetime', label: '开始时间', required: true },
130
+ { code: 'endAt', type: 'datetime', label: '结束时间', required: true },
131
+ { code: 'capacity', type: 'number.integer', label: '容量', required: true, min: 0 },
132
+ { code: 'occupied', type: 'number.integer', label: '已占用', required: true, min: 0 },
133
+ ],
134
+ invariants: [
135
+ { code: 'time-order', expression: { leftField: 'startAt', operator: 'lt', rightField: 'endAt' } },
136
+ { code: 'capacity-not-exceeded', expression: { leftField: 'capacity', operator: 'gte', rightField: 'occupied' } },
137
+ ],
138
+ }
139
+ ```
140
+
141
+ `datetime-range` is always a non-empty half-open interval `[start, end)`.
142
+ Adjacent values such as `[10:00, 11:00)` and `[11:00, 12:00)` do not overlap.
143
+ Use the ordinary `overlaps` query operator or a `query-empty` transaction guard;
144
+ never add or subtract milliseconds at the boundary.
145
+
102
146
  Do not author raw schema or storage words as field types. `string`, `text`,
103
147
  `integer`, `decimal`, `boolean`, `date`, `datetime`, `uuid`, `json` and `file`
104
148
  describe value or storage families only when the platform protocol says so;
@@ -28,17 +28,33 @@ union. Never fetch identity for the header, display role codes, add a second
28
28
  identity selector, or copy Shell and
29
29
  directory-client implementations into application source.
30
30
 
31
+ The application owns the editable admin information architecture through the
32
+ typed `defineAdminNavigation`, `adminNavigationGroup`, `adminResourcePage`,
33
+ `adminOperationPage`, `adminWorkflowWorkCenterPage` and
34
+ `adminWorkflowLaunchPage` helpers in `openxiangda/config`. The compiler emits
35
+ all reachable `adminPages`, but the Shell renders only pages explicitly
36
+ referenced by generated `adminNavigation`, then applies current-user access as
37
+ a final filter. Page existence, route reachability and menu visibility are
38
+ separate: detail/new/edit/dynamic/handoff pages never become menu entries by
39
+ discovery, and permission logic cannot create entries. Read
40
+ `openxiangda://workspace/contracts` or call `contract_describe`, then copy
41
+ `data.adminNavigationAuthoring.suggestion.expression` once into
42
+ `frontend.admin.navigation` with the listed `openxiangda/config` imports. The
43
+ proposal is deterministic and editable; the compiler/runtime never invokes it
44
+ or appends newly added resources later.
45
+
31
46
  For a custom admin operation page, declare the route in
32
47
  `openxiangda.config.ts`, import the generated `appRoutes`, and bind every route
33
48
  key to exactly one local React page with `defineAdminContributions` from
34
49
  `openxiangda/react`. Pass the result to `OpenXiangdaApplication`. Do not wrap the
35
50
  page in another `Shell`: the runtime registers it in the unified router and the
36
51
  same Shell owns its menu entry, title, history and direct-URL capability gate.
37
- Only `navigation: 'menu'` routes enter the menu; hidden routes retain the same
38
- `capability` or `access.allOf/anyOf`, including ancestor constraints. Never add
39
- an application-owned layout, router, menu, identity provider or permission
40
- store. Keep operation pages under `/admin/operations`; parameterized routes are
41
- hidden so they cannot become unresolved menu links.
52
+ Only static admin routes explicitly referenced by `frontend.admin.navigation`
53
+ enter the menu. Hidden routes retain the same `capability` or
54
+ `access.allOf/anyOf`, including ancestor constraints. Never add an
55
+ application-owned layout, router, identity provider, permission store or a
56
+ second menu store. Keep operation pages under `/admin/operations`;
57
+ parameterized routes remain reachable but cannot be menu references.
42
58
 
43
59
  For a small business action on a generated resource page, use the typed
44
60
  `resources[resourceCode].toolbar`, `.row` or `.detail` slots accepted by
@@ -19,6 +19,20 @@ Use these optional modules only when the application has a real standard approva
19
19
 
20
20
  Declare workflow topology and bindings once in `openxiangda.config.ts`. Use only approval, condition and end nodes for the standard module. Keep business data in Data API/App API and pass an immutable `dataRef`, business revision and bounded facts into prepare/start.
21
21
 
22
+ Every definition declares a launch mode: `standalone` for a self-contained
23
+ generated save-and-start page, `custom-page` for an application operation page,
24
+ `hidden-handoff` for a non-menu handoff route, or `work-center-only` when users
25
+ only act on existing tasks. Only `standalone` may be referenced by
26
+ `adminWorkflowLaunchPage`; the generated browser runtime uses the workflow's
27
+ localized definition title, so applications do not maintain code-to-title
28
+ maps. A standalone page receives all durable business context through its
29
+ typed save handler and URL/search contract; it must never depend on transient
30
+ router location state. Work center, task and instance pages remain reachable
31
+ without becoming launch menu entries. Bind the generated metadata with
32
+ `defineWorkflowLaunchContributions(workflowDefinitions, handlers)`; handlers
33
+ only persist the durable business revision, while generated code keeps title
34
+ and launch mode authoritative.
35
+
22
36
  Use an assignee Provider only when resolution depends on application data. The Provider returns stable Native user/role subjects and never makes the final task authorization decision.
23
37
 
24
38
  The standard operations are approve, reject, return, resubmit, transfer, delegate, add-sign, withdraw, admin reassign, admin terminate and reminder. Render only operations returned by the task/instance Surface. A template or application action cannot add a Workflow command that is absent from the Surface.
@@ -3,8 +3,8 @@
3
3
  - Use only the workspace-pinned CLI: `pnpm openxiangda <command>`. Never invoke a bare global `openxiangda` inside a 2.0 task.
4
4
  - `appspec/` is the optional OpenXiangda 2.0 business-intent layer. Before changing observable behavior, read the bounded index with `pnpm openxiangda spec context --json`, then select only the relevant stable ID; use no ChangeSpec for L0 work, one short ChangeSpec for L1, and add permission/rollback/concurrency detail only for L2/L3. Before close, the user—not AI—confirms `currentSpec=merged` or `not-applicable`. AppSpec is advisory and never a release gate. Never read, import or migrate 1.x `openspec/` or SDD.
5
5
  - Use Vite, React Router, Refine Core and Ant Design. Do not add Umi, ProComponents or another admin shell.
6
- - Keep generated admin routes and custom actions inside the platform Shell. Bind generated `appRoutes` to local operation pages with `defineAdminContributions`, and use only its typed `toolbar`, `row` and `detail` resource slots. Do not create another router, menu, layout, identity provider, permission store or copied CRUD page; route/action access uses capability or `allOf`/`anyOf`, while Data/App API authorization remains server-owned.
7
- - Declare each resource once in `openxiangda.config.ts` with only `code`, `name`, `fields` and optional list/layout/data-policy settings. Each field owns type, label, required state, Surface flags, reference/file metadata and access. Resource codes are lower kebab-case.
6
+ - Keep generated admin routes and custom actions inside the platform Shell. Bind generated `appRoutes` to local operation pages with `defineAdminContributions`, and use only its typed `toolbar`, `row` and `detail` resource slots. Declare the complete editable menu with `defineAdminNavigation` and its page/group helpers; the Shell renders only generated `adminNavigation` references and permissions only filter them. Do not create another router, menu store, layout, identity provider, permission store or copied CRUD page; route/action access uses capability or `allOf`/`anyOf`, while Data/App API authorization remains server-owned.
7
+ - Declare each resource once in `openxiangda.config.ts` with only `code`, `name`, `fields` and optional `mutationOwner`, generated/list/layout/data-policy settings. Each field owns type, label, required state, Surface flags, reference/file metadata and access. Resource codes are lower kebab-case. Use `native` for direct Data API mutations, `action`, `readonly` or `workflow` for non-Native ownership; never grant or generate Native mutation for a non-Native owner.
8
8
  - Never write resource-level `schemaVersion`, `appCode`, `schema`, `surface`, `capabilities`, `fieldPolicies` or `platform/data` modules. The compiler derives the strict DataResource, CRUD capabilities, Surface and AI Schema. The application manifest still starts with its one top-level `schemaVersion: 3`.
9
9
  - Ordinary list/get/create/update/delete, filters, export and batch operations use the platform Native Data API. Do not create Function CRUD or NestJS wrappers.
10
10
  - Add NestJS only for a named business action that needs a cross-resource transaction, an invariant or an external side effect.
@@ -20,6 +20,6 @@
20
20
  - `option.*`, `user.*`, `department.*` and `resource-ref.*` values never collapse to scalar IDs. Single values store one labeled object and multiple values store object arrays. `resource-ref.*` JSON is not a foreign key, trusted target snapshot or automatically refreshed copy; current target state is read by `resourceCode` plus `value`. A resource source `labelField` must be `text.short` or `text.long`; `serial-number` is allowed in source search, description and snapshot fields, but not as the label. `location` accepts only exact WGS84 coordinates captured by DingTalk or browser geolocation; it has no manual input or `manual` source. Roles that consume directory-backed fields explicitly include `app:<app-code>:directory:read`.
21
21
  - Derive role grants with `resourceCapabilityCodes(appCode, resourceCode)`. Declare current-user rows only with `currentUserDataPolicy(...)`; do not invent operators, values or alternate current-user spellings.
22
22
  - Do not add compatibility aliases, migration branches or silent fallbacks for an earlier 2.0 alpha contract. Replace an incorrect contract and regenerate the application.
23
- - Standard Workflow and Notification Hub are optional 2.0 modules. Enable them only through the canonical `openxiangda.config.ts` declarations and generated clients; never copy 1.x workflow/message code, tables, APIs, templates or callbacks into this workspace. Keep ordinary CRUD and application-specific state machines independent of them.
23
+ - Standard Workflow and Notification Hub are optional 2.0 modules. Enable them only through the canonical `openxiangda.config.ts` declarations and generated clients; declare each Workflow launch as `standalone`, `custom-page`, `hidden-handoff` or `work-center-only`, put only self-contained standalone launch pages in navigation, and bind durable save handlers with `defineWorkflowLaunchContributions` without repeating generated titles. Never depend on temporary router location state or copy 1.x workflow/message code, tables, APIs, templates or callbacks into this workspace. Keep ordinary CRUD and application-specific state machines independent of them.
24
24
  - Run `pnpm openxiangda check --json` after contract changes and read `data.sealedArtifact`; check never seals, and an older `.openxiangda/build/app-package.json` is not the current check result. Use `pnpm openxiangda accept --plan <file>` only for optional real preproduction identity acceptance; it never blocks delivery. Deploy with `pnpm openxiangda deploy`, inspect with `pnpm openxiangda status` and `pnpm openxiangda logs`, and use the platform rollback command rather than mutating K3s directly.
25
- - AI-native clients start the workspace protocol through the same pinned binary: `pnpm exec openxiangda --mcp-stdio --cwd <workspace>`. Read `openxiangda://workspace/contracts` or call `contract_describe`; when AppSpec is enabled, also read `openxiangda://workspace/appspec` or call `appspec_context`. Require `aiCatalog` and `aiCatalogDigest` to match the normal compiler output. This is a stdio transport mode, not another application-owned server. Never write an application MCP server, Catalog file, preview store or second authorization path.
25
+ - AI-native clients start the workspace protocol through the same pinned binary: `pnpm exec openxiangda --mcp-stdio --cwd <workspace>`. Read `openxiangda://workspace/contracts` or call `contract_describe`; for first-time menu authoring, copy `data.adminNavigationAuthoring.suggestion.expression` once into `frontend.admin.navigation` with its listed `openxiangda/config` imports, then edit that application-owned declaration. Never treat the proposal as runtime discovery. When AppSpec is enabled, also read `openxiangda://workspace/appspec` or call `appspec_context`. Require `aiCatalog` and `aiCatalogDigest` to match the normal compiler output. This is a stdio transport mode, not another application-owned server. Never write an application MCP server, Catalog file, preview store or second authorization path.