ultra-builder-pro-cli 0.5.1 → 0.5.3
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 +24 -1
- package/README.md +1 -1
- package/adapters/_shared/tests/runtime-assets.test.cjs +12 -0
- package/adapters/codex.js +85 -13
- package/agents/tdd-runner.md +4 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.5.3] — 2026-07-17
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- Removed the final bundled agent instruction that asked workers to update and
|
|
15
|
+
consult project memory. Test workers now return reusable findings to the
|
|
16
|
+
parent agent, while persistent memory remains owned by a separately installed
|
|
17
|
+
host provider.
|
|
18
|
+
- Added a release regression guard that rejects private memory ownership,
|
|
19
|
+
`.ultra/memory`, and retired `/recall` instructions from every bundled agent.
|
|
20
|
+
|
|
21
|
+
## [0.5.2] — 2026-07-16
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
- Preserved Codex hook entry points for already-running tasks across plugin
|
|
26
|
+
refreshes, including cache versions whose adapter file or entire cache
|
|
27
|
+
directory had already disappeared. Historical cache versions are now kept in
|
|
28
|
+
the managed runtime manifest and restored as validated forwarders to the
|
|
29
|
+
current adapter.
|
|
30
|
+
|
|
10
31
|
## [0.5.1] — 2026-07-16
|
|
11
32
|
|
|
12
33
|
### Changed
|
|
@@ -211,7 +232,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
211
232
|
skill manifest, CLI protocol + mapping table; 5 spec validators.
|
|
212
233
|
- **Phase 0 — skeleton**: multi-runtime installer scaffolding.
|
|
213
234
|
|
|
214
|
-
[Unreleased]: https://github.com/rocky2431/ultra-builder-pro-cli/compare/v0.5.
|
|
235
|
+
[Unreleased]: https://github.com/rocky2431/ultra-builder-pro-cli/compare/v0.5.3...HEAD
|
|
236
|
+
[0.5.3]: https://github.com/rocky2431/ultra-builder-pro-cli/compare/v0.5.2...v0.5.3
|
|
237
|
+
[0.5.2]: https://github.com/rocky2431/ultra-builder-pro-cli/compare/v0.5.1...v0.5.2
|
|
215
238
|
[0.5.1]: https://github.com/rocky2431/ultra-builder-pro-cli/compare/v0.5.0...v0.5.1
|
|
216
239
|
[0.5.0]: https://github.com/rocky2431/ultra-builder-pro-cli/releases/tag/v0.5.0
|
|
217
240
|
[0.4.0]: https://github.com/rocky2431/ultra-builder-pro-cli/releases/tag/v0.4.0
|
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ authoritative `.ultra/state.db`.
|
|
|
8
8
|
|
|
9
9
|
<div align="center">
|
|
10
10
|
|
|
11
|
-
[](./CHANGELOG.md)
|
|
12
12
|
[](#verification)
|
|
13
13
|
[](./LICENSE)
|
|
14
14
|
[](./package.json)
|
|
@@ -89,6 +89,18 @@ test('workflow hook allowlist contains no memory, prompt capture, or generic pol
|
|
|
89
89
|
assert.doesNotMatch(WORKFLOW_HOOK_FILES.join('\n'), /memory|recall|journal|observation|prompt|dangerous|post_edit/);
|
|
90
90
|
});
|
|
91
91
|
|
|
92
|
+
test('bundled agents never instruct workers to own persistent memory', () => {
|
|
93
|
+
const agentsDir = path.join(REPO_ROOT, 'agents');
|
|
94
|
+
const agentText = fs.readdirSync(agentsDir)
|
|
95
|
+
.filter((name) => name.endsWith('.md'))
|
|
96
|
+
.map((name) => fs.readFileSync(path.join(agentsDir, name), 'utf8'))
|
|
97
|
+
.join('\n');
|
|
98
|
+
|
|
99
|
+
assert.doesNotMatch(agentText, /^## Memory$/m);
|
|
100
|
+
assert.doesNotMatch(agentText, /Update your project memory|Consult memory before starting work/);
|
|
101
|
+
assert.doesNotMatch(agentText, /\.ultra\/memory|\/recall(?:\s|`|$)/m);
|
|
102
|
+
});
|
|
103
|
+
|
|
92
104
|
test('npm publish list uses the same explicit skill boundary', () => {
|
|
93
105
|
const pkg = JSON.parse(fs.readFileSync(path.join(REPO_ROOT, 'package.json'), 'utf8'));
|
|
94
106
|
const publishedSkills = pkg.files
|
package/adapters/codex.js
CHANGED
|
@@ -191,14 +191,53 @@ function pluginCacheRoot(configDir, marketplaceName) {
|
|
|
191
191
|
return path.join(configDir, 'plugins', 'cache', marketplaceName, PLUGIN_NAME);
|
|
192
192
|
}
|
|
193
193
|
|
|
194
|
-
function
|
|
194
|
+
function normalizeHookCacheVersions(versions) {
|
|
195
|
+
const normalized = new Set();
|
|
196
|
+
for (const version of versions) {
|
|
197
|
+
if (typeof version !== 'string'
|
|
198
|
+
|| !/^[A-Za-z0-9][A-Za-z0-9.+_-]*$/.test(version)) {
|
|
199
|
+
throw new Error(`invalid Codex plugin cache version: ${String(version)}`);
|
|
200
|
+
}
|
|
201
|
+
normalized.add(version);
|
|
202
|
+
}
|
|
203
|
+
return [...normalized].sort();
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function listKnownHookCacheVersions(configDir, marketplaceName, manifest = null) {
|
|
207
|
+
const root = pluginCacheRoot(configDir, marketplaceName);
|
|
208
|
+
const versions = [];
|
|
209
|
+
if (fs.existsSync(root)) {
|
|
210
|
+
versions.push(...fs.readdirSync(root, { withFileTypes: true })
|
|
211
|
+
.filter((entry) => entry.isDirectory() || entry.isSymbolicLink())
|
|
212
|
+
.map((entry) => entry.name));
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (manifest && manifest.source === SOURCE_TAG && manifest.adapter === 'codex') {
|
|
216
|
+
if (manifest.plugin && manifest.plugin.version !== undefined) {
|
|
217
|
+
versions.push(manifest.plugin.version);
|
|
218
|
+
}
|
|
219
|
+
if (manifest.hook_cache_versions !== undefined) {
|
|
220
|
+
if (!Array.isArray(manifest.hook_cache_versions)) {
|
|
221
|
+
throw new Error('invalid Codex runtime manifest hook_cache_versions');
|
|
222
|
+
}
|
|
223
|
+
versions.push(...manifest.hook_cache_versions);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return normalizeHookCacheVersions(versions);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function hookAdaptersForVersions(configDir, marketplaceName, versions) {
|
|
195
230
|
const root = pluginCacheRoot(configDir, marketplaceName);
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
231
|
+
return normalizeHookCacheVersions(versions)
|
|
232
|
+
.map((version) => path.join(root, version, HOOK_ADAPTER_RELATIVE));
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function listCachedHookAdapters(configDir, marketplaceName, manifest = null) {
|
|
236
|
+
return hookAdaptersForVersions(
|
|
237
|
+
configDir,
|
|
238
|
+
marketplaceName,
|
|
239
|
+
listKnownHookCacheVersions(configDir, marketplaceName, manifest),
|
|
240
|
+
);
|
|
202
241
|
}
|
|
203
242
|
|
|
204
243
|
function hookForwarder(target) {
|
|
@@ -211,6 +250,20 @@ runpy.run_path(${JSON.stringify(path.resolve(target))}, run_name="__main__")
|
|
|
211
250
|
`;
|
|
212
251
|
}
|
|
213
252
|
|
|
253
|
+
function prepareHookAdapterPath(file) {
|
|
254
|
+
const versionRoot = path.dirname(path.dirname(path.dirname(file)));
|
|
255
|
+
try {
|
|
256
|
+
const stat = fs.lstatSync(versionRoot);
|
|
257
|
+
if (stat.isSymbolicLink()) {
|
|
258
|
+
fs.unlinkSync(versionRoot);
|
|
259
|
+
} else if (!stat.isDirectory()) {
|
|
260
|
+
throw new Error(`Codex plugin cache version is not a directory: ${versionRoot}`);
|
|
261
|
+
}
|
|
262
|
+
} catch (error) {
|
|
263
|
+
if (error.code !== 'ENOENT') throw error;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
214
267
|
function restoreCachedHookAdapters(previousAdapters, target) {
|
|
215
268
|
const resolvedTarget = path.resolve(target);
|
|
216
269
|
if (!fs.existsSync(resolvedTarget)) {
|
|
@@ -219,6 +272,7 @@ function restoreCachedHookAdapters(previousAdapters, target) {
|
|
|
219
272
|
const restored = [];
|
|
220
273
|
for (const previous of previousAdapters) {
|
|
221
274
|
if (path.resolve(previous) === resolvedTarget || fs.existsSync(previous)) continue;
|
|
275
|
+
prepareHookAdapterPath(previous);
|
|
222
276
|
writeAtomic(previous, hookForwarder(resolvedTarget));
|
|
223
277
|
restored.push(previous);
|
|
224
278
|
}
|
|
@@ -239,6 +293,7 @@ function writeRuntimeManifest(configDir, data) {
|
|
|
239
293
|
plugin: data.plugin,
|
|
240
294
|
marketplace: data.marketplace,
|
|
241
295
|
agents: data.agents,
|
|
296
|
+
hook_cache_versions: data.hookCacheVersions,
|
|
242
297
|
}, null, 2) + '\n');
|
|
243
298
|
return file;
|
|
244
299
|
}
|
|
@@ -250,20 +305,25 @@ function install(ctx = {}) {
|
|
|
250
305
|
const marketplaceFile = resolveMarketplaceFile(ctx);
|
|
251
306
|
ensureDir(configDir);
|
|
252
307
|
|
|
308
|
+
const previousManifest = readRuntimeManifest(configDir);
|
|
253
309
|
const legacy = cleanupLegacyConfig(configDir);
|
|
254
310
|
const plugin = buildPlugin({ repoRoot, pluginRoot });
|
|
255
311
|
const agents = installAgents({ repoRoot, configDir });
|
|
256
312
|
const marketplace = upsertMarketplace(marketplaceFile);
|
|
257
|
-
const
|
|
258
|
-
|
|
259
|
-
marketplace
|
|
260
|
-
|
|
261
|
-
|
|
313
|
+
const previousVersions = listKnownHookCacheVersions(
|
|
314
|
+
configDir,
|
|
315
|
+
marketplace.name,
|
|
316
|
+
previousManifest,
|
|
317
|
+
);
|
|
262
318
|
|
|
263
319
|
let registration = null;
|
|
264
320
|
let hookCompatibility = null;
|
|
265
321
|
if (shouldRunPluginCli(ctx)) {
|
|
266
|
-
const previousAdapters =
|
|
322
|
+
const previousAdapters = hookAdaptersForVersions(
|
|
323
|
+
configDir,
|
|
324
|
+
marketplace.name,
|
|
325
|
+
previousVersions,
|
|
326
|
+
);
|
|
267
327
|
try {
|
|
268
328
|
registration = runPluginCli('add', marketplace.name, ctx);
|
|
269
329
|
} catch (registrationError) {
|
|
@@ -285,6 +345,16 @@ function install(ctx = {}) {
|
|
|
285
345
|
currentHookAdapter(configDir, marketplace.name, plugin),
|
|
286
346
|
);
|
|
287
347
|
}
|
|
348
|
+
const hookCacheVersions = normalizeHookCacheVersions([
|
|
349
|
+
...previousVersions,
|
|
350
|
+
plugin.version,
|
|
351
|
+
]);
|
|
352
|
+
const manifestFile = writeRuntimeManifest(configDir, {
|
|
353
|
+
plugin: { root: plugin.root, version: plugin.version },
|
|
354
|
+
marketplace: { file: marketplace.file, name: marketplace.name },
|
|
355
|
+
agents: agents.installed,
|
|
356
|
+
hookCacheVersions,
|
|
357
|
+
});
|
|
288
358
|
|
|
289
359
|
return {
|
|
290
360
|
target: configDir,
|
|
@@ -379,7 +449,9 @@ module.exports = {
|
|
|
379
449
|
removeMarketplaceEntry,
|
|
380
450
|
runPluginCli,
|
|
381
451
|
pluginCacheRoot,
|
|
452
|
+
listKnownHookCacheVersions,
|
|
382
453
|
listCachedHookAdapters,
|
|
454
|
+
prepareHookAdapterPath,
|
|
383
455
|
restoreCachedHookAdapters,
|
|
384
456
|
},
|
|
385
457
|
};
|
package/agents/tdd-runner.md
CHANGED
|
@@ -86,7 +86,8 @@ Scan test files for forbidden patterns:
|
|
|
86
86
|
ALL PASS / X FAILURES NEED ATTENTION
|
|
87
87
|
```
|
|
88
88
|
|
|
89
|
-
##
|
|
89
|
+
## Handoff
|
|
90
90
|
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
Return reusable test patterns, common failure causes, and framework quirks to the
|
|
92
|
+
parent agent as explicit evidence. Do not create or update a private Ultra memory
|
|
93
|
+
store; persistent memory belongs to the host's separately installed provider.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ultra-builder-pro-cli",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.3",
|
|
4
4
|
"description": "Multi-runtime installer for the Ultra Builder Pro agent engineering system — deploys commands, agents, skills, hooks, and MCP server to Claude Code, OpenCode, Codex CLI, and Gemini CLI.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"ultra-builder-pro-cli": "bin/install.js",
|