cabloy 5.1.192 → 5.1.194
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/.cabloy-version +1 -1
- package/CHANGELOG.md +21 -0
- package/package.json +1 -1
- package/repo-agent-governance/adapters/claude/contract-loop-gate.ts +15 -187
- package/repo-agent-governance/adapters/codex/contract-loop-gate.mjs +25 -0
- package/repo-agent-governance/adapters/codex/hooks.json +19 -0
- package/repo-agent-governance/adapters/cursor/contract-loop-gate.mjs +28 -0
- package/repo-agent-governance/adapters/cursor/hooks.json +19 -0
- package/repo-agent-governance/managed-assets.json +38 -10
- package/repo-agent-governance/manifest.json +24 -0
- package/repo-agent-governance/policies/repository.md +1 -1
- package/repo-agent-governance/scripts/governance.mjs +101 -2
- package/repo-agent-governance/scripts/pack-check.mjs +5 -0
- package/repo-agent-governance/skills/cabloy-contract-loop/SKILL.md +9 -2
- package/repo-agent-governance/skills/cabloy-contract-loop/references/verification-checklist.md +5 -3
- package/repo-agent-governance/tests/governance.test.mjs +306 -0
- package/repo-agent-governance/tools/contract-loop/core.mjs +30 -14
- package/repo-agent-governance/tools/contract-loop/hook-runtime.mjs +368 -0
- package/repo-docs/ai/agent-governance.md +8 -6
- package/repo-docs/ai/docs-skills-rules-mapping.md +4 -1
- package/repo-docs/ai/edition-consistency-checklist.md +1 -1
- package/repo-docs/ai/introduction.md +1 -1
- package/repo-docs/ai/repo-guidance.md +1 -1
- package/repo-docs/ai/rules-and-config.md +5 -3
- package/repo-docs/backend/menu-authorization.md +1 -0
- package/repo-docs/backend/menu-guide.md +18 -7
- package/repo-docs/blogs/cabloy-fullstack-resource-addressing/index.md +1 -0
- package/repo-docs/reference/package-map.md +1 -1
- package/repo-e2e/config/playwright.config.ts +1 -1
- package/repo-e2e/scripts/startE2eVona.ts +6 -2
- package/repo-e2e/specs/controller-boundary.spec.ts +76 -28
- package/vona/packages-vona/vona/package.json +1 -1
- package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/package.json +1 -1
- package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/src/lib/beanSsrSiteBase.ts +2 -0
- package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/src/lib/ssrMenu.ts +9 -3
- package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/src/lib/ssrMenuEligibility.ts +14 -0
- package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/src/lib/ssrMenuGroup.ts +9 -3
- package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/src/lib/ssrMenuSite.ts +10 -0
- package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/src/types/ssrMenu.ts +1 -1
- package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/src/types/ssrMenuGroup.ts +1 -1
- package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/test/ssrMenuEligibility.test.ts +73 -13
- package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/test/ssrMenuSite.test.ts +90 -0
- package/vona/src/suite-vendor/a-cabloy/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-error/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-error/src/lib/onerror.ts +9 -0
- package/vona/src/suite-vendor/a-vona/modules/a-error/test/onerror.test.ts +92 -0
- package/vona/src/suite-vendor/a-vona/package.json +1 -1
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { VonaApplication } from 'vona';
|
|
2
|
+
|
|
3
|
+
import assert from 'node:assert';
|
|
4
|
+
import { PassThrough } from 'node:stream';
|
|
5
|
+
import { describe, it } from 'node:test';
|
|
6
|
+
|
|
7
|
+
import { onerror } from '../src/lib/onerror.ts';
|
|
8
|
+
|
|
9
|
+
function createFixture(aborted: boolean, writable: boolean) {
|
|
10
|
+
const logged: Error[] = [];
|
|
11
|
+
const responses: unknown[] = [];
|
|
12
|
+
const app = { context: {} } as VonaApplication;
|
|
13
|
+
const options = {
|
|
14
|
+
all(_err: Error, ctx: any) {
|
|
15
|
+
ctx.body = 'error response';
|
|
16
|
+
},
|
|
17
|
+
log(err: Error) {
|
|
18
|
+
logged.push(err);
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
onerror(app, options);
|
|
22
|
+
const req = Object.assign(new PassThrough(), { aborted });
|
|
23
|
+
req.destroy();
|
|
24
|
+
const ctx = Object.assign(Object.create(app.context), {
|
|
25
|
+
req,
|
|
26
|
+
writable,
|
|
27
|
+
headerSent: false,
|
|
28
|
+
res: {
|
|
29
|
+
end(body: unknown) {
|
|
30
|
+
responses.push(body);
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
set() {},
|
|
34
|
+
accepts() {
|
|
35
|
+
return 'text';
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
return { ctx, logged, responses };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function createBodyError(type: string, status: number) {
|
|
42
|
+
return Object.assign(new Error(type), { type, status });
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
describe('onerror.test.ts', () => {
|
|
46
|
+
for (const [type, status] of [
|
|
47
|
+
['stream.not.readable', 500],
|
|
48
|
+
['request.aborted', 400],
|
|
49
|
+
] as const) {
|
|
50
|
+
it(`ignores ${type} only for an aborted, unwritable request`, async () => {
|
|
51
|
+
const { ctx, logged, responses } = createFixture(true, false);
|
|
52
|
+
await ctx.onerror(createBodyError(type, status));
|
|
53
|
+
assert.deepEqual(logged, []);
|
|
54
|
+
assert.deepEqual(responses, []);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it(`keeps ${type} visible without confirmed request abortion`, async () => {
|
|
58
|
+
const { ctx, logged, responses } = createFixture(false, false);
|
|
59
|
+
const error = createBodyError(type, status);
|
|
60
|
+
await ctx.onerror(error);
|
|
61
|
+
assert.deepEqual(logged, [error]);
|
|
62
|
+
assert.equal(Reflect.get(error, 'headerSent'), true);
|
|
63
|
+
assert.deepEqual(responses, []);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it(`preserves ${type} handling while the response is writable`, async () => {
|
|
67
|
+
const { ctx, logged, responses } = createFixture(true, true);
|
|
68
|
+
const error = createBodyError(type, status);
|
|
69
|
+
await ctx.onerror(error);
|
|
70
|
+
assert.deepEqual(logged, [error]);
|
|
71
|
+
assert.equal(ctx.status, status);
|
|
72
|
+
assert.deepEqual(responses, ['error response']);
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
it('does not hide unrelated application errors on aborted requests', async () => {
|
|
77
|
+
const { ctx, logged, responses } = createFixture(true, false);
|
|
78
|
+
const error = new Error('application failure');
|
|
79
|
+
await ctx.onerror(error);
|
|
80
|
+
assert.deepEqual(logged, [error]);
|
|
81
|
+
assert.deepEqual(responses, []);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('preserves body parsing errors on a writable request', async () => {
|
|
85
|
+
const { ctx, logged, responses } = createFixture(false, true);
|
|
86
|
+
const error = createBodyError('entity.parse.failed', 400);
|
|
87
|
+
await ctx.onerror(error);
|
|
88
|
+
assert.deepEqual(logged, [error]);
|
|
89
|
+
assert.equal(ctx.status, 400);
|
|
90
|
+
assert.deepEqual(responses, ['error response']);
|
|
91
|
+
});
|
|
92
|
+
});
|