@hasna/skills 0.10.1 → 0.10.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 +46 -9
- package/bin/index.js +470 -160
- package/bin/mcp.js +229 -42
- package/bin/migrate.js +2 -6
- package/bin/server.js +5 -6
- package/bin/worker.js +2 -6
- package/dist/cli/commands/context.d.ts +1 -0
- package/dist/index.js +256 -65
- package/dist/lib/agent-integration.d.ts +2 -0
- package/dist/lib/selection-cache.d.ts +12 -0
- package/dist/lib/session-reconciliation.d.ts +7 -1
- package/dist/sdk/index.js +329 -139
- package/package.json +1 -1
package/bin/index.js
CHANGED
|
@@ -36868,7 +36868,7 @@ var package_default;
|
|
|
36868
36868
|
var init_package = __esm(() => {
|
|
36869
36869
|
package_default = {
|
|
36870
36870
|
name: "@hasna/skills",
|
|
36871
|
-
version: "0.10.
|
|
36871
|
+
version: "0.10.3",
|
|
36872
36872
|
description: "Skills library for AI coding agents",
|
|
36873
36873
|
type: "module",
|
|
36874
36874
|
bin: {
|
|
@@ -49704,7 +49704,9 @@ var init_skill_version = __esm(() => {
|
|
|
49704
49704
|
|
|
49705
49705
|
// src/lib/selection-cache.ts
|
|
49706
49706
|
import { createHash as createHash7, randomUUID as randomUUID3 } from "crypto";
|
|
49707
|
-
import {
|
|
49707
|
+
import { spawnSync as spawnSync2 } from "child_process";
|
|
49708
|
+
import { closeSync as closeSync6, constants as constants4, fstatSync as fstatSync6, fsyncSync, lstatSync as lstatSync9, mkdirSync as mkdirSync3, openSync as openSync6, readFileSync as readFileSync10, readlinkSync as readlinkSync2, readSync as readSync3, renameSync, unlinkSync, writeFileSync as writeFileSync3 } from "fs";
|
|
49709
|
+
import { hostname } from "os";
|
|
49708
49710
|
import { dirname as dirname8, join as join16, parse as parse2, resolve as resolve8 } from "path";
|
|
49709
49711
|
import { isDeepStrictEqual as isDeepStrictEqual2 } from "util";
|
|
49710
49712
|
function selectionCacheRoot(options = {}) {
|
|
@@ -49986,6 +49988,201 @@ function readSkillSessionSnapshot(sessionId, options = {}) {
|
|
|
49986
49988
|
function skillSessionSnapshotBinding(snapshot) {
|
|
49987
49989
|
return { sessionId: snapshot.sessionId, generation: snapshot.generation, receiptSha256: snapshot.receiptSha256 };
|
|
49988
49990
|
}
|
|
49991
|
+
function localBootId() {
|
|
49992
|
+
try {
|
|
49993
|
+
if (process.platform === "linux") {
|
|
49994
|
+
const value = readFileSync10("/proc/sys/kernel/random/boot_id", "utf8").trim();
|
|
49995
|
+
return /^[a-f0-9-]{36}$/i.test(value) ? value : null;
|
|
49996
|
+
}
|
|
49997
|
+
if (process.platform === "darwin") {
|
|
49998
|
+
const result2 = spawnSync2("/usr/sbin/sysctl", ["-n", "kern.boottime"], { encoding: "utf8", timeout: 3000, env: { LC_ALL: "C" } });
|
|
49999
|
+
if (result2.status !== 0 || result2.error)
|
|
50000
|
+
return null;
|
|
50001
|
+
const seconds = /\bsec\s*=\s*(\d+)\b/.exec(result2.stdout)?.[1];
|
|
50002
|
+
return seconds ? `darwin:${seconds}` : null;
|
|
50003
|
+
}
|
|
50004
|
+
} catch {}
|
|
50005
|
+
return null;
|
|
50006
|
+
}
|
|
50007
|
+
function processStart(pid) {
|
|
50008
|
+
if (!Number.isSafeInteger(pid) || pid <= 0)
|
|
50009
|
+
return { state: "unknown" };
|
|
50010
|
+
if (process.platform === "linux") {
|
|
50011
|
+
try {
|
|
50012
|
+
const stat = readFileSync10(`/proc/${pid}/stat`, "utf8");
|
|
50013
|
+
const close = stat.lastIndexOf(")");
|
|
50014
|
+
const start = close < 0 ? undefined : stat.slice(close + 2).trim().split(/\s+/)[19];
|
|
50015
|
+
return start && /^\d+$/.test(start) ? { state: "alive", start: `linux:${start}` } : { state: "unknown" };
|
|
50016
|
+
} catch (error) {
|
|
50017
|
+
return { state: error.code === "ENOENT" ? "absent" : "unknown" };
|
|
50018
|
+
}
|
|
50019
|
+
}
|
|
50020
|
+
if (process.platform === "darwin") {
|
|
50021
|
+
const result2 = spawnSync2("/bin/ps", ["-p", String(pid), "-o", "lstart="], { encoding: "utf8", timeout: 3000, env: { LC_ALL: "C" } });
|
|
50022
|
+
if (result2.error || result2.signal)
|
|
50023
|
+
return { state: "unknown" };
|
|
50024
|
+
const start = result2.stdout.trim();
|
|
50025
|
+
if (result2.status === 1 && !start && !result2.stderr.trim())
|
|
50026
|
+
return { state: "absent" };
|
|
50027
|
+
return result2.status === 0 && start ? { state: "alive", start: `darwin:${start}` } : { state: "unknown" };
|
|
50028
|
+
}
|
|
50029
|
+
return { state: "unknown" };
|
|
50030
|
+
}
|
|
50031
|
+
function localLockIdentity() {
|
|
50032
|
+
const bootId = localBootId(), owner = processStart(process.pid);
|
|
50033
|
+
if (!bootId || owner.state !== "alive")
|
|
50034
|
+
return null;
|
|
50035
|
+
let pidNamespace;
|
|
50036
|
+
if (process.platform === "linux") {
|
|
50037
|
+
try {
|
|
50038
|
+
pidNamespace = readlinkSync2("/proc/self/ns/pid");
|
|
50039
|
+
} catch {
|
|
50040
|
+
return null;
|
|
50041
|
+
}
|
|
50042
|
+
if (!/^pid:\[\d+\]$/.test(pidNamespace))
|
|
50043
|
+
return null;
|
|
50044
|
+
}
|
|
50045
|
+
return { host: hostname(), bootId, pidNamespace, processStart: owner.start };
|
|
50046
|
+
}
|
|
50047
|
+
function readSessionLock(sessionId, options) {
|
|
50048
|
+
const path = `${sessionReceiptPath(sessionId, options)}.write-lock`;
|
|
50049
|
+
const before2 = lstatSync9(path, { throwIfNoEntry: false });
|
|
50050
|
+
if (!before2)
|
|
50051
|
+
return null;
|
|
50052
|
+
if (!before2.isFile() || before2.nlink !== 1 || process.getuid && before2.uid !== process.getuid()) {
|
|
50053
|
+
throw new SkillSelectionError("SESSION_WRITE_LOCKED", "The session lock is not a private regular file; recovery requires review.");
|
|
50054
|
+
}
|
|
50055
|
+
const bytes = readRegularFile(path, SESSION_LOCK_MAX_BYTES);
|
|
50056
|
+
const after2 = lstatSync9(path, { throwIfNoEntry: false });
|
|
50057
|
+
if (!bytes || !after2?.isFile() || before2.dev !== after2.dev || before2.ino !== after2.ino || before2.mtimeMs !== after2.mtimeMs) {
|
|
50058
|
+
throw new SkillSelectionError("SESSION_WRITE_LOCKED", "The session lock changed during inspection; recovery requires review.");
|
|
50059
|
+
}
|
|
50060
|
+
let marker;
|
|
50061
|
+
try {
|
|
50062
|
+
marker = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
|
|
50063
|
+
} catch {
|
|
50064
|
+
throw new SkillSelectionError("SESSION_WRITE_LOCKED", "The session lock is unreadable; recovery requires review.");
|
|
50065
|
+
}
|
|
50066
|
+
if (!marker || ![1, 2].includes(marker.schemaVersion) || marker.sessionId !== sessionId || !/^[a-f0-9-]{36}$/i.test(marker.operationId) || !Number.isSafeInteger(marker.pid) || marker.pid <= 0 || marker.schemaVersion === 2 && (!marker.host || !marker.bootId || !marker.processStart || process.platform === "linux" && !marker.pidNamespace)) {
|
|
50067
|
+
throw new SkillSelectionError("SESSION_WRITE_LOCKED", "The session lock has invalid ownership metadata; recovery requires review.");
|
|
50068
|
+
}
|
|
50069
|
+
return { path, bytes, marker, sha256: sha256Hex(bytes), dev: after2.dev, ino: after2.ino, mtimeMs: after2.mtimeMs };
|
|
50070
|
+
}
|
|
50071
|
+
function writerIsGone(lock, explicitLocalHost) {
|
|
50072
|
+
if (Date.now() - lock.mtimeMs < SESSION_LOCK_MIN_AGE_MS)
|
|
50073
|
+
return false;
|
|
50074
|
+
const owner = processStart(lock.marker.pid);
|
|
50075
|
+
if (owner.state === "unknown")
|
|
50076
|
+
return false;
|
|
50077
|
+
if (lock.marker.schemaVersion === 1)
|
|
50078
|
+
return explicitLocalHost && owner.state === "absent";
|
|
50079
|
+
const local = localLockIdentity();
|
|
50080
|
+
if (!local || lock.marker.host !== local.host || lock.marker.bootId !== local.bootId || lock.marker.pidNamespace !== local.pidNamespace)
|
|
50081
|
+
return false;
|
|
50082
|
+
return owner.state === "absent" || owner.state === "alive" && owner.start !== lock.marker.processStart;
|
|
50083
|
+
}
|
|
50084
|
+
function lockReviewDigest(lock, receipt) {
|
|
50085
|
+
return hash({
|
|
50086
|
+
sessionId: lock.marker.sessionId,
|
|
50087
|
+
lockSha256: lock.sha256,
|
|
50088
|
+
lockDev: lock.dev,
|
|
50089
|
+
lockIno: lock.ino,
|
|
50090
|
+
lockMtimeMs: lock.mtimeMs,
|
|
50091
|
+
receiptSha256: receipt?.sha256 ?? null,
|
|
50092
|
+
receiptGeneration: receipt?.generation ?? null
|
|
50093
|
+
});
|
|
50094
|
+
}
|
|
50095
|
+
function inspectSessionWriteLock(sessionId, options = {}) {
|
|
50096
|
+
const receipt = readSkillSessionSnapshotIfExists(sessionId, options), lock = readSessionLock(sessionId, options);
|
|
50097
|
+
if (!lock)
|
|
50098
|
+
throw new SkillSelectionError("SESSION_WRITE_LOCK_NOT_FOUND", "The session has no write lock to recover.");
|
|
50099
|
+
return {
|
|
50100
|
+
sessionId,
|
|
50101
|
+
schemaVersion: lock.marker.schemaVersion,
|
|
50102
|
+
pid: lock.marker.pid,
|
|
50103
|
+
lockSha256: lock.sha256,
|
|
50104
|
+
lockMtime: new Date(lock.mtimeMs).toISOString(),
|
|
50105
|
+
receiptSha256: receipt?.sha256 ?? null,
|
|
50106
|
+
receiptGeneration: receipt?.generation ?? null,
|
|
50107
|
+
reviewDigest: lockReviewDigest(lock, receipt),
|
|
50108
|
+
hostBound: lock.marker.schemaVersion === 2
|
|
50109
|
+
};
|
|
50110
|
+
}
|
|
50111
|
+
function archiveSessionLock(lock, receipt, explicitLocalHost) {
|
|
50112
|
+
const guardPath = `${lock.path}.recovery-guard`;
|
|
50113
|
+
let guardFd;
|
|
50114
|
+
try {
|
|
50115
|
+
guardFd = openSync6(guardPath, constants4.O_WRONLY | constants4.O_CREAT | constants4.O_EXCL | constants4.O_NOFOLLOW, 384);
|
|
50116
|
+
} catch (error) {
|
|
50117
|
+
if (error.code === "EEXIST")
|
|
50118
|
+
return null;
|
|
50119
|
+
throw error;
|
|
50120
|
+
}
|
|
50121
|
+
const guardStat = fstatSync6(guardFd);
|
|
50122
|
+
try {
|
|
50123
|
+
writeFileSync3(guardFd, `${JSON.stringify({ schemaVersion: 1, pid: process.pid, operationId: randomUUID3() })}
|
|
50124
|
+
`);
|
|
50125
|
+
fsyncSync(guardFd);
|
|
50126
|
+
const cacheOptions = { cacheDir: dirname8(dirname8(lock.path)) };
|
|
50127
|
+
const current = readSessionLock(lock.marker.sessionId, cacheOptions);
|
|
50128
|
+
if (!current || current.dev !== lock.dev || current.ino !== lock.ino || current.sha256 !== lock.sha256 || current.mtimeMs !== lock.mtimeMs || !writerIsGone(current, explicitLocalHost))
|
|
50129
|
+
return null;
|
|
50130
|
+
const currentReceipt = readSkillSessionSnapshotIfExists(lock.marker.sessionId, cacheOptions);
|
|
50131
|
+
if (currentReceipt?.sha256 !== receipt?.sha256 || currentReceipt?.generation !== receipt?.generation)
|
|
50132
|
+
return null;
|
|
50133
|
+
const directory = join16(dirname8(dirname8(lock.path)), "session-lock-recoveries", randomUUID3());
|
|
50134
|
+
const archivePath = join16(directory, "original.write-lock");
|
|
50135
|
+
const recordPath = join16(directory, "recovery.json");
|
|
50136
|
+
assertRegularPath(archivePath, true);
|
|
50137
|
+
archiveBytes(recordPath, Buffer.from(`${JSON.stringify({
|
|
50138
|
+
schemaVersion: 1,
|
|
50139
|
+
sessionId: lock.marker.sessionId,
|
|
50140
|
+
originalPath: lock.path,
|
|
50141
|
+
lockSha256: lock.sha256,
|
|
50142
|
+
lockMtime: new Date(lock.mtimeMs).toISOString(),
|
|
50143
|
+
lockPid: lock.marker.pid,
|
|
50144
|
+
receiptSha256: receipt?.sha256 ?? null,
|
|
50145
|
+
receiptGeneration: receipt?.generation ?? null,
|
|
50146
|
+
status: "prepared"
|
|
50147
|
+
})}
|
|
50148
|
+
`));
|
|
50149
|
+
syncDirectory(directory);
|
|
50150
|
+
syncDirectory(dirname8(directory));
|
|
50151
|
+
const finalLock = readSessionLock(lock.marker.sessionId, cacheOptions);
|
|
50152
|
+
if (!finalLock || finalLock.dev !== lock.dev || finalLock.ino !== lock.ino || finalLock.sha256 !== lock.sha256 || readSkillSessionSnapshotIfExists(lock.marker.sessionId, cacheOptions)?.sha256 !== receipt?.sha256)
|
|
50153
|
+
return null;
|
|
50154
|
+
let moved = false;
|
|
50155
|
+
try {
|
|
50156
|
+
renameSync(lock.path, archivePath);
|
|
50157
|
+
moved = true;
|
|
50158
|
+
syncDirectory(directory);
|
|
50159
|
+
syncDirectory(dirname8(lock.path));
|
|
50160
|
+
if (sha256Hex(readRegularFile(archivePath, SESSION_LOCK_MAX_BYTES)) !== lock.sha256) {
|
|
50161
|
+
throw new Error("Archived lock bytes changed");
|
|
50162
|
+
}
|
|
50163
|
+
} catch (error) {
|
|
50164
|
+
if (moved)
|
|
50165
|
+
throw new SkillSelectionError("SESSION_LOCK_RECOVERY_INCOMPLETE", "The lock moved, but durable recovery could not be confirmed; inspect the preserved recovery directory and session receipt.");
|
|
50166
|
+
throw error;
|
|
50167
|
+
}
|
|
50168
|
+
return archivePath;
|
|
50169
|
+
} finally {
|
|
50170
|
+
closeSync6(guardFd);
|
|
50171
|
+
const current = lstatSync9(guardPath, { throwIfNoEntry: false });
|
|
50172
|
+
if (current?.isFile() && current.dev === guardStat.dev && current.ino === guardStat.ino)
|
|
50173
|
+
unlinkSync(guardPath);
|
|
50174
|
+
}
|
|
50175
|
+
}
|
|
50176
|
+
function recoverSessionWriteLock(sessionId, reviewDigest, options = {}) {
|
|
50177
|
+
const receipt = readSkillSessionSnapshotIfExists(sessionId, options), lock = readSessionLock(sessionId, options);
|
|
50178
|
+
if (!lock || lockReviewDigest(lock, receipt) !== reviewDigest) {
|
|
50179
|
+
throw new SkillSelectionError("SESSION_LOCK_REVIEW_CHANGED", "The lock or receipt changed after review; inspect the session lock again.");
|
|
50180
|
+
}
|
|
50181
|
+
const archivePath = archiveSessionLock(lock, receipt, true);
|
|
50182
|
+
if (!archivePath)
|
|
50183
|
+
throw new SkillSelectionError("SESSION_WRITE_LOCKED", "The lock is live, too recent, or changed during recovery; leave it in place and inspect again.");
|
|
50184
|
+
return archivePath;
|
|
50185
|
+
}
|
|
49989
50186
|
function withSessionWriteLocks(sessionIds, options, action) {
|
|
49990
50187
|
const operationId = randomUUID3();
|
|
49991
50188
|
const locks = [...new Set(sessionIds)].map((sessionId) => ({ sessionId, path: `${sessionReceiptPath(sessionId, options)}.write-lock` })).sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
|
|
@@ -50005,13 +50202,30 @@ function withSessionWriteLocks(sessionIds, options, action) {
|
|
|
50005
50202
|
try {
|
|
50006
50203
|
fd = openSync6(lock.path, constants4.O_WRONLY | constants4.O_CREAT | constants4.O_EXCL | constants4.O_NOFOLLOW, 384);
|
|
50007
50204
|
} catch (error) {
|
|
50008
|
-
if (error.code
|
|
50009
|
-
throw
|
|
50010
|
-
|
|
50205
|
+
if (error.code !== "EEXIST")
|
|
50206
|
+
throw error;
|
|
50207
|
+
try {
|
|
50208
|
+
const stale = readSessionLock(lock.sessionId, options);
|
|
50209
|
+
const receipt = stale && readSkillSessionSnapshotIfExists(lock.sessionId, options);
|
|
50210
|
+
if (stale?.marker.schemaVersion === 2 && writerIsGone(stale, false)) {
|
|
50211
|
+
archiveSessionLock(stale, receipt, false);
|
|
50212
|
+
}
|
|
50213
|
+
} catch (recoveryError) {
|
|
50214
|
+
if (recoveryError instanceof SkillSelectionError && recoveryError.code === "SESSION_LOCK_RECOVERY_INCOMPLETE")
|
|
50215
|
+
throw recoveryError;
|
|
50216
|
+
}
|
|
50217
|
+
try {
|
|
50218
|
+
fd = openSync6(lock.path, constants4.O_WRONLY | constants4.O_CREAT | constants4.O_EXCL | constants4.O_NOFOLLOW, 384);
|
|
50219
|
+
} catch (retryError) {
|
|
50220
|
+
if (retryError.code === "EEXIST")
|
|
50221
|
+
throw new SkillSelectionError("SESSION_WRITE_LOCKED", "Another Skills process owns a required session write lock; retry after it completes. A surviving legacy lock requires explicit recovery review.");
|
|
50222
|
+
throw retryError;
|
|
50223
|
+
}
|
|
50011
50224
|
}
|
|
50012
50225
|
const stat = fstatSync6(fd);
|
|
50013
50226
|
owned.push({ path: lock.path, fd, dev: stat.dev, ino: stat.ino });
|
|
50014
|
-
|
|
50227
|
+
const identity4 = localLockIdentity();
|
|
50228
|
+
writeFileSync3(fd, `${JSON.stringify({ schemaVersion: identity4 ? 2 : 1, operationId, sessionId: lock.sessionId, pid: process.pid, ...identity4 })}
|
|
50015
50229
|
`);
|
|
50016
50230
|
}
|
|
50017
50231
|
return action(assertOwned);
|
|
@@ -50128,7 +50342,7 @@ function replaceSkillSession(expected, replacement, plan, options = {}, beforeCo
|
|
|
50128
50342
|
return { archivePath, receiptPath, beforeSha256: before2.sha256, afterSha256 };
|
|
50129
50343
|
});
|
|
50130
50344
|
}
|
|
50131
|
-
var SkillSelectionError, MAX_CACHED_PROFILE_AGE_MS, SELECTION_LOCK_FILE = "selection.lock.json";
|
|
50345
|
+
var SkillSelectionError, MAX_CACHED_PROFILE_AGE_MS, SELECTION_LOCK_FILE = "selection.lock.json", SESSION_LOCK_MAX_BYTES = 4096, SESSION_LOCK_MIN_AGE_MS = 30000;
|
|
50132
50346
|
var init_selection_cache = __esm(() => {
|
|
50133
50347
|
init_config();
|
|
50134
50348
|
init_skill_bundle();
|
|
@@ -50186,7 +50400,7 @@ function capturePreparationProcess(child, platform2 = process.platform, signalGr
|
|
|
50186
50400
|
}
|
|
50187
50401
|
|
|
50188
50402
|
// src/lib/dependency-preparation.ts
|
|
50189
|
-
import { constants as constants5, closeSync as closeSync7, fstatSync as fstatSync7, lstatSync as lstatSync10, mkdirSync as mkdirSync4, openSync as openSync7, readFileSync as
|
|
50403
|
+
import { constants as constants5, closeSync as closeSync7, fstatSync as fstatSync7, lstatSync as lstatSync10, mkdirSync as mkdirSync4, openSync as openSync7, readFileSync as readFileSync11, readdirSync as readdirSync5, rmdirSync, unlinkSync as unlinkSync2, ftruncateSync, writeSync } from "fs";
|
|
50190
50404
|
import { join as join17 } from "path";
|
|
50191
50405
|
function hasDependencyPreparationMarker(skillPath) {
|
|
50192
50406
|
try {
|
|
@@ -50216,7 +50430,7 @@ function claimPreparation(skillPath) {
|
|
|
50216
50430
|
return;
|
|
50217
50431
|
if (!lstatSync10(state).isFile() || lstatSync10(state).isSymbolicLink() || lstatSync10(state).size > 1024)
|
|
50218
50432
|
return;
|
|
50219
|
-
const previous = JSON.parse(
|
|
50433
|
+
const previous = JSON.parse(readFileSync11(state, "utf8"));
|
|
50220
50434
|
if (previous.version !== 1 || previous.status !== "failed" || Object.keys(previous).length !== 2)
|
|
50221
50435
|
return;
|
|
50222
50436
|
}
|
|
@@ -50436,7 +50650,7 @@ var init_managed_policy = __esm(() => {
|
|
|
50436
50650
|
|
|
50437
50651
|
// src/lib/agent-bridge.ts
|
|
50438
50652
|
import { createHash as createHash8 } from "crypto";
|
|
50439
|
-
import { lstatSync as lstatSync12, readFileSync as
|
|
50653
|
+
import { lstatSync as lstatSync12, readFileSync as readFileSync12, readdirSync as readdirSync6 } from "fs";
|
|
50440
50654
|
import { join as join19 } from "path";
|
|
50441
50655
|
function isOwnedCliBridge(path, expectedPaths) {
|
|
50442
50656
|
if (!expectedPaths.includes(path))
|
|
@@ -50448,7 +50662,7 @@ function isOwnedCliBridge(path, expectedPaths) {
|
|
|
50448
50662
|
return false;
|
|
50449
50663
|
return Object.entries(CLI_BRIDGE_FILES).every(([name, content]) => {
|
|
50450
50664
|
const file = join19(path, name), stat = lstatSync12(file);
|
|
50451
|
-
return stat.isFile() && !stat.isSymbolicLink() && stat.size === Buffer.byteLength(content) &&
|
|
50665
|
+
return stat.isFile() && !stat.isSymbolicLink() && stat.size === Buffer.byteLength(content) && readFileSync12(file, "utf8") === content;
|
|
50452
50666
|
});
|
|
50453
50667
|
} catch {
|
|
50454
50668
|
return false;
|
|
@@ -50822,7 +51036,7 @@ var init_claude_settings_witness = __esm(() => {
|
|
|
50822
51036
|
|
|
50823
51037
|
// src/lib/agent-integration.ts
|
|
50824
51038
|
import { createHash as createHash10, randomUUID as randomUUID5 } from "crypto";
|
|
50825
|
-
import { existsSync as existsSync12, lstatSync as lstatSync14, statSync as statSync7, mkdirSync as mkdirSync5, readFileSync as
|
|
51039
|
+
import { existsSync as existsSync12, lstatSync as lstatSync14, statSync as statSync7, mkdirSync as mkdirSync5, readFileSync as readFileSync13, readdirSync as readdirSync7, opendirSync as opendirSync3, readlinkSync as readlinkSync3, realpathSync as realpathSync3, renameSync as renameSync2, rmdirSync as rmdirSync2, writeFileSync as writeFileSync4, unlinkSync as unlinkSync3, chmodSync, openSync as openSync10, closeSync as closeSync10, fsyncSync as fsyncSync2, fstatSync as fstatSync10, readSync as readSync6, constants as constants8, linkSync } from "fs";
|
|
50826
51040
|
import { dirname as dirname10, join as join20, resolve as resolve10, relative as relative4, isAbsolute as isAbsolute9, sep as sep4 } from "path";
|
|
50827
51041
|
import { homedir as homedir3 } from "os";
|
|
50828
51042
|
function assertSafePath(path) {
|
|
@@ -50842,7 +51056,7 @@ function readRootAlias(home, agent) {
|
|
|
50842
51056
|
const stat = lstatSync14(alias, { throwIfNoEntry: false, bigint: true });
|
|
50843
51057
|
if (!stat?.isSymbolicLink())
|
|
50844
51058
|
throw new Error(`Agent root alias changed after planning: ${alias}`);
|
|
50845
|
-
const link2 =
|
|
51059
|
+
const link2 = readlinkSync3(alias), targetPath = resolve10(dirname10(alias), link2);
|
|
50846
51060
|
assertSafePath(targetPath);
|
|
50847
51061
|
const targetStat = lstatSync14(targetPath, { throwIfNoEntry: false });
|
|
50848
51062
|
if (!targetStat?.isDirectory())
|
|
@@ -50950,7 +51164,7 @@ function parseNativeMigrationTargetManifest(input) {
|
|
|
50950
51164
|
if (!target || typeof target !== "object" || Array.isArray(target))
|
|
50951
51165
|
throw new Error("Invalid native migration target");
|
|
50952
51166
|
const item = target;
|
|
50953
|
-
if (Object.keys(item).some((key) => !["agent", "projectRoot", "path", "treeSha256"].includes(key)) || typeof item.agent !== "string" || typeof item.projectRoot !== "string" || typeof item.path !== "string" || typeof item.treeSha256 !== "string")
|
|
51167
|
+
if (Object.keys(item).some((key) => !["agent", "projectRoot", "path", "treeSha256", "vendor"].includes(key)) || typeof item.agent !== "string" || typeof item.projectRoot !== "string" || typeof item.path !== "string" || typeof item.treeSha256 !== "string" || item.vendor !== undefined && item.vendor !== true)
|
|
50954
51168
|
throw new Error("Invalid native migration target fields");
|
|
50955
51169
|
if (!ROOTS.some(([agent]) => agent === item.agent))
|
|
50956
51170
|
throw new Error(`Unsupported native migration target agent: ${item.agent}`);
|
|
@@ -50969,7 +51183,7 @@ function parseNativeMigrationTargetManifest(input) {
|
|
|
50969
51183
|
if (identities.has(identity4))
|
|
50970
51184
|
throw new Error(`Duplicate native migration target: ${item.path}`);
|
|
50971
51185
|
identities.add(identity4);
|
|
50972
|
-
targets.push({ agent: item.agent, projectRoot, path: normalized, treeSha256: item.treeSha256 });
|
|
51186
|
+
targets.push({ agent: item.agent, projectRoot, path: normalized, treeSha256: item.treeSha256, ...item.vendor === true ? { vendor: true } : {} });
|
|
50973
51187
|
}
|
|
50974
51188
|
return { schema: "hasna.skills-native-migration-targets.v1", targets, digest };
|
|
50975
51189
|
}
|
|
@@ -50997,8 +51211,8 @@ function selectNativeMigrationTargets(inventory, manifest) {
|
|
|
50997
51211
|
if (matches2.length !== 1)
|
|
50998
51212
|
throw new Error(`Native migration target was not found exactly once: ${target.agent} ${target.projectRoot}/${target.path}`);
|
|
50999
51213
|
const entry = matches2[0];
|
|
51000
|
-
if (entry.bridge || entry.system || entry.vendor)
|
|
51001
|
-
throw new Error(`Native migration target is protected or vendor
|
|
51214
|
+
if (entry.bridge || entry.system || entry.vendor !== (target.vendor === true))
|
|
51215
|
+
throw new Error(`Native migration target is protected or vendor classification changed: ${entry.path}`);
|
|
51002
51216
|
if (entry.hash !== target.treeSha256 || treeHash(entry.path) !== target.treeSha256)
|
|
51003
51217
|
throw new Error(`Native migration target changed after review: ${entry.path}`);
|
|
51004
51218
|
selected.push(entry);
|
|
@@ -51021,6 +51235,8 @@ function projectAncestorDirectories(projects) {
|
|
|
51021
51235
|
return [...directories];
|
|
51022
51236
|
}
|
|
51023
51237
|
function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
51238
|
+
if (options.reviewedCacheAlias !== undefined && (!options.includeVendor || !isAbsolute9(options.reviewedCacheAlias) || resolve10(options.reviewedCacheAlias) !== options.reviewedCacheAlias))
|
|
51239
|
+
throw new Error("A reviewed cache alias requires vendor inventory and an exact absolute path");
|
|
51024
51240
|
const aliases = rootAliases(home, options.allowRootAliases);
|
|
51025
51241
|
const selectedAgents = options.agents ? new Set(options.agents) : undefined;
|
|
51026
51242
|
const includesAgent = (agent) => !selectedAgents || selectedAgents.has(agent);
|
|
@@ -51041,14 +51257,22 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
51041
51257
|
if (discoveryPathBytes > 4 * 1024 * 1024)
|
|
51042
51258
|
throw new Error("Native skill discovery metadata limit exceeded");
|
|
51043
51259
|
}
|
|
51044
|
-
|
|
51045
|
-
|
|
51260
|
+
let reviewedCacheAliasFound = false;
|
|
51261
|
+
function verifiedSiblingCacheAlias(path, parent) {
|
|
51262
|
+
const link2 = readlinkSync3(path), target = resolve10(parent, link2);
|
|
51046
51263
|
if (dirname10(target) !== parent || (isAbsolute9(link2) ? link2 !== target : dirname10(link2) !== "."))
|
|
51047
51264
|
return false;
|
|
51048
51265
|
if (!lstatSync14(target, { throwIfNoEntry: false })?.isDirectory())
|
|
51049
51266
|
return false;
|
|
51050
51267
|
const scan = cacheScans.get(target);
|
|
51051
|
-
|
|
51268
|
+
if (!scan?.complete || scan.entries > maxAliasProofEntries)
|
|
51269
|
+
return false;
|
|
51270
|
+
if (scan.hasSkills) {
|
|
51271
|
+
if (path !== options.reviewedCacheAlias)
|
|
51272
|
+
return false;
|
|
51273
|
+
reviewedCacheAliasFound = true;
|
|
51274
|
+
}
|
|
51275
|
+
return true;
|
|
51052
51276
|
}
|
|
51053
51277
|
function visit2(agent, path, vendor = false, depth = 0, pluginCache = false, admitted = false) {
|
|
51054
51278
|
if (!admitted)
|
|
@@ -51071,7 +51295,7 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
51071
51295
|
const marker = join20(path, ".hasna-skills.json");
|
|
51072
51296
|
if (existsSync12(marker)) {
|
|
51073
51297
|
try {
|
|
51074
|
-
managed = JSON.parse(
|
|
51298
|
+
managed = JSON.parse(readFileSync13(marker, "utf8")).managedBy === "@hasna/skills";
|
|
51075
51299
|
} catch {}
|
|
51076
51300
|
}
|
|
51077
51301
|
const bridge = !vendor && isOwnedCliBridge(path, bridgePaths);
|
|
@@ -51105,7 +51329,7 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
51105
51329
|
const child = join20(path, name);
|
|
51106
51330
|
if (isVendor && lstatSync14(child, { throwIfNoEntry: false })?.isSymbolicLink()) {
|
|
51107
51331
|
const target = statSync7(child, { throwIfNoEntry: false });
|
|
51108
|
-
if (target?.isFile() || pluginCache && target?.isDirectory() &&
|
|
51332
|
+
if (target?.isFile() || pluginCache && target?.isDirectory() && verifiedSiblingCacheAlias(child, path)) {
|
|
51109
51333
|
scan.entries++;
|
|
51110
51334
|
continue;
|
|
51111
51335
|
}
|
|
@@ -51139,12 +51363,14 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
51139
51363
|
for (const root of [...options.agentRoots ?? [], ...configured])
|
|
51140
51364
|
if (includesAgent(root.agent))
|
|
51141
51365
|
scanRoot(root.agent, canonicalAgentPath(root.path, aliases), true);
|
|
51366
|
+
if (options.reviewedCacheAlias !== undefined && !reviewedCacheAliasFound)
|
|
51367
|
+
throw new Error("Reviewed cache alias was not an inventoried skill-containing sibling alias");
|
|
51142
51368
|
recheckRootAliases(aliases);
|
|
51143
51369
|
return entries;
|
|
51144
51370
|
}
|
|
51145
51371
|
function readOptional(path) {
|
|
51146
51372
|
assertSafePath(path);
|
|
51147
|
-
return existsSync12(path) ?
|
|
51373
|
+
return existsSync12(path) ? readFileSync13(path, "utf8") : null;
|
|
51148
51374
|
}
|
|
51149
51375
|
function jsonObject(text2, path) {
|
|
51150
51376
|
if (text2 === null)
|
|
@@ -51945,7 +52171,7 @@ import {
|
|
|
51945
52171
|
lstatSync as lstatSync15,
|
|
51946
52172
|
mkdirSync as mkdirSync7,
|
|
51947
52173
|
mkdtempSync,
|
|
51948
|
-
readFileSync as
|
|
52174
|
+
readFileSync as readFileSync14,
|
|
51949
52175
|
readdirSync as readdirSync9,
|
|
51950
52176
|
renameSync as renameSync4,
|
|
51951
52177
|
rmSync as rmSync2,
|
|
@@ -51962,7 +52188,7 @@ function hasSkillsOwnershipMarker(dir) {
|
|
|
51962
52188
|
try {
|
|
51963
52189
|
if (!lstatSync15(path).isFile())
|
|
51964
52190
|
return false;
|
|
51965
|
-
const marker = JSON.parse(
|
|
52191
|
+
const marker = JSON.parse(readFileSync14(path, "utf8"));
|
|
51966
52192
|
return isSkillsOwnershipMarker(marker);
|
|
51967
52193
|
} catch {
|
|
51968
52194
|
return false;
|
|
@@ -52170,7 +52396,7 @@ function writeManagedSkillDir(dir, skillMd, options) {
|
|
|
52170
52396
|
if (dirExists && managed && hasSkillMd && !options.force && isPointerSkillMd(skillMd)) {
|
|
52171
52397
|
let existingIsStub = false;
|
|
52172
52398
|
try {
|
|
52173
|
-
existingIsStub = isPointerSkillMd(
|
|
52399
|
+
existingIsStub = isPointerSkillMd(readFileSync14(skillMdPath, "utf-8"));
|
|
52174
52400
|
} catch {
|
|
52175
52401
|
existingIsStub = false;
|
|
52176
52402
|
}
|
|
@@ -52243,7 +52469,7 @@ function sourceSkillMd(skillPath, name, description, kind, preferBundledDocs = f
|
|
|
52243
52469
|
if (kind === undefined || kind === "instruction" || preferBundledDocs) {
|
|
52244
52470
|
const skillMdPath = join23(skillPath, "SKILL.md");
|
|
52245
52471
|
if (existsSync14(skillMdPath))
|
|
52246
|
-
return
|
|
52472
|
+
return readFileSync14(skillMdPath, "utf-8");
|
|
52247
52473
|
}
|
|
52248
52474
|
return pointerSkillMd(name, description);
|
|
52249
52475
|
}
|
|
@@ -52293,7 +52519,7 @@ var init_skill_aliases = __esm(() => {
|
|
|
52293
52519
|
});
|
|
52294
52520
|
|
|
52295
52521
|
// src/lib/project-state.ts
|
|
52296
|
-
import { existsSync as existsSync15, mkdirSync as mkdirSync8, readFileSync as
|
|
52522
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync8, readFileSync as readFileSync15, writeFileSync as writeFileSync7 } from "fs";
|
|
52297
52523
|
import { join as join25 } from "path";
|
|
52298
52524
|
function getProjectStateDir(targetDir = process.cwd()) {
|
|
52299
52525
|
return join25(targetDir, SKILLS_PROJECT_DIR);
|
|
@@ -52306,7 +52532,7 @@ function loadProjectConfig(targetDir = process.cwd()) {
|
|
|
52306
52532
|
if (!existsSync15(path))
|
|
52307
52533
|
return null;
|
|
52308
52534
|
try {
|
|
52309
|
-
return normalizeProjectConfig(JSON.parse(
|
|
52535
|
+
return normalizeProjectConfig(JSON.parse(readFileSync15(path, "utf-8")));
|
|
52310
52536
|
} catch {
|
|
52311
52537
|
return null;
|
|
52312
52538
|
}
|
|
@@ -52460,7 +52686,7 @@ __export(exports_installer, {
|
|
|
52460
52686
|
AGENT_TARGETS: () => AGENT_TARGETS,
|
|
52461
52687
|
AGENT_LABELS: () => AGENT_LABELS
|
|
52462
52688
|
});
|
|
52463
|
-
import { existsSync as existsSync16, readFileSync as
|
|
52689
|
+
import { existsSync as existsSync16, readFileSync as readFileSync16, rmSync as rmSync3 } from "fs";
|
|
52464
52690
|
import { join as join26 } from "path";
|
|
52465
52691
|
import { homedir as homedir5 } from "os";
|
|
52466
52692
|
function getSkillPath(name) {
|
|
@@ -52559,7 +52785,7 @@ function createLocalSkillManifest(name, generateSkillMd) {
|
|
|
52559
52785
|
let skillMd = "";
|
|
52560
52786
|
const skillMdPath = join26(sourcePath, "SKILL.md");
|
|
52561
52787
|
if (existsSync16(skillMdPath)) {
|
|
52562
|
-
skillMd =
|
|
52788
|
+
skillMd = readFileSync16(skillMdPath, "utf-8");
|
|
52563
52789
|
} else if (generateSkillMd) {
|
|
52564
52790
|
skillMd = generateSkillMd(name) ?? "";
|
|
52565
52791
|
} else {
|
|
@@ -52686,7 +52912,7 @@ function resolveAgentSkillMd(name, generateSkillMd) {
|
|
|
52686
52912
|
const sourcePath = getSkillPath(name);
|
|
52687
52913
|
const skillMdPath = join26(sourcePath, "SKILL.md");
|
|
52688
52914
|
if (existsSync16(skillMdPath))
|
|
52689
|
-
return
|
|
52915
|
+
return readFileSync16(skillMdPath, "utf-8");
|
|
52690
52916
|
if (generateSkillMd)
|
|
52691
52917
|
return generateSkillMd(name);
|
|
52692
52918
|
return generateMinimalSkillMd(name);
|
|
@@ -52742,14 +52968,14 @@ function readBundledSkillVersion(name) {
|
|
|
52742
52968
|
if (!existsSync16(pkgPath))
|
|
52743
52969
|
return "unknown";
|
|
52744
52970
|
try {
|
|
52745
|
-
const pkg = JSON.parse(
|
|
52971
|
+
const pkg = JSON.parse(readFileSync16(pkgPath, "utf-8"));
|
|
52746
52972
|
return pkg.version || "unknown";
|
|
52747
52973
|
} catch {
|
|
52748
52974
|
return "unknown";
|
|
52749
52975
|
}
|
|
52750
52976
|
}
|
|
52751
52977
|
function readFileIfExists(path) {
|
|
52752
|
-
return existsSync16(path) ?
|
|
52978
|
+
return existsSync16(path) ? readFileSync16(path, "utf-8") : null;
|
|
52753
52979
|
}
|
|
52754
52980
|
function loadProjectConfigCompat(targetDir) {
|
|
52755
52981
|
return loadProjectConfig(targetDir);
|
|
@@ -52824,7 +53050,7 @@ __export(exports_skillinfo, {
|
|
|
52824
53050
|
generateEnvExample: () => generateEnvExample,
|
|
52825
53051
|
detectProjectSkills: () => detectProjectSkills
|
|
52826
53052
|
});
|
|
52827
|
-
import { existsSync as existsSync17, readFileSync as
|
|
53053
|
+
import { existsSync as existsSync17, readFileSync as readFileSync17 } from "fs";
|
|
52828
53054
|
import { join as join27 } from "path";
|
|
52829
53055
|
function isInstructionSkillDir(skillPath, meta) {
|
|
52830
53056
|
if (meta?.kind === "instruction")
|
|
@@ -52833,7 +53059,7 @@ function isInstructionSkillDir(skillPath, meta) {
|
|
|
52833
53059
|
if (!existsSync17(skillMdPath))
|
|
52834
53060
|
return false;
|
|
52835
53061
|
try {
|
|
52836
|
-
return parseSkillFrontmatter(
|
|
53062
|
+
return parseSkillFrontmatter(readFileSync17(skillMdPath, "utf-8"))?.kind === "instruction";
|
|
52837
53063
|
} catch {
|
|
52838
53064
|
return false;
|
|
52839
53065
|
}
|
|
@@ -52868,7 +53094,7 @@ function getSkillRequirements(name) {
|
|
|
52868
53094
|
const meta = getSkill(name);
|
|
52869
53095
|
let dependencies = {};
|
|
52870
53096
|
try {
|
|
52871
|
-
dependencies = JSON.parse(
|
|
53097
|
+
dependencies = JSON.parse(readFileSync17(join27(skillPath, "package.json"), "utf8")).dependencies || {};
|
|
52872
53098
|
} catch {}
|
|
52873
53099
|
return getSkillRequirementsFromContent(name, texts, dependencies, meta);
|
|
52874
53100
|
}
|
|
@@ -52957,7 +53183,7 @@ async function runSkill(name, args, options = {}) {
|
|
|
52957
53183
|
}
|
|
52958
53184
|
let entryPoint2;
|
|
52959
53185
|
try {
|
|
52960
|
-
const pkg = JSON.parse(
|
|
53186
|
+
const pkg = JSON.parse(readFileSync17(pkgPath, "utf-8"));
|
|
52961
53187
|
if (pkg.bin) {
|
|
52962
53188
|
const binValues = Object.values(pkg.bin);
|
|
52963
53189
|
entryPoint2 = binValues[0];
|
|
@@ -53002,7 +53228,7 @@ async function runSkill(name, args, options = {}) {
|
|
|
53002
53228
|
function detectProjectSkills(cwd2 = process.cwd()) {
|
|
53003
53229
|
let pkg;
|
|
53004
53230
|
try {
|
|
53005
|
-
pkg = JSON.parse(
|
|
53231
|
+
pkg = JSON.parse(readFileSync17(join27(cwd2, "package.json"), "utf8"));
|
|
53006
53232
|
} catch {
|
|
53007
53233
|
return { detected: [], recommended: [] };
|
|
53008
53234
|
}
|
|
@@ -53088,7 +53314,7 @@ function generateSkillMd(name) {
|
|
|
53088
53314
|
const pkgPath = join27(skillPath, "package.json");
|
|
53089
53315
|
if (existsSync17(pkgPath)) {
|
|
53090
53316
|
try {
|
|
53091
|
-
const pkg = JSON.parse(
|
|
53317
|
+
const pkg = JSON.parse(readFileSync17(pkgPath, "utf-8"));
|
|
53092
53318
|
if (pkg.bin) {
|
|
53093
53319
|
const binKeys = Object.keys(pkg.bin);
|
|
53094
53320
|
if (binKeys.length > 0)
|
|
@@ -53162,7 +53388,7 @@ function extractEnvVars(text2) {
|
|
|
53162
53388
|
function readIfExists(path) {
|
|
53163
53389
|
try {
|
|
53164
53390
|
if (existsSync17(path)) {
|
|
53165
|
-
return
|
|
53391
|
+
return readFileSync17(path, "utf-8");
|
|
53166
53392
|
}
|
|
53167
53393
|
} catch {}
|
|
53168
53394
|
return null;
|
|
@@ -55007,7 +55233,7 @@ var init_codex_hook_discovery_recovery = __esm(() => {
|
|
|
55007
55233
|
|
|
55008
55234
|
// src/lib/agent-discovery.ts
|
|
55009
55235
|
import { createHash as createHash16 } from "crypto";
|
|
55010
|
-
import { lstatSync as lstatSync20, readFileSync as
|
|
55236
|
+
import { lstatSync as lstatSync20, readFileSync as readFileSync18, readdirSync as readdirSync10, realpathSync as realpathSync4 } from "fs";
|
|
55011
55237
|
import { basename as basename8, dirname as dirname16, isAbsolute as isAbsolute15, join as join31, resolve as resolve15, sep as sep5 } from "path";
|
|
55012
55238
|
import { isDeepStrictEqual as isDeepStrictEqual7 } from "util";
|
|
55013
55239
|
function parseConfig(text3, path, toml = false) {
|
|
@@ -55039,7 +55265,7 @@ function read2(path, changes) {
|
|
|
55039
55265
|
return null;
|
|
55040
55266
|
if (!stat2.isFile() || stat2.size > 16 * 1024 * 1024)
|
|
55041
55267
|
throw new Error(`Unsupported or oversized native discovery input: ${path}`);
|
|
55042
|
-
return
|
|
55268
|
+
return readFileSync18(path, "utf8");
|
|
55043
55269
|
}
|
|
55044
55270
|
function projected(source, changes, budget = discoveryByteBudget()) {
|
|
55045
55271
|
if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3") {
|
|
@@ -56087,7 +56313,7 @@ __export(exports_registry, {
|
|
|
56087
56313
|
CATEGORIES: () => CATEGORIES,
|
|
56088
56314
|
BASIC_SKILL_NAMES: () => BASIC_SKILL_NAMES
|
|
56089
56315
|
});
|
|
56090
|
-
import { existsSync as existsSync19, readFileSync as
|
|
56316
|
+
import { existsSync as existsSync19, readFileSync as readFileSync19, readdirSync as readdirSync12 } from "fs";
|
|
56091
56317
|
import { join as join34 } from "path";
|
|
56092
56318
|
function isBasicSkillName(name) {
|
|
56093
56319
|
return BASIC_SKILL_NAMES.includes(name);
|
|
@@ -56137,7 +56363,7 @@ function discoverSkillsInDir(dir, source = "custom") {
|
|
|
56137
56363
|
continue;
|
|
56138
56364
|
let content;
|
|
56139
56365
|
try {
|
|
56140
|
-
content =
|
|
56366
|
+
content = readFileSync19(skillMdPath, "utf-8");
|
|
56141
56367
|
} catch {
|
|
56142
56368
|
continue;
|
|
56143
56369
|
}
|
|
@@ -56174,7 +56400,7 @@ function findExtensionSkillPath(name) {
|
|
|
56174
56400
|
continue;
|
|
56175
56401
|
let content;
|
|
56176
56402
|
try {
|
|
56177
|
-
content =
|
|
56403
|
+
content = readFileSync19(skillMdPath, "utf-8");
|
|
56178
56404
|
} catch {
|
|
56179
56405
|
continue;
|
|
56180
56406
|
}
|
|
@@ -57886,7 +58112,7 @@ var require_cli_spinners = __commonJS((exports, module) => {
|
|
|
57886
58112
|
});
|
|
57887
58113
|
|
|
57888
58114
|
// src/lib/auth-store.ts
|
|
57889
|
-
import { chmodSync as chmodSync2, existsSync as existsSync20, mkdirSync as mkdirSync11, readFileSync as
|
|
58115
|
+
import { chmodSync as chmodSync2, existsSync as existsSync20, mkdirSync as mkdirSync11, readFileSync as readFileSync20, renameSync as renameSync7, statSync as statSync11, unlinkSync as unlinkSync5, writeFileSync as writeFileSync10 } from "fs";
|
|
57890
58116
|
import { basename as basename11, dirname as dirname19, join as join35 } from "path";
|
|
57891
58117
|
function getAuthFilePath(env3 = process.env) {
|
|
57892
58118
|
return skillsCredentialFilePath(env3);
|
|
@@ -57900,7 +58126,7 @@ function getAuthIdentity(env3 = process.env) {
|
|
|
57900
58126
|
}
|
|
57901
58127
|
function readIdentity(env3 = process.env) {
|
|
57902
58128
|
try {
|
|
57903
|
-
const parsed = JSON.parse(
|
|
58129
|
+
const parsed = JSON.parse(readFileSync20(getIdentityFilePath(env3), "utf-8"));
|
|
57904
58130
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
57905
58131
|
return {};
|
|
57906
58132
|
const record2 = parsed;
|
|
@@ -57931,7 +58157,7 @@ function writeCredentialValues(values2, env3 = process.env) {
|
|
|
57931
58157
|
const lines = [];
|
|
57932
58158
|
const written = new Set;
|
|
57933
58159
|
if (existsSync20(file)) {
|
|
57934
|
-
for (const raw of
|
|
58160
|
+
for (const raw of readFileSync20(file, "utf-8").split(/\r?\n/)) {
|
|
57935
58161
|
const match = /^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=/.exec(raw);
|
|
57936
58162
|
const key = match?.[1];
|
|
57937
58163
|
if (key && key in values2) {
|
|
@@ -57969,7 +58195,7 @@ function readCredentialValue(key, env3 = process.env) {
|
|
|
57969
58195
|
if (!existsSync20(file))
|
|
57970
58196
|
return null;
|
|
57971
58197
|
try {
|
|
57972
|
-
for (const raw of
|
|
58198
|
+
for (const raw of readFileSync20(file, "utf-8").split(/\r?\n/)) {
|
|
57973
58199
|
const match = new RegExp(`^\\s*(?:export\\s+)?${key}\\s*=\\s*(.*)$`).exec(raw);
|
|
57974
58200
|
if (!match)
|
|
57975
58201
|
continue;
|
|
@@ -57987,7 +58213,7 @@ function readCredentialValue(key, env3 = process.env) {
|
|
|
57987
58213
|
}
|
|
57988
58214
|
function readIdentityRecord(env3 = process.env) {
|
|
57989
58215
|
try {
|
|
57990
|
-
const parsed = JSON.parse(
|
|
58216
|
+
const parsed = JSON.parse(readFileSync20(getIdentityFilePath(env3), "utf-8"));
|
|
57991
58217
|
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
57992
58218
|
} catch {
|
|
57993
58219
|
return null;
|
|
@@ -60276,7 +60502,7 @@ __export(exports_regexes, {
|
|
|
60276
60502
|
idnEmail: () => idnEmail,
|
|
60277
60503
|
httpProtocol: () => httpProtocol,
|
|
60278
60504
|
html5Email: () => html5Email,
|
|
60279
|
-
hostname: () =>
|
|
60505
|
+
hostname: () => hostname2,
|
|
60280
60506
|
hex: () => hex,
|
|
60281
60507
|
guid: () => guid,
|
|
60282
60508
|
extendedDuration: () => extendedDuration,
|
|
@@ -60336,7 +60562,7 @@ var cuid, cuid2, ulid, xid, ksuid, nanoid, duration, extendedDuration, guid, uui
|
|
|
60336
60562
|
}, uuid42, uuid6, uuid7, email2, html5Email, rfc5322Email, unicodeEmail, idnEmail, browserEmail, _emoji = `^[\\p{Extended_Pictographic}\\p{Emoji_Component}]+$`, ipv4, ipv6, mac = (delimiter) => {
|
|
60337
60563
|
const escapedDelim = escapeRegex(delimiter ?? ":");
|
|
60338
60564
|
return new RegExp(`^(?:[0-9A-F]{2}${escapedDelim}){5}[0-9A-F]{2}$|^(?:[0-9a-f]{2}${escapedDelim}){5}[0-9a-f]{2}$`);
|
|
60339
|
-
}, cidrv4, cidrv6, base64, base64url,
|
|
60565
|
+
}, cidrv4, cidrv6, base64, base64url, hostname2, domain, httpProtocol, e164, creditCard, dateSource = `(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))`, date2, string = (params) => {
|
|
60340
60566
|
const regex2 = params ? `[\\s\\S]{${params?.minimum ?? 0},${params?.maximum ?? ""}}` : `[\\s\\S]*`;
|
|
60341
60567
|
return new RegExp(`^${regex2}$`);
|
|
60342
60568
|
}, bigint, integer, number, boolean, _null, _undefined, lowercase, uppercase, hex, md5_hex, md5_base64, md5_base64url, sha1_hex, sha1_base64, sha1_base64url, sha256_hex, sha256_base64, sha256_base64url, sha384_hex, sha384_base64, sha384_base64url, sha512_hex, sha512_base64, sha512_base64url;
|
|
@@ -60366,7 +60592,7 @@ var init_regexes = __esm(() => {
|
|
|
60366
60592
|
cidrv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/;
|
|
60367
60593
|
base64 = /^$|^(?:[0-9a-zA-Z+/]{4})*(?:(?:[0-9a-zA-Z+/]{2}==)|(?:[0-9a-zA-Z+/]{3}=))?$/;
|
|
60368
60594
|
base64url = /^[A-Za-z0-9_-]*$/;
|
|
60369
|
-
|
|
60595
|
+
hostname2 = /^(?=.{1,253}\.?$)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[-0-9a-zA-Z]{0,61}[0-9a-zA-Z])?)*\.?$/;
|
|
60370
60596
|
domain = /^(?=.{1,253}$)([a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,63}$/;
|
|
60371
60597
|
httpProtocol = /^https?$/;
|
|
60372
60598
|
e164 = /^\+[1-9]\d{6,14}$/;
|
|
@@ -61018,9 +61244,9 @@ function parseURLObject(trimmed, def) {
|
|
|
61018
61244
|
function stripTabAndNewline(value) {
|
|
61019
61245
|
return value.replace(asciiTabOrNewline, "");
|
|
61020
61246
|
}
|
|
61021
|
-
function urlHostnameOk(url,
|
|
61022
|
-
|
|
61023
|
-
return
|
|
61247
|
+
function urlHostnameOk(url, hostname3) {
|
|
61248
|
+
hostname3.lastIndex = 0;
|
|
61249
|
+
return hostname3.test(url.hostname);
|
|
61024
61250
|
}
|
|
61025
61251
|
function urlProtocolOk(url, protocol) {
|
|
61026
61252
|
protocol.lastIndex = 0;
|
|
@@ -75322,7 +75548,7 @@ __export(exports_schemas2, {
|
|
|
75322
75548
|
int: () => int,
|
|
75323
75549
|
instanceof: () => _instanceof,
|
|
75324
75550
|
httpUrl: () => httpUrl,
|
|
75325
|
-
hostname: () =>
|
|
75551
|
+
hostname: () => hostname3,
|
|
75326
75552
|
hex: () => hex2,
|
|
75327
75553
|
hash: () => hash4,
|
|
75328
75554
|
guid: () => guid2,
|
|
@@ -75524,7 +75750,7 @@ function jwt(params) {
|
|
|
75524
75750
|
function stringFormat(format, fnOrRegex, _params = {}) {
|
|
75525
75751
|
return _stringFormat(ZodCustomStringFormat, format, fnOrRegex, _params);
|
|
75526
75752
|
}
|
|
75527
|
-
function
|
|
75753
|
+
function hostname3(_params) {
|
|
75528
75754
|
return _stringFormat(ZodCustomStringFormat, "hostname", exports_regexes.hostname, _params);
|
|
75529
75755
|
}
|
|
75530
75756
|
function hex2(_params) {
|
|
@@ -77788,7 +78014,7 @@ __export(exports_external, {
|
|
|
77788
78014
|
input: () => input,
|
|
77789
78015
|
includes: () => _includes,
|
|
77790
78016
|
httpUrl: () => httpUrl,
|
|
77791
|
-
hostname: () =>
|
|
78017
|
+
hostname: () => hostname3,
|
|
77792
78018
|
hex: () => hex2,
|
|
77793
78019
|
hash: () => hash4,
|
|
77794
78020
|
guid: () => guid2,
|
|
@@ -79916,7 +80142,7 @@ var init_remote_auth = __esm(() => {
|
|
|
79916
80142
|
|
|
79917
80143
|
// src/lib/sign-in.ts
|
|
79918
80144
|
import { createHash as createHash19 } from "crypto";
|
|
79919
|
-
import { chmodSync as chmodSync3, mkdirSync as mkdirSync12, readFileSync as
|
|
80145
|
+
import { chmodSync as chmodSync3, mkdirSync as mkdirSync12, readFileSync as readFileSync21, readdirSync as readdirSync13, renameSync as renameSync8, unlinkSync as unlinkSync6, writeFileSync as writeFileSync11 } from "fs";
|
|
79920
80146
|
import { basename as basename12, dirname as dirname20, join as join36 } from "path";
|
|
79921
80147
|
function isRecord6(value) {
|
|
79922
80148
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
@@ -80092,7 +80318,7 @@ function loadPendingDeviceSignIn(origin, env3 = process.env, now3 = Date.now())
|
|
|
80092
80318
|
let parsed;
|
|
80093
80319
|
try {
|
|
80094
80320
|
path = pendingDeviceSignInPath(origin, env3);
|
|
80095
|
-
parsed = JSON.parse(
|
|
80321
|
+
parsed = JSON.parse(readFileSync21(path, "utf8"));
|
|
80096
80322
|
} catch {
|
|
80097
80323
|
return null;
|
|
80098
80324
|
}
|
|
@@ -80137,7 +80363,7 @@ function pendingDeviceSignInOrigins(env3 = process.env, now3 = Date.now()) {
|
|
|
80137
80363
|
if (!entry.startsWith(`${location.stem}-`) || !/-[0-9a-f]{16}\.json$/.test(entry))
|
|
80138
80364
|
continue;
|
|
80139
80365
|
try {
|
|
80140
|
-
const parsed = JSON.parse(
|
|
80366
|
+
const parsed = JSON.parse(readFileSync21(join36(location.dir, entry), "utf8"));
|
|
80141
80367
|
if (isRecord6(parsed) && typeof parsed.origin === "string" && Number(parsed.expiresAt) > now3 && pendingDeviceSignInPath(parsed.origin, env3) === join36(location.dir, entry))
|
|
80142
80368
|
origins.push(parsed.origin);
|
|
80143
80369
|
} catch {}
|
|
@@ -80811,7 +81037,7 @@ var init_skill_bundles = __esm(() => {
|
|
|
80811
81037
|
});
|
|
80812
81038
|
|
|
80813
81039
|
// src/lib/pull.ts
|
|
80814
|
-
import { existsSync as existsSync21, mkdirSync as mkdirSync13, mkdtempSync as mkdtempSync3, readFileSync as
|
|
81040
|
+
import { existsSync as existsSync21, mkdirSync as mkdirSync13, mkdtempSync as mkdtempSync3, readFileSync as readFileSync23, renameSync as renameSync9, rmSync as rmSync6, writeFileSync as writeFileSync12 } from "fs";
|
|
80815
81041
|
import { dirname as dirname21, join as join37 } from "path";
|
|
80816
81042
|
async function pullSkills(options = {}) {
|
|
80817
81043
|
const client2 = options.client !== undefined ? options.client : await createRemoteSkillsClient();
|
|
@@ -80973,7 +81199,7 @@ function reconcileTombstone(slug2, corpusOptions) {
|
|
|
80973
81199
|
}
|
|
80974
81200
|
function readPullMarker(dir) {
|
|
80975
81201
|
try {
|
|
80976
|
-
return JSON.parse(
|
|
81202
|
+
return JSON.parse(readFileSync23(join37(dir, PULL_MARKER_FILE), "utf-8"));
|
|
80977
81203
|
} catch {
|
|
80978
81204
|
return null;
|
|
80979
81205
|
}
|
|
@@ -81343,6 +81569,7 @@ var init_skill_context = __esm(() => {
|
|
|
81343
81569
|
|
|
81344
81570
|
// src/lib/session-reconciliation.ts
|
|
81345
81571
|
import { createHash as createHash22 } from "crypto";
|
|
81572
|
+
import { isDeepStrictEqual as isDeepStrictEqual8 } from "util";
|
|
81346
81573
|
function exactTimestamp(value) {
|
|
81347
81574
|
const parsed = value === undefined ? Number.NaN : Date.parse(value);
|
|
81348
81575
|
if (!Number.isFinite(parsed) || new Date(parsed).toISOString() !== value) {
|
|
@@ -81375,6 +81602,52 @@ function inspectSkillSession(sessionId, options = {}) {
|
|
|
81375
81602
|
loadedCount: receipt.loaded.length
|
|
81376
81603
|
};
|
|
81377
81604
|
}
|
|
81605
|
+
async function reconcileSkillSessionIfSafe(sessionId, profileId, options = {}) {
|
|
81606
|
+
const snapshot2 = readSkillSessionSnapshotIfExists(sessionId, options);
|
|
81607
|
+
if (!snapshot2)
|
|
81608
|
+
return false;
|
|
81609
|
+
const old = snapshot2.receipt;
|
|
81610
|
+
if (old.profile.profileId !== profileId)
|
|
81611
|
+
throw new SkillSelectionError("PROFILE_LOCK_MISMATCH", "The session is pinned to a different Skills profile.");
|
|
81612
|
+
const now3 = (options.now ?? Date.now)();
|
|
81613
|
+
const age = now3 - Date.parse(old.verifiedAt);
|
|
81614
|
+
if (age >= 0 && age <= MAX_CACHED_PROFILE_AGE_MS)
|
|
81615
|
+
return false;
|
|
81616
|
+
if (age < 0)
|
|
81617
|
+
throw new SkillSelectionError("SESSION_RECONCILIATION_REQUIRED", "The session receipt has a future timestamp; inspect it before changing its pin.");
|
|
81618
|
+
const client2 = options.client ?? await createProfileClient();
|
|
81619
|
+
const target = structuredClone(await client2.resolveProfile(profileId));
|
|
81620
|
+
validateResolvedProfile(target, client2.authority);
|
|
81621
|
+
if (target.profileId !== profileId || target.authority !== old.profile.authority || target.workspaceId !== old.profile.workspaceId) {
|
|
81622
|
+
throw new SkillSelectionError("PROFILE_IDENTITY_MISMATCH", "The authenticated Skills profile does not match this session's profile, authority and workspace.");
|
|
81623
|
+
}
|
|
81624
|
+
const oldByKey = new Map(old.profile.selections.map((selection) => [selectionKey(selection), selection]));
|
|
81625
|
+
const targetBySlug = new Map(target.selections.map((selection) => [selection.slug, selection]));
|
|
81626
|
+
for (const key of old.loaded) {
|
|
81627
|
+
const previous = oldByKey.get(key);
|
|
81628
|
+
const current = targetBySlug.get(previous.slug);
|
|
81629
|
+
if (!current || !isDeepStrictEqual8({ ...previous, profileRevision: target.profileRevision }, current)) {
|
|
81630
|
+
throw new SkillSelectionError("SESSION_RECONCILIATION_REQUIRED", "A loaded Skills selection was removed or changed; review skills sessions reconcile before changing this session's pin.");
|
|
81631
|
+
}
|
|
81632
|
+
}
|
|
81633
|
+
const replacement = {
|
|
81634
|
+
...old,
|
|
81635
|
+
generation: nextSkillSessionGeneration(snapshot2.generation),
|
|
81636
|
+
verifiedAt: new Date((options.now ?? Date.now)()).toISOString(),
|
|
81637
|
+
profile: target,
|
|
81638
|
+
loaded: [...old.loaded]
|
|
81639
|
+
};
|
|
81640
|
+
replaceSkillSession(skillSessionSnapshotBinding(snapshot2), replacement, {
|
|
81641
|
+
schemaVersion: 1,
|
|
81642
|
+
kind: "managed-hook-safe-reconciliation",
|
|
81643
|
+
sessionId,
|
|
81644
|
+
fromProfileRevision: old.profile.profileRevision,
|
|
81645
|
+
toProfileRevision: target.profileRevision,
|
|
81646
|
+
retainedLoadedCount: old.loaded.length,
|
|
81647
|
+
retiredLoadedCount: 0
|
|
81648
|
+
}, options);
|
|
81649
|
+
return true;
|
|
81650
|
+
}
|
|
81378
81651
|
async function reconcileSkillSession(input2, options = {}) {
|
|
81379
81652
|
if (![input2.fromProfile, input2.fromRevision, input2.selectionProfile, input2.profileRevision].every((value) => typeof value === "string" && value.trim()) || !/^[a-f0-9]{64}$/.test(input2.receiptSha256)) {
|
|
81380
81653
|
throw new SkillSelectionError("INVALID_SESSION_RECONCILIATION", "Name the exact old receipt SHA256, old profile/revision and intended target profile/revision.");
|
|
@@ -81475,7 +81748,25 @@ Receipt SHA256: ${result2.receiptSha256}`);
|
|
|
81475
81748
|
reportContextError(error61, options.json);
|
|
81476
81749
|
}
|
|
81477
81750
|
});
|
|
81478
|
-
sessions.command("
|
|
81751
|
+
sessions.command("recover-lock <id>").option("--apply", "Archive the exact reviewed stale lock", false).option("--review-digest <sha256>", "Exact digest returned by the lock review; required with --apply").option("--confirm-local-host", "Confirm this PID-only legacy lock was created on this host", false).option("--json", "Return lock metadata or recovery result as JSON", false).description("Review a stale session write lock, then archive it without changing the receipt").action(async (id, options) => {
|
|
81752
|
+
try {
|
|
81753
|
+
if (!options.apply) {
|
|
81754
|
+
const result2 = inspectSessionWriteLock(id);
|
|
81755
|
+
await writeCliOutput(options.json ? JSON.stringify(result2) : `Lock for ${JSON.stringify(id)}: PID ${result2.pid}, schema ${result2.schemaVersion}, modified ${result2.lockMtime}.
|
|
81756
|
+
Receipt SHA256: ${result2.receiptSha256}
|
|
81757
|
+
Review digest: ${result2.reviewDigest}`);
|
|
81758
|
+
return;
|
|
81759
|
+
}
|
|
81760
|
+
if (!options.reviewDigest || !/^[a-f0-9]{64}$/.test(options.reviewDigest) || !options.confirmLocalHost) {
|
|
81761
|
+
throw new SkillSelectionError("SESSION_LOCK_REVIEW_REQUIRED", "Apply requires the exact review digest and --confirm-local-host after verifying this lock belongs to this host.");
|
|
81762
|
+
}
|
|
81763
|
+
const archivePath = recoverSessionWriteLock(id, options.reviewDigest);
|
|
81764
|
+
await writeCliOutput(options.json ? JSON.stringify({ sessionId: id, recovered: true, archivePath }) : `Archived the stale lock at ${archivePath}. The session receipt was not changed.`);
|
|
81765
|
+
} catch (error61) {
|
|
81766
|
+
reportContextError(error61, options.json);
|
|
81767
|
+
}
|
|
81768
|
+
});
|
|
81769
|
+
sessions.command("reconcile <id>").requiredOption("--from-profile <id>", "Expected current session profile").requiredOption("--from-revision <revision>", "Expected current session profile revision").requiredOption("--receipt-sha256 <sha256>", "Expected exact current receipt bytes").requiredOption("--selection-profile <id>", "Intended target selection profile").requiredOption("--profile-revision <revision>", "Expected current API target revision").option("--apply", "Archive the old receipt and atomically apply the reviewed plan", false).option("--plan-digest <sha256>", "Exact reviewed plan digest; required with --apply").option("--plan-issued-at <timestamp>", "Exact reviewed plan issuedAt; required with --apply").option("--plan-expires-at <timestamp>", "Exact reviewed plan expiresAt; required with --apply").option("--json", "Return the plan or application receipt as JSON", false).description("Plan an intentional migration of one session pin when loaded selections changed").action(async (id, options) => {
|
|
81479
81770
|
try {
|
|
81480
81771
|
const result2 = await reconcileSkillSession({ ...options, sessionId: id });
|
|
81481
81772
|
await writeCliOutput(options.json ? JSON.stringify(result2) : result2.applied ? `Reconciled ${JSON.stringify(id)} to ${result2.plan.target.profileId} at ${result2.plan.target.profileRevision}.
|
|
@@ -81497,18 +81788,27 @@ Preserved original receipt: ${result2.archivePath}` : `Planned one session recon
|
|
|
81497
81788
|
reportContextError(error61, options.json);
|
|
81498
81789
|
}
|
|
81499
81790
|
});
|
|
81500
|
-
parent.command("context [prompt]").description("Select bounded, versioned skill context for this prompt without running skills").option("--stdin", "Read native hook JSON or a prompt from stdin", false).option("--selection-profile <id>", "Selection profile (separate from the credential --profile)").option("--cached", "Use only an explicitly selected verified cache, at most 24 hours old", false).option("--session <id>", "Keep the same skill versions across this session").option("--restore", "Re-emit loaded session context after compaction or resume", false).option("--max-chars <count>", "Maximum injected characters", "8000").option("--max-skills <count>", "Maximum loaded skills", "3").option("--json", "Return context and selection receipts as JSON", false).action(async (prompt, options) => {
|
|
81791
|
+
parent.command("context [prompt]").description("Select bounded, versioned skill context for this prompt without running skills").option("--stdin", "Read native hook JSON or a prompt from stdin", false).option("--selection-profile <id>", "Selection profile (separate from the credential --profile)").option("--cached", "Use only an explicitly selected verified cache, at most 24 hours old", false).option("--auto-reconcile-safe", "For managed hooks, archive and renew an expired session only when all loaded selections are unchanged", false).option("--session <id>", "Keep the same skill versions across this session").option("--restore", "Re-emit loaded session context after compaction or resume", false).option("--max-chars <count>", "Maximum injected characters", "8000").option("--max-skills <count>", "Maximum loaded skills", "3").option("--json", "Return context and selection receipts as JSON", false).action(async (prompt, options) => {
|
|
81501
81792
|
try {
|
|
81793
|
+
if (options.autoReconcileSafe && !options.cached)
|
|
81794
|
+
throw new SkillSelectionError("INVALID_CONTEXT_INPUT", "--auto-reconcile-safe requires --cached.");
|
|
81502
81795
|
const input2 = options.stdin ? parseSkillContextInput(await readContextStdin()) : { prompt: prompt ?? "" };
|
|
81503
81796
|
input2.profileId = selectedProfileId(options.selectionProfile ?? input2.profileId);
|
|
81504
81797
|
input2.cwd ??= process.cwd();
|
|
81505
81798
|
input2.sessionId = options.session ?? input2.sessionId;
|
|
81506
81799
|
input2.restore ||= options.restore;
|
|
81507
|
-
const
|
|
81508
|
-
|
|
81509
|
-
|
|
81510
|
-
|
|
81511
|
-
})
|
|
81800
|
+
const resolverOptions = { ...contextResolverOptions(options), maxChars: Number(options.maxChars), maxSkills: Number(options.maxSkills) };
|
|
81801
|
+
let result2;
|
|
81802
|
+
try {
|
|
81803
|
+
result2 = await buildSkillContext(input2, resolverOptions);
|
|
81804
|
+
} catch (error61) {
|
|
81805
|
+
if (!options.cached || !options.autoReconcileSafe || !(error61 instanceof SkillSelectionError) || error61.code !== "CACHED_PROFILE_EXPIRED" || !input2.sessionId)
|
|
81806
|
+
throw error61;
|
|
81807
|
+
const sessionId = input2.agentId ? `${input2.sessionId}:${input2.agentId}` : input2.sessionId;
|
|
81808
|
+
if (!await reconcileSkillSessionIfSafe(sessionId, input2.profileId, resolverOptions))
|
|
81809
|
+
throw error61;
|
|
81810
|
+
result2 = await buildSkillContext(input2, resolverOptions);
|
|
81811
|
+
}
|
|
81512
81812
|
await writeCliOutput(options.json ? JSON.stringify(result2) : result2.context);
|
|
81513
81813
|
} catch (error61) {
|
|
81514
81814
|
reportContextError(error61, options.json);
|
|
@@ -81592,13 +81892,13 @@ var init_context = __esm(() => {
|
|
|
81592
81892
|
});
|
|
81593
81893
|
|
|
81594
81894
|
// src/cli/commands/profile-sync.ts
|
|
81595
|
-
import { hostname as
|
|
81895
|
+
import { hostname as hostname4 } from "os";
|
|
81596
81896
|
async function handleProfileSync(options, dependencies = {}) {
|
|
81597
81897
|
try {
|
|
81598
81898
|
const result2 = await syncSelectionProfile(selectedProfileId(options.selectionProfile ?? options.profile), {
|
|
81599
81899
|
...dependencies,
|
|
81600
81900
|
projectDir: options.project ? process.cwd() : dependencies.projectDir,
|
|
81601
|
-
stationId: options.stationReport === false ? undefined : options.station ?? dependencies.stationId ?? process.env.HASNA_STATION ??
|
|
81901
|
+
stationId: options.stationReport === false ? undefined : options.station ?? dependencies.stationId ?? process.env.HASNA_STATION ?? hostname4(),
|
|
81602
81902
|
check: options.check ?? dependencies.check
|
|
81603
81903
|
});
|
|
81604
81904
|
if (options.json)
|
|
@@ -82326,7 +82626,7 @@ var exports_introspect = {};
|
|
|
82326
82626
|
__export(exports_introspect, {
|
|
82327
82627
|
registerIntrospect: () => registerIntrospect
|
|
82328
82628
|
});
|
|
82329
|
-
import { existsSync as existsSync22, readFileSync as
|
|
82629
|
+
import { existsSync as existsSync22, readFileSync as readFileSync25 } from "fs";
|
|
82330
82630
|
import { join as join38 } from "path";
|
|
82331
82631
|
import { execSync } from "child_process";
|
|
82332
82632
|
function registerIntrospect(parent) {
|
|
@@ -82548,7 +82848,7 @@ function handleDiff(name, options) {
|
|
|
82548
82848
|
present: existsSync22(canonicalSkillMd),
|
|
82549
82849
|
path: canonicalDir,
|
|
82550
82850
|
...existsSync22(canonicalSkillMd) ? { hash: hashSkillMarkdownFile(canonicalSkillMd) } : {},
|
|
82551
|
-
...existsSync22(canonicalSkillMd) ? { stub: isPointerSkillMd(
|
|
82851
|
+
...existsSync22(canonicalSkillMd) ? { stub: isPointerSkillMd(readFileSync25(canonicalSkillMd, "utf-8")) } : {}
|
|
82552
82852
|
};
|
|
82553
82853
|
const pinned = getInstalledSkills().includes(bare);
|
|
82554
82854
|
const installMeta = getInstallMeta();
|
|
@@ -82557,7 +82857,7 @@ function handleDiff(name, options) {
|
|
|
82557
82857
|
let registryVersion = "unknown";
|
|
82558
82858
|
if (existsSync22(registryPkgPath)) {
|
|
82559
82859
|
try {
|
|
82560
|
-
registryVersion = JSON.parse(
|
|
82860
|
+
registryVersion = JSON.parse(readFileSync25(registryPkgPath, "utf-8")).version || "unknown";
|
|
82561
82861
|
} catch {}
|
|
82562
82862
|
}
|
|
82563
82863
|
const upToDate = installedVersion === registryVersion;
|
|
@@ -82571,7 +82871,7 @@ function handleDiff(name, options) {
|
|
|
82571
82871
|
let stub;
|
|
82572
82872
|
if (present && existsSync22(skillMdPath)) {
|
|
82573
82873
|
try {
|
|
82574
|
-
stub = isPointerSkillMd(
|
|
82874
|
+
stub = isPointerSkillMd(readFileSync25(skillMdPath, "utf-8"));
|
|
82575
82875
|
} catch {
|
|
82576
82876
|
stub = undefined;
|
|
82577
82877
|
}
|
|
@@ -83109,7 +83409,7 @@ var exports_init = {};
|
|
|
83109
83409
|
__export(exports_init, {
|
|
83110
83410
|
registerSetup: () => registerSetup
|
|
83111
83411
|
});
|
|
83112
|
-
import { existsSync as existsSync23, readFileSync as
|
|
83412
|
+
import { existsSync as existsSync23, readFileSync as readFileSync26, writeFileSync as writeFileSync13, appendFileSync } from "fs";
|
|
83113
83413
|
import { join as join39 } from "path";
|
|
83114
83414
|
function registerSetup(parent) {
|
|
83115
83415
|
parent.command("init").option("--json", "Output as JSON", false).option("--for <agent>", "Detect project type and show MCP registration guidance for agent").option("--scope <scope>", "Deprecated; agent skill-folder installs are disabled", "global").description("Initialize project for pinned skills (.env.example, .gitignore)").action((options) => handleInit(options));
|
|
@@ -83204,7 +83504,7 @@ Use: skills render`));
|
|
|
83204
83504
|
console.log(source_default.dim(" No environment variables detected across pinned skills"));
|
|
83205
83505
|
const gitignorePath = join39(cwd2, ".gitignore");
|
|
83206
83506
|
const gitignoreEntries = [".skills/runs/", ".skills/exports/", ".skills/tmp/"];
|
|
83207
|
-
let gitignoreContent = existsSync23(gitignorePath) ?
|
|
83507
|
+
let gitignoreContent = existsSync23(gitignorePath) ? readFileSync26(gitignorePath, "utf-8") : "";
|
|
83208
83508
|
let gitignoreUpdated = false;
|
|
83209
83509
|
const missingEntries = gitignoreEntries.filter((entry) => !gitignoreContent.includes(entry));
|
|
83210
83510
|
if (missingEntries.length > 0) {
|
|
@@ -83259,7 +83559,7 @@ async function handleImport(file2, options) {
|
|
|
83259
83559
|
process.exitCode = 1;
|
|
83260
83560
|
return;
|
|
83261
83561
|
}
|
|
83262
|
-
raw =
|
|
83562
|
+
raw = readFileSync26(file2, "utf-8");
|
|
83263
83563
|
}
|
|
83264
83564
|
} catch (err) {
|
|
83265
83565
|
const error61 = `Failed to read file: ${err.message}`;
|
|
@@ -83356,7 +83656,7 @@ var init_init = __esm(() => {
|
|
|
83356
83656
|
});
|
|
83357
83657
|
|
|
83358
83658
|
// src/lib/home-adoption.ts
|
|
83359
|
-
import { constants as constants13, closeSync as closeSync15, fstatSync as fstatSync15, lstatSync as lstatSync22, openSync as openSync15, readSync as readSync12, existsSync as existsSync24, mkdirSync as mkdirSync14, readdirSync as readdirSync14, readFileSync as
|
|
83659
|
+
import { constants as constants13, closeSync as closeSync15, fstatSync as fstatSync15, lstatSync as lstatSync22, openSync as openSync15, readSync as readSync12, existsSync as existsSync24, mkdirSync as mkdirSync14, readdirSync as readdirSync14, readFileSync as readFileSync27, rmSync as rmSync7, statSync as statSync12, writeFileSync as writeFileSync14 } from "fs";
|
|
83360
83660
|
import { homedir as homedir8 } from "os";
|
|
83361
83661
|
import { join as join40 } from "path";
|
|
83362
83662
|
function indexCanonicalCorpus(corpusRoot) {
|
|
@@ -83460,7 +83760,7 @@ function appendConflictsLedger(appDir, conflicts) {
|
|
|
83460
83760
|
let ledger = { version: 1, entries: [] };
|
|
83461
83761
|
if (existsSync24(ledgerPath)) {
|
|
83462
83762
|
try {
|
|
83463
|
-
const parsed = JSON.parse(
|
|
83763
|
+
const parsed = JSON.parse(readFileSync27(ledgerPath, "utf-8"));
|
|
83464
83764
|
if (parsed && typeof parsed === "object" && Array.isArray(parsed.entries)) {
|
|
83465
83765
|
ledger = parsed;
|
|
83466
83766
|
}
|
|
@@ -83609,7 +83909,7 @@ var init_home_adoption = __esm(() => {
|
|
|
83609
83909
|
});
|
|
83610
83910
|
|
|
83611
83911
|
// src/lib/home-census.ts
|
|
83612
|
-
import { existsSync as existsSync25, readFileSync as
|
|
83912
|
+
import { existsSync as existsSync25, readFileSync as readFileSync28, readdirSync as readdirSync15, statSync as statSync13 } from "fs";
|
|
83613
83913
|
import { homedir as homedir9 } from "os";
|
|
83614
83914
|
import { join as join41 } from "path";
|
|
83615
83915
|
function sortEntries(entries) {
|
|
@@ -83680,14 +83980,14 @@ function censusHomeDrift(options = {}) {
|
|
|
83680
83980
|
if (homeHash !== canonicalHash) {
|
|
83681
83981
|
let homeStub;
|
|
83682
83982
|
try {
|
|
83683
|
-
homeStub = isPointerSkillMd(
|
|
83983
|
+
homeStub = isPointerSkillMd(readFileSync28(skillMdPath, "utf-8"));
|
|
83684
83984
|
} catch {
|
|
83685
83985
|
homeStub = undefined;
|
|
83686
83986
|
}
|
|
83687
83987
|
let canonicalStub;
|
|
83688
83988
|
const canonicalSkillMd = join41(corpusRoot, skill, "SKILL.md");
|
|
83689
83989
|
try {
|
|
83690
|
-
canonicalStub = isPointerSkillMd(
|
|
83990
|
+
canonicalStub = isPointerSkillMd(readFileSync28(canonicalSkillMd, "utf-8"));
|
|
83691
83991
|
} catch {
|
|
83692
83992
|
canonicalStub = undefined;
|
|
83693
83993
|
}
|
|
@@ -83725,7 +84025,7 @@ var init_home_census = __esm(() => {
|
|
|
83725
84025
|
});
|
|
83726
84026
|
|
|
83727
84027
|
// src/cli/env-assignment.ts
|
|
83728
|
-
import { closeSync as closeSync16, constants as constants14, fstatSync as fstatSync16, ftruncateSync as ftruncateSync2, lstatSync as lstatSync23, openSync as openSync16, readFileSync as
|
|
84028
|
+
import { closeSync as closeSync16, constants as constants14, fstatSync as fstatSync16, ftruncateSync as ftruncateSync2, lstatSync as lstatSync23, openSync as openSync16, readFileSync as readFileSync29, writeSync as writeSync3 } from "fs";
|
|
83729
84029
|
function serializeValue(value) {
|
|
83730
84030
|
if (controls.test(value))
|
|
83731
84031
|
throw new EnvAssignmentError("Environment values cannot contain control characters or newlines.");
|
|
@@ -83820,7 +84120,7 @@ function setEnvAssignment(path, assignment) {
|
|
|
83820
84120
|
}
|
|
83821
84121
|
let prepared = initial2;
|
|
83822
84122
|
if (previous) {
|
|
83823
|
-
const original =
|
|
84123
|
+
const original = readFileSync29(descriptor), text4 = original.toString("utf8");
|
|
83824
84124
|
if (!Buffer.from(text4, "utf8").equals(original))
|
|
83825
84125
|
throw new EnvAssignmentError(INVALID_LAYOUT);
|
|
83826
84126
|
prepared = prepareEnvAssignment(assignment, text4);
|
|
@@ -83907,7 +84207,7 @@ var exports_diagnostic = {};
|
|
|
83907
84207
|
__export(exports_diagnostic, {
|
|
83908
84208
|
registerDiagnostic: () => registerDiagnostic
|
|
83909
84209
|
});
|
|
83910
|
-
import { existsSync as existsSync26, readFileSync as
|
|
84210
|
+
import { existsSync as existsSync26, readFileSync as readFileSync30, readdirSync as readdirSync16, statSync as statSync14 } from "fs";
|
|
83911
84211
|
import { join as join42 } from "path";
|
|
83912
84212
|
import { execSync as execSync2 } from "child_process";
|
|
83913
84213
|
function registerDiagnostic(parent) {
|
|
@@ -84148,7 +84448,7 @@ function handleOutdated(options) {
|
|
|
84148
84448
|
let registryVersion = "unknown";
|
|
84149
84449
|
if (existsSync26(registryPkgPath))
|
|
84150
84450
|
try {
|
|
84151
|
-
registryVersion = JSON.parse(
|
|
84451
|
+
registryVersion = JSON.parse(readFileSync30(registryPkgPath, "utf-8")).version || "unknown";
|
|
84152
84452
|
} catch {}
|
|
84153
84453
|
if (installedVersion !== registryVersion)
|
|
84154
84454
|
pins.push({ skill: name, installedVersion, registryVersion });
|
|
@@ -84358,8 +84658,8 @@ var init_cloud_executions = __esm(() => {
|
|
|
84358
84658
|
|
|
84359
84659
|
// node_modules/@hasna/secrets/dist/sdk.js
|
|
84360
84660
|
import { isIP as isIP3 } from "net";
|
|
84361
|
-
import { spawnSync as
|
|
84362
|
-
import { closeSync as closeSync17, fstatSync as fstatSync17, openSync as openSync17, readFileSync as
|
|
84661
|
+
import { spawnSync as spawnSync3 } from "child_process";
|
|
84662
|
+
import { closeSync as closeSync17, fstatSync as fstatSync17, openSync as openSync17, readFileSync as readFileSync31 } from "fs";
|
|
84363
84663
|
import { O_NOFOLLOW as O_NOFOLLOW3, O_NONBLOCK as O_NONBLOCK3, O_RDONLY as O_RDONLY3 } from "constants";
|
|
84364
84664
|
import { createRequire as createRequire2 } from "module";
|
|
84365
84665
|
import { hostname as osHostname2 } from "os";
|
|
@@ -84485,7 +84785,7 @@ function readAppConfigFile2(path) {
|
|
|
84485
84785
|
unsafe("the file is not owned by the current user");
|
|
84486
84786
|
if (before2.size > MAX_CREDENTIAL_FILE_BYTES2)
|
|
84487
84787
|
unsafe("the file exceeds the size limit");
|
|
84488
|
-
const bytes =
|
|
84788
|
+
const bytes = readFileSync31(fd);
|
|
84489
84789
|
const after2 = fstatSync17(fd);
|
|
84490
84790
|
if (!configFileReadsCoherent2(before2, after2)) {
|
|
84491
84791
|
unsafe("the file changed while being read");
|
|
@@ -84633,7 +84933,7 @@ function isAmbientEnvironment2(env3) {
|
|
|
84633
84933
|
return env3 === process.env || env3[AMBIENT_ENVIRONMENT2] === true;
|
|
84634
84934
|
}
|
|
84635
84935
|
function defaultKeychainRunner2(argv) {
|
|
84636
|
-
const result2 =
|
|
84936
|
+
const result2 = spawnSync3(KEYCHAIN_SECURITY_BIN2, [...argv], {
|
|
84637
84937
|
encoding: "utf8",
|
|
84638
84938
|
stdio: ["ignore", "pipe", "pipe"],
|
|
84639
84939
|
timeout: KEYCHAIN_SPAWN_TIMEOUT_MS2
|
|
@@ -85926,7 +86226,7 @@ var init_execution_grants = __esm(() => {
|
|
|
85926
86226
|
});
|
|
85927
86227
|
|
|
85928
86228
|
// src/lib/execution-grant-client.ts
|
|
85929
|
-
import { isDeepStrictEqual as
|
|
86229
|
+
import { isDeepStrictEqual as isDeepStrictEqual9 } from "util";
|
|
85930
86230
|
function id(value) {
|
|
85931
86231
|
if (!grantIdentifier(value))
|
|
85932
86232
|
throw new Error("Invalid execution grant profile or revision identifier.");
|
|
@@ -85978,7 +86278,7 @@ async function saveExecutionGrantPolicy(profileId, grants, revision) {
|
|
|
85978
86278
|
headers: revision === undefined ? { "If-None-Match": "*" } : { "If-Match": `"${revision}"` },
|
|
85979
86279
|
body: JSON.stringify({ grants: snapshot2 })
|
|
85980
86280
|
}));
|
|
85981
|
-
if (policy.profileId !== profileId || policy.previousRevision !== (revision ?? null) || !
|
|
86281
|
+
if (policy.profileId !== profileId || policy.previousRevision !== (revision ?? null) || !isDeepStrictEqual9(policy.grants, snapshot2)) {
|
|
85982
86282
|
throw new Error("The API did not preserve the reviewed execution grant policy; read it before retrying.");
|
|
85983
86283
|
}
|
|
85984
86284
|
return policy;
|
|
@@ -85989,7 +86289,7 @@ async function resolveExecutionGrant(input2) {
|
|
|
85989
86289
|
if (!grantRecord(value) || Object.keys(value).length !== 3 || !grantIdentifier(value.policyRevision) || !grantIdentifier(value.grantId) || !grantRecord(value.bindings)) {
|
|
85990
86290
|
throw new SkillSelectionError("INVALID_EXECUTION_GRANT", "The Skills API returned an invalid execution grant.");
|
|
85991
86291
|
}
|
|
85992
|
-
if (!
|
|
86292
|
+
if (!isDeepStrictEqual9(value.bindings.selection, snapshot2.selection) || !isDeepStrictEqual9(value.bindings.consumer, snapshot2.consumer)) {
|
|
85993
86293
|
throw new SkillSelectionError("EXECUTION_GRANT_SCOPE_MISMATCH", "The Skills API returned a grant for a different selection or consumer.");
|
|
85994
86294
|
}
|
|
85995
86295
|
return value;
|
|
@@ -90352,7 +90652,7 @@ var init_runs = __esm(() => {
|
|
|
90352
90652
|
|
|
90353
90653
|
// src/lib/run-state.ts
|
|
90354
90654
|
import { createHash as createHash24, randomBytes } from "crypto";
|
|
90355
|
-
import { existsSync as existsSync27, mkdirSync as mkdirSync16, readFileSync as
|
|
90655
|
+
import { existsSync as existsSync27, mkdirSync as mkdirSync16, readFileSync as readFileSync32, readdirSync as readdirSync17, statSync as statSync15, writeFileSync as writeFileSync16 } from "fs";
|
|
90356
90656
|
import { extname, join as join45, relative as relative6 } from "path";
|
|
90357
90657
|
function createSkillRun(params, targetDir = process.cwd()) {
|
|
90358
90658
|
const now3 = new Date;
|
|
@@ -90424,7 +90724,7 @@ function appendRunEvent(context, event, data = {}) {
|
|
|
90424
90724
|
const line = JSON.stringify({ ts: new Date().toISOString(), event, ...data }) + `
|
|
90425
90725
|
`;
|
|
90426
90726
|
const path = join45(context.runDir, "events.ndjson");
|
|
90427
|
-
const previous = existsSync27(path) ?
|
|
90727
|
+
const previous = existsSync27(path) ? readFileSync32(path, "utf-8") : "";
|
|
90428
90728
|
writeFileSync16(path, previous + line);
|
|
90429
90729
|
}
|
|
90430
90730
|
function listSkillRuns(targetDir = process.cwd(), limit = 50) {
|
|
@@ -90484,7 +90784,7 @@ function collectRunArtifacts(context) {
|
|
|
90484
90784
|
const artifacts = [];
|
|
90485
90785
|
for (const path of walkFiles(context.exportDir)) {
|
|
90486
90786
|
const stat2 = statSync15(path);
|
|
90487
|
-
const bytes =
|
|
90787
|
+
const bytes = readFileSync32(path);
|
|
90488
90788
|
artifacts.push({
|
|
90489
90789
|
path: toProjectRelative(context.targetDir, path),
|
|
90490
90790
|
mime: mimeForPath(path),
|
|
@@ -90499,7 +90799,7 @@ function readRunRecord(runDir) {
|
|
|
90499
90799
|
if (!existsSync27(path))
|
|
90500
90800
|
return null;
|
|
90501
90801
|
try {
|
|
90502
|
-
return JSON.parse(
|
|
90802
|
+
return JSON.parse(readFileSync32(path, "utf-8"));
|
|
90503
90803
|
} catch {
|
|
90504
90804
|
return null;
|
|
90505
90805
|
}
|
|
@@ -102524,7 +102824,7 @@ var init_remote_customer_operations = __esm(() => {
|
|
|
102524
102824
|
});
|
|
102525
102825
|
|
|
102526
102826
|
// src/lib/workspace-profile.ts
|
|
102527
|
-
import { constants as constants16, closeSync as closeSync19, fstatSync as fstatSync19, lstatSync as lstatSync24, mkdirSync as mkdirSync17, mkdtempSync as mkdtempSync5, openSync as openSync19, readFileSync as
|
|
102827
|
+
import { constants as constants16, closeSync as closeSync19, fstatSync as fstatSync19, lstatSync as lstatSync24, mkdirSync as mkdirSync17, mkdtempSync as mkdtempSync5, openSync as openSync19, readFileSync as readFileSync33, renameSync as renameSync10, rmSync as rmSync8, writeFileSync as writeFileSync17 } from "fs";
|
|
102528
102828
|
import { dirname as dirname23, join as join46 } from "path";
|
|
102529
102829
|
function stat2(path) {
|
|
102530
102830
|
try {
|
|
@@ -102543,7 +102843,7 @@ function safeText(file2) {
|
|
|
102543
102843
|
const s = fstatSync19(fd);
|
|
102544
102844
|
if (!s.isFile() || s.size > 65536 || ![256, 384].includes(s.mode & 4095) || process.getuid && s.uid !== process.getuid())
|
|
102545
102845
|
return fail3("The selected profile must use bounded owner-only regular files.");
|
|
102546
|
-
return
|
|
102846
|
+
return readFileSync33(fd, "utf8");
|
|
102547
102847
|
} finally {
|
|
102548
102848
|
closeSync19(fd);
|
|
102549
102849
|
}
|
|
@@ -105421,7 +105721,7 @@ var init_resource_meta_tools = __esm(() => {
|
|
|
105421
105721
|
});
|
|
105422
105722
|
|
|
105423
105723
|
// src/lib/scheduler.ts
|
|
105424
|
-
import { existsSync as existsSync30, readFileSync as
|
|
105724
|
+
import { existsSync as existsSync30, readFileSync as readFileSync34, writeFileSync as writeFileSync19, mkdirSync as mkdirSync20 } from "fs";
|
|
105425
105725
|
import { join as join50 } from "path";
|
|
105426
105726
|
function getSchedulesPath(targetDir = process.cwd()) {
|
|
105427
105727
|
return join50(targetDir, ".skills", "schedules.json");
|
|
@@ -105430,7 +105730,7 @@ function loadSchedules(targetDir = process.cwd()) {
|
|
|
105430
105730
|
const path = getSchedulesPath(targetDir);
|
|
105431
105731
|
if (existsSync30(path)) {
|
|
105432
105732
|
try {
|
|
105433
|
-
return JSON.parse(
|
|
105733
|
+
return JSON.parse(readFileSync34(path, "utf-8"));
|
|
105434
105734
|
} catch {}
|
|
105435
105735
|
}
|
|
105436
105736
|
return { version: 1, schedules: [] };
|
|
@@ -105740,7 +106040,7 @@ import { createHash as createHash25, createHmac as createHmac3 } from "crypto";
|
|
|
105740
106040
|
import {
|
|
105741
106041
|
existsSync as existsSync31,
|
|
105742
106042
|
mkdirSync as mkdirSync21,
|
|
105743
|
-
readFileSync as
|
|
106043
|
+
readFileSync as readFileSync35,
|
|
105744
106044
|
readdirSync as readdirSync19,
|
|
105745
106045
|
statSync as statSync17,
|
|
105746
106046
|
writeFileSync as writeFileSync20
|
|
@@ -105808,7 +106108,7 @@ function exportSkillsLocalSnapshot(targetDir = process.cwd(), options = {}) {
|
|
|
105808
106108
|
const files = [];
|
|
105809
106109
|
if (existsSync31(projectStateDir)) {
|
|
105810
106110
|
for (const filePath of walkFiles2(projectStateDir)) {
|
|
105811
|
-
const bytes =
|
|
106111
|
+
const bytes = readFileSync35(filePath);
|
|
105812
106112
|
const relativePath = toPosix(relative7(targetDir, filePath));
|
|
105813
106113
|
files.push({
|
|
105814
106114
|
path: relativePath,
|
|
@@ -106713,7 +107013,7 @@ var exports_runtime_mcp = {};
|
|
|
106713
107013
|
__export(exports_runtime_mcp, {
|
|
106714
107014
|
handleMcp: () => handleMcp
|
|
106715
107015
|
});
|
|
106716
|
-
import { existsSync as existsSync32, mkdirSync as mkdirSync23, readFileSync as
|
|
107016
|
+
import { existsSync as existsSync32, mkdirSync as mkdirSync23, readFileSync as readFileSync36, writeFileSync as writeFileSync22 } from "fs";
|
|
106717
107017
|
import { homedir as homedir10 } from "os";
|
|
106718
107018
|
import { dirname as dirname28, join as join53 } from "path";
|
|
106719
107019
|
async function handleMcp(options) {
|
|
@@ -106824,7 +107124,7 @@ function registerCodexMcp(command) {
|
|
|
106824
107124
|
const config2 = `[mcp_servers.${MCP_SERVER_NAME}]
|
|
106825
107125
|
command = ${JSON.stringify(command)}`;
|
|
106826
107126
|
try {
|
|
106827
|
-
const current = existsSync32(path) ?
|
|
107127
|
+
const current = existsSync32(path) ? readFileSync36(path, "utf-8") : "";
|
|
106828
107128
|
writeTextFile(path, upsertTomlSection(current, `[mcp_servers.${MCP_SERVER_NAME}]`, `command = ${JSON.stringify(command)}`));
|
|
106829
107129
|
return { agent: "codex", success: true, path, config: config2 };
|
|
106830
107130
|
} catch (err) {
|
|
@@ -106876,7 +107176,7 @@ function registerJsonMcpServer(agent, path, containerKey, server2) {
|
|
|
106876
107176
|
function readJsonObject2(path) {
|
|
106877
107177
|
if (!existsSync32(path))
|
|
106878
107178
|
return {};
|
|
106879
|
-
const raw =
|
|
107179
|
+
const raw = readFileSync36(path, "utf-8").trim();
|
|
106880
107180
|
if (!raw)
|
|
106881
107181
|
return {};
|
|
106882
107182
|
const parsed = JSON.parse(raw);
|
|
@@ -107000,7 +107300,7 @@ __export(exports_runtime, {
|
|
|
107000
107300
|
registerRuntime: () => registerRuntime
|
|
107001
107301
|
});
|
|
107002
107302
|
import { createHash as createHash26, randomUUID as randomUUID9 } from "crypto";
|
|
107003
|
-
import { lstatSync as lstatSync27, mkdirSync as mkdirSync24, readFileSync as
|
|
107303
|
+
import { lstatSync as lstatSync27, mkdirSync as mkdirSync24, readFileSync as readFileSync37, realpathSync as realpathSync11, writeFileSync as writeFileSync23 } from "fs";
|
|
107004
107304
|
import { basename as basename13, isAbsolute as isAbsolute22, join as join54 } from "path";
|
|
107005
107305
|
import { createInterface } from "readline";
|
|
107006
107306
|
function registerRuntime(parent) {
|
|
@@ -107453,7 +107753,7 @@ async function handleRun(name, args2, options, separatorBeforeSkill) {
|
|
|
107453
107753
|
const info = lstatSync27(path);
|
|
107454
107754
|
if (!info.isFile() || info.size > 20 * 1024 * 1024)
|
|
107455
107755
|
throw new Error("Input must be a regular file no larger than 20 MiB");
|
|
107456
|
-
return { name: basename13(path), bytes: new Uint8Array(
|
|
107756
|
+
return { name: basename13(path), bytes: new Uint8Array(readFileSync37(path)) };
|
|
107457
107757
|
});
|
|
107458
107758
|
describeRemoteFiles(inputFiles);
|
|
107459
107759
|
client2 = new RemoteSkillsClient(routing.apiKey, routing.apiOrigin);
|
|
@@ -108625,7 +108925,7 @@ import { createHash as createHash27 } from "crypto";
|
|
|
108625
108925
|
import {
|
|
108626
108926
|
copyFileSync,
|
|
108627
108927
|
mkdirSync as mkdirSync25,
|
|
108628
|
-
readFileSync as
|
|
108928
|
+
readFileSync as readFileSync38,
|
|
108629
108929
|
statSync as statSync19,
|
|
108630
108930
|
writeFileSync as writeFileSync24
|
|
108631
108931
|
} from "fs";
|
|
@@ -108636,7 +108936,7 @@ function validateStationId(stationId) {
|
|
|
108636
108936
|
}
|
|
108637
108937
|
}
|
|
108638
108938
|
function sha256File(filePath) {
|
|
108639
|
-
return createHash27("sha256").update(
|
|
108939
|
+
return createHash27("sha256").update(readFileSync38(filePath)).digest("hex");
|
|
108640
108940
|
}
|
|
108641
108941
|
function scanHome(definition, homesRoot) {
|
|
108642
108942
|
const homePath = homePathFor(definition, homesRoot);
|
|
@@ -109208,7 +109508,7 @@ var init_create_sync_config = __esm(() => {
|
|
|
109208
109508
|
});
|
|
109209
109509
|
|
|
109210
109510
|
// src/lib/codex-native-config.ts
|
|
109211
|
-
import { isDeepStrictEqual as
|
|
109511
|
+
import { isDeepStrictEqual as isDeepStrictEqual10 } from "util";
|
|
109212
109512
|
function isRecord7(value) {
|
|
109213
109513
|
if (!value || typeof value !== "object")
|
|
109214
109514
|
return false;
|
|
@@ -109230,7 +109530,7 @@ function decimalIdentity(text4) {
|
|
|
109230
109530
|
return `${match[1]}${coefficient}e${exponent}`;
|
|
109231
109531
|
}
|
|
109232
109532
|
function codexNativeConfigEqual(native, expected) {
|
|
109233
|
-
if (
|
|
109533
|
+
if (isDeepStrictEqual10(native, expected))
|
|
109234
109534
|
return true;
|
|
109235
109535
|
if (typeof expected === "number") {
|
|
109236
109536
|
if (!Number.isFinite(expected) || !isRecord7(native))
|
|
@@ -109396,7 +109696,7 @@ var init_codex_hook_rpc = __esm(() => {
|
|
|
109396
109696
|
// src/lib/codex-hook-trust-identity.ts
|
|
109397
109697
|
import { realpathSync as realpathSync13 } from "fs";
|
|
109398
109698
|
import { dirname as dirname31, isAbsolute as isAbsolute25, join as join57 } from "path";
|
|
109399
|
-
import { isDeepStrictEqual as
|
|
109699
|
+
import { isDeepStrictEqual as isDeepStrictEqual11 } from "util";
|
|
109400
109700
|
function inspectRecordedSkillsCli(command, expected) {
|
|
109401
109701
|
need4(isAbsolute25(command) && !command.includes("\x00"), "RECONCILE_RECORDED_COMMAND_REQUIRED");
|
|
109402
109702
|
const resolved = realpathSync13(command);
|
|
@@ -109406,7 +109706,7 @@ function inspectRecordedSkillsCli(command, expected) {
|
|
|
109406
109706
|
need4(pkg.name === "@hasna/skills" && /^\d+\.\d+\.\d+$/.test(pkg.version) && pkg.bin?.skills === "bin/index.js" && resolved === join57(dirname31(manifest.file), "bin/index.js"), "SKILLS_PACKAGE_MISMATCH");
|
|
109407
109707
|
need4((cli.stat.mode & 0o100n) !== 0n, "SKILLS_COMMAND_NOT_EXECUTABLE");
|
|
109408
109708
|
const receipt = { path: resolved, version: pkg.version, sha256: cli.sha256, manifestSha256: manifest.sha256 };
|
|
109409
|
-
need4(
|
|
109709
|
+
need4(isDeepStrictEqual11(receipt, expected), "RECONCILE_SKILLS_BINDING_CHANGED");
|
|
109410
109710
|
return { receipt, recheck() {
|
|
109411
109711
|
need4(realpathSync13(command) === resolved, "SKILLS_COMMAND_CHANGED");
|
|
109412
109712
|
unchanged2(cli);
|
|
@@ -109442,19 +109742,19 @@ var init_codex_hook_trust_identity = __esm(() => {
|
|
|
109442
109742
|
});
|
|
109443
109743
|
|
|
109444
109744
|
// src/lib/codex-hook-policy-recovery.ts
|
|
109445
|
-
import { isDeepStrictEqual as
|
|
109745
|
+
import { isDeepStrictEqual as isDeepStrictEqual12 } from "util";
|
|
109446
109746
|
function reviewedClaudeDiscoveryChange(beforeText, currentText, options) {
|
|
109447
109747
|
need4(typeof options.reason === "string" && options.reason.trim().length > 0 && options.reason.length <= 512 && !/[\x00-\x1f\x7f]/.test(options.reason), "RECONCILE_RECOVERY_REASON_REQUIRED");
|
|
109448
109748
|
need4(options.reviewedPlanDigest === undefined || /^[a-f0-9]{64}$/.test(options.reviewedPlanDigest), "RECONCILE_RECOVERY_PLAN_CHANGED");
|
|
109449
109749
|
const before2 = parseManagedSkillPolicy(beforeText), current = parseManagedSkillPolicy(currentText);
|
|
109450
109750
|
const oldDiscovery = before2.bridge?.discovery?.claude, newDiscovery = current.bridge?.discovery?.claude;
|
|
109451
109751
|
need4(oldDiscovery?.agent === "claude" && newDiscovery?.agent === "claude" && oldDiscovery.method === "reviewed" && newDiscovery.method === "reviewed", "RECONCILE_POLICY_CHANGED");
|
|
109452
|
-
const changes = ["roots", "sources"].filter((key) => !
|
|
109752
|
+
const changes = ["roots", "sources"].filter((key) => !isDeepStrictEqual12(oldDiscovery[key], newDiscovery[key])).map((key) => ({ path: `bridge.discovery.claude.${key}`, before: oldDiscovery[key], after: newDiscovery[key] }));
|
|
109453
109753
|
need4(changes.length > 0, "RECONCILE_POLICY_CHANGED");
|
|
109454
109754
|
const compared = structuredClone(current);
|
|
109455
109755
|
compared.bridge.discovery.claude.roots = oldDiscovery.roots;
|
|
109456
109756
|
compared.bridge.discovery.claude.sources = oldDiscovery.sources;
|
|
109457
|
-
need4(
|
|
109757
|
+
need4(isDeepStrictEqual12(before2, compared), "RECONCILE_POLICY_CHANGED");
|
|
109458
109758
|
verifyAgentDiscovery(newDiscovery);
|
|
109459
109759
|
return { reason: options.reason, changes };
|
|
109460
109760
|
}
|
|
@@ -109465,23 +109765,23 @@ var init_codex_hook_policy_recovery = __esm(() => {
|
|
|
109465
109765
|
});
|
|
109466
109766
|
|
|
109467
109767
|
// src/lib/agent-codex-trust.ts
|
|
109468
|
-
import { lstatSync as lstatSync29, mkdirSync as mkdirSync26, readdirSync as readdirSync21, readFileSync as
|
|
109768
|
+
import { lstatSync as lstatSync29, mkdirSync as mkdirSync26, readdirSync as readdirSync21, readFileSync as readFileSync39, realpathSync as realpathSync14, statSync as statSync21 } from "fs";
|
|
109469
109769
|
import { createHash as createHash28, randomUUID as randomUUID10 } from "crypto";
|
|
109470
109770
|
import { execFileSync } from "child_process";
|
|
109471
109771
|
import { dirname as dirname32, isAbsolute as isAbsolute26, join as join58, resolve as resolve23 } from "path";
|
|
109472
109772
|
import { homedir as homedir12 } from "os";
|
|
109473
|
-
import { isDeepStrictEqual as
|
|
109773
|
+
import { isDeepStrictEqual as isDeepStrictEqual13 } from "util";
|
|
109474
109774
|
function verifyReleaseArtifact(proof, skillsCli) {
|
|
109475
109775
|
need4(isAbsolute26(proof.packageTarPath) && !proof.packageTarPath.includes("\x00"), "RECONCILE_RELEASE_PROVENANCE_PATH");
|
|
109476
109776
|
const tarPath = realpathSync14(proof.packageTarPath);
|
|
109477
109777
|
need4(statSync21(tarPath).isFile(), "RECONCILE_RELEASE_PROVENANCE_PATH");
|
|
109478
|
-
const tarBytes =
|
|
109778
|
+
const tarBytes = readFileSync39(tarPath);
|
|
109479
109779
|
need4(tarBytes.byteLength === proof.packageTarBytes && createHash28("sha256").update(tarBytes).digest("hex") === proof.packageTarSha256, "RECONCILE_RELEASE_ARTIFACT_CHANGED");
|
|
109480
109780
|
const packageRoot = dirname32(dirname32(realpathSync14(skillsCli.receipt.path)));
|
|
109481
|
-
const manifest =
|
|
109781
|
+
const manifest = readFileSync39(join58(packageRoot, "package.json"));
|
|
109482
109782
|
need4(createHash28("sha256").update(manifest).digest("hex") === skillsCli.receipt.manifestSha256 && skillsCli.receipt.manifestSha256 === proof.manifestSha256, "RECONCILE_RELEASE_MANIFEST_CHANGED");
|
|
109483
|
-
need4(createHash28("sha256").update(
|
|
109484
|
-
const members2 = [["package/package.json", manifest], ["package/bin/index.js",
|
|
109783
|
+
need4(createHash28("sha256").update(readFileSync39(skillsCli.receipt.path)).digest("hex") === proof.executableSha256 && skillsCli.receipt.sha256 === proof.executableSha256, "RECONCILE_RELEASE_EXECUTABLE_CHANGED");
|
|
109784
|
+
const members2 = [["package/package.json", manifest], ["package/bin/index.js", readFileSync39(skillsCli.receipt.path)]];
|
|
109485
109785
|
for (const [member, expected] of members2) {
|
|
109486
109786
|
let actual;
|
|
109487
109787
|
try {
|
|
@@ -109512,7 +109812,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
109512
109812
|
const configSha256 = intent.configSha256 ?? configBefore.sha256, configVersion = intent.configVersion ?? intent.expectedVersion;
|
|
109513
109813
|
const digestInput = { version: 1, home: intent.home ?? home, configPath: intent.configPath, ...intent.nativeConfigPath !== undefined ? { nativeConfigPath: intent.nativeConfigPath } : {}, configSha256, configVersion, policySha256: intent.policySha256, hooksSha256: intent.hooksSha256, skillsCli: intent.skillsCli, nativeVersion: intent.nativeVersion, declarations, admitted };
|
|
109514
109814
|
need4(makePlanDigest(digestInput) === intent.planDigest, "RECONCILE_PLAN_CHANGED");
|
|
109515
|
-
need4(
|
|
109815
|
+
need4(isDeepStrictEqual13(intent.hooks, admitted.filter((hook) => !hook.enabled || hook.trustStatus !== "trusted")), "RECONCILE_INTENT_HOOKS_CHANGED");
|
|
109516
109816
|
need4(configBefore.sha256 === (intent.beforeSha256 ?? intent.configSha256) && hooksBefore.sha256 === intent.hooksSha256 && policyBefore.sha256 === intent.policySha256, "RECONCILE_JOURNAL_CHANGED");
|
|
109517
109817
|
const policyCurrent = snapshot(join58(dataDir3, "agent-policy.json"), true);
|
|
109518
109818
|
const { claudeDiscoveryRecovery: claudeRecovery, nativeHookAdditionsRecovery: additionsRecovery } = options;
|
|
@@ -109525,7 +109825,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
109525
109825
|
if (policyCurrent.sha256 !== policyBefore.sha256 && !claudeRecovery) {
|
|
109526
109826
|
need4(options.supersedeBinding === true, "RECONCILE_POLICY_CHANGED");
|
|
109527
109827
|
const oldPolicy = JSON.parse(policyBefore.text), currentPolicy = JSON.parse(policyCurrent.text);
|
|
109528
|
-
need4(
|
|
109828
|
+
need4(isDeepStrictEqual13(withoutCodexCommand(oldPolicy), withoutCodexCommand(currentPolicy)), "RECONCILE_POLICY_CHANGED");
|
|
109529
109829
|
supersededBinding = true;
|
|
109530
109830
|
}
|
|
109531
109831
|
if (supersededBinding || recovery) {
|
|
@@ -109561,7 +109861,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
109561
109861
|
need4(state?.enabled === true && typeof state.trusted_hash === "string" && /^sha256:[a-f0-9]{64}$/.test(state.trusted_hash), "RECONCILE_CONFIG_DRIFT");
|
|
109562
109862
|
}
|
|
109563
109863
|
} else
|
|
109564
|
-
need4(
|
|
109864
|
+
need4(isDeepStrictEqual13(expectedConfig, current), "RECONCILE_CONFIG_DRIFT");
|
|
109565
109865
|
const configDiscoveryRecovery = recovery && binding.discovery?.codex ? createCodexHookDiscoveryRecovery(binding.discovery.codex, configBefore, currentConfig, intent.hooks, additions?.trustProof) : undefined;
|
|
109566
109866
|
assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home, codexDiscoveryRecovery: configDiscoveryRecovery });
|
|
109567
109867
|
const recoveryCli = recovery ? bindSkillsCli("skills", options.reviewedSkillsCli) : undefined;
|
|
@@ -109570,14 +109870,14 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
109570
109870
|
const skillsCli = recovery ? inspectRecordedSkillsCli(binding.commands.codex, intent.skillsCli) : bindSkillsCli(binding.commands.codex, options.reviewedSkillsCli);
|
|
109571
109871
|
if (supersededBinding)
|
|
109572
109872
|
verifyReleaseArtifact(options.releaseProof, skillsCli);
|
|
109573
|
-
const skillsBindingChanged = !
|
|
109873
|
+
const skillsBindingChanged = !isDeepStrictEqual13(skillsCli.receipt, intent.skillsCli);
|
|
109574
109874
|
need4(!skillsBindingChanged || supersededBinding, "RECONCILE_SKILLS_BINDING_CHANGED");
|
|
109575
109875
|
if (!additions && hooksCurrent.sha256 !== intent.hooksSha256 && hooksCurrent.sha256 !== hooksBefore.sha256) {
|
|
109576
109876
|
need4(supersededBinding, "RECONCILE_HOOKS_CHANGED");
|
|
109577
109877
|
const currentDeclarations = JSON.parse(hooksCurrent.text).hooks;
|
|
109578
109878
|
for (const [event, [nativeEvent]] of Object.entries(eventNames)) {
|
|
109579
109879
|
const command = renderAgentHookCommand(binding.commands.codex, "codex", binding.profiles.codex, event);
|
|
109580
|
-
need4(
|
|
109880
|
+
need4(isDeepStrictEqual13(currentDeclarations?.[event], [{ hooks: [{ type: "command", command, timeout: 15 }] }]), "RECONCILE_BINDING_HOOK_CHANGED");
|
|
109581
109881
|
}
|
|
109582
109882
|
}
|
|
109583
109883
|
rpc = await connect({ command: options.codexCommand ?? "codex", home, codexHome });
|
|
@@ -109600,9 +109900,9 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
109600
109900
|
delete identity4.command;
|
|
109601
109901
|
return identity4;
|
|
109602
109902
|
};
|
|
109603
|
-
need4(
|
|
109903
|
+
need4(isDeepStrictEqual13(stable(actual), stable(expected)), "RECONCILE_NATIVE_IDENTITY_CHANGED");
|
|
109604
109904
|
if (!plannedKeys.has(expected.key))
|
|
109605
|
-
need4(
|
|
109905
|
+
need4(isDeepStrictEqual13(actual, expected), "RECONCILE_UNRELATED_HOOK_CHANGED");
|
|
109606
109906
|
}
|
|
109607
109907
|
for (const wanted of intent.hooks) {
|
|
109608
109908
|
const matches2 = nativeHooks.filter((h2) => h2.key === wanted.key || h2.key === wanted.key.replace(join58(home, ".codex/hooks.json"), hooksPath));
|
|
@@ -109621,7 +109921,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
|
|
|
109621
109921
|
const layers = config2?.layers?.filter((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
|
|
109622
109922
|
need4(layers?.length === 1 && !layers[0].disabledReason && codexNativeConfigEqual(layers[0].config, current), "RECONCILE_NATIVE_CONFIG_MISMATCH");
|
|
109623
109923
|
const finalDiscovery = await rpc.request("hooks/list", { cwds: [home] });
|
|
109624
|
-
need4(Array.isArray(finalDiscovery?.data) && finalDiscovery.data.length === 1 && finalDiscovery.data[0].cwd === home && !finalDiscovery.data[0].errors?.length && !finalDiscovery.data[0].warnings?.length && (!recordedNativeHooks ||
|
|
109924
|
+
need4(Array.isArray(finalDiscovery?.data) && finalDiscovery.data.length === 1 && finalDiscovery.data[0].cwd === home && !finalDiscovery.data[0].errors?.length && !finalDiscovery.data[0].warnings?.length && (!recordedNativeHooks || isDeepStrictEqual13(finalDiscovery.data[0].hooks.map(safeNativeHook), nativeHooks.map(safeNativeHook))), "RECONCILE_NATIVE_STATE_CHANGED");
|
|
109625
109925
|
const finalConfig = await rpc.request("config/read", { includeLayers: true, cwd: home });
|
|
109626
109926
|
const finalLayers = finalConfig?.layers?.filter((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
|
|
109627
109927
|
need4(finalLayers?.length === 1 && !finalLayers[0].disabledReason && codexNativeConfigEqual(finalLayers[0].config, current), "RECONCILE_NATIVE_CONFIG_CHANGED");
|
|
@@ -109682,7 +109982,7 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
|
|
|
109682
109982
|
const groups = declarations[event];
|
|
109683
109983
|
need4(Array.isArray(groups), "DECLARATION_CHANGED");
|
|
109684
109984
|
const matches2 = groups.flatMap((group, gi) => (group.hooks ?? []).flatMap((entry, hi) => entry.command === command ? [{ group, entry, gi, hi }] : []));
|
|
109685
|
-
need4(matches2.length === 1 &&
|
|
109985
|
+
need4(matches2.length === 1 && isDeepStrictEqual13(matches2[0].group, { hooks: [{ type: "command", command, timeout: 15 }] }), "DECLARATION_CHANGED");
|
|
109686
109986
|
expected.push({ event: nativeEvent, key: `${join58(home, ".codex/hooks.json")}:${label}:${matches2[0].gi}:${matches2[0].hi}`, command });
|
|
109687
109987
|
}
|
|
109688
109988
|
codexTrustTextWitness(configFile.text, expected.map((h) => h.key));
|
|
@@ -109748,7 +110048,7 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
|
|
|
109748
110048
|
save(join58(journal, "hooks.before.json"), hooksFile.bytes);
|
|
109749
110049
|
save(join58(journal, "policy.before.json"), policyFile.bytes);
|
|
109750
110050
|
save(join58(journal, "intent.json"), json2({ ...digestInput, planDigest, hooks: planned, nativeHooks: discovered.map(safeNativeHook) }));
|
|
109751
|
-
need4(
|
|
110051
|
+
need4(isDeepStrictEqual13(admit(await list2()), admitted), "NATIVE_DISCOVERY_CHANGED");
|
|
109752
110052
|
checkInputs();
|
|
109753
110053
|
let result2;
|
|
109754
110054
|
try {
|
|
@@ -109762,7 +110062,7 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
|
|
|
109762
110062
|
expectedConfig.hooks.state ??= {};
|
|
109763
110063
|
for (const h of planned)
|
|
109764
110064
|
expectedConfig.hooks.state[h.key] = { ...expectedConfig.hooks.state[h.key], enabled: true, trusted_hash: h.currentHash };
|
|
109765
|
-
need4(
|
|
110065
|
+
need4(isDeepStrictEqual13(structure3(after2.text), expectedConfig) && codexTrustTextWitness(after2.text, keys3) === preservationText, "PRESERVATION_FAILED");
|
|
109766
110066
|
const savedConfig = snapshot(join58(journal, "config.before.toml"), true);
|
|
109767
110067
|
need4(savedConfig.sha256 === configFile.sha256, "JOURNAL_CHANGED");
|
|
109768
110068
|
const discoveryTransition = binding.discovery?.codex ? createCodexHookDiscoveryRecovery(binding.discovery.codex, savedConfig, after2, planned) : undefined;
|
|
@@ -109770,8 +110070,8 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
|
|
|
109770
110070
|
unchanged2(hooksFile);
|
|
109771
110071
|
assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home, codexDiscoveryRecovery: discoveryTransition });
|
|
109772
110072
|
const current = await list2(), confirmed = admit(current);
|
|
109773
|
-
need4(confirmed.every((h) => h.enabled && h.trustStatus === "trusted") &&
|
|
109774
|
-
need4(
|
|
110073
|
+
need4(confirmed.every((h) => h.enabled && h.trustStatus === "trusted") && isDeepStrictEqual13(confirmed.map((h) => [h.key, h.currentHash]), admitted.map((h) => [h.key, h.currentHash])), "NATIVE_NOT_ELIGIBLE");
|
|
110074
|
+
need4(isDeepStrictEqual13(current.filter((h) => !keys3.includes(h.key)), discovered.filter((h) => !keys3.includes(h.key))), "UNRELATED_HOOK_CHANGED");
|
|
109775
110075
|
unchanged2(after2);
|
|
109776
110076
|
unchanged2(savedConfig);
|
|
109777
110077
|
unchanged2(hooksFile);
|
|
@@ -109838,6 +110138,9 @@ function hookFailureReason(error61, profileId) {
|
|
|
109838
110138
|
if (code2 === "PROFILE_LOCK_MISMATCH") {
|
|
109839
110139
|
return `${prefix} This session or project is pinned to a different profile. Inspect the session with skills sessions show <session-id> --json; review skills sessions reconcile for an intentional session change, or explicit project sync for a project change. Sync alone does not change that pin.`;
|
|
109840
110140
|
}
|
|
110141
|
+
if (code2 === "SESSION_RECONCILIATION_REQUIRED") {
|
|
110142
|
+
return `${prefix} A loaded skill changed or was removed. Inspect this session with skills sessions show <session-id> --json, then review skills sessions reconcile for an intentional change. Sync alone does not change this pin.`;
|
|
110143
|
+
}
|
|
109841
110144
|
if (code2.startsWith("SESSION_")) {
|
|
109842
110145
|
return `${prefix} Inspect the session with skills sessions show <session-id> --json and review its parent or concurrent writer before retrying. Do not remove or rewrite its receipt to bypass this refusal.`;
|
|
109843
110146
|
}
|
|
@@ -109880,9 +110183,11 @@ var init_hook_diagnostics = __esm(() => {
|
|
|
109880
110183
|
"SESSION_GENERATION_EXHAUSTED",
|
|
109881
110184
|
"SESSION_PARENT_CHANGED",
|
|
109882
110185
|
"SESSION_RECEIPT_CHANGED",
|
|
110186
|
+
"SESSION_RECONCILIATION_REQUIRED",
|
|
109883
110187
|
"SESSION_RECONCILIATION_INCOMPLETE",
|
|
109884
110188
|
"SESSION_WRITE_LOCKED",
|
|
109885
|
-
"SESSION_WRITE_LOCK_CHANGED"
|
|
110189
|
+
"SESSION_WRITE_LOCK_CHANGED",
|
|
110190
|
+
"SESSION_LOCK_RECOVERY_INCOMPLETE"
|
|
109886
110191
|
]);
|
|
109887
110192
|
HookDiagnosticError = class HookDiagnosticError extends Error {
|
|
109888
110193
|
code;
|
|
@@ -109900,7 +110205,7 @@ var exports_agent_integration = {};
|
|
|
109900
110205
|
__export(exports_agent_integration, {
|
|
109901
110206
|
registerAgentIntegration: () => registerAgentIntegration
|
|
109902
110207
|
});
|
|
109903
|
-
import { readFileSync as
|
|
110208
|
+
import { readFileSync as readFileSync40 } from "fs";
|
|
109904
110209
|
import { isAbsolute as isAbsolute27 } from "path";
|
|
109905
110210
|
function pinnedHookProfile(input3, configuredProfile) {
|
|
109906
110211
|
try {
|
|
@@ -109923,7 +110228,7 @@ async function contextForHook(input3, profileId, cached2, deadline) {
|
|
|
109923
110228
|
throw new HookDiagnosticError("SKILLS_HOOK_TIMEOUT", "context");
|
|
109924
110229
|
const args2 = [process.execPath, process.argv[1], "context", "--stdin", "--json", "--selection-profile", profileId];
|
|
109925
110230
|
if (cached2)
|
|
109926
|
-
args2.push("--cached");
|
|
110231
|
+
args2.push("--cached", "--auto-reconcile-safe");
|
|
109927
110232
|
const child = Bun.spawn(args2, { stdin: new Blob([JSON.stringify(input3)]), stdout: "pipe", stderr: "pipe", env: { ...process.env, NO_COLOR: "1" } });
|
|
109928
110233
|
let timedOut = false;
|
|
109929
110234
|
const timer = setTimeout(() => {
|
|
@@ -109978,7 +110283,7 @@ function registerAgentIntegration(parent) {
|
|
|
109978
110283
|
});
|
|
109979
110284
|
hook.command("install").option("--agent <agent>", `Agent to configure: ${INTEGRATION_AGENTS.join(", ")}, all`, "all").option("--command <path>", "Skills executable used by the hook (preserves existing binding; new agents use skills)").option("--selection-profile <id>", "Selection profile (preserves existing binding; new agents use default)").option("--include-vendor", "Retained for compatibility; vendor system skills are always inventoried and disabled", false).option("--discovery-inputs <file>", "Advanced reviewed active plugin roots and source hashes for unsupported registrations").option("--allow-root-aliases", "Allow home .claude/.codex aliases to existing directories within this home", false).option("--apply", "Apply the plan, preserving prior configuration in private backups", false).option("--json", "Output a receipt as JSON", false).description("Plan or install one Skills CLI bridge plus native prompt hooks").action(async (options) => {
|
|
109980
110285
|
try {
|
|
109981
|
-
const discoveryInputs = options.discoveryInputs ? JSON.parse(
|
|
110286
|
+
const discoveryInputs = options.discoveryInputs ? JSON.parse(readFileSync40(options.discoveryInputs, "utf8")) : undefined;
|
|
109982
110287
|
const plan = planAgentIntegration({ agents: agents(options.agent), command: options.command, profileId: options.selectionProfile, includeVendor: options.includeVendor, discoveryInputs, allowRootAliases: options.allowRootAliases });
|
|
109983
110288
|
const result2 = options.apply ? applyAgentIntegration(plan) : { changed: [], backups: [] };
|
|
109984
110289
|
const receipt = { applied: options.apply, planned: plan.changes.map((change) => change.path), ...result2, rootAliases: plan.rootAliases ?? [], discovery: plan.discoveryAfter, nativeSkills: plan.nativeSkills.map((entry) => ({ agent: entry.agent, path: entry.path, managed: entry.managed, vendor: entry.vendor, system: entry.system === true, bridge: entry.bridge === true })), requiresNativeRetirement: plan.nativeSkills.some((entry) => !entry.bridge && !entry.system) };
|
|
@@ -110036,7 +110341,7 @@ function registerAgentIntegration(parent) {
|
|
|
110036
110341
|
try {
|
|
110037
110342
|
if (agents(options.agent).length !== 1)
|
|
110038
110343
|
throw new Error("A hook invocation requires one agent");
|
|
110039
|
-
const inputText =
|
|
110344
|
+
const inputText = readFileSync40(0, "utf8");
|
|
110040
110345
|
if (inputText.length > 1024 * 1024)
|
|
110041
110346
|
throw new Error("Hook input is too large");
|
|
110042
110347
|
let input3 = JSON.parse(inputText);
|
|
@@ -110130,13 +110435,18 @@ function registerAgentIntegration(parent) {
|
|
|
110130
110435
|
}
|
|
110131
110436
|
});
|
|
110132
110437
|
const migrate = parent.command("migrate").description("Preserve and retire native agent skill copies");
|
|
110133
|
-
migrate.command("native").option("--project <directory>", "Also inventory a project and its ancestors (the current directory and its ancestors are always included)").option("--include-unmanaged", "Archive user-authored skills as well as Skills-managed copies", false).option("--include-vendor", "Retire vendor SKILL.md discovery files while preserving plugin scripts and assets", false).option("--target-manifest <file>", "Reviewed exact native migration target manifest").option("--discovery-inputs <file>", "Advanced reviewed active plugin roots and source hashes").option("--allow-root-aliases", "Allow home .claude/.codex aliases to existing directories within this home", false).option("--apply", "Move selected skills to private archives outside agent discovery roots", false).option("--json", "Output inventory and archive receipt as JSON", false).description("Inventory native skill copies; preserve complete directories before retiring them").action(async (options) => {
|
|
110438
|
+
migrate.command("native").option("--agent <agent>", "Limit inventory and migration to one maintained agent").option("--project <directory>", "Also inventory a project and its ancestors (the current directory and its ancestors are always included)").option("--include-unmanaged", "Archive user-authored skills as well as Skills-managed copies", false).option("--include-vendor", "Retire vendor SKILL.md discovery files while preserving plugin scripts and assets", false).option("--reviewed-cache-alias <path>", "Exact skill-containing vendor cache alias reviewed for migration; runtime hooks still refuse it").option("--target-manifest <file>", "Reviewed exact native migration target manifest").option("--discovery-inputs <file>", "Advanced reviewed active plugin roots and source hashes").option("--allow-root-aliases", "Allow home .claude/.codex aliases to existing directories within this home", false).option("--apply", "Move selected skills to private archives outside agent discovery roots", false).option("--json", "Output inventory and archive receipt as JSON", false).description("Inventory native skill copies; preserve complete directories before retiring them").action(async (options) => {
|
|
110134
110439
|
try {
|
|
110135
|
-
|
|
110440
|
+
if (options.agent && !INTEGRATION_AGENTS.includes(options.agent))
|
|
110441
|
+
throw new Error(`Unsupported migration agent: ${options.agent}`);
|
|
110442
|
+
const discoveryInputs = options.discoveryInputs ? JSON.parse(readFileSync40(options.discoveryInputs, "utf8")) : undefined;
|
|
110136
110443
|
if (options.targetManifest && (options.includeUnmanaged || options.includeVendor))
|
|
110137
110444
|
throw new Error("--target-manifest cannot be combined with broad native migration selectors");
|
|
110138
110445
|
const targetManifest = options.targetManifest ? readNativeMigrationTargetManifest(options.targetManifest) : undefined;
|
|
110139
|
-
|
|
110446
|
+
if (options.apply && options.reviewedCacheAlias && !targetManifest)
|
|
110447
|
+
throw new Error("Applying a reviewed cache alias requires an exact --target-manifest");
|
|
110448
|
+
const includeVendor = options.includeVendor || Boolean(targetManifest?.targets.some((target) => target.vendor));
|
|
110449
|
+
const inventory = inventoryNativeSkills(undefined, { projectDirs: [process.cwd(), ...options.project ? [options.project] : []], agents: options.agent ? [options.agent] : undefined, includeVendor, configured: includeVendor, discoveryInputs, allowRootAliases: options.allowRootAliases, reviewedCacheAlias: options.reviewedCacheAlias });
|
|
110140
110450
|
if (targetManifest)
|
|
110141
110451
|
selectNativeMigrationTargets(inventory, targetManifest);
|
|
110142
110452
|
const result2 = options.apply ? archiveNativeSkills(inventory, { includeUnmanaged: options.includeUnmanaged, includeVendor: options.includeVendor, allowRootAliases: options.allowRootAliases, targetManifest }) : { entries: [], ...targetManifest ? { targetManifest: { schema: targetManifest.schema, digest: targetManifest.digest, targetCount: targetManifest.targets.length } } : {} };
|
|
@@ -110439,7 +110749,7 @@ import {
|
|
|
110439
110749
|
copyFileSync as copyFileSync2,
|
|
110440
110750
|
mkdirSync as mkdirSync27,
|
|
110441
110751
|
readdirSync as readdirSync22,
|
|
110442
|
-
readFileSync as
|
|
110752
|
+
readFileSync as readFileSync41,
|
|
110443
110753
|
statSync as statSync22,
|
|
110444
110754
|
writeFileSync as writeFileSync27
|
|
110445
110755
|
} from "fs";
|
|
@@ -110455,7 +110765,7 @@ function readSnapshotManifest(repoRoot, stationId) {
|
|
|
110455
110765
|
const manifestPath = join59(snapshotRoot, "sync-manifest.json");
|
|
110456
110766
|
let manifest;
|
|
110457
110767
|
try {
|
|
110458
|
-
manifest = JSON.parse(
|
|
110768
|
+
manifest = JSON.parse(readFileSync41(manifestPath, "utf8"));
|
|
110459
110769
|
} catch (error61) {
|
|
110460
110770
|
fail5("MANIFEST_UNREADABLE", `cannot read snapshot manifest: ${manifestPath}: ${error61.message}`);
|
|
110461
110771
|
}
|
|
@@ -110591,7 +110901,7 @@ function planStationHydration(stationId, repoRoot) {
|
|
|
110591
110901
|
for (const copy of copies) {
|
|
110592
110902
|
let isStub = false;
|
|
110593
110903
|
try {
|
|
110594
|
-
isStub = isPointerSkillMd(
|
|
110904
|
+
isStub = isPointerSkillMd(readFileSync41(copy.fullPath, "utf8"));
|
|
110595
110905
|
} catch {
|
|
110596
110906
|
isStub = false;
|
|
110597
110907
|
}
|
|
@@ -110795,7 +111105,7 @@ var init_hydrate = __esm(() => {
|
|
|
110795
111105
|
|
|
110796
111106
|
// src/lib/prepare-skill.ts
|
|
110797
111107
|
import { createHash as createHash30, randomUUID as randomUUID11 } from "crypto";
|
|
110798
|
-
import { chmodSync as chmodSync4, existsSync as existsSync34, lstatSync as lstatSync30, mkdirSync as mkdirSync28, mkdtempSync as mkdtempSync6, readFileSync as
|
|
111108
|
+
import { chmodSync as chmodSync4, existsSync as existsSync34, lstatSync as lstatSync30, mkdirSync as mkdirSync28, mkdtempSync as mkdtempSync6, readFileSync as readFileSync42, readdirSync as readdirSync23, renameSync as renameSync13, rmSync as rmSync9, writeFileSync as writeFileSync28 } from "fs";
|
|
110799
111109
|
import { tmpdir as tmpdir2 } from "os";
|
|
110800
111110
|
import { dirname as dirname34, isAbsolute as isAbsolute28, join as join60, relative as relative9, resolve as resolve25, sep as sep12 } from "path";
|
|
110801
111111
|
function prepareSkill(name, options) {
|
|
@@ -111015,7 +111325,7 @@ function snapshot2(root2) {
|
|
|
111015
111325
|
bytes += stat3.size;
|
|
111016
111326
|
if (bytes > 50000000)
|
|
111017
111327
|
throw new Error("Skill exceeds the preparation size limit (50000000 bytes).");
|
|
111018
|
-
const content =
|
|
111328
|
+
const content = readFileSync42(absolute);
|
|
111019
111329
|
if (content.length !== stat3.size)
|
|
111020
111330
|
throw new Error("Skill changed during preparation.");
|
|
111021
111331
|
files.push({ path, bytes: content, mode: stat3.mode & 511 });
|
|
@@ -111697,8 +112007,8 @@ __export(exports_publish, {
|
|
|
111697
112007
|
PushSkillError: () => PushSkillError
|
|
111698
112008
|
});
|
|
111699
112009
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
111700
|
-
import { existsSync as existsSync35, readFileSync as
|
|
111701
|
-
import { hostname as
|
|
112010
|
+
import { existsSync as existsSync35, readFileSync as readFileSync43 } from "fs";
|
|
112011
|
+
import { hostname as hostname5 } from "os";
|
|
111702
112012
|
import { join as join61 } from "path";
|
|
111703
112013
|
function registerPublish(parent) {
|
|
111704
112014
|
parent.command("push").argument("<name>", "Name of a skill in the local corpus (~/.hasna/skills/installed or the migrated ~/.hasna/skills/skills)").option("--version <version>", "Override the version recorded on the instance").option("--force-new-version", "If name@version already exists with different content, publish as the next patch version", false).option("--dry-run", "Pack and validate without uploading", false).option("--json", "Output result as JSON", false).description("Publish a local skill to the configured skills instance").action(async (name, options) => {
|
|
@@ -111752,7 +112062,7 @@ async function pushSkill(name, options = {}) {
|
|
|
111752
112062
|
await verifyPackedCanonicalHash(skill.name, packed);
|
|
111753
112063
|
const versionManifest = buildVersionManifest(skill.path, packed);
|
|
111754
112064
|
const skillMdPath = join61(skill.path, "SKILL.md");
|
|
111755
|
-
const skillMd = existsSync35(skillMdPath) ?
|
|
112065
|
+
const skillMd = existsSync35(skillMdPath) ? readFileSync43(skillMdPath, "utf-8") : undefined;
|
|
111756
112066
|
const base3 = {
|
|
111757
112067
|
slug: skill.name,
|
|
111758
112068
|
path: skill.path,
|
|
@@ -111882,7 +112192,7 @@ function buildVersionManifest(skillDir, packed) {
|
|
|
111882
112192
|
unpackedByteSize: packed.unpackedByteSize,
|
|
111883
112193
|
bundleSha256: packed.sha256,
|
|
111884
112194
|
provenance: {
|
|
111885
|
-
machine:
|
|
112195
|
+
machine: hostname5(),
|
|
111886
112196
|
agent: process.env.SKILLS_AGENT_ID ?? process.env.HASNA_AGENT_ID ?? process.env.AGENT_ID ?? null,
|
|
111887
112197
|
cliVersion: package_default.version,
|
|
111888
112198
|
gitRemote: sanitizeGitRemote(gitValue(skillDir, ["remote", "get-url", "origin"])),
|
|
@@ -113471,7 +113781,7 @@ var init_storage2 = __esm(() => {
|
|
|
113471
113781
|
});
|
|
113472
113782
|
|
|
113473
113783
|
// src/lib/registry-reconcile.ts
|
|
113474
|
-
import { existsSync as existsSync36, readFileSync as
|
|
113784
|
+
import { existsSync as existsSync36, readFileSync as readFileSync44, statSync as statSync23, writeFileSync as writeFileSync30 } from "fs";
|
|
113475
113785
|
import { join as join62 } from "path";
|
|
113476
113786
|
function isDirectory2(path) {
|
|
113477
113787
|
try {
|
|
@@ -113491,7 +113801,7 @@ function readBaseline(skillDir) {
|
|
|
113491
113801
|
if (!existsSync36(markerPath))
|
|
113492
113802
|
return;
|
|
113493
113803
|
try {
|
|
113494
|
-
const marker = JSON.parse(
|
|
113804
|
+
const marker = JSON.parse(readFileSync44(markerPath, "utf-8"));
|
|
113495
113805
|
if (!isSkillsOwnershipMarker(marker))
|
|
113496
113806
|
return;
|
|
113497
113807
|
return {
|
|
@@ -113507,7 +113817,7 @@ function readCursor(root2) {
|
|
|
113507
113817
|
if (!existsSync36(path))
|
|
113508
113818
|
return { runCount: 0 };
|
|
113509
113819
|
try {
|
|
113510
|
-
const cursor2 = JSON.parse(
|
|
113820
|
+
const cursor2 = JSON.parse(readFileSync44(path, "utf-8"));
|
|
113511
113821
|
return { runCount: typeof cursor2.runCount === "number" ? cursor2.runCount : 0 };
|
|
113512
113822
|
} catch {
|
|
113513
113823
|
return { runCount: 0 };
|