@aperant/framework 0.19.0 → 0.20.0
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/CHANGELOG.md +109 -0
- package/agents/apt-executor.md +6 -0
- package/agents/apt-planner.md +3 -2
- package/bin/features-reconcile-check.mjs +77 -0
- package/dist/cli/artifacts/self-stage.d.mts.map +1 -1
- package/dist/cli/artifacts/self-stage.mjs +2 -1
- package/dist/cli/artifacts/self-stage.mjs.map +1 -1
- package/dist/cli/cli-wrappers/features-reconcile.d.mts +2 -0
- package/dist/cli/cli-wrappers/features-reconcile.d.mts.map +1 -0
- package/dist/cli/cli-wrappers/features-reconcile.mjs +9 -0
- package/dist/cli/cli-wrappers/features-reconcile.mjs.map +1 -0
- package/dist/cli/commands/features-reconcile.d.mts +2 -0
- package/dist/cli/commands/features-reconcile.d.mts.map +1 -0
- package/dist/cli/commands/features-reconcile.mjs +143 -0
- package/dist/cli/commands/features-reconcile.mjs.map +1 -0
- package/dist/cli/commands/health-check.d.mts +2 -2
- package/dist/cli/commands/health-check.mjs +2 -2
- package/dist/cli/dispatch.mjs +2 -2
- package/dist/cli/dispatch.mjs.map +1 -1
- package/dist/cli/features/area-shape.d.mts +11 -0
- package/dist/cli/features/area-shape.d.mts.map +1 -0
- package/dist/cli/features/area-shape.mjs +141 -0
- package/dist/cli/features/area-shape.mjs.map +1 -0
- package/dist/cli/features/delta.d.mts +78 -0
- package/dist/cli/features/delta.d.mts.map +1 -0
- package/dist/cli/features/delta.mjs +591 -0
- package/dist/cli/features/delta.mjs.map +1 -0
- package/dist/cli/features/reconcile.d.mts +236 -0
- package/dist/cli/features/reconcile.d.mts.map +1 -0
- package/dist/cli/features/reconcile.mjs +1126 -0
- package/dist/cli/features/reconcile.mjs.map +1 -0
- package/dist/cli/features/surface-map.d.mts +63 -0
- package/dist/cli/features/surface-map.d.mts.map +1 -0
- package/dist/cli/features/surface-map.mjs +191 -0
- package/dist/cli/features/surface-map.mjs.map +1 -0
- package/dist/cli/{commands/features-audit.d.mts → features/write-root.d.mts} +4 -3
- package/dist/cli/features/write-root.d.mts.map +1 -0
- package/dist/cli/features/write-root.mjs +137 -0
- package/dist/cli/features/write-root.mjs.map +1 -0
- package/dist/cli/gate/gates/features-reconciled.d.mts +36 -0
- package/dist/cli/gate/gates/features-reconciled.d.mts.map +1 -0
- package/dist/cli/gate/gates/features-reconciled.mjs +67 -0
- package/dist/cli/gate/gates/features-reconciled.mjs.map +1 -0
- package/dist/cli/gate/gates/index.mjs +1 -0
- package/dist/cli/gate/gates/index.mjs.map +1 -1
- package/dist/cli/help.mjs +1 -1
- package/dist/cli/release-notes/ship-autodraft.mjs +2 -2
- package/dist/cli/variant/gallery.d.mts.map +1 -1
- package/dist/cli/variant/gallery.mjs +7 -3
- package/dist/cli/variant/gallery.mjs.map +1 -1
- package/dist/plugin/.claude-plugin/plugin.json +1 -1
- package/dist/plugin/agents/apt-executor.md +6 -0
- package/dist/plugin/agents/apt-planner.md +3 -2
- package/dist/plugin/skills/apt-close-task/SKILL.md +2 -2
- package/dist/plugin/skills/apt-debug/SKILL.md +8 -0
- package/dist/plugin/skills/apt-execute/SKILL.md +35 -26
- package/dist/plugin/skills/apt-mockup/SKILL.md +1 -1
- package/dist/plugin/skills/apt-quick/SKILL.md +13 -11
- package/dist/plugin/skills/apt-review/SKILL.md +14 -11
- package/dist/plugin/skills/apt-run/SKILL.md +9 -3
- package/dist/plugin/skills/apt-ship/SKILL.md +27 -5
- package/dist/plugin/skills/apt-watch-ci/SKILL.md +2 -0
- package/dist/schemas/feature-registry.d.ts.map +1 -1
- package/dist/schemas/feature-registry.js +34 -3
- package/dist/schemas/feature-registry.js.map +1 -1
- package/dist/types/config.d.ts +8 -5
- package/dist/types/config.d.ts.map +1 -1
- package/package.json +1 -1
- package/skills/apt-close-task/SKILL.md +2 -2
- package/skills/apt-debug/SKILL.md +8 -0
- package/skills/apt-execute/SKILL.md +35 -26
- package/skills/apt-mockup/SKILL.md +1 -1
- package/skills/apt-quick/SKILL.md +13 -11
- package/skills/apt-review/SKILL.md +14 -11
- package/skills/apt-run/SKILL.md +9 -3
- package/skills/apt-ship/SKILL.md +27 -5
- package/skills/apt-watch-ci/SKILL.md +2 -0
- package/src/cli/artifacts/self-stage.mjs +2 -1
- package/src/cli/cli-wrappers/features-reconcile.mjs +9 -0
- package/src/cli/commands/features-reconcile.mjs +157 -0
- package/src/cli/commands/health-check.mjs +2 -2
- package/src/cli/dispatch.mjs +2 -2
- package/src/cli/features/area-shape.mjs +140 -0
- package/src/cli/features/delta.mjs +625 -0
- package/src/cli/features/reconcile.mjs +1169 -0
- package/src/cli/features/surface-map.mjs +192 -0
- package/src/cli/features/write-root.mjs +140 -0
- package/src/cli/gate/gates/features-reconciled.mjs +70 -0
- package/src/cli/gate/gates/index.mjs +1 -0
- package/src/cli/help.mjs +1 -1
- package/src/cli/release-notes/ship-autodraft.mjs +2 -2
- package/src/cli/variant/gallery.mjs +7 -3
- package/templates/aperant-claude-md-appendix.md +2 -2
- package/workflows/scan-features.md +17 -11
- package/dist/cli/cli-wrappers/features-audit.d.mts +0 -2
- package/dist/cli/cli-wrappers/features-audit.d.mts.map +0 -1
- package/dist/cli/cli-wrappers/features-audit.mjs +0 -8
- package/dist/cli/cli-wrappers/features-audit.mjs.map +0 -1
- package/dist/cli/commands/features-audit.d.mts.map +0 -1
- package/dist/cli/commands/features-audit.mjs +0 -293
- package/dist/cli/commands/features-audit.mjs.map +0 -1
- package/dist/cli/features/registry-audit.d.mts +0 -56
- package/dist/cli/features/registry-audit.d.mts.map +0 -1
- package/dist/cli/features/registry-audit.mjs +0 -264
- package/dist/cli/features/registry-audit.mjs.map +0 -1
- package/src/cli/cli-wrappers/features-audit.mjs +0 -8
- package/src/cli/commands/features-audit.mjs +0 -302
- package/src/cli/features/registry-audit.mjs +0 -254
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* area-shape.mjs — hand-rolled structural validator for feature-registry
|
|
3
|
+
* area files, mirroring `src/schemas/feature-registry.ts` (FeatureRegistrySchema)
|
|
4
|
+
* PLUS the uniqueness refinement (feature ids unique per area; sub_feature ids
|
|
5
|
+
* unique per feature group).
|
|
6
|
+
*
|
|
7
|
+
* WHY A TWIN VALIDATOR EXISTS (ID-07): the bare-node CI check
|
|
8
|
+
* (`bin/features-reconcile-check.mjs`) runs with NO node_modules, so it cannot
|
|
9
|
+
* import zod. This module is node:-builtins only (in fact, zero imports).
|
|
10
|
+
* `feature-registry-schema-parity.test.ts` validates shared fixtures against
|
|
11
|
+
* BOTH this validator and the zod schema so they cannot drift.
|
|
12
|
+
*
|
|
13
|
+
* Semantics mirror zod defaults:
|
|
14
|
+
* - unknown keys are ALLOWED (zod objects are non-strict);
|
|
15
|
+
* - `components` and `sub_features` may be absent (zod `.default([])`);
|
|
16
|
+
* - `route` stays required non-empty — non-routed areas use the literal
|
|
17
|
+
* "(cross-cutting)" (chrome.json precedent), never null.
|
|
18
|
+
*
|
|
19
|
+
* Returns { ok, errors: [] } — never throws.
|
|
20
|
+
*/
|
|
21
|
+
const ID_RE = /^[a-z0-9-]+$/;
|
|
22
|
+
const LAST_SCANNED_RE = /^\d{4}-\d{2}-\d{2}(T[\d:.Z+-]+)?$/;
|
|
23
|
+
const TESTABLE_VALUES = new Set(['testable', 'observable', 'blocked']);
|
|
24
|
+
const WIRED_VALUES = new Set([true, false, 'stubbed', 'partial']);
|
|
25
|
+
function isNonEmptyString(v) {
|
|
26
|
+
return typeof v === 'string' && v.length > 0;
|
|
27
|
+
}
|
|
28
|
+
function checkOptionalString(errors, at, v) {
|
|
29
|
+
if (v !== undefined && !isNonEmptyString(v)) {
|
|
30
|
+
errors.push(`${at}: must be a non-empty string when present`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function validateSubFeature(errors, at, sub) {
|
|
34
|
+
if (!sub || typeof sub !== 'object' || Array.isArray(sub)) {
|
|
35
|
+
errors.push(`${at}: must be an object`);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (!isNonEmptyString(sub.id) || !ID_RE.test(sub.id)) {
|
|
39
|
+
errors.push(`${at}.id: must match ${ID_RE}`);
|
|
40
|
+
}
|
|
41
|
+
if (!isNonEmptyString(sub.name))
|
|
42
|
+
errors.push(`${at}.name: required non-empty string`);
|
|
43
|
+
checkOptionalString(errors, `${at}.component`, sub.component);
|
|
44
|
+
if (!isNonEmptyString(sub.type))
|
|
45
|
+
errors.push(`${at}.type: required non-empty string`);
|
|
46
|
+
if (!WIRED_VALUES.has(sub.wired)) {
|
|
47
|
+
errors.push(`${at}.wired: must be true|false|"stubbed"|"partial"`);
|
|
48
|
+
}
|
|
49
|
+
if (sub.handler !== undefined && typeof sub.handler !== 'string') {
|
|
50
|
+
errors.push(`${at}.handler: must be a string when present`);
|
|
51
|
+
}
|
|
52
|
+
if (sub.shortcut !== undefined && typeof sub.shortcut !== 'string') {
|
|
53
|
+
errors.push(`${at}.shortcut: must be a string when present`);
|
|
54
|
+
}
|
|
55
|
+
if (sub.testable !== undefined && !TESTABLE_VALUES.has(sub.testable)) {
|
|
56
|
+
errors.push(`${at}.testable: must be "testable"|"observable"|"blocked" when present`);
|
|
57
|
+
}
|
|
58
|
+
if (sub.test_hint !== undefined && typeof sub.test_hint !== 'string') {
|
|
59
|
+
errors.push(`${at}.test_hint: must be a string when present`);
|
|
60
|
+
}
|
|
61
|
+
// default / range / options are `unknown` in the zod schema — anything goes.
|
|
62
|
+
}
|
|
63
|
+
function validateFeatureGroup(errors, at, group) {
|
|
64
|
+
if (!group || typeof group !== 'object' || Array.isArray(group)) {
|
|
65
|
+
errors.push(`${at}: must be an object`);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (!isNonEmptyString(group.id) || !ID_RE.test(group.id)) {
|
|
69
|
+
errors.push(`${at}.id: must match ${ID_RE}`);
|
|
70
|
+
}
|
|
71
|
+
if (!isNonEmptyString(group.name))
|
|
72
|
+
errors.push(`${at}.name: required non-empty string`);
|
|
73
|
+
checkOptionalString(errors, `${at}.component`, group.component);
|
|
74
|
+
if (group.sub_features !== undefined) {
|
|
75
|
+
if (!Array.isArray(group.sub_features)) {
|
|
76
|
+
errors.push(`${at}.sub_features: must be an array when present`);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
const seen = new Set();
|
|
80
|
+
for (const [i, sub] of group.sub_features.entries()) {
|
|
81
|
+
validateSubFeature(errors, `${at}.sub_features[${i}]`, sub);
|
|
82
|
+
const id = sub?.id;
|
|
83
|
+
if (isNonEmptyString(id)) {
|
|
84
|
+
if (seen.has(id)) {
|
|
85
|
+
errors.push(`${at}.sub_features[${i}].id: duplicate sub_feature id "${id}" in group`);
|
|
86
|
+
}
|
|
87
|
+
seen.add(id);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Structural + uniqueness validation of an area-file value.
|
|
95
|
+
*
|
|
96
|
+
* @param {unknown} data — parsed JSON of a `.aperant/features/<area>.json`
|
|
97
|
+
* @returns {{ ok: boolean, errors: string[] }}
|
|
98
|
+
*/
|
|
99
|
+
export function validateAreaShape(data) {
|
|
100
|
+
const errors = [];
|
|
101
|
+
if (!data || typeof data !== 'object' || Array.isArray(data)) {
|
|
102
|
+
return { ok: false, errors: ['area file must be a JSON object'] };
|
|
103
|
+
}
|
|
104
|
+
if (!isNonEmptyString(data.area))
|
|
105
|
+
errors.push('area: required non-empty string');
|
|
106
|
+
if (!isNonEmptyString(data.route)) {
|
|
107
|
+
errors.push('route: required non-empty string — use "(cross-cutting)" for non-routed areas, never null');
|
|
108
|
+
}
|
|
109
|
+
if (data.components !== undefined) {
|
|
110
|
+
if (!Array.isArray(data.components)) {
|
|
111
|
+
errors.push('components: must be an array when present');
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
for (const [i, c] of data.components.entries()) {
|
|
115
|
+
if (!isNonEmptyString(c))
|
|
116
|
+
errors.push(`components[${i}]: must be a non-empty string`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (!isNonEmptyString(data.last_scanned) || !LAST_SCANNED_RE.test(data.last_scanned)) {
|
|
121
|
+
errors.push('last_scanned: must be a YYYY-MM-DD or full ISO 8601 date string');
|
|
122
|
+
}
|
|
123
|
+
if (!Array.isArray(data.features)) {
|
|
124
|
+
errors.push('features: required array');
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
const seen = new Set();
|
|
128
|
+
for (const [i, group] of data.features.entries()) {
|
|
129
|
+
validateFeatureGroup(errors, `features[${i}]`, group);
|
|
130
|
+
const id = group?.id;
|
|
131
|
+
if (isNonEmptyString(id)) {
|
|
132
|
+
if (seen.has(id)) {
|
|
133
|
+
errors.push(`features[${i}].id: duplicate feature id "${id}" in area`);
|
|
134
|
+
}
|
|
135
|
+
seen.add(id);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return { ok: errors.length === 0, errors };
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=area-shape.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"area-shape.mjs","sourceRoot":"","sources":["../../../src/cli/features/area-shape.mjs"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/** Canonical JSON string per ID-17. No default-filling — hash what was written. */
|
|
2
|
+
export function canonicalJson(value: any): string;
|
|
3
|
+
/** sha256 hex over the canonical JSON of a value (entity hashing). */
|
|
4
|
+
export function sha256Canonical(value: any): string;
|
|
5
|
+
/** sha256 hex over raw bytes (delta file content, area file bytes). */
|
|
6
|
+
export function sha256Bytes(data: any): string;
|
|
7
|
+
/** expected_hash for a targeted entity — alias making the call sites read clearly. */
|
|
8
|
+
export function hashEntity(entity: any): string;
|
|
9
|
+
/**
|
|
10
|
+
* Shape + SEMANTIC ISO 8601 datetime validation (ST11). The regex alone
|
|
11
|
+
* accepted '2026-99-99T99:99:99Z' and '2026-02-30T12:00:00Z' — both could
|
|
12
|
+
* max-sort above real dates and stamp an invalid last_scanned. After the
|
|
13
|
+
* shape passes, the components are verified deterministically: month 1-12,
|
|
14
|
+
* a REAL calendar day via UTC round-trip (leap years included), hours<24,
|
|
15
|
+
* minutes<60, seconds<60 (offsets too).
|
|
16
|
+
*/
|
|
17
|
+
export function isValidIsoDatetime(value: any): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Validate a parsed delta object. `mode: 'draft'` relaxes exactly two rules:
|
|
20
|
+
* the `needs-disposition` sentinel is allowed, and `area: null` is allowed
|
|
21
|
+
* (writer-must-assign). Everything else is identical.
|
|
22
|
+
*
|
|
23
|
+
* @returns {{ ok: boolean, errors: string[] }}
|
|
24
|
+
*/
|
|
25
|
+
export function validateDelta(delta: any, { mode }?: {
|
|
26
|
+
mode?: string | undefined;
|
|
27
|
+
}): {
|
|
28
|
+
ok: boolean;
|
|
29
|
+
errors: string[];
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Read + parse + validate a delta file. Never throws.
|
|
33
|
+
*
|
|
34
|
+
* @returns {{ ok: boolean, delta?: Record<string, any>, errors: string[], path: string }}
|
|
35
|
+
*/
|
|
36
|
+
export function parseDeltaFile(path: any, { mode }?: {
|
|
37
|
+
mode?: string | undefined;
|
|
38
|
+
}): {
|
|
39
|
+
ok: boolean;
|
|
40
|
+
delta?: Record<string, any>;
|
|
41
|
+
errors: string[];
|
|
42
|
+
path: string;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Merge validated deltas per the ID-02 conflict matrix.
|
|
46
|
+
*
|
|
47
|
+
* @param {Array<{source: string, delta: object}>} sources — validated deltas
|
|
48
|
+
* annotated with their file path (conflicts name BOTH writers).
|
|
49
|
+
* @param {{ getFeature: (area, featureId) => object|null,
|
|
50
|
+
* getSubFeature: (area, featureId, subId) => object|null }} lookup
|
|
51
|
+
* — reads against the CURRENT registry pre-image (rules e/f).
|
|
52
|
+
* @returns {{ ok: true, operations: Array<Record<string, any>>, files: Array<Record<string, any>> }
|
|
53
|
+
* | { ok: false, conflicts: Array<{kind: string, message: string, sources: string[]}> }}
|
|
54
|
+
*/
|
|
55
|
+
export function mergeDeltas(sources: Array<{
|
|
56
|
+
source: string;
|
|
57
|
+
delta: object;
|
|
58
|
+
}>, lookup: {
|
|
59
|
+
getFeature: (area: any, featureId: any) => object | null;
|
|
60
|
+
getSubFeature: (area: any, featureId: any, subId: any) => object | null;
|
|
61
|
+
}): {
|
|
62
|
+
ok: true;
|
|
63
|
+
operations: Array<Record<string, any>>;
|
|
64
|
+
files: Array<Record<string, any>>;
|
|
65
|
+
} | {
|
|
66
|
+
ok: false;
|
|
67
|
+
conflicts: Array<{
|
|
68
|
+
kind: string;
|
|
69
|
+
message: string;
|
|
70
|
+
sources: string[];
|
|
71
|
+
}>;
|
|
72
|
+
};
|
|
73
|
+
export const CHANGE_KINDS: readonly string[];
|
|
74
|
+
export const DISPOSITIONS: readonly string[];
|
|
75
|
+
/** Draft-only sentinel — NEVER valid at --write/--check time. */
|
|
76
|
+
export const DRAFT_ONLY_DISPOSITION: "needs-disposition";
|
|
77
|
+
export const OP_KINDS: readonly string[];
|
|
78
|
+
//# sourceMappingURL=delta.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delta.d.mts","sourceRoot":"","sources":["../../../src/cli/features/delta.mjs"],"names":[],"mappings":"AAoFA,mFAAmF;AACnF,kDAEC;AAED,sEAAsE;AACtE,oDAEC;AAED,uEAAuE;AACvE,+CAEC;AAED,sFAAsF;AACtF,gDAEC;AASD;;;;;;;GAOG;AACH,wDAiBC;AAuBD;;;;;;GAMG;AACH;;IAFa;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CA0K7C;AAED;;;;GAIG;AACH;;IAFa;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAiBxF;AAqDD;;;;;;;;;;GAUG;AACH,qCARW,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAC,CAAC,UAEtC;IAAE,UAAU,EAAE,CAAC,IAAI,KAAA,EAAE,SAAS,KAAA,KAAK,MAAM,GAAC,IAAI,CAAC;IAC7C,aAAa,EAAE,CAAC,IAAI,KAAA,EAAE,SAAS,KAAA,EAAE,KAAK,KAAA,KAAK,MAAM,GAAC,IAAI,CAAA;CAAE,GAExD;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,UAAU,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;IAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAA;CAAE,GACvF;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,SAAS,EAAE,KAAK,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAA;KAAC,CAAC,CAAA;CAAE,CA8M/F;AAteD,6CAAsF;AACtF,6CAKE;AACF,iEAAiE;AACjE,qCAAsC,mBAAmB,CAAA;AACzD,yCAA6F"}
|