cabloy 5.1.190 → 5.1.192

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/.cabloy-version +1 -1
  2. package/.github/workflows/agent-governance.yml +39 -0
  3. package/.github/workflows/docs-pages.yml +1 -0
  4. package/.gitignore +3 -0
  5. package/CHANGELOG.md +17 -0
  6. package/README.md +2 -2
  7. package/package.json +11 -5
  8. package/repo-agent-governance/adapters/claude/contract-loop-gate.ts +199 -0
  9. package/{.claude → repo-agent-governance}/commands/release.md +20 -20
  10. package/repo-agent-governance/managed-assets.json +887 -0
  11. package/repo-agent-governance/manifest.json +56 -0
  12. package/{CLAUDE.md → repo-agent-governance/policies/repository.md} +4 -2
  13. package/repo-agent-governance/scripts/governance.mjs +570 -0
  14. package/repo-agent-governance/scripts/pack-check.mjs +43 -0
  15. package/{.claude → repo-agent-governance}/skills/cabloy-contract-loop/references/contract-loop-map.md +4 -4
  16. package/{.claude → repo-agent-governance}/skills/cabloy-master-detail/SKILL.md +1 -1
  17. package/{.claude → repo-agent-governance}/skills/cabloy-module-removal/SKILL.md +1 -1
  18. package/{.claude → repo-agent-governance}/skills/cabloy-spec-execution/SKILL.md +1 -1
  19. package/{.claude → repo-agent-governance}/skills/cabloy-spec-execution/references/execution-protocol.md +8 -8
  20. package/{.claude → repo-agent-governance}/skills/cabloy-spec-execution/references/status-and-evidence.md +9 -9
  21. package/{.claude → repo-agent-governance}/skills/cabloy-spec-generation/SKILL.md +2 -2
  22. package/{.claude → repo-agent-governance}/skills/cabloy-spec-generation/references/repo-aware-discovery.md +7 -7
  23. package/{.claude → repo-agent-governance}/skills/cabloy-spec-generation/references/repo-specs-document-set.md +30 -30
  24. package/{.claude → repo-agent-governance}/skills/cabloy-spec-generation/references/traceability-and-status-rules.md +9 -9
  25. package/{.claude → repo-agent-governance}/skills/cabloy-workflow/SKILL.md +7 -8
  26. package/{.claude → repo-agent-governance}/skills/cabloy-worktree-environment/SKILL.md +9 -9
  27. package/{.claude → repo-agent-governance}/skills/cabloy-zova-source-reading/SKILL.md +5 -5
  28. package/repo-agent-governance/tests/governance.test.mjs +295 -0
  29. package/repo-agent-governance/tools/contract-loop/check.mjs +71 -0
  30. package/repo-agent-governance/tools/contract-loop/core.mjs +189 -0
  31. package/repo-agent-governance/tools/spec-charts/generate-implementation-charts.mjs +858 -0
  32. package/{.claude/skills/cabloy-spec-generation/scripts → repo-agent-governance/tools/spec-charts}/generate-implementation-charts.test.mjs +95 -20
  33. package/repo-docs/.vitepress/config.mjs +2 -0
  34. package/repo-docs/ai/agent-governance.md +80 -0
  35. package/repo-docs/ai/cli-to-skill-map.md +3 -3
  36. package/repo-docs/ai/docs-skills-rules-mapping.md +27 -26
  37. package/repo-docs/ai/edition-consistency-checklist.md +8 -6
  38. package/repo-docs/ai/future-skill-roadmap.md +2 -2
  39. package/repo-docs/ai/introduction.md +7 -6
  40. package/repo-docs/ai/repo-guidance.md +3 -2
  41. package/repo-docs/ai/rules-and-config.md +23 -15
  42. package/repo-docs/ai/skills.md +7 -7
  43. package/repo-docs/ai/verification.md +2 -1
  44. package/repo-docs/demo.md +12 -0
  45. package/repo-docs/fullstack/contract-loop-playbook.md +1 -1
  46. package/repo-docs/fullstack/quickstart.md +1 -1
  47. package/repo-docs/index.md +3 -0
  48. package/repo-docs/reference/package-map.md +3 -2
  49. package/repo-docs/reference/repo-scripts.md +17 -2
  50. package/scripts/bootstrapAgentGovernance.mjs +81 -0
  51. package/scripts/init.ts +1 -0
  52. package/scripts/release.ts +15 -0
  53. package/scripts/upgrade.ts +66 -7
  54. package/zova/packages-zova/zova/package.json +2 -2
  55. package/zova/pnpm-lock.yaml +3 -3
  56. package/zova/src/suite/a-home/modules/home-passport/src/model/passport.ts +2 -7
  57. package/zova/src/suite/cabloy-basic/modules/basic-details/src/bean/tableCell.actionOperationsRow.tsx +19 -13
  58. package/zova/src/suite/cabloy-basic/modules/basic-details/src/component/blockDetails/controller.tsx +11 -0
  59. package/zova/src/suite/cabloy-basic/modules/basic-details/src/component/blockToolbarBulk/controller.tsx +7 -4
  60. package/zova/src/suite/cabloy-basic/modules/basic-details/src/component/formFieldDetails/controller.tsx +14 -0
  61. package/zova/src/suite/cabloy-basic/modules/basic-details/src/lib/detailsPermissions.ts +65 -0
  62. package/zova/src/suite/cabloy-basic/modules/basic-details/src/lib/index.ts +1 -0
  63. package/zova/src/suite/cabloy-basic/modules/basic-details/src/lib/utils.ts +3 -3
  64. package/zova/src/suite/cabloy-basic/modules/basic-details/src/types/details.ts +6 -1
  65. package/zova/src/suite/cabloy-basic/modules/basic-details/test/lib/detailsPermissions.test.ts +125 -0
  66. package/zova/src/suite-vendor/a-zova/modules/a-openapi/package.json +1 -1
  67. package/zova/src/suite-vendor/a-zova/modules/a-openapi/src/types/permissions.ts +2 -8
  68. package/zova/src/suite-vendor/a-zova/modules/a-table/package.json +1 -1
  69. package/zova/src/suite-vendor/a-zova/modules/a-table/src/component/table/controller.tsx +2 -1
  70. package/zova/src/suite-vendor/a-zova/package.json +3 -3
  71. package/.claude/hooks/contract-loop-gate.ts +0 -421
  72. package/.claude/scheduled_tasks.lock +0 -1
  73. package/.claude/skills/cabloy-spec-generation/scripts/generate-implementation-charts.mjs +0 -385
  74. /package/{.claude → repo-agent-governance/adapters/claude}/settings.json +0 -0
  75. /package/{.claude → repo-agent-governance}/skills/cabloy-backend-scaffold/SKILL.md +0 -0
  76. /package/{.claude → repo-agent-governance}/skills/cabloy-backend-scaffold/evals/evals.json +0 -0
  77. /package/{.claude → repo-agent-governance}/skills/cabloy-backend-scaffold/references/backend-thread-map.md +0 -0
  78. /package/{.claude → repo-agent-governance}/skills/cabloy-backend-scaffold/references/follow-up-checklist.md +0 -0
  79. /package/{.claude → repo-agent-governance}/skills/cabloy-contract-loop/SKILL.md +0 -0
  80. /package/{.claude → repo-agent-governance}/skills/cabloy-contract-loop/evals/evals.json +0 -0
  81. /package/{.claude → repo-agent-governance}/skills/cabloy-contract-loop/references/resource-custom-state-pattern.md +0 -0
  82. /package/{.claude → repo-agent-governance}/skills/cabloy-contract-loop/references/verification-checklist.md +0 -0
  83. /package/{.claude → repo-agent-governance}/skills/cabloy-domain-planning/SKILL.md +0 -0
  84. /package/{.claude → repo-agent-governance}/skills/cabloy-frontend-scaffold/SKILL.md +0 -0
  85. /package/{.claude → repo-agent-governance}/skills/cabloy-frontend-scaffold/evals/evals.json +0 -0
  86. /package/{.claude → repo-agent-governance}/skills/cabloy-frontend-scaffold/references/follow-up-checklist.md +0 -0
  87. /package/{.claude → repo-agent-governance}/skills/cabloy-frontend-scaffold/references/frontend-thread-map.md +0 -0
  88. /package/{.claude → repo-agent-governance}/skills/cabloy-resource-field-update/SKILL.md +0 -0
  89. /package/{.claude → repo-agent-governance}/skills/cabloy-resource-field-update/evals/evals.json +0 -0
  90. /package/{.claude → repo-agent-governance}/skills/cabloy-resource-field-update/references/custom-renderer-demo-checklist.md +0 -0
  91. /package/{.claude → repo-agent-governance}/skills/cabloy-resource-field-update/references/field-update-decision-tree.md +0 -0
  92. /package/{.claude → repo-agent-governance}/skills/cabloy-resource-field-update/references/follow-up-checklist.md +0 -0
  93. /package/{.claude → repo-agent-governance}/skills/cabloy-resource-field-update/references/verification-checklist.md +0 -0
  94. /package/{.claude → repo-agent-governance}/skills/cabloy-spec-execution/evals/evals.json +0 -0
  95. /package/{.claude → repo-agent-governance}/skills/cabloy-spec-generation/evals/evals.json +0 -0
  96. /package/{.claude → repo-agent-governance}/skills/cabloy-workflow/evals/evals.json +0 -0
  97. /package/{.claude → repo-agent-governance}/skills/cabloy-workflow/references/cli-strategy.md +0 -0
  98. /package/{.claude → repo-agent-governance}/skills/cabloy-workflow/references/edition-detection.md +0 -0
  99. /package/{.claude → repo-agent-governance}/skills/cabloy-worktree-environment/evals/evals.json +0 -0
  100. /package/{.claude → repo-agent-governance}/skills/cabloy-zova-source-reading/references/analysis-modes.md +0 -0
  101. /package/{.claude → repo-agent-governance}/skills/cabloy-zova-source-reading/references/core-reading-paths.md +0 -0
@@ -2,15 +2,15 @@
2
2
 
3
3
  Skills are the procedural layer of Cabloy’s AI development model.
4
4
 
5
- ## Using a Skill in Claude Code
5
+ ## Using a Skill
6
6
 
7
- Invoke a Cabloy Skill by typing its slash name followed by the task input. For example, describe the business capability you want to plan:
7
+ Root Cabloy skill bundles are authored in `repo-agent-governance/skills/` and rendered to configured Claude Code, Codex, and Cursor adapter locations. Codex and Cursor skill discovery must be confirmed by a version-pinned external smoke check before being presented as supported client behavior. Use the invocation UI and syntax of the active agent; for example, in Claude Code:
8
8
 
9
9
  ```text
10
10
  /cabloy-spec-generation <business description>
11
11
  ```
12
12
 
13
- The AI guides you through the task-specific confirmation and next steps. See [Generate a Cabloy Suite Specification](/ai/playbook-spec-generation) for the complete planning experience.
13
+ The AI guides you through the task-specific confirmation and next steps. See [Generate a Cabloy Suite Specification](/ai/playbook-spec-generation) for the complete planning experience. See [Agent Governance](/ai/agent-governance) for adapter and capability details.
14
14
 
15
15
  ## What a skill should do here
16
16
 
@@ -29,8 +29,8 @@ If a generator or refactor command exists, the skill should orchestrate it inste
29
29
 
30
30
  ## Skill placement
31
31
 
32
- - Use root `.claude/skills/` for cross-stack, monorepo-wide workflows.
33
- - Use subtree-local `.claude/skills/` only when a workflow is truly specific to one framework area.
32
+ - Author cross-stack, monorepo-wide workflow bundles in `repo-agent-governance/skills/`; generated root adapter copies are not a second authoring surface.
33
+ - Use subtree-local agent skill directories only when a workflow is truly specific to one framework area and has not been approved for portable root governance.
34
34
 
35
35
  ## Skill structure recommendation
36
36
 
@@ -48,7 +48,7 @@ For edition-aware skills, use [Cabloy Editions: For AI Development](/editions/ov
48
48
 
49
49
  ## Current root workflow skills
50
50
 
51
- The repository currently provides these cross-stack and monorepo-wide workflows in root `.claude/skills/`:
51
+ The repository currently authors these cross-stack and monorepo-wide workflows in `repo-agent-governance/skills/` and renders them to root platform adapters; Codex and Cursor discovery remains subject to external client validation:
52
52
 
53
53
  - `cabloy-workflow` for choosing the correct Cabloy work path before implementation
54
54
  - `cabloy-domain-planning` for proposing and confirming providerId, suite, and initial module names before scaffolding a new business domain
@@ -65,7 +65,7 @@ The repository currently provides these cross-stack and monorepo-wide workflows
65
65
 
66
66
  The specification workflows show the same boundary: [AI Spec-Driven Development](/ai/ai-spec-driven-development) explains the public Traceable Spec Delivery method, while [Generate a Cabloy Suite Specification](/ai/playbook-spec-generation) and [Execute an Approved Cabloy Specification Increment](/ai/playbook-spec-execution) explain its operational paths. The skills retain branching, confirmation gates, specialist routing, and evidence protocol; suite-local records remain the authority for a specific increment.
67
67
 
68
- The module-removal workflow is a good example of why skills belong in `.claude/skills/` instead of `CLAUDE.md`: the task needs branching, cleanup order, recovery guidance for generated runtime directories such as `vona/.vona` and `zova/.zova`, and a verification checklist that would be too large for a short repo-wide rule.
68
+ The module-removal workflow is a good example of why skills belong in `repo-agent-governance/skills/` instead of the concise repository policy: the task needs branching, cleanup order, recovery guidance for generated runtime directories such as `vona/.vona` and `zova/.zova`, and a verification checklist that would be too large for a short repo-wide rule. The canonical bundle is rendered to each supported platform skill adapter.
69
69
 
70
70
  ## Advanced subtree-local diagnostics
71
71
 
@@ -17,7 +17,8 @@ For skills and repo guidance:
17
17
 
18
18
  - confirm the workflow still points to real command entrypoints
19
19
  - confirm edition branches match the active repo markers and scripts
20
- - confirm public docs, skills, and root `CLAUDE.md` tell the same story
20
+ - confirm public docs, canonical `repo-agent-governance/` assets, and generated platform adapters tell the same story
21
+ - run the deterministic governance checker after changing shared rules, skills, tools, or adapter metadata
21
22
  - review edition-aware changes against [Edition Consistency Checklist](/ai/edition-consistency-checklist)
22
23
 
23
24
  ## Code-generation verification
@@ -0,0 +1,12 @@
1
+ ---
2
+ title: Demo
3
+ ---
4
+
5
+ # Demo
6
+
7
+ Explore the Cabloy demonstration sites:
8
+
9
+ | Site | URL |
10
+ | ---------- | ---------------------------------------------------------------- |
11
+ | Web site | [https://demo.cabloy.com/](https://demo.cabloy.com/) |
12
+ | Admin site | [https://demo.cabloy.com/admin/](https://demo.cabloy.com/admin/) |
@@ -235,7 +235,7 @@ That means:
235
235
 
236
236
  For resource-bound custom endpoints, prefer `rest-resource.model.resource` as the state owner. A module-local model may still exist, but it should remain a semantic facade instead of becoming a second cache owner. When Admin Resource consumption and Web self-service consumption have genuinely different API, scope, projection, or SSR semantics, see [Admin Resource and Web Self-Service](/fullstack/admin-resource-and-web-self-service) for the boundary between Admin owner reuse and a dedicated Web model.
237
237
 
238
- See the downstream pattern in `.claude/skills/cabloy-contract-loop/references/resource-custom-state-pattern.md`.
238
+ See the canonical downstream pattern in `repo-agent-governance/skills/cabloy-contract-loop/references/resource-custom-state-pattern.md`.
239
239
 
240
240
  ### Stage 5: Consumer verification
241
241
 
@@ -24,7 +24,7 @@ Before creating a new Cabloy project, make sure your environment has:
24
24
  npm create cabloy
25
25
  ```
26
26
 
27
- The generated project already includes `CLAUDE.md` and the `.claude/` workspace assets. This path creates a Cabloy Basic project baseline. Open this project in Claude Code and start coding immediately with project-specific guidance.
27
+ The generated project includes `repo-agent-governance/` plus committed adapters for Claude Code, Codex, and Cursor. This path creates a Cabloy Basic project baseline. Open it in a supported coding agent and start with the project-specific guidance; regenerate adapters from the canonical governance source rather than editing generated files directly.
28
28
 
29
29
  `npm create cabloy` automatically runs `npm run init` after creating the project. If you later need to reinstall the project's frontend and backend dependencies, you can run `npm run init` directly.
30
30
 
@@ -9,6 +9,9 @@ hero:
9
9
  - theme: brand
10
10
  text: Get Started
11
11
  link: /fullstack/quickstart
12
+ - theme: alt
13
+ text: Demo
14
+ link: /demo
12
15
  - theme: alt
13
16
  text: Editions
14
17
  link: /editions/overview
@@ -7,11 +7,12 @@ This monorepo is organized around a small set of stable top-level areas.
7
7
  - `package.json` — shared scripts and release entrypoints
8
8
  - `lerna.json` — package topology
9
9
  - `repo-docs-internal/` — edition-local maintainer notes and ADRs
10
- - `.claude/` — Claude commands, skills, and local settings
10
+ - `repo-agent-governance/` — authored portable agent rules, root skill bundles, adapter definitions, and deterministic tools
11
+ - `CLAUDE.md`, `AGENTS.md`, `.claude/`, `.agents/`, `.cursor/` — generated platform adapters plus platform-specific runtime integration
11
12
  - `repo-docs/` — unified public docs
12
13
  - `repo-specs/` — suite-local product, technical, delivery, ATP, progress, observed-evidence, and ADR authority
13
14
 
14
- `repo-specs/` is distinct from `repo-docs/`, which explains reusable public guidance, `.claude/`, which contains executable workflow behavior, and `repo-docs-internal/`, which preserves supporting maintainer rationale. For the public planning workflow, see [Generate a Cabloy Suite Specification](/ai/playbook-spec-generation).
15
+ `repo-specs/` is distinct from `repo-docs/`, which explains reusable public guidance, `repo-agent-governance/`, which owns portable executable workflow behavior and adapter generation, and `repo-docs-internal/`, which preserves supporting maintainer rationale. For the public planning workflow, see [Generate a Cabloy Suite Specification](/ai/playbook-spec-generation).
15
16
 
16
17
  ## Backend side
17
18
 
@@ -60,7 +60,7 @@ npm run spec:charts -- <suite>
60
60
  npm run spec:charts:check -- <suite>
61
61
  ```
62
62
 
63
- `spec:charts` refreshes the generated Gantt and burndown SVG views for a chart-compatible `repo-specs/<suite>/` record. `spec:charts:check` validates the supported input contract and detects stale generated views; `test:spec-charts` runs the chart-tool test suite.
63
+ `spec:charts` refreshes the generated Gantt and burndown SVG views for a chart-compatible `repo-specs/<suite>/` record. `spec:charts:check` validates the supported input contract and detects stale generated views; `test:spec-charts` runs the chart-tool test suite. The deterministic implementation lives in `repo-agent-governance/tools/spec-charts/`, not inside a provider-specific skill discovery directory.
64
64
 
65
65
  ### Chart input contract
66
66
 
@@ -75,6 +75,21 @@ A legacy suite with a different WBS or progress-table layout is not chart-compat
75
75
 
76
76
  These commands do not create planning authority, implement a WBS task, execute an ATP, produce acceptance evidence, or replace traceability/status review. Confirm the active root `package.json` and script input expectations before assuming equivalent behavior in Cabloy Start or another repository.
77
77
 
78
+ ## Agent-governance maintenance
79
+
80
+ Use these Cabloy Basic maintenance commands when changing shared agent rules, root skill bundles, or adapter tooling:
81
+
82
+ ```bash
83
+ npm run agent:governance:render
84
+ npm run agent:governance:check
85
+ npm run agent:governance:adopt
86
+ npm run agent:governance:pack-check
87
+ npm run test:agent-governance
88
+ npm run contract:gate -- --file <source-path> --format json
89
+ ```
90
+
91
+ The renderer updates committed Claude Code, Codex, and Cursor adapters from `repo-agent-governance/`. The checker is read-only. Adoption preserves locally modified or unowned adapter files as conflicts rather than overwriting them. The contract gate is advisory and does not run builds automatically; use the active edition's verified contract-loop workflow for completion evidence.
92
+
78
93
  ## Cabloy Start entrypoints
79
94
 
80
95
  Cabloy Start exposes the equivalent Start repository surface:
@@ -104,7 +119,7 @@ Cabloy Start does not expose Basic Commerce or root documentation wrappers.
104
119
 
105
120
  ## Upgrade
106
121
 
107
- Run `npm run upgrade:dry-run` before `npm run upgrade` to inspect framework files and root manifest entries that an upgrade would synchronize.
122
+ Run `npm run upgrade:dry-run` before `npm run upgrade` to inspect framework files and root manifest entries that an upgrade would synchronize. The upgrader replaces the framework-owned `repo-agent-governance/` source, reconciles only its named package scripts, and uses ownership-aware adapter adoption. It preserves locally modified or legacy adapter outputs as conflicts for explicit review instead of blindly overwriting root Claude, Codex, or Cursor files.
108
123
 
109
124
  ### Cabloy Basic public projects
110
125
 
@@ -0,0 +1,81 @@
1
+ import { execFileSync } from 'node:child_process';
2
+ import { cpSync, existsSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
3
+ import { dirname, resolve } from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+
6
+ const ROOT_DIR = resolve(dirname(fileURLToPath(import.meta.url)), '..');
7
+ const UPGRADE_SOURCE_DIR = resolve(ROOT_DIR, 'node_modules/.cabloy-upgrade');
8
+ const GOVERNANCE_SCRIPT_NAMES = [
9
+ 'test:spec-charts',
10
+ 'spec:charts',
11
+ 'spec:charts:check',
12
+ 'agent:governance:render',
13
+ 'agent:governance:check',
14
+ 'agent:governance:adopt',
15
+ 'agent:governance:pack-check',
16
+ 'test:agent-governance',
17
+ 'contract:gate',
18
+ ];
19
+
20
+ function reconcileGovernancePackageJson(sourceRoot) {
21
+ const sourcePackagePath = resolve(sourceRoot, 'package.json');
22
+ if (!existsSync(sourcePackagePath)) return;
23
+ const projectPackagePath = resolve(ROOT_DIR, 'package.json');
24
+ const sourcePackage = JSON.parse(readFileSync(sourcePackagePath, 'utf-8'));
25
+ const projectPackage = JSON.parse(readFileSync(projectPackagePath, 'utf-8'));
26
+ let changed = false;
27
+ for (const name of GOVERNANCE_SCRIPT_NAMES) {
28
+ const command = sourcePackage.scripts?.[name];
29
+ if (!command) {
30
+ throw new Error(`Expected governance script in ${sourcePackagePath}: ${name}`);
31
+ }
32
+ if (projectPackage.scripts?.[name] === command) continue;
33
+ projectPackage.scripts ??= {};
34
+ projectPackage.scripts[name] = command;
35
+ changed = true;
36
+ }
37
+ if (changed) {
38
+ writeFileSync(projectPackagePath, `${JSON.stringify(projectPackage, null, 2)}\n`);
39
+ // eslint-disable-next-line no-console
40
+ console.log('[init] Reconciled agent-governance package scripts');
41
+ }
42
+ }
43
+
44
+ function adoptAgentGovernance() {
45
+ const executable = resolve(ROOT_DIR, 'repo-agent-governance/scripts/governance.mjs');
46
+ if (!existsSync(executable)) return;
47
+ try {
48
+ execFileSync(process.execPath, [executable, 'adopt', '--apply'], {
49
+ cwd: ROOT_DIR,
50
+ env: {
51
+ ...process.env,
52
+ CABLOY_GOVERNANCE_ROOT: ROOT_DIR,
53
+ },
54
+ stdio: 'inherit',
55
+ });
56
+ } catch (error) {
57
+ if (error.status !== 2) throw error;
58
+ // eslint-disable-next-line no-console
59
+ console.log(
60
+ '[init] Agent-governance adoption preserved locally modified or legacy adapter outputs. Review the reported conflicts before explicitly forcing an individual managed target.',
61
+ );
62
+ }
63
+ }
64
+
65
+ export function bootstrapAgentGovernance() {
66
+ const sourceDir = resolve(UPGRADE_SOURCE_DIR, 'repo-agent-governance');
67
+ const targetDir = resolve(ROOT_DIR, 'repo-agent-governance');
68
+ if (existsSync(sourceDir)) {
69
+ // A pre-governance upgrader has already loaded its own upgrade.ts before it overwrites
70
+ // scripts/. Replace the canonical source here, before the current initializer adopts
71
+ // individual adapter outputs.
72
+ rmSync(targetDir, { recursive: true, force: true });
73
+ cpSync(sourceDir, targetDir, { recursive: true });
74
+ reconcileGovernancePackageJson(UPGRADE_SOURCE_DIR);
75
+ }
76
+ // The npm package deliberately excludes generated adapter outputs for the migration
77
+ // release. This also covers a fresh project, where no staged upgrade source exists.
78
+ adoptAgentGovernance();
79
+ }
80
+
81
+ bootstrapAgentGovernance();
package/scripts/init.ts CHANGED
@@ -297,6 +297,7 @@ function initRepoDocs(): void {
297
297
  // --- Main ---
298
298
 
299
299
  checkPnpm();
300
+ exec('node scripts/bootstrapAgentGovernance.mjs');
300
301
  pnpmInstall();
301
302
  setAppName();
302
303
  generateEnvProdLocal();
@@ -107,6 +107,19 @@ function readPackageJson(): Record<string, any> {
107
107
  return readJson(PACKAGE_JSON_PATH);
108
108
  }
109
109
 
110
+ function runGovernancePreflight(dryRun?: boolean): void {
111
+ const commands = [
112
+ 'npm run test:agent-governance',
113
+ 'npm run agent:governance:check',
114
+ 'npm run agent:governance:pack-check',
115
+ ];
116
+ // eslint-disable-next-line
117
+ console.log('\n🔎 Validating agent-governance assets...');
118
+ for (const command of commands) {
119
+ execInherited(command, dryRun);
120
+ }
121
+ }
122
+
110
123
  function assertPublicBasicReleaseSurface(): void {
111
124
  const edition = resolveEdition();
112
125
  if (edition !== 'basic') {
@@ -949,6 +962,8 @@ async function release(options: ReleaseOptions): Promise<void> {
949
962
  process.exit(1);
950
963
  }
951
964
 
965
+ runGovernancePreflight(options.dryRun);
966
+
952
967
  // Determine the version to use
953
968
  let version: string;
954
969
 
@@ -30,6 +30,7 @@ const OVERWRITE_DIRS: string[] = [
30
30
  '.husky',
31
31
  'repo-docs',
32
32
  'repo-observability',
33
+ 'repo-agent-governance',
33
34
  // vona
34
35
  'vona/packages-vona',
35
36
  'vona/packages-cli',
@@ -72,10 +73,6 @@ const FRAMEWORK_E2E_SCRIPT_NAMES_CABLOY_BASIC: string[] = ['test:e2e', 'test:e2e
72
73
  const FRAMEWORK_E2E_DEV_DEPENDENCY_CABLOY_BASIC = '@playwright/test';
73
74
 
74
75
  const MERGE_DIRS: string[] = [
75
- // Claude project assets
76
- '.claude/commands',
77
- '.claude/hooks',
78
- '.claude/skills',
79
76
  // Vona Claude project assets
80
77
  'vona/.claude/commands',
81
78
  'vona/.claude/skills',
@@ -91,8 +88,6 @@ const BLACKLIST_DIRS: string[] = [
91
88
 
92
89
  const WHITELIST_FILES: string[] = [
93
90
  // root
94
- 'CLAUDE.md',
95
- '.claude/settings.json',
96
91
  'tsconfig.json',
97
92
  'tsconfig.base.json',
98
93
  'tsconfig.base.esm.json',
@@ -280,6 +275,64 @@ function mergeFrameworkE2eAssets(dryRun?: boolean): void {
280
275
  }
281
276
  }
282
277
 
278
+ function reconcileGovernancePackageJson(dryRun?: boolean): void {
279
+ const projectPackagePath = resolve(ROOT_DIR, 'package.json');
280
+ const sourcePackagePath = resolve(TEMP_DIR, 'package.json');
281
+ const projectPackage = readPackageJson(projectPackagePath);
282
+ const sourcePackage = readPackageJson(sourcePackagePath);
283
+ const baselineScripts = ['test:spec-charts', 'spec:charts', 'spec:charts:check'];
284
+ const governanceScripts = [
285
+ 'agent:governance:render',
286
+ 'agent:governance:check',
287
+ 'agent:governance:adopt',
288
+ 'agent:governance:pack-check',
289
+ 'test:agent-governance',
290
+ 'contract:gate',
291
+ ];
292
+ const managedScripts = [...baselineScripts, ...governanceScripts];
293
+ let changed = false;
294
+ for (const name of managedScripts) {
295
+ const sourceValue = sourcePackage.scripts?.[name];
296
+ if (!sourceValue) {
297
+ if (
298
+ governanceScripts.includes(name) &&
299
+ !existsSync(resolve(TEMP_DIR, 'repo-agent-governance'))
300
+ ) {
301
+ continue;
302
+ }
303
+ throw new Error(`Expected agent-governance script in package.json: ${name}`);
304
+ }
305
+ if (projectPackage.scripts?.[name] === sourceValue) continue;
306
+ changed = true;
307
+ if (dryRun) {
308
+ log(` [dry-run] Set package.json scripts.${name}`);
309
+ } else {
310
+ projectPackage.scripts ??= {};
311
+ projectPackage.scripts[name] = sourceValue;
312
+ }
313
+ }
314
+ if (changed && !dryRun) {
315
+ writeFileSync(projectPackagePath, `${JSON.stringify(projectPackage, null, 2)}\n`);
316
+ }
317
+ }
318
+
319
+ function reconcileGovernanceAssets(dryRun?: boolean): void {
320
+ const command = 'node repo-agent-governance/scripts/governance.mjs adopt --apply';
321
+ if (dryRun) {
322
+ log(` [dry-run] Run non-destructive governance adoption: ${command}`);
323
+ return;
324
+ }
325
+ try {
326
+ execSync(command, { cwd: ROOT_DIR, stdio: 'inherit' });
327
+ } catch (error) {
328
+ const status = (error as { status?: number }).status;
329
+ if (status !== 2) throw error;
330
+ log(
331
+ ' Agent-governance adoption preserved locally modified or legacy adapter outputs. Review the reported conflicts before explicitly forcing an individual managed target.',
332
+ );
333
+ }
334
+ }
335
+
283
336
  function reconcileFrameworkE2ePackageJson(dryRun?: boolean): void {
284
337
  if (!isCabloyBasic()) return;
285
338
 
@@ -545,7 +598,13 @@ async function main(): Promise<void> {
545
598
  selectiveOverwrite(dryRun);
546
599
  log('');
547
600
 
548
- // 4. Reconcile Cabloy Basic framework E2E manifest entries
601
+ // 4. Reconcile agent-governance manifest entries and managed adapters
602
+ log('Reconciling agent-governance package entries and managed adapters...');
603
+ reconcileGovernancePackageJson(dryRun);
604
+ reconcileGovernanceAssets(dryRun);
605
+ log('');
606
+
607
+ // 5. Reconcile Cabloy Basic framework E2E manifest entries
549
608
  if (isCabloyBasic()) {
550
609
  log('Reconciling framework-owned E2E package entries...');
551
610
  reconcileFrameworkE2ePackageJson(dryRun);
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zova",
3
- "version": "5.1.166",
3
+ "version": "5.1.167",
4
4
  "gitHead": "2c5c19284bab738e492856189acb6fad74b8a7b7",
5
5
  "description": "A vue3 framework with ioc",
6
6
  "keywords": [
@@ -46,7 +46,7 @@
46
46
  },
47
47
  "dependencies": {
48
48
  "zova-core": "^5.1.92",
49
- "zova-suite-a-zova": "^5.1.165"
49
+ "zova-suite-a-zova": "^5.1.166"
50
50
  },
51
51
  "devDependencies": {
52
52
  "clean-package": "^2.2.0",
@@ -876,7 +876,7 @@ importers:
876
876
  specifier: ^5.1.92
877
877
  version: link:../zova-core
878
878
  zova-suite-a-zova:
879
- specifier: ^5.1.165
879
+ specifier: ^5.1.166
880
880
  version: link:../../src/suite-vendor/a-zova
881
881
  devDependencies:
882
882
  clean-package:
@@ -1109,7 +1109,7 @@ importers:
1109
1109
  specifier: ^5.1.37
1110
1110
  version: link:modules/a-model
1111
1111
  zova-module-a-openapi:
1112
- specifier: ^5.1.54
1112
+ specifier: ^5.1.55
1113
1113
  version: link:modules/a-openapi
1114
1114
  zova-module-a-router:
1115
1115
  specifier: ^5.1.41
@@ -1133,7 +1133,7 @@ importers:
1133
1133
  specifier: ^5.1.35
1134
1134
  version: link:modules/a-style
1135
1135
  zova-module-a-table:
1136
- specifier: ^5.1.43
1136
+ specifier: ^5.1.44
1137
1137
  version: link:modules/a-table
1138
1138
  zova-module-a-zod:
1139
1139
  specifier: ^5.1.37
@@ -10,12 +10,7 @@ import type {
10
10
  import { combineQueries, isNil } from '@cabloy/utils';
11
11
  import { SchemaObject } from 'openapi3-ts/oas31';
12
12
  import { $QueryEnsureFresh, $QueryGetFresh, BeanModelBase, Model } from 'zova-module-a-model';
13
- import {
14
- IPermissionHintGeneral,
15
- IResourceFormActionRowNameRecord,
16
- IResourceTableActionNameRecord,
17
- TypeOpenapiPermissions,
18
- } from 'zova-module-a-openapi';
13
+ import { IPermissionHintGeneral, TypeOpenapiPermissions } from 'zova-module-a-openapi';
19
14
  import { ApiApiHomeUserPassportloginOauthPath, OpenApiBaseURL } from 'zova-module-home-api';
20
15
  import { isRoleSiteAdmitted } from 'zova-module-home-base';
21
16
 
@@ -272,7 +267,7 @@ export class ModelPassport extends BeanModelBase {
272
267
 
273
268
  public checkPermission(
274
269
  permissions: TypeOpenapiPermissions | undefined,
275
- actionName?: keyof (IResourceTableActionNameRecord & IResourceFormActionRowNameRecord),
270
+ actionName?: string,
276
271
  permissionHint?: IPermissionHintGeneral,
277
272
  currentData?: Record<string, unknown> | readonly Record<string, unknown>[],
278
273
  ): boolean {
@@ -14,7 +14,8 @@ import { VNode } from 'vue';
14
14
  import { BeanBase } from 'zova';
15
15
  import { TableCell } from 'zova-module-a-table';
16
16
 
17
- import { checkPermission } from '../lib/utils.js';
17
+ import { filterDetailsRowActions } from '../lib/detailsPermissions.js';
18
+ import { checkFormScene } from '../lib/utils.js';
18
19
 
19
20
  declare module 'zova-module-a-openapi' {
20
21
  export interface IResourceDetailsActionRowRecord {
@@ -37,16 +38,16 @@ export class TableCellActionOperationsRow extends BeanBase implements ITableCell
37
38
  const { $celScope, $$table } = renderContext;
38
39
  const actions = options.actions;
39
40
  if (!actions || actions.length === 0) return false;
40
- // renders
41
+ const $$details = $celScope.$$details!;
42
+ const actionsVisible = actions.filter(action => {
43
+ return checkFormScene($$details.formScene, action.options?.permission);
44
+ });
41
45
  const renders: TypeTableCellRenderComponent[] = [];
42
- for (const action of actions) {
46
+ for (const action of actionsVisible) {
43
47
  const actionName = action.name;
44
48
  const actionRender = action.render;
45
- const permissionHint = action.options?.permission;
46
- if (checkPermission($celScope.formMeta!.formScene!, permissionHint)) {
47
- if (!actionRender) throw new Error(`should specify action render: ${actionName}`);
48
- renders.push(actionRender);
49
- }
49
+ if (!actionRender) throw new Error(`should specify action render: ${actionName}`);
50
+ renders.push(actionRender);
50
51
  }
51
52
  await $$table.cellRenderPrepare(renders);
52
53
  return renders.length > 0;
@@ -60,13 +61,18 @@ export class TableCellActionOperationsRow extends BeanBase implements ITableCell
60
61
  const { $celScope, $$table } = renderContext;
61
62
  const actions = options.actions;
62
63
  if (!actions || actions.length === 0) return;
64
+ const $$details = $celScope.$$details!;
65
+ const actionsAllowed = filterDetailsRowActions(
66
+ $$details.formScene,
67
+ $$details.checkPermission.bind($$details),
68
+ actions,
69
+ );
63
70
  const domActions: VNode[] = [];
64
- actions.forEach((action, index) => {
65
- const permissionHint = action.options?.permission;
66
- if (!checkPermission($celScope.formMeta!.formScene!, permissionHint)) return;
67
- const options2 = Object.assign({ key: index }, action.options);
68
- domActions.push($$table.cellRender(action.render!, options2, renderContext));
71
+ actionsAllowed.forEach((action, index) => {
72
+ const actionOptions = Object.assign({ key: index }, action.options);
73
+ domActions.push($$table.cellRender(action.render!, actionOptions, renderContext));
69
74
  });
75
+ if (domActions.length === 0) return;
70
76
  return <div class={options.class}>{domActions}</div>;
71
77
  }
72
78
  }
@@ -13,6 +13,8 @@ import {
13
13
  } from 'zova-module-a-openapi';
14
14
  import { BeanControllerTableBase } from 'zova-module-a-table';
15
15
 
16
+ import type { TypeDetailsCheckPermission } from '../../types/details.js';
17
+
16
18
  declare module 'zova-module-a-openapi' {
17
19
  export interface IResourceBlockRecord {
18
20
  'basic-details:blockDetails'?: ControllerBlockDetailsProps;
@@ -26,6 +28,7 @@ export interface ControllerBlockDetailsProps<
26
28
  formMeta?: IFormMeta;
27
29
  schemaRow?: ISchemaObjectExtensionField;
28
30
  schemaForm?: ISchemaObjectExtensionField;
31
+ checkPermission?: TypeDetailsCheckPermission;
29
32
  getDetailItems?: () => TData[] | undefined;
30
33
  setDetailItems?: (detailItems: TData[]) => void;
31
34
  }
@@ -70,6 +73,14 @@ export class ControllerBlockDetails<TData extends {} = {}> extends BeanControlle
70
73
  return this.$props.schemaForm!;
71
74
  }
72
75
 
76
+ checkPermission(...args: Parameters<TypeDetailsCheckPermission>) {
77
+ const checkPermission = this.$props.checkPermission;
78
+ if (!checkPermission) {
79
+ throw new Error('should provide enclosing Resource permission checker for details');
80
+ }
81
+ return checkPermission(...args);
82
+ }
83
+
73
84
  public async setTableRef(tableRef: BeanControllerTableBase<TData> | undefined) {
74
85
  this.tableRef = tableRef;
75
86
  }
@@ -9,7 +9,7 @@ import { VNode } from 'vue';
9
9
  import { BeanControllerBase, Use } from 'zova';
10
10
  import { Controller } from 'zova-module-a-bean';
11
11
 
12
- import { checkPermission } from '../../lib/utils.js';
12
+ import { filterDetailsBulkActions } from '../../lib/detailsPermissions.js';
13
13
 
14
14
  declare module 'zova-module-a-openapi' {
15
15
  export interface IResourceBlockRecord {
@@ -46,9 +46,12 @@ export class ControllerBlockToolbarBulk extends BeanControllerBase {
46
46
  const actions = this.$props.actions;
47
47
  if (!actions || actions.length === 0) return;
48
48
  const domActions: VNode[] = [];
49
- actions.forEach((action, index) => {
50
- const permissionHint = action.options?.permission;
51
- if (!checkPermission($$details.formScene, permissionHint)) return;
49
+ const allowedActions = filterDetailsBulkActions(
50
+ $$details.formScene,
51
+ $$details.checkPermission.bind($$details),
52
+ actions,
53
+ );
54
+ allowedActions.forEach((action, index) => {
52
55
  const options = Object.assign({ key: index }, action.options);
53
56
  const domAction = $jsx.render(action.render!, options, $celScope, this.$$renderContext);
54
57
  if (!domAction) return;
@@ -8,6 +8,7 @@ import type {
8
8
  IResourceFormFieldOptionsBase,
9
9
  ISchemaObjectExtensionField,
10
10
  TypeFormScene,
11
+ TypeOpenapiPermissions,
11
12
  } from 'zova-module-a-openapi';
12
13
 
13
14
  import { VNode } from 'vue';
@@ -16,6 +17,10 @@ import { ZovaJsx } from 'zova-jsx';
16
17
  import { Controller } from 'zova-module-a-bean';
17
18
  import { formMetaFromFormScene, ZFormField } from 'zova-module-a-form';
18
19
 
20
+ import type { TypeDetailsCheckPermission } from '../../types/details.js';
21
+
22
+ import { createDetailsPermissionChecker } from '../../lib/detailsPermissions.js';
23
+
19
24
  declare module 'zova-module-a-openapi' {
20
25
  export interface IResourceFormFieldRecord {
21
26
  'basic-details:formFieldDetails'?: IResourceFormFieldDetailsOptions;
@@ -76,6 +81,14 @@ export class ControllerFormFieldDetails extends BeanControllerBase {
76
81
  // blocks
77
82
  const blocks = schemaRow?.rest?.blocks;
78
83
  if (!blocks || blocks.length === 0) return;
84
+ const checkPermission: TypeDetailsCheckPermission = createDetailsPermissionChecker(
85
+ () =>
86
+ (formFieldRenderContext.celScope as { permissions?: TypeOpenapiPermissions }).permissions,
87
+ () => $$formField.$$form.formState.values as Record<string, unknown>,
88
+ (permissions, actionName, permissionHint, currentData) => {
89
+ return this.$passport.checkPermission(permissions, actionName, permissionHint, currentData);
90
+ },
91
+ );
79
92
  const domBlocks: VNode[] = [];
80
93
  blocks.forEach((block, index) => {
81
94
  const options = deepExtend(
@@ -92,6 +105,7 @@ export class ControllerFormFieldDetails extends BeanControllerBase {
92
105
  },
93
106
  },
94
107
  block.options,
108
+ { checkPermission },
95
109
  );
96
110
  const domBlock = this.jsxZova.render(block.render!, options);
97
111
  if (!domBlock) return;