@unblocklabs/unblock-codex-prompt 0.2.2 → 0.2.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/README.md +18 -6
- package/dist/adapter.js +66 -15
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Unblock Codex Prompt
|
|
2
2
|
|
|
3
3
|
A small, explicit prompt-management bridge for dedicated OpenClaw Mac agents.
|
|
4
|
-
**Version 0.2.
|
|
4
|
+
**Version 0.2.3.** The frozen bridge supports OpenClaw/Codex 2026.9.2 and newer
|
|
5
5
|
stable releases with a compatible context-assembly layout.
|
|
6
6
|
|
|
7
7
|
## What you control
|
|
@@ -29,8 +29,8 @@ files use private permissions. Missing identity documents are recorded as absent
|
|
|
29
29
|
## Compatibility
|
|
30
30
|
|
|
31
31
|
- Frozen bridge: **OpenClaw and @openclaw/codex >=2026.9.2**. Reviewed layouts cover
|
|
32
|
-
2026.9.2, 2026.9.3, 2026.9.4 and 2026.
|
|
33
|
-
`dist/.setup/` bundles. Bundle names
|
|
32
|
+
2026.9.2, 2026.9.3, 2026.9.4, 2026.9.8, 2026.10.6 and 2026.10.8, including parent-local context,
|
|
33
|
+
refreshable instructions and split `dist/.setup/` bundles. Bundle names
|
|
34
34
|
may change; fingerprints of the context-assembly functions must still match.
|
|
35
35
|
Changed assembly is refused pending review, rather than patched blindly.
|
|
36
36
|
- Local stdio Codex with an OpenClaw agent-scoped home. Operator-selected
|
|
@@ -42,8 +42,12 @@ files use private permissions. Missing identity documents are recorded as absent
|
|
|
42
42
|
|
|
43
43
|
This bridge uses two private upstream seams because public prompt hooks cannot
|
|
44
44
|
fix the dropped-context path: one skill-catalog builder and guarded Codex context
|
|
45
|
-
carriers.
|
|
46
|
-
separate thread-level skills append. The
|
|
45
|
+
carriers. Older builds require parent-local suppression and removal of the
|
|
46
|
+
separate thread-level skills append. The 2026.10.6/2026.10.8 recipe suppresses live
|
|
47
|
+
persona, memory and OpenClaw skills at their producers, so initial threads, reuse,
|
|
48
|
+
parent-local inference and compaction all receive the frozen context. Native
|
|
49
|
+
AGENTS and operational context remain live; cron guidance and execution permissions
|
|
50
|
+
are unchanged. The installer backs up and tracks every
|
|
47
51
|
patched bundle; old single-file receipts remain restorable. Runtime module paths
|
|
48
52
|
come from the loader's selected entry, never its temporary execution capture.
|
|
49
53
|
It validates private seams and is not a promise of compatibility with unseen layouts.
|
|
@@ -57,7 +61,7 @@ Remote-node-only skills are not added; this is for dedicated local Mac agents.
|
|
|
57
61
|
npm ci
|
|
58
62
|
npm run preflight
|
|
59
63
|
npm pack
|
|
60
|
-
openclaw plugins install ./unblocklabs-unblock-codex-prompt-0.2.
|
|
64
|
+
openclaw plugins install ./unblocklabs-unblock-codex-prompt-0.2.3.tgz --force --accept-capabilities
|
|
61
65
|
```
|
|
62
66
|
|
|
63
67
|
Include the plugin in `plugins.allow` if applicable, then configure:
|
|
@@ -140,6 +144,14 @@ possible higher-priority Codex config override. An upgrade replacing the adapter
|
|
|
140
144
|
removes the guard; startup status is diagnostic, not a global inference gate.
|
|
141
145
|
Restore before upgrading, then revalidate compatibility before reenrollment.
|
|
142
146
|
|
|
147
|
+
If an upgrade already removed the old package generation, do not run restore
|
|
148
|
+
against replacement files or rewrite receipt paths. Verify that every old target
|
|
149
|
+
is absent and each retained original backup matches its receipt hash, privately
|
|
150
|
+
archive the stale receipt, then install the reviewed adapter against the current
|
|
151
|
+
inspected official package. Keep the frozen snapshot and operator-selected launcher intact
|
|
152
|
+
unless a new snapshot was requested. A source update still requires idle activation
|
|
153
|
+
and fresh-session verification; disk status alone does not prove adoption.
|
|
154
|
+
|
|
143
155
|
### Daily shared-prompt refresh
|
|
144
156
|
|
|
145
157
|
No additional setting is needed beyond an enrolled `promptUrl`. The service checks
|
package/dist/adapter.js
CHANGED
|
@@ -5,7 +5,7 @@ import { readOptional, replaceFile, sha256 } from "./manager.js";
|
|
|
5
5
|
import { openclawRoot } from "./compiler.js";
|
|
6
6
|
import { assertSupportedVersion, MINIMUM_OPENCLAW } from "./compatibility.js";
|
|
7
7
|
const MARKER = "// unblock-codex-prompt bridge v1";
|
|
8
|
-
const BUNDLE_NAME = /^thread-(lifecycle|requests)-[\w-]+\.m?js$/u;
|
|
8
|
+
const BUNDLE_NAME = /^(?:thread-(?:lifecycle|requests|policy)|dynamic-tools|attempt-workspace-context|run-attempt)-[\w-]+\.m?js$/u;
|
|
9
9
|
const HASH = /^[a-f0-9]{64}$/u;
|
|
10
10
|
// Reviewed context carriers, independent of release-specific bundle names.
|
|
11
11
|
const CONTEXT_HASHES = {
|
|
@@ -16,6 +16,17 @@ const CONTEXT_HASHES = {
|
|
|
16
16
|
legacyThread: "703a32a0b18eacd45a9fd3d68c04a13527bdbeaae50a11a6b76768b84b99a9ed",
|
|
17
17
|
thread: "3aa4c414cb449cdb9167e6ed2df9397559176310ce7cff882652bd669ac8cee8",
|
|
18
18
|
};
|
|
19
|
+
// Identical context producers/carriers in the published 2026.10.6 and 2026.10.8 bundles.
|
|
20
|
+
const REFRESHABLE_CONTEXT_HASHES = {
|
|
21
|
+
buildDeveloperInstructions: "4b4054cdd5ce65358508182d65e71a4c742b2e9debfa51eb65c5b4e26d1eb0bb",
|
|
22
|
+
buildCodexWorkspaceBootstrapContext: "91bb36eddcf16741957a775af106ab3226ec02dbbe2576b71675ea6db922c0b9",
|
|
23
|
+
renderCodexSkillsInstructions: "b3b53dccaa80cbd80070f69939909ed7947e5503ab128630a42ed6e255c56039",
|
|
24
|
+
prepareCodexAttemptContext: "5e38fc7a339ef241acfce3fa1dfae8d06d7f2c4106ee0e511108e680e262a67a",
|
|
25
|
+
buildCodexParentLocalInstructions: "d68a84359b515949483f5559f3ab4ef6b43f9b5005d5976f5e1559bb9a9f651b",
|
|
26
|
+
buildCodexThreadConfiguration: "e6994e63d7f408b82ea55a9e9c3e1a87967e13c168d6d72a50a4c16466cca093",
|
|
27
|
+
refreshCodexThreadInstructions: "23068afa77e3286acc06885b7440d6a1b44ede4c93a6e322fbbbcd6df8fb8777",
|
|
28
|
+
restoreCodexThreadInstructionsAfterCompaction: "86d6f792175cfbc604f5408016e00b77ed1f7fbefa33b0210d6fbf8d56a2c0a4",
|
|
29
|
+
};
|
|
19
30
|
function receiptPath(agentDir) { return join(agentDir, "codex-home", ".unblock-codex-prompt-adapter.json"); }
|
|
20
31
|
function receiptFiles(receipt) { return receipt.schema === 1 ? [receipt] : receipt.files; }
|
|
21
32
|
function backupPath(agentDir, file, legacy = false) {
|
|
@@ -57,6 +68,22 @@ function parseReceipt(source) {
|
|
|
57
68
|
return value.schema === 1 ? { schema: 1, packageDir, ...files[0] } : { schema: 2, packageDir, files };
|
|
58
69
|
}
|
|
59
70
|
export async function readReceipt(agentDir) { return parseReceipt(await readOptional(receiptPath(agentDir))); }
|
|
71
|
+
function bridgePrefix(agentDir, agentId, runtimePath) {
|
|
72
|
+
return `${MARKER}
|
|
73
|
+
import { createRequire as unblockPromptCreateRequire } from "node:module";
|
|
74
|
+
const unblockPromptRequire = unblockPromptCreateRequire(import.meta.url);
|
|
75
|
+
function unblockFrozenPolicy(params) {
|
|
76
|
+
const plugins = params.config?.plugins;
|
|
77
|
+
const entry = plugins?.entries?.["unblock-codex-prompt"];
|
|
78
|
+
if (plugins?.enabled === false || entry?.enabled !== true || entry.config?.frozenContext !== true ||
|
|
79
|
+
(Array.isArray(plugins.allow) && !plugins.allow.includes("unblock-codex-prompt"))) return null;
|
|
80
|
+
const target = entry.config?.agentId ?? "main";
|
|
81
|
+
if (params.agentId !== target) return null;
|
|
82
|
+
if (target !== ${JSON.stringify(agentId)}) throw new Error("Frozen bridge target changed; restore and reinstall the adapter");
|
|
83
|
+
return unblockPromptRequire(${JSON.stringify(runtimePath)}).readFrozenPolicy(${JSON.stringify(agentDir)});
|
|
84
|
+
}
|
|
85
|
+
`;
|
|
86
|
+
}
|
|
60
87
|
export function patchAdapterSources(sources, agentDir, agentId, runtimePath) {
|
|
61
88
|
if (sources.some(source => source.includes(MARKER)))
|
|
62
89
|
throw new Error("Unsupported Codex adapter shape: already patched");
|
|
@@ -68,6 +95,9 @@ export function patchAdapterSources(sources, agentDir, agentId, runtimePath) {
|
|
|
68
95
|
throw new Error("Unsupported Codex adapter shape: " + name);
|
|
69
96
|
return matches[0];
|
|
70
97
|
};
|
|
98
|
+
if (functions.some(fn => fn.node.id?.name === "buildCodexWorkspaceBootstrapContext")) {
|
|
99
|
+
return patchRefreshableAdapter(sources, find, bridgePrefix(agentDir, agentId, runtimePath));
|
|
100
|
+
}
|
|
71
101
|
const developer = find("buildDeveloperInstructions");
|
|
72
102
|
const collaboration = find("buildTurnScopedCollaborationInstructions");
|
|
73
103
|
const parent = functions.some(fn => fn.node.id?.name === "buildCodexParentLocalInstructions") ? find("buildCodexParentLocalInstructions") : null;
|
|
@@ -89,20 +119,7 @@ export function patchAdapterSources(sources, agentDir, agentId, runtimePath) {
|
|
|
89
119
|
(thread && thread.bundle !== developer.bundle) ||
|
|
90
120
|
(split ? !thread || fingerprint(thread) !== CONTEXT_HASHES.thread : thread !== null && fingerprint(thread) !== CONTEXT_HASHES.legacyThread))
|
|
91
121
|
throw new Error("Unsupported Codex context assembly; review the changed upstream functions before syncing");
|
|
92
|
-
const prefix =
|
|
93
|
-
import { createRequire as unblockPromptCreateRequire } from "node:module";
|
|
94
|
-
const unblockPromptRequire = unblockPromptCreateRequire(import.meta.url);
|
|
95
|
-
function unblockFrozenPolicy(params) {
|
|
96
|
-
const plugins = params.config?.plugins;
|
|
97
|
-
const entry = plugins?.entries?.["unblock-codex-prompt"];
|
|
98
|
-
if (plugins?.enabled === false || entry?.enabled !== true || entry.config?.frozenContext !== true ||
|
|
99
|
-
(Array.isArray(plugins.allow) && !plugins.allow.includes("unblock-codex-prompt"))) return null;
|
|
100
|
-
const target = entry.config?.agentId ?? "main";
|
|
101
|
-
if (params.agentId !== target) return null;
|
|
102
|
-
if (target !== ${JSON.stringify(agentId)}) throw new Error("Frozen bridge target changed; restore and reinstall the adapter");
|
|
103
|
-
return unblockPromptRequire(${JSON.stringify(runtimePath)}).readFrozenPolicy(${JSON.stringify(agentDir)});
|
|
104
|
-
}
|
|
105
|
-
`;
|
|
122
|
+
const prefix = bridgePrefix(agentDir, agentId, runtimePath);
|
|
106
123
|
const insertions = [
|
|
107
124
|
{ fn: developer, text: '\n\tconst unblockPolicy = unblockFrozenPolicy(params);\n\tif (unblockPolicy !== null) return [unblockPolicy, params.gitCoauthorPrompt, params.extraSystemPrompt].filter(section => typeof section === "string" && section.trim()).join("\\n\\n");' },
|
|
108
125
|
{ fn: collaboration, text: '\n\tif (unblockFrozenPolicy(params) !== null) return params.trigger === "cron" ? buildCronCollaborationInstructions() : buildDefaultCollaborationInstructions();' },
|
|
@@ -119,6 +136,40 @@ function unblockFrozenPolicy(params) {
|
|
|
119
136
|
return edits.length ? prefix + source : source;
|
|
120
137
|
});
|
|
121
138
|
}
|
|
139
|
+
function patchRefreshableAdapter(sources, find, prefix) {
|
|
140
|
+
for (const [name, expected] of Object.entries(REFRESHABLE_CONTEXT_HASHES)) {
|
|
141
|
+
const { node, bundle } = find(name);
|
|
142
|
+
if (sha256(sources[bundle].slice(node.start, node.end)) !== expected) {
|
|
143
|
+
throw new Error("Unsupported Codex context assembly: " + name + "; review the changed upstream function before syncing");
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
const developer = find("buildDeveloperInstructions");
|
|
147
|
+
const skills = find("renderCodexSkillsInstructions");
|
|
148
|
+
const workspace = find("buildCodexWorkspaceBootstrapContext");
|
|
149
|
+
const originalWorkspace = sources[workspace.bundle].slice(workspace.node.start, workspace.node.end)
|
|
150
|
+
.replace("async function buildCodexWorkspaceBootstrapContext", "async function unblockOriginalWorkspaceContext");
|
|
151
|
+
// Suppress at the producers: initial, warm, fork, parent-local and post-compaction
|
|
152
|
+
// carriers all receive the same empty refreshable section. Native AGENTS stays live.
|
|
153
|
+
const wrapper = `async function buildCodexWorkspaceBootstrapContext(params) {
|
|
154
|
+
const policy = unblockFrozenPolicy(params.params);
|
|
155
|
+
const context = await unblockOriginalWorkspaceContext(params);
|
|
156
|
+
return policy === null ? context : { ...context, personaInstructions: undefined, sharedPersonaInstructions: undefined, memoryInstructions: undefined };
|
|
157
|
+
}
|
|
158
|
+
`;
|
|
159
|
+
const edits = [
|
|
160
|
+
{ bundle: developer.bundle, start: developer.node.body.start + 1, end: developer.node.body.start + 1,
|
|
161
|
+
text: '\n\tconst unblockPolicy = unblockFrozenPolicy(params);\n\tif (unblockPolicy !== null) return [unblockPolicy, params.gitCoauthorPrompt, params.extraSystemPrompt].filter(section => typeof section === "string" && section.trim()).join("\\n\\n");' },
|
|
162
|
+
{ bundle: skills.bundle, start: skills.node.body.start + 1, end: skills.node.body.start + 1,
|
|
163
|
+
text: '\n\tif (unblockFrozenPolicy(params.attempt) !== null) return;' },
|
|
164
|
+
{ bundle: workspace.bundle, start: workspace.node.start, end: workspace.node.end, text: wrapper + originalWorkspace },
|
|
165
|
+
];
|
|
166
|
+
return sources.map((source, bundle) => {
|
|
167
|
+
const selected = edits.filter(edit => edit.bundle === bundle).sort((a, b) => b.start - a.start);
|
|
168
|
+
for (const edit of selected)
|
|
169
|
+
source = source.slice(0, edit.start) + edit.text + source.slice(edit.end);
|
|
170
|
+
return selected.length ? prefix + source : source;
|
|
171
|
+
});
|
|
172
|
+
}
|
|
122
173
|
export async function prepareAdapter(agentDir, agentId, suppliedDir, runtimePath) {
|
|
123
174
|
await openclawRoot();
|
|
124
175
|
if (!isAbsolute(runtimePath) || await readOptional(runtimePath) === null)
|
package/openclaw.plugin.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "unblock-codex-prompt",
|
|
3
3
|
"name": "Unblock Codex Prompt",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.3",
|
|
5
5
|
"description": "Maintain an agent-scoped Codex base prompt and its model_instructions_file pointer.",
|
|
6
6
|
"activation": { "onStartup": true },
|
|
7
7
|
"configSchema": {
|