universal-dev-standards 6.13.1 → 6.14.0-beta.1
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/bundled/ai/standards/open-work-tracking.ai.yaml +69 -4
- package/bundled/ai/standards/turn-completion-integrity.ai.yaml +14 -7
- package/bundled/core/open-work-tracking.md +111 -8
- package/bundled/core/turn-completion-integrity.md +58 -11
- package/bundled/hooks/check-turn-completion-agy.mjs +147 -0
- package/bundled/locales/zh-CN/CHANGELOG.md +15 -3
- package/bundled/locales/zh-CN/README.md +1 -1
- package/bundled/locales/zh-CN/SECURITY.md +1 -0
- package/bundled/locales/zh-CN/core/turn-completion-integrity.md +46 -13
- package/bundled/locales/zh-CN/docs/CHEATSHEET.md +4 -1
- package/bundled/locales/zh-CN/docs/CLI-INIT-OPTIONS.md +9 -8
- package/bundled/locales/zh-CN/docs/FEATURE-REFERENCE.md +9 -6
- package/bundled/locales/zh-TW/CHANGELOG.md +15 -3
- package/bundled/locales/zh-TW/README.md +1 -1
- package/bundled/locales/zh-TW/SECURITY.md +1 -0
- package/bundled/locales/zh-TW/core/open-work-tracking.md +88 -9
- package/bundled/locales/zh-TW/core/turn-completion-integrity.md +46 -13
- package/bundled/locales/zh-TW/docs/CHEATSHEET.md +4 -1
- package/bundled/locales/zh-TW/docs/CLI-INIT-OPTIONS.md +9 -8
- package/bundled/locales/zh-TW/docs/FEATURE-REFERENCE.md +9 -6
- package/package.json +1 -1
- package/src/commands/init.js +15 -2
- package/src/commands/uninstall.js +1 -1
- package/src/installers/hooks-installer.js +89 -2
- package/src/uninstallers/hook-uninstaller.js +107 -4
- package/standards-registry.json +8 -8
|
@@ -2,7 +2,7 @@ import { existsSync, readFileSync, writeFileSync, unlinkSync } from 'fs';
|
|
|
2
2
|
import { join, basename } from 'path';
|
|
3
3
|
import {
|
|
4
4
|
collectHookConfigs, standardsSourceDir, hooksSourceDir,
|
|
5
|
-
CODEX_HOOK_SCRIPT, GEMINI_HOOK_SCRIPT,
|
|
5
|
+
CODEX_HOOK_SCRIPT, GEMINI_HOOK_SCRIPT, AGY_HOOK_SCRIPT,
|
|
6
6
|
} from '../installers/hooks-installer.js';
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
* test placing a user hook at `scripts/hooks/my-own-hook.mjs` lost it).
|
|
18
18
|
* The safe signature is path *and* a script basename UDS is actually known to
|
|
19
19
|
* ship right now — the same set collectHookConfigs() derives for install,
|
|
20
|
-
* plus the
|
|
20
|
+
* plus the three fixed Codex/Gemini/agy script names.
|
|
21
21
|
*
|
|
22
22
|
* 🔴 Until this file added the three functions below, uninstall only ever
|
|
23
23
|
* touched .husky/pre-commit and .git/hooks/pre-commit — the settings.json /
|
|
@@ -37,7 +37,7 @@ function commandOf(entry) {
|
|
|
37
37
|
/** Script basenames UDS currently ships and would install a hook entry for. */
|
|
38
38
|
function knownUdsHookScripts() {
|
|
39
39
|
const { scripts } = collectHookConfigs(standardsSourceDir(), hooksSourceDir());
|
|
40
|
-
return new Set([...scripts.map((s) => basename(s)), CODEX_HOOK_SCRIPT, GEMINI_HOOK_SCRIPT]);
|
|
40
|
+
return new Set([...scripts.map((s) => basename(s)), CODEX_HOOK_SCRIPT, GEMINI_HOOK_SCRIPT, AGY_HOOK_SCRIPT]);
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
function isUdsHookEntry(entry, knownScripts) {
|
|
@@ -159,10 +159,112 @@ export function uninstallGeminiHooks(projectPath, options = {}) {
|
|
|
159
159
|
});
|
|
160
160
|
}
|
|
161
161
|
|
|
162
|
+
/**
|
|
163
|
+
* A bare `{ type, command }` handler (agy's shape — no `hooks[]` wrapper) that
|
|
164
|
+
* runs one of the scripts UDS ships.
|
|
165
|
+
*/
|
|
166
|
+
function isUdsAgyHandler(handler, knownScripts) {
|
|
167
|
+
const cmd = handler && typeof handler.command === 'string' ? handler.command : undefined;
|
|
168
|
+
// agy's hook cwd is `.agents/`, so the installed command climbs out first
|
|
169
|
+
// (`node ../scripts/hooks/...`); the earlier `node scripts/hooks/...` form
|
|
170
|
+
// is still recognised so an install made before that fix can be removed.
|
|
171
|
+
return typeof cmd === 'string' && /^node (?:\.\.\/)?scripts\/hooks\//.test(cmd) && knownScripts.has(basename(cmd));
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Remove UDS's Stop handler from .agents/hooks.json (installAgyHooks()'s output).
|
|
176
|
+
*
|
|
177
|
+
* agy's file is `{ "<hook name>": { "<Event>": handler[] } }`, not the
|
|
178
|
+
* `{ hooks: { <Event>: entry[] } }` the other three share, so the generic
|
|
179
|
+
* stripper cannot be used. Only handlers that run a UDS-shipped script are
|
|
180
|
+
* removed, and from ANY hook name (an adopter may have renamed our key); a
|
|
181
|
+
* user's own handler, even inside the same name or the same event array, stays.
|
|
182
|
+
* A name left with no event after removal is dropped, and a file left empty is
|
|
183
|
+
* deleted.
|
|
184
|
+
*/
|
|
185
|
+
export function uninstallAgyHooks(projectPath, options = {}) {
|
|
186
|
+
const configPath = join(projectPath, '.agents', 'hooks.json');
|
|
187
|
+
const label = '.agents/hooks.json';
|
|
188
|
+
const dryRun = options.dryRun || false;
|
|
189
|
+
const result = { removed: [], skipped: [], errors: [] };
|
|
190
|
+
if (!existsSync(configPath)) return result;
|
|
191
|
+
|
|
192
|
+
let config;
|
|
193
|
+
try {
|
|
194
|
+
config = JSON.parse(readFileSync(configPath, 'utf-8'));
|
|
195
|
+
} catch (error) {
|
|
196
|
+
result.errors.push(`${label} — could not parse (${error.message}); left untouched`);
|
|
197
|
+
return result;
|
|
198
|
+
}
|
|
199
|
+
if (!config || typeof config !== 'object' || Array.isArray(config)) {
|
|
200
|
+
result.skipped.push(`${label} (no UDS hook entries found)`);
|
|
201
|
+
return result;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const knownScripts = knownUdsHookScripts();
|
|
205
|
+
let removedCount = 0;
|
|
206
|
+
const next = {};
|
|
207
|
+
for (const [name, def] of Object.entries(config)) {
|
|
208
|
+
if (!def || typeof def !== 'object' || Array.isArray(def)) {
|
|
209
|
+
next[name] = def;
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
const nextDef = {};
|
|
213
|
+
let touched = false;
|
|
214
|
+
let eventsLeft = 0;
|
|
215
|
+
for (const [key, value] of Object.entries(def)) {
|
|
216
|
+
if (!Array.isArray(value)) {
|
|
217
|
+
nextDef[key] = value; // e.g. `enabled`
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
const kept = value.filter((h) => {
|
|
221
|
+
if (isUdsAgyHandler(h, knownScripts)) {
|
|
222
|
+
removedCount += 1;
|
|
223
|
+
touched = true;
|
|
224
|
+
return false;
|
|
225
|
+
}
|
|
226
|
+
return true;
|
|
227
|
+
});
|
|
228
|
+
if (kept.length > 0) {
|
|
229
|
+
nextDef[key] = kept;
|
|
230
|
+
eventsLeft += 1;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
// A name we emptied is dropped (nothing but `enabled` would remain);
|
|
234
|
+
// a name we did not touch is kept exactly as found.
|
|
235
|
+
if (touched && eventsLeft === 0) continue;
|
|
236
|
+
next[name] = touched ? nextDef : def;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (removedCount === 0) {
|
|
240
|
+
result.skipped.push(`${label} (no UDS hook entries found)`);
|
|
241
|
+
return result;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const entryLabel = `${label} (${removedCount} UDS hook ${removedCount === 1 ? 'entry' : 'entries'})`;
|
|
245
|
+
if (dryRun) {
|
|
246
|
+
result.removed.push(entryLabel);
|
|
247
|
+
return result;
|
|
248
|
+
}
|
|
249
|
+
try {
|
|
250
|
+
if (Object.keys(next).length === 0) {
|
|
251
|
+
unlinkSync(configPath);
|
|
252
|
+
result.removed.push(`${entryLabel}, file removed — created by UDS, now empty`);
|
|
253
|
+
} else {
|
|
254
|
+
writeFileSync(configPath, JSON.stringify(next, null, 2) + '\n');
|
|
255
|
+
result.removed.push(entryLabel);
|
|
256
|
+
}
|
|
257
|
+
} catch (error) {
|
|
258
|
+
result.errors.push(`${label} — ${error.message}`);
|
|
259
|
+
}
|
|
260
|
+
return result;
|
|
261
|
+
}
|
|
262
|
+
|
|
162
263
|
/**
|
|
163
264
|
* Remove UDS-related lines from .husky/pre-commit, the native
|
|
164
265
|
* .git/hooks/pre-commit fallback, and the enforcement-hook entries UDS wrote
|
|
165
|
-
* into .claude/settings.json, .codex/hooks.json
|
|
266
|
+
* into .claude/settings.json, .codex/hooks.json, .gemini/settings.json and
|
|
267
|
+
* .agents/hooks.json.
|
|
166
268
|
* @param {string} projectPath - Project root path
|
|
167
269
|
* @param {Object} options - { dryRun: boolean }
|
|
168
270
|
* @returns {Object} { removed: string[], skipped: string[], errors: string[] }
|
|
@@ -231,6 +333,7 @@ export function uninstallHook(projectPath, options = {}) {
|
|
|
231
333
|
uninstallClaudeCodeHooks(projectPath, { dryRun }),
|
|
232
334
|
uninstallCodexHooks(projectPath, { dryRun }),
|
|
233
335
|
uninstallGeminiHooks(projectPath, { dryRun }),
|
|
336
|
+
uninstallAgyHooks(projectPath, { dryRun }),
|
|
234
337
|
]) {
|
|
235
338
|
result.removed.push(...sub.removed);
|
|
236
339
|
result.skipped.push(...sub.skipped);
|
package/standards-registry.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.14.0-beta.1",
|
|
4
4
|
"lastUpdated": "2026-05-13",
|
|
5
5
|
"description": "Standards registry for universal-dev-standards with integrated skills and AI-optimized formats",
|
|
6
6
|
"formats": {
|
|
@@ -58,14 +58,14 @@
|
|
|
58
58
|
"standards": {
|
|
59
59
|
"name": "universal-dev-standards",
|
|
60
60
|
"url": "https://github.com/AsiaOstrich/universal-dev-standards",
|
|
61
|
-
"version": "6.
|
|
61
|
+
"version": "6.14.0-beta.1"
|
|
62
62
|
},
|
|
63
63
|
"skills": {
|
|
64
64
|
"name": "universal-dev-standards",
|
|
65
65
|
"url": "https://github.com/AsiaOstrich/universal-dev-standards",
|
|
66
66
|
"localPath": "skills",
|
|
67
67
|
"rawUrl": "https://raw.githubusercontent.com/AsiaOstrich/universal-dev-standards/main/skills",
|
|
68
|
-
"version": "6.
|
|
68
|
+
"version": "6.14.0-beta.1",
|
|
69
69
|
"note": "Skills are now included in the main repository under skills/"
|
|
70
70
|
}
|
|
71
71
|
},
|
|
@@ -1799,7 +1799,7 @@
|
|
|
1799
1799
|
},
|
|
1800
1800
|
"category": "reference",
|
|
1801
1801
|
"skillName": null,
|
|
1802
|
-
"description": "Downstream of deferred-item-exit: once an item has an exit, its carrier must stay trustworthy. Capture costs no more than two fields; a waiting item records its release condition; derivable fields are generated, not hand-written; a coverage figure states what it could not see; a checkpoint at turn end reports open work but never blocks"
|
|
1802
|
+
"description": "Downstream of deferred-item-exit: once an item has an exit, its carrier must stay trustworthy. Capture costs no more than two fields; a waiting item records its release condition; derivable fields are generated, not hand-written; a coverage figure states what it could not see; a checkpoint at turn end reports open work but never blocks; goal and progress live in different carriers, an edit to the goal leaves a record, and a next action names a file, test, command or requirement"
|
|
1803
1803
|
},
|
|
1804
1804
|
{
|
|
1805
1805
|
"id": "verification-evidence",
|
|
@@ -2295,7 +2295,7 @@
|
|
|
2295
2295
|
"id": "license-compliance",
|
|
2296
2296
|
"name": "License Compliance Standards",
|
|
2297
2297
|
"nameZh": "授權合規標準",
|
|
2298
|
-
"version": "6.
|
|
2298
|
+
"version": "6.14.0-beta.1",
|
|
2299
2299
|
"source": {
|
|
2300
2300
|
"human": "core/license-compliance.md",
|
|
2301
2301
|
"ai": "ai/standards/license-compliance.ai.yaml"
|
|
@@ -2307,7 +2307,7 @@
|
|
|
2307
2307
|
"id": "verification-oracle",
|
|
2308
2308
|
"name": "Verification Oracle Standards",
|
|
2309
2309
|
"nameZh": "驗證 Oracle 標準",
|
|
2310
|
-
"version": "6.
|
|
2310
|
+
"version": "6.14.0-beta.1",
|
|
2311
2311
|
"source": {
|
|
2312
2312
|
"human": "core/verification-oracle.md",
|
|
2313
2313
|
"ai": "ai/standards/verification-oracle.ai.yaml"
|
|
@@ -2319,7 +2319,7 @@
|
|
|
2319
2319
|
"id": "model-provenance",
|
|
2320
2320
|
"name": "Model Provenance Policy Standards",
|
|
2321
2321
|
"nameZh": "模型來源政策標準",
|
|
2322
|
-
"version": "6.
|
|
2322
|
+
"version": "6.14.0-beta.1",
|
|
2323
2323
|
"source": {
|
|
2324
2324
|
"human": "core/model-provenance.md",
|
|
2325
2325
|
"ai": "ai/standards/model-provenance.ai.yaml"
|
|
@@ -2331,7 +2331,7 @@
|
|
|
2331
2331
|
"id": "resource-cost-boundary",
|
|
2332
2332
|
"name": "Resource / Cost Boundary Declaration Standards",
|
|
2333
2333
|
"nameZh": "資源/成本邊界宣告標準",
|
|
2334
|
-
"version": "6.
|
|
2334
|
+
"version": "6.14.0-beta.1",
|
|
2335
2335
|
"source": {
|
|
2336
2336
|
"human": "core/resource-cost-boundary.md",
|
|
2337
2337
|
"ai": "ai/standards/resource-cost-boundary.ai.yaml"
|