@astrosheep/keiyaku 2.8.2 → 2.8.4
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/build/.tsbuildinfo +1 -1
- package/build/cli/skills-install.js +115 -22
- package/build/core/addressing.js +2 -3
- package/build/core/call.js +10 -10
- package/build/generated/version.js +1 -1
- package/package.json +1 -1
|
@@ -4,10 +4,12 @@ import * as os from "node:os";
|
|
|
4
4
|
import * as path from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
import { FlowError, asMessage } from "../flow-error.js";
|
|
7
|
+
import { VERSION } from "../generated/version.js";
|
|
7
8
|
const MODULE_DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
8
9
|
const PACKAGE_ROOT = path.resolve(MODULE_DIR, "../..");
|
|
9
10
|
const OFFICIAL_SKILLS = ["keiyaku", "keiyaku-akuma"];
|
|
10
11
|
const SKILL_ROOT = path.join(PACKAGE_ROOT, "skills");
|
|
12
|
+
const INSTALL_MARKER = ".keiyaku-skill-owned.json";
|
|
11
13
|
function skillSource(skill) {
|
|
12
14
|
return path.join(SKILL_ROOT, skill);
|
|
13
15
|
}
|
|
@@ -50,6 +52,76 @@ function objectKind(stat) {
|
|
|
50
52
|
return "directory";
|
|
51
53
|
return "other";
|
|
52
54
|
}
|
|
55
|
+
function updateHashField(hash, value) {
|
|
56
|
+
const bytes = typeof value === "string" ? Buffer.from(value, "utf8") : value;
|
|
57
|
+
const length = Buffer.allocUnsafe(4);
|
|
58
|
+
length.writeUInt32BE(bytes.length);
|
|
59
|
+
hash.update(length);
|
|
60
|
+
hash.update(bytes);
|
|
61
|
+
}
|
|
62
|
+
async function contentHash(root) {
|
|
63
|
+
const hash = crypto.createHash("sha256");
|
|
64
|
+
const walk = async (directory, relativeDirectory) => {
|
|
65
|
+
const entries = await fs.readdir(directory, { withFileTypes: true });
|
|
66
|
+
entries.sort((left, right) => Buffer.compare(Buffer.from(left.name, "utf8"), Buffer.from(right.name, "utf8")));
|
|
67
|
+
for (const entry of entries) {
|
|
68
|
+
const relative = relativeDirectory ? `${relativeDirectory}/${entry.name}` : entry.name;
|
|
69
|
+
if (relative === INSTALL_MARKER)
|
|
70
|
+
continue;
|
|
71
|
+
const absolute = path.join(directory, entry.name);
|
|
72
|
+
const stat = await fs.lstat(absolute);
|
|
73
|
+
const kind = stat.isDirectory() ? "directory"
|
|
74
|
+
: stat.isFile() ? "file"
|
|
75
|
+
: stat.isSymbolicLink() ? "symlink"
|
|
76
|
+
: "other";
|
|
77
|
+
updateHashField(hash, kind);
|
|
78
|
+
updateHashField(hash, relative);
|
|
79
|
+
if (kind === "file")
|
|
80
|
+
updateHashField(hash, await fs.readFile(absolute));
|
|
81
|
+
if (kind === "symlink")
|
|
82
|
+
updateHashField(hash, await fs.readlink(absolute));
|
|
83
|
+
if (kind === "other")
|
|
84
|
+
updateHashField(hash, `${stat.mode}:${stat.rdev}`);
|
|
85
|
+
if (kind === "directory")
|
|
86
|
+
await walk(absolute, relative);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
await walk(root, "");
|
|
90
|
+
return hash.digest("hex");
|
|
91
|
+
}
|
|
92
|
+
function validMarker(value, skill) {
|
|
93
|
+
if (!value || typeof value !== "object")
|
|
94
|
+
return false;
|
|
95
|
+
const marker = value;
|
|
96
|
+
return marker.kind === "official-skill-copy"
|
|
97
|
+
&& marker.skill === skill
|
|
98
|
+
&& typeof marker.sourceVersion === "string"
|
|
99
|
+
&& typeof marker.contentHash === "string"
|
|
100
|
+
&& /^[0-9a-f]{64}$/.test(marker.contentHash);
|
|
101
|
+
}
|
|
102
|
+
async function readInstallMarker(target, skill) {
|
|
103
|
+
try {
|
|
104
|
+
const markerPath = path.join(target, INSTALL_MARKER);
|
|
105
|
+
if (!(await fs.lstat(markerPath)).isFile())
|
|
106
|
+
return undefined;
|
|
107
|
+
const marker = JSON.parse(await fs.readFile(markerPath, "utf8"));
|
|
108
|
+
return validMarker(marker, skill) ? marker : undefined;
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
if (isMissing(error) || error instanceof SyntaxError)
|
|
112
|
+
return undefined;
|
|
113
|
+
throw error;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
async function writeInstallMarker(target, skill, hash) {
|
|
117
|
+
const marker = {
|
|
118
|
+
kind: "official-skill-copy",
|
|
119
|
+
skill,
|
|
120
|
+
sourceVersion: VERSION,
|
|
121
|
+
contentHash: hash,
|
|
122
|
+
};
|
|
123
|
+
await fs.writeFile(path.join(target, INSTALL_MARKER), `${JSON.stringify(marker, null, 2)}\n`, "utf8");
|
|
124
|
+
}
|
|
53
125
|
async function classifyTarget(skill, target, canonicalSource) {
|
|
54
126
|
let stat;
|
|
55
127
|
try {
|
|
@@ -61,21 +133,39 @@ async function classifyTarget(skill, target, canonicalSource) {
|
|
|
61
133
|
throw error;
|
|
62
134
|
}
|
|
63
135
|
const kind = objectKind(stat);
|
|
64
|
-
if (
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
136
|
+
if (stat.isDirectory()) {
|
|
137
|
+
const marker = await readInstallMarker(target, skill);
|
|
138
|
+
if (marker) {
|
|
139
|
+
const installedHash = await contentHash(target);
|
|
140
|
+
if (installedHash === marker.contentHash) {
|
|
141
|
+
const sourceHash = await contentHash(canonicalSource);
|
|
142
|
+
return {
|
|
143
|
+
skill,
|
|
144
|
+
path: target,
|
|
145
|
+
source: canonicalSource,
|
|
146
|
+
kind: "owned",
|
|
147
|
+
needsUpgrade: marker.sourceVersion !== VERSION || marker.contentHash !== sourceHash,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
return {
|
|
151
|
+
skill,
|
|
152
|
+
path: target,
|
|
153
|
+
source: canonicalSource,
|
|
154
|
+
kind: "foreign",
|
|
155
|
+
collisionReason: "modified",
|
|
156
|
+
foreignIdentity: { kind, dev: stat.dev, ino: stat.ino },
|
|
157
|
+
};
|
|
158
|
+
}
|
|
78
159
|
}
|
|
160
|
+
const link = stat.isSymbolicLink() ? await fs.readlink(target) : undefined;
|
|
161
|
+
return {
|
|
162
|
+
skill,
|
|
163
|
+
path: target,
|
|
164
|
+
source: canonicalSource,
|
|
165
|
+
kind: "foreign",
|
|
166
|
+
collisionReason: "foreign",
|
|
167
|
+
foreignIdentity: { kind, dev: stat.dev, ino: stat.ino, link },
|
|
168
|
+
};
|
|
79
169
|
}
|
|
80
170
|
async function ensureParent(parent, createdDirectories) {
|
|
81
171
|
const absentBeforeMutation = [];
|
|
@@ -159,9 +249,8 @@ async function rollbackAndVerify(originalError, states, createdDirectories) {
|
|
|
159
249
|
}
|
|
160
250
|
else if (state.kind === "owned") {
|
|
161
251
|
try {
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
if (link !== state.originalLink || resolved !== state.source) {
|
|
252
|
+
const marker = await readInstallMarker(state.path, state.skill);
|
|
253
|
+
if (!marker || await contentHash(state.path) !== marker.contentHash) {
|
|
165
254
|
failures.push(`owned target changed at ${state.path}`);
|
|
166
255
|
}
|
|
167
256
|
}
|
|
@@ -210,17 +299,21 @@ export async function installOfficialSkills(force = false) {
|
|
|
210
299
|
}
|
|
211
300
|
const collisions = states.filter((state) => state.kind === "foreign");
|
|
212
301
|
if (collisions.length > 0 && !force) {
|
|
213
|
-
|
|
302
|
+
const details = collisions.map((state) => state.collisionReason === "modified"
|
|
303
|
+
? `${state.path} (owned fact exists but copied content was modified)`
|
|
304
|
+
: `${state.path} (foreign target or missing ownership fact)`);
|
|
305
|
+
throw new FlowError("EMPTY_PARAM", `Skill target collision at ${details.join(", ")}. Re-run with -f or --force to replace it.`);
|
|
214
306
|
}
|
|
215
307
|
const createdDirectories = [];
|
|
216
308
|
try {
|
|
217
309
|
for (const state of states) {
|
|
218
|
-
if (state.kind === "owned")
|
|
310
|
+
if (state.kind === "owned" && !state.needsUpgrade)
|
|
219
311
|
continue;
|
|
220
312
|
await ensureParent(path.dirname(state.path), createdDirectories);
|
|
221
313
|
state.temp = siblingArtifact(state.path, "tmp");
|
|
222
|
-
await fs.
|
|
223
|
-
|
|
314
|
+
await fs.cp(state.source, state.temp, { recursive: true, errorOnExist: true, force: false });
|
|
315
|
+
await writeInstallMarker(state.temp, state.skill, await contentHash(state.temp));
|
|
316
|
+
if (state.kind === "foreign" || state.kind === "owned") {
|
|
224
317
|
state.backup = siblingArtifact(state.path, "backup");
|
|
225
318
|
await fs.rename(state.path, state.backup);
|
|
226
319
|
}
|
|
@@ -248,7 +341,7 @@ export async function installOfficialSkills(force = false) {
|
|
|
248
341
|
skill: state.skill,
|
|
249
342
|
path: state.path,
|
|
250
343
|
source: state.source,
|
|
251
|
-
status: state.
|
|
344
|
+
status: state.installed ? "installed" : "owned",
|
|
252
345
|
})),
|
|
253
346
|
warnings,
|
|
254
347
|
};
|
package/build/core/addressing.js
CHANGED
|
@@ -180,10 +180,9 @@ export function buildUncommissionedAddress(input) {
|
|
|
180
180
|
inference: [...(input.inference ?? [])],
|
|
181
181
|
};
|
|
182
182
|
}
|
|
183
|
-
export
|
|
184
|
-
const repo = await resolvedRepository(input.repoCwd);
|
|
183
|
+
export function buildUncommissionedRepositoryAddress(input) {
|
|
185
184
|
return buildUncommissionedAddress({
|
|
186
|
-
repo,
|
|
185
|
+
repo: { kind: "repository", stableRoot: input.stableRoot },
|
|
187
186
|
workdir: input.workdir,
|
|
188
187
|
binding: input.binding,
|
|
189
188
|
inference: input.inference,
|
package/build/core/call.js
CHANGED
|
@@ -18,7 +18,7 @@ import { requireResumableArtifact } from "./transcripts.js";
|
|
|
18
18
|
import { appendDebugBlock } from "../telemetry/debug-log.js";
|
|
19
19
|
import { logInfo } from "../telemetry/logger.js";
|
|
20
20
|
import { SubagentFailure } from "../agents/types.js";
|
|
21
|
-
import { AddressResolutionError, buildResolutionAttempt, buildUncommissionedAddress,
|
|
21
|
+
import { AddressResolutionError, buildResolutionAttempt, buildUncommissionedAddress, buildUncommissionedRepositoryAddress, resolveContractAddress, withResolvedAddress, } from "./addressing.js";
|
|
22
22
|
import { readLedger } from "./ledger.js";
|
|
23
23
|
import { findOpenArcView } from "./arc.js";
|
|
24
24
|
import { deriveContractState, isTerminalState } from "./status.js";
|
|
@@ -159,7 +159,7 @@ async function readCallKeiyakuContext(executionCwd, input) {
|
|
|
159
159
|
address: buildUncommissionedAddress({
|
|
160
160
|
repo: { kind: "user" },
|
|
161
161
|
workdir: executionCwd,
|
|
162
|
-
binding:
|
|
162
|
+
binding: "bare",
|
|
163
163
|
}),
|
|
164
164
|
};
|
|
165
165
|
}
|
|
@@ -176,8 +176,8 @@ async function readCallKeiyakuContext(executionCwd, input) {
|
|
|
176
176
|
historyCwd: ledgerCwd,
|
|
177
177
|
profileCwd: ledgerCwd,
|
|
178
178
|
projectionCwd: ledgerCwd,
|
|
179
|
-
address:
|
|
180
|
-
|
|
179
|
+
address: buildUncommissionedRepositoryAddress({
|
|
180
|
+
stableRoot: ledgerCwd,
|
|
181
181
|
workdir: executionCwd,
|
|
182
182
|
binding: input.reviveBinding.kind,
|
|
183
183
|
}),
|
|
@@ -185,8 +185,8 @@ async function readCallKeiyakuContext(executionCwd, input) {
|
|
|
185
185
|
}
|
|
186
186
|
}
|
|
187
187
|
if (input.bare && input.contractId) {
|
|
188
|
-
const repositoryAddress =
|
|
189
|
-
|
|
188
|
+
const repositoryAddress = buildUncommissionedRepositoryAddress({
|
|
189
|
+
stableRoot: ledgerCwd,
|
|
190
190
|
workdir: executionCwd,
|
|
191
191
|
binding: "bare",
|
|
192
192
|
});
|
|
@@ -209,8 +209,8 @@ async function readCallKeiyakuContext(executionCwd, input) {
|
|
|
209
209
|
historyCwd: ledgerCwd,
|
|
210
210
|
profileCwd: ledgerCwd,
|
|
211
211
|
projectionCwd: ledgerCwd,
|
|
212
|
-
address:
|
|
213
|
-
|
|
212
|
+
address: buildUncommissionedRepositoryAddress({
|
|
213
|
+
stableRoot: ledgerCwd,
|
|
214
214
|
workdir: executionCwd,
|
|
215
215
|
binding: "bare",
|
|
216
216
|
}),
|
|
@@ -250,8 +250,8 @@ async function readCallKeiyakuContext(executionCwd, input) {
|
|
|
250
250
|
historyCwd: ledgerCwd,
|
|
251
251
|
profileCwd: ledgerCwd,
|
|
252
252
|
projectionCwd: ledgerCwd,
|
|
253
|
-
address:
|
|
254
|
-
|
|
253
|
+
address: buildUncommissionedRepositoryAddress({
|
|
254
|
+
stableRoot: ledgerCwd,
|
|
255
255
|
workdir: executionCwd,
|
|
256
256
|
binding: "unbound",
|
|
257
257
|
}),
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Auto-generated by scripts/generate-version.mjs
|
|
2
|
-
export const VERSION = "2.8.
|
|
2
|
+
export const VERSION = "2.8.4";
|