loadout-ai 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/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.3 - 2026-07-17
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- Validate large rollback snapshots in linear, constant-stack time so project-aware activation can safely snapshot large reviewed skills.
|
|
8
|
+
- Preserve strict malformed-base64 rejection without relying on a stack-intensive regular expression.
|
|
9
|
+
- Rewrite every generated Graphify top-level lookup, repair, and optional Gemini install to the reviewed hashed artifact instead of leaving unpinned package fallbacks.
|
|
10
|
+
|
|
3
11
|
## 0.2.2 - 2026-07-17
|
|
4
12
|
|
|
5
13
|
### Fixed
|
package/dist/src/cli.js
CHANGED
|
@@ -262,7 +262,7 @@ async function runSetup(options) {
|
|
|
262
262
|
reader?.close();
|
|
263
263
|
}
|
|
264
264
|
}
|
|
265
|
-
const LOADOUT_VERSION = "0.2.
|
|
265
|
+
const LOADOUT_VERSION = "0.2.3";
|
|
266
266
|
function durableSchedulerLauncher() {
|
|
267
267
|
return [
|
|
268
268
|
join(dirname(process.execPath), process.platform === "win32" ? "npx.cmd" : "npx"),
|
|
@@ -118,7 +118,14 @@ const generatedFilesSchema = z
|
|
|
118
118
|
.object({
|
|
119
119
|
fileExtension: z.string().regex(/^\.[A-Za-z0-9]+$/),
|
|
120
120
|
from: nonControlTextSchema,
|
|
121
|
-
to: nonControlTextSchema.refine((value) =>
|
|
121
|
+
to: nonControlTextSchema.refine((value) => {
|
|
122
|
+
const rendered = [
|
|
123
|
+
"{artifactRequirement}",
|
|
124
|
+
"{artifactUrl}",
|
|
125
|
+
"{artifactSha256}",
|
|
126
|
+
].reduce((current, placeholder) => current.replaceAll(placeholder, ""), value);
|
|
127
|
+
return !/[{}]/u.test(rendered);
|
|
128
|
+
}, "unknown rewrite template variable"),
|
|
122
129
|
mustEliminate: z.boolean(),
|
|
123
130
|
})
|
|
124
131
|
.strict()),
|
|
@@ -306,6 +313,8 @@ export function runtimeArtifactRequirement(recipe) {
|
|
|
306
313
|
export function renderRuntimeRecipeValue(value, recipe) {
|
|
307
314
|
return value
|
|
308
315
|
.replaceAll("{artifactRequirement}", runtimeArtifactRequirement(recipe))
|
|
316
|
+
.replaceAll("{artifactUrl}", recipe.artifactUrl)
|
|
317
|
+
.replaceAll("{artifactSha256}", recipe.artifactSha256)
|
|
309
318
|
.replaceAll("{version}", recipe.version);
|
|
310
319
|
}
|
|
311
320
|
/** Resolve reviewed path segments without ever accepting a recipe-owned root. */
|
|
@@ -162,6 +162,24 @@ export const GRAPHIFY_RECIPE = deepFreeze(parseRuntimeToolRecipe({
|
|
|
162
162
|
to: "--from '{artifactRequirement}'",
|
|
163
163
|
mustEliminate: true,
|
|
164
164
|
},
|
|
165
|
+
{
|
|
166
|
+
fileExtension: ".md",
|
|
167
|
+
from: "install --upgrade graphifyy",
|
|
168
|
+
to: "install '{artifactRequirement}' --exclude-newer 2026-07-17T00:00:00Z",
|
|
169
|
+
mustEliminate: true,
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
fileExtension: ".md",
|
|
173
|
+
from: "pip install graphifyy",
|
|
174
|
+
to: "pip install '{artifactRequirement}'",
|
|
175
|
+
mustEliminate: true,
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
fileExtension: ".md",
|
|
179
|
+
from: "pip install 'graphifyy[gemini]'",
|
|
180
|
+
to: "pip install 'graphifyy[gemini] @ {artifactUrl}#sha256={artifactSha256}'",
|
|
181
|
+
mustEliminate: true,
|
|
182
|
+
},
|
|
165
183
|
],
|
|
166
184
|
},
|
|
167
185
|
guarantees: [
|
|
@@ -169,7 +187,7 @@ export const GRAPHIFY_RECIPE = deepFreeze(parseRuntimeToolRecipe({
|
|
|
169
187
|
"exact top-level wheel URL and SHA-256; dependency uploads bounded by the reviewed cutoff",
|
|
170
188
|
"no API keys or provider credentials inherited by installer subprocesses",
|
|
171
189
|
"agent skill targets and isolated runtime are snapshotted for rollback/removal",
|
|
172
|
-
"generated
|
|
190
|
+
"generated top-level Graphify lookups and repair commands are rewritten to the same pinned artifact",
|
|
173
191
|
],
|
|
174
192
|
}));
|
|
175
193
|
export const REVIEWED_RUNTIME_TOOLS = [GRAPHIFY_RECIPE];
|
|
@@ -205,6 +205,19 @@ export function validateSnapshot(value) {
|
|
|
205
205
|
return value;
|
|
206
206
|
}
|
|
207
207
|
function isCanonicalBase64(value) {
|
|
208
|
-
|
|
209
|
-
|
|
208
|
+
if (value.length % 4 !== 0)
|
|
209
|
+
return false;
|
|
210
|
+
const padding = value.endsWith("==") ? 2 : value.endsWith("=") ? 1 : 0;
|
|
211
|
+
const contentLength = value.length - padding;
|
|
212
|
+
for (let index = 0; index < contentLength; index += 1) {
|
|
213
|
+
const code = value.charCodeAt(index);
|
|
214
|
+
const valid = (code >= 65 && code <= 90) ||
|
|
215
|
+
(code >= 97 && code <= 122) ||
|
|
216
|
+
(code >= 48 && code <= 57) ||
|
|
217
|
+
code === 43 ||
|
|
218
|
+
code === 47;
|
|
219
|
+
if (!valid)
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
return value.slice(contentLength) === "=".repeat(padding);
|
|
210
223
|
}
|