@hasna/skills 0.8.10 → 0.8.12
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 +62 -1
- package/bin/index.js +1558 -591
- package/bin/mcp.js +389 -82
- package/bin/migrate.js +6 -5
- package/bin/server.js +12312 -73626
- package/bin/worker.js +7635 -60520
- package/dist/index.d.ts +5 -1
- package/dist/index.js +1058 -267
- package/dist/lib/agent-discovery.d.ts +1 -1
- package/dist/lib/claude-marketplace-registry.d.ts +17 -0
- package/dist/lib/claude-settings-witness.d.ts +19 -0
- package/dist/lib/fleet-credentials.d.ts +18 -0
- package/dist/lib/hook-diagnostics.d.ts +7 -0
- package/dist/lib/recurring-recovery.d.ts +2 -2
- package/dist/lib/recurring-surface.d.ts +1 -1
- package/dist/lib/remote-client.d.ts +10 -3
- package/dist/lib/remote-credit-checkout.d.ts +22 -0
- package/dist/lib/remote-customer-operations.d.ts +2 -3
- package/dist/lib/selection-cache.d.ts +32 -0
- package/dist/lib/selection-resolver.d.ts +3 -1
- package/dist/lib/session-reconciliation.d.ts +100 -0
- package/dist/sdk/index.d.ts +3 -1
- package/dist/sdk/index.js +13419 -73945
- package/docs/plugin-admission.md +90 -0
- package/package.json +6 -5
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.8.
|
|
36871
|
+
version: "0.8.12",
|
|
36872
36872
|
description: "Skills library for AI coding agents",
|
|
36873
36873
|
type: "module",
|
|
36874
36874
|
bin: {
|
|
@@ -36930,10 +36930,11 @@ var init_package = __esm(() => {
|
|
|
36930
36930
|
typecheck: "tsc --noEmit",
|
|
36931
36931
|
"verify:release": "bun run scripts/release-guard.ts",
|
|
36932
36932
|
"verify:consumer-types": "bun run scripts/consumer-types.ts",
|
|
36933
|
-
|
|
36934
|
-
prepack: "bun run build && bun run verify:release && bun run verify:consumer-types",
|
|
36933
|
+
prepack: "bun run verify:generated && bun run verify:release && bun run verify:consumer-types",
|
|
36935
36934
|
prepublishOnly: "bun run verify:producer && bun run typecheck && bun run test",
|
|
36936
|
-
"verify:producer": "bun run scripts/release-dependencies.ts"
|
|
36935
|
+
"verify:producer": "bun run scripts/release-dependencies.ts",
|
|
36936
|
+
"verify:generated": "HASNA_SKILLS_RELEASE_ARTIFACT_TEST=1 bun test src/lib/release-artifacts.test.ts",
|
|
36937
|
+
"verify:consumer-credentials": "bun run scripts/consumer-credentials.ts"
|
|
36937
36938
|
},
|
|
36938
36939
|
keywords: [
|
|
36939
36940
|
"skills",
|
|
@@ -36955,7 +36956,6 @@ var init_package = __esm(() => {
|
|
|
36955
36956
|
license: "Apache-2.0",
|
|
36956
36957
|
devDependencies: {
|
|
36957
36958
|
"@hasna/contracts": "1.1.0",
|
|
36958
|
-
"@hasna/secrets": "0.4.2",
|
|
36959
36959
|
"@types/bun": "1.3.14",
|
|
36960
36960
|
"@types/node": "25.2.3",
|
|
36961
36961
|
"@types/react": "^18.2.0",
|
|
@@ -36968,6 +36968,7 @@ var init_package = __esm(() => {
|
|
|
36968
36968
|
"@aws-sdk/client-ecs": "^3.1079.0",
|
|
36969
36969
|
"@aws-sdk/client-s3": "^3.1079.0",
|
|
36970
36970
|
"@hasna/events": "0.1.18",
|
|
36971
|
+
"@hasna/secrets": "0.4.2",
|
|
36971
36972
|
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
36972
36973
|
chalk: "^5.3.0",
|
|
36973
36974
|
commander: "^12.1.0",
|
|
@@ -42784,14 +42785,15 @@ function profileSelectionSnapshot(selections) {
|
|
|
42784
42785
|
var MAX_PROFILE_SELECTIONS = 4096, MAX_PROFILE_DOCUMENT_BYTES, MAX_SKILL_SESSION_ID_CHARS = 256, PROFILE_SESSION_ENVELOPE_BYTES, MAX_RESOLVED_PROFILE_BYTES, LEGACY_PROFILE_SELECTIONS = 256, LEGACY_PROFILE_DOCUMENT_BYTES = 1e6;
|
|
42785
42786
|
var init_profile_limits = __esm(() => {
|
|
42786
42787
|
MAX_PROFILE_DOCUMENT_BYTES = 8 * 1024 * 1024;
|
|
42787
|
-
PROFILE_SESSION_ENVELOPE_BYTES = MAX_PROFILE_SELECTIONS * 67 + MAX_SKILL_SESSION_ID_CHARS *
|
|
42788
|
+
PROFILE_SESSION_ENVELOPE_BYTES = MAX_PROFILE_SELECTIONS * 67 + MAX_SKILL_SESSION_ID_CHARS * 12 + 512;
|
|
42788
42789
|
MAX_RESOLVED_PROFILE_BYTES = MAX_PROFILE_DOCUMENT_BYTES - PROFILE_SESSION_ENVELOPE_BYTES;
|
|
42789
42790
|
});
|
|
42790
42791
|
|
|
42791
42792
|
// src/lib/selection-cache.ts
|
|
42792
42793
|
import { createHash as createHash3, randomUUID as randomUUID3 } from "crypto";
|
|
42793
|
-
import { closeSync, constants as constants2, fstatSync, lstatSync as lstatSync3, mkdirSync as mkdirSync4, openSync, readSync, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync4 } from "fs";
|
|
42794
|
+
import { closeSync, constants as constants2, fstatSync, fsyncSync, lstatSync as lstatSync3, mkdirSync as mkdirSync4, openSync, readSync, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync4 } from "fs";
|
|
42794
42795
|
import { dirname as dirname4, join as join14, parse, resolve as resolve4 } from "path";
|
|
42796
|
+
import { isDeepStrictEqual as isDeepStrictEqual2 } from "util";
|
|
42795
42797
|
function selectionCacheRoot(options = {}) {
|
|
42796
42798
|
return resolve4(options.cacheDir ?? join14(getDataDirReadOnly(), "selection-cache"));
|
|
42797
42799
|
}
|
|
@@ -42895,12 +42897,21 @@ function writeSelectionJson(path, value) {
|
|
|
42895
42897
|
throw new SkillSelectionError("RECEIPT_TOO_LARGE", "The Skills selection receipt exceeds its size limit.");
|
|
42896
42898
|
atomicWrite(path, bytes, 384);
|
|
42897
42899
|
}
|
|
42898
|
-
function atomicWrite(path, bytes, mode) {
|
|
42900
|
+
function atomicWrite(path, bytes, mode, durable = false) {
|
|
42899
42901
|
assertRegularPath(path, true);
|
|
42900
42902
|
const temporary = join14(dirname4(path), `.selection-${randomUUID3()}.tmp`);
|
|
42901
42903
|
try {
|
|
42902
|
-
|
|
42904
|
+
const fd = openSync(temporary, constants2.O_WRONLY | constants2.O_CREAT | constants2.O_EXCL | constants2.O_NOFOLLOW, mode);
|
|
42905
|
+
try {
|
|
42906
|
+
writeFileSync4(fd, bytes);
|
|
42907
|
+
if (durable)
|
|
42908
|
+
fsyncSync(fd);
|
|
42909
|
+
} finally {
|
|
42910
|
+
closeSync(fd);
|
|
42911
|
+
}
|
|
42903
42912
|
renameSync2(temporary, path);
|
|
42913
|
+
if (durable)
|
|
42914
|
+
syncDirectory(dirname4(path));
|
|
42904
42915
|
} finally {
|
|
42905
42916
|
try {
|
|
42906
42917
|
unlinkSync(temporary);
|
|
@@ -43019,16 +43030,190 @@ function sessionReceiptPath(sessionId, options = {}) {
|
|
|
43019
43030
|
throw new SkillSelectionError("INVALID_SESSION", `A Skills session id must contain 1\u2013${MAX_SKILL_SESSION_ID_CHARS} characters.`);
|
|
43020
43031
|
return join14(selectionCacheRoot(options), "sessions", `${hash(sessionId)}.json`);
|
|
43021
43032
|
}
|
|
43022
|
-
function
|
|
43023
|
-
|
|
43024
|
-
|
|
43025
|
-
|
|
43026
|
-
|
|
43027
|
-
|
|
43028
|
-
|
|
43033
|
+
function skillSessionGeneration(receipt) {
|
|
43034
|
+
return receipt.generation ?? 0;
|
|
43035
|
+
}
|
|
43036
|
+
function validateSkillSessionBinding(binding) {
|
|
43037
|
+
if (!binding || typeof binding.sessionId !== "string" || !binding.sessionId.trim() || binding.sessionId.length > MAX_SKILL_SESSION_ID_CHARS || !Number.isSafeInteger(binding.generation) || binding.generation < 0 || !/^[a-f0-9]{64}$/.test(binding.receiptSha256)) {
|
|
43038
|
+
throw new SkillSelectionError("INVALID_RECEIPT", "The Skills session receipt contains an invalid parent snapshot binding.");
|
|
43039
|
+
}
|
|
43040
|
+
}
|
|
43041
|
+
function validateSkillSessionReceipt(receipt, sessionId) {
|
|
43042
|
+
validateSelectionReceipt(receipt);
|
|
43043
|
+
const keys2 = new Set(receipt.profile.selections.map(selectionKey));
|
|
43044
|
+
if (receipt.sessionId !== sessionId || !Array.isArray(receipt.loaded) || receipt.loaded.length > keys2.size || new Set(receipt.loaded).size !== receipt.loaded.length || !receipt.loaded.every((key) => keys2.has(key)) || receipt.generation !== undefined && (!Number.isSafeInteger(receipt.generation) || receipt.generation < 1)) {
|
|
43045
|
+
throw new SkillSelectionError("INVALID_RECEIPT", "The Skills session receipt is invalid.");
|
|
43046
|
+
}
|
|
43047
|
+
if (receipt.parent) {
|
|
43048
|
+
validateSkillSessionBinding(receipt.parent);
|
|
43049
|
+
if (receipt.parent.sessionId === sessionId)
|
|
43050
|
+
throw new SkillSelectionError("INVALID_RECEIPT", "A Skills child session cannot name itself as its parent.");
|
|
43051
|
+
}
|
|
43052
|
+
}
|
|
43053
|
+
function readSkillSessionSnapshotIfExists(sessionId, options = {}) {
|
|
43054
|
+
const path = sessionReceiptPath(sessionId, options), bytes = readRegularFile(path, MAX_PROFILE_DOCUMENT_BYTES);
|
|
43055
|
+
if (!bytes)
|
|
43056
|
+
return null;
|
|
43057
|
+
let receipt;
|
|
43058
|
+
try {
|
|
43059
|
+
receipt = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
|
|
43060
|
+
} catch {
|
|
43061
|
+
throw new SkillSelectionError("INVALID_RECEIPT", "The Skills session receipt is unreadable.");
|
|
43062
|
+
}
|
|
43063
|
+
validateSkillSessionReceipt(receipt, sessionId);
|
|
43064
|
+
const sha256 = sha256Hex(bytes);
|
|
43065
|
+
return { path, bytes, receipt, sha256, sessionId, generation: skillSessionGeneration(receipt), receiptSha256: sha256 };
|
|
43066
|
+
}
|
|
43067
|
+
function readSkillSessionSnapshot(sessionId, options = {}) {
|
|
43068
|
+
const snapshot = readSkillSessionSnapshotIfExists(sessionId, options);
|
|
43069
|
+
if (!snapshot)
|
|
43070
|
+
throw new SkillSelectionError("SESSION_NOT_FOUND", "The requested Skills session receipt does not exist.");
|
|
43071
|
+
return snapshot;
|
|
43072
|
+
}
|
|
43073
|
+
function skillSessionSnapshotBinding(snapshot) {
|
|
43074
|
+
return { sessionId: snapshot.sessionId, generation: snapshot.generation, receiptSha256: snapshot.receiptSha256 };
|
|
43075
|
+
}
|
|
43076
|
+
function withSessionWriteLocks(sessionIds, options, action) {
|
|
43077
|
+
const operationId = randomUUID3();
|
|
43078
|
+
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);
|
|
43079
|
+
const owned = [];
|
|
43080
|
+
const assertOwned = () => {
|
|
43081
|
+
for (const lock of owned) {
|
|
43082
|
+
const current = lstatSync3(lock.path, { throwIfNoEntry: false });
|
|
43083
|
+
if (!current?.isFile() || current.dev !== lock.dev || current.ino !== lock.ino) {
|
|
43084
|
+
throw new SkillSelectionError("SESSION_WRITE_LOCK_CHANGED", "A session write lock changed during the operation; no replacement is permitted.");
|
|
43085
|
+
}
|
|
43086
|
+
}
|
|
43087
|
+
};
|
|
43088
|
+
try {
|
|
43089
|
+
for (const lock of locks) {
|
|
43090
|
+
assertRegularPath(lock.path, true);
|
|
43091
|
+
let fd;
|
|
43092
|
+
try {
|
|
43093
|
+
fd = openSync(lock.path, constants2.O_WRONLY | constants2.O_CREAT | constants2.O_EXCL | constants2.O_NOFOLLOW, 384);
|
|
43094
|
+
} catch (error) {
|
|
43095
|
+
if (error.code === "EEXIST")
|
|
43096
|
+
throw new SkillSelectionError("SESSION_WRITE_LOCKED", "Another Skills process owns a required session write lock; retry after it completes. A surviving lock requires explicit recovery review.");
|
|
43097
|
+
throw error;
|
|
43098
|
+
}
|
|
43099
|
+
const stat = fstatSync(fd);
|
|
43100
|
+
owned.push({ path: lock.path, fd, dev: stat.dev, ino: stat.ino });
|
|
43101
|
+
writeFileSync4(fd, `${JSON.stringify({ schemaVersion: 1, operationId, sessionId: lock.sessionId, pid: process.pid })}
|
|
43102
|
+
`);
|
|
43103
|
+
}
|
|
43104
|
+
return action(assertOwned);
|
|
43105
|
+
} finally {
|
|
43106
|
+
for (const lock of owned.reverse()) {
|
|
43107
|
+
closeSync(lock.fd);
|
|
43108
|
+
const current = lstatSync3(lock.path, { throwIfNoEntry: false });
|
|
43109
|
+
if (current?.isFile() && current.dev === lock.dev && current.ino === lock.ino)
|
|
43110
|
+
unlinkSync(lock.path);
|
|
43029
43111
|
}
|
|
43030
43112
|
}
|
|
43031
|
-
|
|
43113
|
+
}
|
|
43114
|
+
function withSessionWriteLock(sessionId, options, action) {
|
|
43115
|
+
return withSessionWriteLocks([sessionId], options, action);
|
|
43116
|
+
}
|
|
43117
|
+
function sameSnapshot(actual, expected) {
|
|
43118
|
+
return actual === null ? expected === null : expected !== null && actual.sessionId === expected.sessionId && actual.generation === expected.generation && actual.receiptSha256 === expected.receiptSha256;
|
|
43119
|
+
}
|
|
43120
|
+
function nextSkillSessionGeneration(generation) {
|
|
43121
|
+
if (!Number.isSafeInteger(generation) || generation < 0 || generation >= Number.MAX_SAFE_INTEGER) {
|
|
43122
|
+
throw new SkillSelectionError("SESSION_GENERATION_EXHAUSTED", "The Skills session generation cannot advance safely; preserve the receipt and review recovery before continuing.");
|
|
43123
|
+
}
|
|
43124
|
+
return generation + 1;
|
|
43125
|
+
}
|
|
43126
|
+
function parentChanged() {
|
|
43127
|
+
throw new SkillSelectionError("SESSION_PARENT_CHANGED", "The parent Skills session changed while the child was resolving; resolve the child again from the current parent pin.");
|
|
43128
|
+
}
|
|
43129
|
+
function writeSkillSession(receipt, expected, options = {}) {
|
|
43130
|
+
validateSkillSessionReceipt(receipt, receipt.sessionId);
|
|
43131
|
+
if (expected.parent)
|
|
43132
|
+
validateSkillSessionBinding(expected.parent);
|
|
43133
|
+
if (expected.parent?.sessionId === receipt.sessionId)
|
|
43134
|
+
throw new SkillSelectionError("INVALID_RECEIPT", "A Skills child session cannot name itself as its parent.");
|
|
43135
|
+
const lockIds = expected.parent ? [receipt.sessionId, expected.parent.sessionId] : [receipt.sessionId];
|
|
43136
|
+
withSessionWriteLocks(lockIds, options, (assertOwned) => {
|
|
43137
|
+
const current = readSkillSessionSnapshotIfExists(receipt.sessionId, options);
|
|
43138
|
+
if (!sameSnapshot(current, expected.current) || current && !isDeepStrictEqual2(current.receipt.profile, receipt.profile)) {
|
|
43139
|
+
throw new SkillSelectionError("SESSION_RECEIPT_CHANGED", "The Skills session receipt changed while context was loading; resolve context again without replacing the current pin.");
|
|
43140
|
+
}
|
|
43141
|
+
let parent = null;
|
|
43142
|
+
if (expected.parent) {
|
|
43143
|
+
parent = readSkillSessionSnapshotIfExists(expected.parent.sessionId, options);
|
|
43144
|
+
if (!sameSnapshot(parent, expected.parent) || !parent || !isDeepStrictEqual2(parent.receipt.profile, receipt.profile))
|
|
43145
|
+
parentChanged();
|
|
43146
|
+
}
|
|
43147
|
+
const generation = nextSkillSessionGeneration(current?.generation ?? 0);
|
|
43148
|
+
const next = current ? { ...current.receipt, generation, loaded: [...new Set([...current.receipt.loaded, ...receipt.loaded])] } : { ...receipt, generation, ...expected.parent ? { parent: expected.parent } : {} };
|
|
43149
|
+
assertOwned();
|
|
43150
|
+
if (expected.parent) {
|
|
43151
|
+
parent = readSkillSessionSnapshotIfExists(expected.parent.sessionId, options);
|
|
43152
|
+
if (!sameSnapshot(parent, expected.parent))
|
|
43153
|
+
parentChanged();
|
|
43154
|
+
}
|
|
43155
|
+
writeSelectionJson(sessionReceiptPath(receipt.sessionId, options), next);
|
|
43156
|
+
});
|
|
43157
|
+
}
|
|
43158
|
+
function syncDirectory(path) {
|
|
43159
|
+
assertRegularPath(path);
|
|
43160
|
+
const fd = openSync(path, constants2.O_RDONLY | constants2.O_DIRECTORY | constants2.O_NOFOLLOW);
|
|
43161
|
+
try {
|
|
43162
|
+
fsyncSync(fd);
|
|
43163
|
+
} finally {
|
|
43164
|
+
closeSync(fd);
|
|
43165
|
+
}
|
|
43166
|
+
}
|
|
43167
|
+
function archiveBytes(path, bytes) {
|
|
43168
|
+
assertRegularPath(path, true);
|
|
43169
|
+
const fd = openSync(path, constants2.O_WRONLY | constants2.O_CREAT | constants2.O_EXCL | constants2.O_NOFOLLOW, 384);
|
|
43170
|
+
try {
|
|
43171
|
+
writeFileSync4(fd, bytes);
|
|
43172
|
+
fsyncSync(fd);
|
|
43173
|
+
} finally {
|
|
43174
|
+
closeSync(fd);
|
|
43175
|
+
}
|
|
43176
|
+
}
|
|
43177
|
+
function replaceSkillSession(expected, replacement, plan, options = {}, beforeCommit = () => {}) {
|
|
43178
|
+
validateSkillSessionReceipt(replacement, replacement.sessionId);
|
|
43179
|
+
const bytes = Buffer.from(`${JSON.stringify(replacement)}
|
|
43180
|
+
`);
|
|
43181
|
+
if (bytes.length > MAX_PROFILE_DOCUMENT_BYTES)
|
|
43182
|
+
throw new SkillSelectionError("RECEIPT_TOO_LARGE", "The Skills selection receipt exceeds its size limit.");
|
|
43183
|
+
return withSessionWriteLock(replacement.sessionId, options, (assertOwned) => {
|
|
43184
|
+
const before2 = readSkillSessionSnapshot(replacement.sessionId, options);
|
|
43185
|
+
if (!sameSnapshot(before2, expected))
|
|
43186
|
+
throw new SkillSelectionError("SESSION_RECEIPT_CHANGED", "The Skills session receipt generation or bytes changed after review; inspect it and prepare a new plan.");
|
|
43187
|
+
if (replacement.generation !== nextSkillSessionGeneration(before2.generation))
|
|
43188
|
+
throw new SkillSelectionError("SESSION_GENERATION_CHANGED", "The replacement Skills session must advance exactly one generation.");
|
|
43189
|
+
if (before2.receipt.profile.authority !== replacement.profile.authority || before2.receipt.profile.workspaceId !== replacement.profile.workspaceId) {
|
|
43190
|
+
throw new SkillSelectionError("PROFILE_IDENTITY_MISMATCH", "A session reconciliation cannot change its Skills authority or workspace.");
|
|
43191
|
+
}
|
|
43192
|
+
const directory = join14(selectionCacheRoot(options), "session-reconciliations", randomUUID3());
|
|
43193
|
+
const archivePath = join14(directory, "original.json"), replacementPath = join14(directory, "replacement.json"), receiptPath = join14(directory, "receipt.json");
|
|
43194
|
+
const afterSha256 = sha256Hex(bytes);
|
|
43195
|
+
archiveBytes(archivePath, before2.bytes);
|
|
43196
|
+
archiveBytes(replacementPath, bytes);
|
|
43197
|
+
const receipt = { schemaVersion: 1, status: "prepared", sessionId: replacement.sessionId, beforeGeneration: before2.generation, afterGeneration: replacement.generation, beforeSha256: before2.sha256, afterSha256, archivePath, replacementPath, plan };
|
|
43198
|
+
archiveBytes(receiptPath, Buffer.from(`${JSON.stringify(receipt)}
|
|
43199
|
+
`));
|
|
43200
|
+
syncDirectory(directory);
|
|
43201
|
+
syncDirectory(dirname4(directory));
|
|
43202
|
+
syncDirectory(selectionCacheRoot(options));
|
|
43203
|
+
if (sha256Hex(readRegularFile(archivePath, MAX_PROFILE_DOCUMENT_BYTES)) !== before2.sha256 || !sameSnapshot(readSkillSessionSnapshot(replacement.sessionId, options), expected)) {
|
|
43204
|
+
throw new SkillSelectionError("SESSION_RECEIPT_CHANGED", "The session or its preservation archive changed before replacement; retained evidence must be reviewed.");
|
|
43205
|
+
}
|
|
43206
|
+
beforeCommit();
|
|
43207
|
+
assertOwned();
|
|
43208
|
+
try {
|
|
43209
|
+
atomicWrite(before2.path, bytes, 384, true);
|
|
43210
|
+
atomicWrite(receiptPath, Buffer.from(`${JSON.stringify({ ...receipt, status: "applied" })}
|
|
43211
|
+
`), 384, true);
|
|
43212
|
+
} catch {
|
|
43213
|
+
throw new SkillSelectionError("SESSION_RECONCILIATION_INCOMPLETE", `Inspect sessions show and the preserved operation receipt at ${receiptPath} before any retry; replacement may already have committed.`);
|
|
43214
|
+
}
|
|
43215
|
+
return { archivePath, receiptPath, beforeSha256: before2.sha256, afterSha256 };
|
|
43216
|
+
});
|
|
43032
43217
|
}
|
|
43033
43218
|
var SkillSelectionError, MAX_CACHED_PROFILE_AGE_MS, SELECTION_LOCK_FILE = "selection.lock.json";
|
|
43034
43219
|
var init_selection_cache = __esm(() => {
|
|
@@ -43048,6 +43233,7 @@ var init_selection_cache = __esm(() => {
|
|
|
43048
43233
|
});
|
|
43049
43234
|
|
|
43050
43235
|
// src/lib/agent-policy-limits.ts
|
|
43236
|
+
import { basename as basename3, isAbsolute as isAbsolute3, resolve as resolve5 } from "path";
|
|
43051
43237
|
function object(value) {
|
|
43052
43238
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
43053
43239
|
}
|
|
@@ -43112,7 +43298,11 @@ function assertAgentPolicyCollections(policy) {
|
|
|
43112
43298
|
text(source.path);
|
|
43113
43299
|
requireBound(source.sha256 === null || typeof source.sha256 === "string" && /^[a-f0-9]{64}$/.test(source.sha256));
|
|
43114
43300
|
if (source.hashMode !== undefined)
|
|
43115
|
-
requireBound(["bytes", "path-bytes", "claude-plugin-registry"].includes(source.hashMode) && source.format === undefined && source.fields === undefined && (source.hashMode === "bytes" || source.sha256 !== null));
|
|
43301
|
+
requireBound(["bytes", "path-bytes", "claude-plugin-registry", "claude-marketplace-registry", "claude-settings-v1"].includes(source.hashMode) && source.format === undefined && source.fields === undefined && (source.hashMode === "bytes" || source.sha256 !== null));
|
|
43302
|
+
if (source.hashMode === "claude-settings-v1")
|
|
43303
|
+
requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute3(source.path) && resolve5(source.path) === source.path && basename3(source.path) === "settings.json");
|
|
43304
|
+
if (source.hashMode === "claude-marketplace-registry")
|
|
43305
|
+
requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute3(source.path) && resolve5(source.path) === source.path && basename3(source.path) === "known_marketplaces.json");
|
|
43116
43306
|
if (source.hashMode === "claude-plugin-registry") {
|
|
43117
43307
|
requireBound(agent === "claude");
|
|
43118
43308
|
const managed = array(source.managedPlugins, 64);
|
|
@@ -50265,7 +50455,7 @@ var init_dist = __esm(() => {
|
|
|
50265
50455
|
});
|
|
50266
50456
|
|
|
50267
50457
|
// src/lib/agent-hermes.ts
|
|
50268
|
-
import { dirname as dirname5, isAbsolute as
|
|
50458
|
+
import { dirname as dirname5, isAbsolute as isAbsolute4, join as join17, resolve as resolve6 } from "path";
|
|
50269
50459
|
import { lstatSync as lstatSync6, readFileSync as readFileSync10, opendirSync } from "fs";
|
|
50270
50460
|
function object2(value) {
|
|
50271
50461
|
return Boolean(value && typeof value === "object" && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null));
|
|
@@ -50301,7 +50491,7 @@ function quoted(value) {
|
|
|
50301
50491
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
50302
50492
|
}
|
|
50303
50493
|
function hermesHookDefinitions(supervisor) {
|
|
50304
|
-
if (!
|
|
50494
|
+
if (!isAbsolute4(supervisor.runtime) || !isAbsolute4(supervisor.path))
|
|
50305
50495
|
throw new Error("Expected absolute Hermes supervisor paths");
|
|
50306
50496
|
const entry = (event) => ({ command: `${quoted(supervisor.runtime)} ${quoted(supervisor.path)} --event ${event}`, timeout: 15, ...event === "pre_tool_call" ? { fail_closed: true } : {} });
|
|
50307
50497
|
return { pre_llm_call: entry("pre_llm_call"), pre_tool_call: entry("pre_tool_call") };
|
|
@@ -50337,7 +50527,7 @@ function assertHermesEnvironment(home) {
|
|
|
50337
50527
|
throw new Error(`NATIVE_SKILL_DRIFT: Hermes ${variable} requires a dedicated discovery adapter; unset it before using this adapter`);
|
|
50338
50528
|
}
|
|
50339
50529
|
const selected = process.env.HERMES_HOME?.trim();
|
|
50340
|
-
if (selected && (!
|
|
50530
|
+
if (selected && (!isAbsolute4(selected) || resolve6(selected) !== join17(resolve6(home), ".hermes")))
|
|
50341
50531
|
throw new Error("NATIVE_SKILL_DRIFT: custom Hermes homes/profiles require their own reviewed bridge");
|
|
50342
50532
|
if (process.env.HERMES_ENABLE_PROJECT_PLUGINS?.trim() && !["0", "false", "no", "off"].includes(process.env.HERMES_ENABLE_PROJECT_PLUGINS.trim().toLowerCase()))
|
|
50343
50533
|
throw new Error("NATIVE_SKILL_DRIFT: Hermes project plugins require a dedicated discovery review");
|
|
@@ -50360,7 +50550,7 @@ function assertHermesProtection(home, config, command, profile, supervisor) {
|
|
|
50360
50550
|
assertHermesEnvironment(home);
|
|
50361
50551
|
if (read(join17(home, ".hermes", HERMES_OPT_OUT)) === null)
|
|
50362
50552
|
throw new Error("NATIVE_SKILL_DRIFT: Hermes bundled skill reseeding is not disabled; run skills hook install");
|
|
50363
|
-
if (!supervisor || !
|
|
50553
|
+
if (!supervisor || !isAbsolute4(supervisor.path) || supervisor.runtime !== process.execPath || read(supervisor.path) !== renderHermesSupervisor(command, profile))
|
|
50364
50554
|
throw new Error("NATIVE_SKILL_DRIFT: Hermes owned supervisor changed; run skills hook install");
|
|
50365
50555
|
const raw = read(join17(home, ".hermes/shell-hooks-allowlist.json"));
|
|
50366
50556
|
let trust;
|
|
@@ -50386,7 +50576,7 @@ function assertHermesProtection(home, config, command, profile, supervisor) {
|
|
|
50386
50576
|
}
|
|
50387
50577
|
function assertNoHermesLegacyShadow(root) {
|
|
50388
50578
|
let entries = 0;
|
|
50389
|
-
for (let cursor =
|
|
50579
|
+
for (let cursor = resolve6(root);; cursor = dirname5(cursor)) {
|
|
50390
50580
|
if (lstatSync6(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
50391
50581
|
throw new Error("NATIVE_SKILL_DRIFT: symlink Hermes legacy discovery root");
|
|
50392
50582
|
if (dirname5(cursor) === cursor)
|
|
@@ -50490,13 +50680,13 @@ var init_agent_hermes = __esm(() => {
|
|
|
50490
50680
|
// src/lib/agent-discovery-directories.ts
|
|
50491
50681
|
import { createHash as createHash5 } from "crypto";
|
|
50492
50682
|
import { lstatSync as lstatSync7, opendirSync as opendirSync2 } from "fs";
|
|
50493
|
-
import { dirname as dirname6, isAbsolute as
|
|
50683
|
+
import { dirname as dirname6, isAbsolute as isAbsolute5, join as join18, resolve as resolve7 } from "path";
|
|
50494
50684
|
function need(value, message) {
|
|
50495
50685
|
if (!value)
|
|
50496
50686
|
throw new Error(message);
|
|
50497
50687
|
}
|
|
50498
50688
|
function safe(path) {
|
|
50499
|
-
need(typeof path === "string" && path.length <= AGENT_POLICY_LIMITS.pathCharacters &&
|
|
50689
|
+
need(typeof path === "string" && path.length <= AGENT_POLICY_LIMITS.pathCharacters && isAbsolute5(path) && resolve7(path) === path && !path.includes("\x00"), "Expected a canonical absolute discovery directory path");
|
|
50500
50690
|
for (let cursor = path;; cursor = dirname6(cursor)) {
|
|
50501
50691
|
need(!lstatSync7(cursor, { throwIfNoEntry: false })?.isSymbolicLink(), "Refusing symlink native discovery directory");
|
|
50502
50692
|
if (dirname6(cursor) === cursor)
|
|
@@ -50564,12 +50754,12 @@ var init_agent_discovery_directories = __esm(() => {
|
|
|
50564
50754
|
// src/lib/agent-discovery-bytes.ts
|
|
50565
50755
|
import { createHash as createHash6 } from "crypto";
|
|
50566
50756
|
import { closeSync as closeSync3, constants as constants4, fstatSync as fstatSync3, lstatSync as lstatSync8, openSync as openSync3, readSync as readSync3 } from "fs";
|
|
50567
|
-
import { dirname as dirname7, isAbsolute as
|
|
50757
|
+
import { dirname as dirname7, isAbsolute as isAbsolute6, resolve as resolve8 } from "path";
|
|
50568
50758
|
function discoveryByteBudget() {
|
|
50569
50759
|
return { remaining: AGENT_POLICY_LIMITS.discoveryRawTotalBytes };
|
|
50570
50760
|
}
|
|
50571
50761
|
function safe2(path) {
|
|
50572
|
-
if (typeof path !== "string" || !
|
|
50762
|
+
if (typeof path !== "string" || !isAbsolute6(path) || path !== resolve8(path) || path.length > AGENT_POLICY_LIMITS.pathCharacters || path.includes("\x00"))
|
|
50573
50763
|
throw new Error("Expected a canonical absolute raw discovery path");
|
|
50574
50764
|
for (let cursor = path;; cursor = dirname7(cursor)) {
|
|
50575
50765
|
if (lstatSync8(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
@@ -50635,7 +50825,7 @@ var init_agent_discovery_bytes = __esm(() => {
|
|
|
50635
50825
|
// src/lib/agent-discovery-path-bytes.ts
|
|
50636
50826
|
import { createHash as createHash7 } from "crypto";
|
|
50637
50827
|
import { lstatSync as lstatSync9, readlinkSync } from "fs";
|
|
50638
|
-
import { dirname as dirname8, isAbsolute as
|
|
50828
|
+
import { dirname as dirname8, isAbsolute as isAbsolute7, join as join19, parse as parse2, resolve as resolve9, sep as sep3 } from "path";
|
|
50639
50829
|
function identity3(stat, mutable = false) {
|
|
50640
50830
|
return {
|
|
50641
50831
|
dev: String(stat.dev),
|
|
@@ -50647,7 +50837,7 @@ function identity3(stat, mutable = false) {
|
|
|
50647
50837
|
};
|
|
50648
50838
|
}
|
|
50649
50839
|
function canonical(path) {
|
|
50650
|
-
if (typeof path !== "string" || !
|
|
50840
|
+
if (typeof path !== "string" || !isAbsolute7(path) || path !== resolve9(path) || path.length > AGENT_POLICY_LIMITS.pathCharacters || path.includes("\x00") || Buffer.from(path).toString("utf8") !== path)
|
|
50651
50841
|
throw new Error("Expected a canonical absolute discovery path");
|
|
50652
50842
|
}
|
|
50653
50843
|
function trace(path) {
|
|
@@ -50696,11 +50886,11 @@ function trace(path) {
|
|
|
50696
50886
|
if (!target || target.includes("\x00") || Buffer.byteLength(target) > AGENT_POLICY_LIMITS.pathCharacters || !after2.isSymbolicLink() || JSON.stringify(identity3(stat, true)) !== JSON.stringify(identity3(after2, true)))
|
|
50697
50887
|
throw new Error("Discovery link changed during read");
|
|
50698
50888
|
record2(candidate, { type: "link", target, ...identity3(stat, true) });
|
|
50699
|
-
if (
|
|
50889
|
+
if (isAbsolute7(target)) {
|
|
50700
50890
|
cursor = parse2(target).root;
|
|
50701
50891
|
root();
|
|
50702
50892
|
}
|
|
50703
|
-
const remainder =
|
|
50893
|
+
const remainder = isAbsolute7(target) ? target.slice(parse2(target).root.length) : target;
|
|
50704
50894
|
pending = [...remainder.split(sep3), ...pending];
|
|
50705
50895
|
if (pending.length + steps > AGENT_POLICY_LIMITS.discoveryPathSteps)
|
|
50706
50896
|
throw new Error("Discovery path step limit exceeded");
|
|
@@ -50756,12 +50946,12 @@ import { spawnSync } from "child_process";
|
|
|
50756
50946
|
import { closeSync as closeSync22, fstatSync as fstatSync22, openSync as openSync22, readFileSync as readFileSync22 } from "fs";
|
|
50757
50947
|
import { O_NOFOLLOW as O_NOFOLLOW2, O_NONBLOCK as O_NONBLOCK2, O_RDONLY as O_RDONLY2 } from "constants";
|
|
50758
50948
|
import { hostname as osHostname } from "os";
|
|
50759
|
-
import { isAbsolute as
|
|
50949
|
+
import { isAbsolute as isAbsolute8, join as join22 } from "path";
|
|
50760
50950
|
import { createRequire } from "module";
|
|
50761
50951
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
50762
50952
|
import { closeSync as closeSync4, fstatSync as fstatSync4, lstatSync as lstatSync10, openSync as openSync4, readFileSync as readFileSync11, realpathSync as realpathSync3, statSync as statSync7 } from "fs";
|
|
50763
50953
|
import { O_NOFOLLOW, O_NONBLOCK, O_RDONLY } from "constants";
|
|
50764
|
-
import { basename as
|
|
50954
|
+
import { basename as basename4, dirname as dirname9, join as join20, relative as relative4, sep as sep4 } from "path";
|
|
50765
50955
|
import { fileURLToPath, pathToFileURL } from "url";
|
|
50766
50956
|
function envToken(name) {
|
|
50767
50957
|
return name.toUpperCase().replace(/-/g, "_");
|
|
@@ -50866,7 +51056,7 @@ function entryPoint(directory) {
|
|
|
50866
51056
|
function resolveInstalledSecrets(parentUrl) {
|
|
50867
51057
|
let directory = dirname9(fileURLToPath(parentUrl));
|
|
50868
51058
|
for (;; ) {
|
|
50869
|
-
if (
|
|
51059
|
+
if (basename4(directory) !== "node_modules") {
|
|
50870
51060
|
const candidate = join20(directory, "node_modules", PACKAGE);
|
|
50871
51061
|
let absent = false;
|
|
50872
51062
|
try {
|
|
@@ -50891,7 +51081,7 @@ function homeDir(env3) {
|
|
|
50891
51081
|
}
|
|
50892
51082
|
function absoluteOverride(env3, key) {
|
|
50893
51083
|
const value = env3[key]?.trim();
|
|
50894
|
-
return value &&
|
|
51084
|
+
return value && isAbsolute8(value) ? value : null;
|
|
50895
51085
|
}
|
|
50896
51086
|
function hasnaHomeDir(env3) {
|
|
50897
51087
|
const override = absoluteOverride(env3, HASNA_HOME_ENV_KEY);
|
|
@@ -51709,6 +51899,7 @@ __export(exports_fleet_credentials, {
|
|
|
51709
51899
|
SKILLS_API_URL_ENV: () => SKILLS_API_URL_ENV,
|
|
51710
51900
|
SKILLS_API_KEY_ENV_KEYS: () => SKILLS_API_KEY_ENV_KEYS,
|
|
51711
51901
|
SKILLS_API_KEY_ENV: () => SKILLS_API_KEY_ENV,
|
|
51902
|
+
REDACTED_VAULT_REFERENCE: () => REDACTED_VAULT_REFERENCE,
|
|
51712
51903
|
MissingSkillsFleetError: () => MissingSkillsFleetError
|
|
51713
51904
|
});
|
|
51714
51905
|
function isCredentialResolutionError(error) {
|
|
@@ -51717,10 +51908,15 @@ function isCredentialResolutionError(error) {
|
|
|
51717
51908
|
function isSkillsFleetCredentialError(error) {
|
|
51718
51909
|
return error instanceof SkillsFleetCredentialError || typeof error === "object" && error !== null && error.name === "SkillsFleetCredentialError";
|
|
51719
51910
|
}
|
|
51720
|
-
function
|
|
51911
|
+
function redactVaultReference(message, vaultReference) {
|
|
51912
|
+
if (!vaultReference)
|
|
51913
|
+
return message;
|
|
51914
|
+
return message.split(vaultReference).join(REDACTED_VAULT_REFERENCE);
|
|
51915
|
+
}
|
|
51916
|
+
function asSkillsFleetCredentialError(error, vaultReference) {
|
|
51721
51917
|
if (!isCredentialResolutionError(error))
|
|
51722
51918
|
return null;
|
|
51723
|
-
return new SkillsFleetCredentialError(error.message, "MISSING_API_CREDENTIAL");
|
|
51919
|
+
return new SkillsFleetCredentialError(redactVaultReference(error.message, vaultReference), "MISSING_API_CREDENTIAL");
|
|
51724
51920
|
}
|
|
51725
51921
|
function normalizeSkillsApiOrigin(apiUrl) {
|
|
51726
51922
|
const url = new URL(apiUrl);
|
|
@@ -51907,7 +52103,7 @@ async function resolveSkillsConnection(env3 = process.env, options = {}) {
|
|
|
51907
52103
|
try {
|
|
51908
52104
|
completed = await completePointerCredential(SKILLS_APP, pointer, env3);
|
|
51909
52105
|
} catch (error) {
|
|
51910
|
-
const translated = asSkillsFleetCredentialError(error);
|
|
52106
|
+
const translated = asSkillsFleetCredentialError(error, pointer.pointerVaultKey);
|
|
51911
52107
|
if (translated)
|
|
51912
52108
|
throw translated;
|
|
51913
52109
|
throw error;
|
|
@@ -51963,7 +52159,7 @@ function requireSkillsFleet(action = "This command", env3 = process.env, options
|
|
|
51963
52159
|
return fleet;
|
|
51964
52160
|
throw new MissingSkillsFleetError(action);
|
|
51965
52161
|
}
|
|
51966
|
-
var SKILLS_APP = "skills", ENV_KEYS, SKILLS_API_URL_ENV_KEYS, SKILLS_API_KEY_ENV_KEYS, SKILLS_API_URL_ENV, SKILLS_API_KEY_ENV, SkillsFleetCredentialError, localNoticePrinted = false, MissingSkillsFleetError;
|
|
52162
|
+
var SKILLS_APP = "skills", ENV_KEYS, SKILLS_API_URL_ENV_KEYS, SKILLS_API_KEY_ENV_KEYS, SKILLS_API_URL_ENV, SKILLS_API_KEY_ENV, SkillsFleetCredentialError, REDACTED_VAULT_REFERENCE = "[redacted vault reference]", localNoticePrinted = false, MissingSkillsFleetError;
|
|
51967
52163
|
var init_fleet_credentials = __esm(() => {
|
|
51968
52164
|
init_transport();
|
|
51969
52165
|
init_instance_credentials();
|
|
@@ -52909,11 +53105,18 @@ async function syncSelectionProfile(profileId, options = {}) {
|
|
|
52909
53105
|
return { profile, receipt, changed, downloaded, stationReported };
|
|
52910
53106
|
}
|
|
52911
53107
|
async function resolveSelectionContext(profileId, options = {}) {
|
|
52912
|
-
const
|
|
52913
|
-
const
|
|
53108
|
+
const sessionState = options.sessionId ? readSkillSessionSnapshotIfExists(options.sessionId, options) : null;
|
|
53109
|
+
const session = sessionState?.receipt ?? null;
|
|
53110
|
+
const parentState = !session && options.parentSessionId ? readSkillSessionSnapshotIfExists(options.parentSessionId, options) : null;
|
|
53111
|
+
if (!session && options.parentSessionId && !parentState) {
|
|
53112
|
+
throw new SkillSelectionError("SESSION_PARENT_NOT_FOUND", "A child Skills session requires an existing parent receipt so its inherited pin can be bound exactly.");
|
|
53113
|
+
}
|
|
53114
|
+
const parentSession = parentState?.receipt ?? null;
|
|
53115
|
+
const sessionSnapshot = sessionState ? skillSessionSnapshotBinding(sessionState) : null;
|
|
53116
|
+
const parentSnapshot = parentState ? skillSessionSnapshotBinding(parentState) : undefined;
|
|
52914
53117
|
const project = options.projectDir ? readProjectSelection(options.projectDir) : null;
|
|
52915
53118
|
if (session && session.profile.profileId !== profileId || parentSession && parentSession.profile.profileId !== profileId || project && project.profile.profileId !== profileId) {
|
|
52916
|
-
throw new SkillSelectionError("PROFILE_LOCK_MISMATCH", "The session or project is pinned to a different Skills profile. Select
|
|
53119
|
+
throw new SkillSelectionError("PROFILE_LOCK_MISMATCH", "The session or project is pinned to a different Skills profile. Select the pinned profile, or review skills sessions reconcile for an intentional session change and explicit project sync for a project change.");
|
|
52917
53120
|
}
|
|
52918
53121
|
if (options.cached) {
|
|
52919
53122
|
const receipt2 = session ?? parentSession ?? project ?? readSelectionProfile(profileId, options);
|
|
@@ -52921,7 +53124,7 @@ async function resolveSelectionContext(profileId, options = {}) {
|
|
|
52921
53124
|
throw new SkillSelectionError("CACHED_PROFILE_MISSING", "No verified Skills profile is cached; authenticate and sync it first.");
|
|
52922
53125
|
assertFreshCachedProfile(receipt2, options);
|
|
52923
53126
|
assertBinding(receipt2.profile, options);
|
|
52924
|
-
return { receipt: receipt2, session, inheritedLoaded: parentSession?.loaded };
|
|
53127
|
+
return { receipt: receipt2, session, sessionSnapshot, parentSnapshot, inheritedLoaded: parentSession?.loaded };
|
|
52925
53128
|
}
|
|
52926
53129
|
const client = options.client ?? await createProfileClient();
|
|
52927
53130
|
const current = await client.resolveProfile(profileId);
|
|
@@ -52934,7 +53137,7 @@ async function resolveSelectionContext(profileId, options = {}) {
|
|
|
52934
53137
|
throw new SkillSelectionError("PROFILE_IDENTITY_MISMATCH", "The pinned selection belongs to another Skills authority or workspace.");
|
|
52935
53138
|
}
|
|
52936
53139
|
const receipt = locked ?? { schemaVersion: 1, verifiedAt: new Date((options.now ?? Date.now)()).toISOString(), profile: current };
|
|
52937
|
-
return { receipt, session, client, inheritedLoaded: parentSession?.loaded };
|
|
53140
|
+
return { receipt, session, sessionSnapshot, parentSnapshot, client, inheritedLoaded: parentSession?.loaded };
|
|
52938
53141
|
}
|
|
52939
53142
|
function assertBinding(profile, options) {
|
|
52940
53143
|
if (options.authority !== undefined && profile.authority !== options.authority || options.workspaceId !== undefined && profile.workspaceId !== options.workspaceId) {
|
|
@@ -52973,7 +53176,7 @@ async function loadSelectedSkill(spec, profileId, options = {}) {
|
|
|
52973
53176
|
sessionId: options.sessionId,
|
|
52974
53177
|
loaded: [...new Set([...context.session?.loaded ?? [], selectionKey(selection)])]
|
|
52975
53178
|
};
|
|
52976
|
-
|
|
53179
|
+
writeSkillSession(session, { current: context.sessionSnapshot, parent: context.parentSnapshot }, options);
|
|
52977
53180
|
}
|
|
52978
53181
|
return { content, selection, receipt };
|
|
52979
53182
|
}
|
|
@@ -53214,8 +53417,8 @@ var init_plugin_projection = __esm(() => {
|
|
|
53214
53417
|
|
|
53215
53418
|
// src/lib/plugin-projection-store.ts
|
|
53216
53419
|
import { createHash as createHash10, randomUUID as randomUUID5 } from "crypto";
|
|
53217
|
-
import { constants as constants7, closeSync as closeSync7, fchmodSync, fstatSync as fstatSync7, fsyncSync, linkSync, lstatSync as lstatSync13, mkdirSync as mkdirSync6, openSync as openSync7, opendirSync as opendirSync3, readSync as readSync5, renameSync as renameSync3, rmdirSync as rmdirSync2, rmSync as rmSync2, unlinkSync as unlinkSync3, writeSync as writeSync2 } from "fs";
|
|
53218
|
-
import { dirname as dirname10, isAbsolute as
|
|
53420
|
+
import { constants as constants7, closeSync as closeSync7, fchmodSync, fstatSync as fstatSync7, fsyncSync as fsyncSync2, linkSync, lstatSync as lstatSync13, mkdirSync as mkdirSync6, openSync as openSync7, opendirSync as opendirSync3, readSync as readSync5, renameSync as renameSync3, rmdirSync as rmdirSync2, rmSync as rmSync2, unlinkSync as unlinkSync3, writeSync as writeSync2 } from "fs";
|
|
53421
|
+
import { dirname as dirname10, isAbsolute as isAbsolute9, join as join25, parse as parse4, resolve as resolve10 } from "path";
|
|
53219
53422
|
function stat(path) {
|
|
53220
53423
|
try {
|
|
53221
53424
|
return lstatSync13(path, { bigint: true });
|
|
@@ -53226,7 +53429,7 @@ function stat(path) {
|
|
|
53226
53429
|
}
|
|
53227
53430
|
}
|
|
53228
53431
|
function canonical2(path) {
|
|
53229
|
-
pluginNeed(typeof path === "string" && path.length <= 8192 &&
|
|
53432
|
+
pluginNeed(typeof path === "string" && path.length <= 8192 && isAbsolute9(path) && resolve10(path) === path && !/[\x00-\x1f\x7f]/.test(path), "Plugin storage paths must be canonical absolute paths");
|
|
53230
53433
|
}
|
|
53231
53434
|
function owner(stats, system = false) {
|
|
53232
53435
|
const current = uid();
|
|
@@ -53435,7 +53638,7 @@ function writeExclusive(path, bytes, mode) {
|
|
|
53435
53638
|
pluginNeed(count > 0, "Plugin file write did not progress");
|
|
53436
53639
|
offset += count;
|
|
53437
53640
|
}
|
|
53438
|
-
|
|
53641
|
+
fsyncSync2(fd);
|
|
53439
53642
|
} catch (error) {
|
|
53440
53643
|
if (created) {
|
|
53441
53644
|
same3(created, stat(path), true);
|
|
@@ -53608,7 +53811,7 @@ var init_selected_manifest = __esm(() => {
|
|
|
53608
53811
|
|
|
53609
53812
|
// src/lib/plugin-admission.ts
|
|
53610
53813
|
import { homedir as homedir3 } from "os";
|
|
53611
|
-
import { isAbsolute as
|
|
53814
|
+
import { isAbsolute as isAbsolute10, join as join26, resolve as resolve11 } from "path";
|
|
53612
53815
|
function pluginAdmissionRoot() {
|
|
53613
53816
|
return join26(homedir3(), ".hasna", "skills", "plugin-admission");
|
|
53614
53817
|
}
|
|
@@ -53621,7 +53824,7 @@ function validatePluginTarget(value) {
|
|
|
53621
53824
|
for (const registration of value.registrations) {
|
|
53622
53825
|
pluginKeys(registration, ["scope", "projectPath"]);
|
|
53623
53826
|
pluginNeed(registration.scope === "user" || registration.scope === "project", "Unsupported plugin registration scope");
|
|
53624
|
-
pluginNeed(registration.scope === "user" ? registration.projectPath === null : typeof registration.projectPath === "string" &&
|
|
53827
|
+
pluginNeed(registration.scope === "user" ? registration.projectPath === null : typeof registration.projectPath === "string" && isAbsolute10(registration.projectPath) && resolve11(registration.projectPath) === registration.projectPath, "Plugin scope requires its exact project path");
|
|
53625
53828
|
const key = JSON.stringify([registration.scope, registration.projectPath]);
|
|
53626
53829
|
pluginNeed(!scopes.has(key), "Duplicate plugin registration scope");
|
|
53627
53830
|
scopes.add(key);
|
|
@@ -53629,7 +53832,7 @@ function validatePluginTarget(value) {
|
|
|
53629
53832
|
for (const key of ["native", "resolver"]) {
|
|
53630
53833
|
pluginKeys(value[key], key === "native" ? ["version", "executable", "digest"] : ["executable", "digest"]);
|
|
53631
53834
|
pluginText(value[key].executable);
|
|
53632
|
-
pluginNeed(
|
|
53835
|
+
pluginNeed(isAbsolute10(value[key].executable) && resolve11(value[key].executable) === value[key].executable, "Plugin executable must have a canonical absolute path");
|
|
53633
53836
|
pluginDigest(value[key].digest);
|
|
53634
53837
|
}
|
|
53635
53838
|
pluginNeed(["2.1.274", "2.1.276"].includes(value.native.version), "Plugin admission requires a certified Claude command-source runtime (2.1.274 or 2.1.276)");
|
|
@@ -53779,7 +53982,7 @@ function pluginResolverCommand(binding) {
|
|
|
53779
53982
|
}
|
|
53780
53983
|
function root(options) {
|
|
53781
53984
|
const path = options.storeRoot ?? pluginAdmissionRoot();
|
|
53782
|
-
pluginNeed(
|
|
53985
|
+
pluginNeed(isAbsolute10(path) && resolve11(path) === path, "Invalid plugin admission store root");
|
|
53783
53986
|
return path;
|
|
53784
53987
|
}
|
|
53785
53988
|
function pluginBindingPath(storeRoot, id) {
|
|
@@ -53987,7 +54190,7 @@ var init_plugin_admission = __esm(() => {
|
|
|
53987
54190
|
|
|
53988
54191
|
// src/lib/plugin-discovery.ts
|
|
53989
54192
|
import { closeSync as closeSync8, constants as constants8, fstatSync as fstatSync8, lstatSync as lstatSync14, openSync as openSync8, opendirSync as opendirSync4, readSync as readSync6 } from "fs";
|
|
53990
|
-
import { basename as
|
|
54193
|
+
import { basename as basename5, dirname as dirname11, isAbsolute as isAbsolute11, join as join27, resolve as resolve12 } from "path";
|
|
53991
54194
|
function validateManagedPluginWitnesses(value) {
|
|
53992
54195
|
pluginNeed(Array.isArray(value) && value.length > 0 && value.length <= PLUGIN_PROJECTION_LIMITS.registrations, "Invalid managed plugin witness collection");
|
|
53993
54196
|
const seen = new Set;
|
|
@@ -53996,12 +54199,12 @@ function validateManagedPluginWitnesses(value) {
|
|
|
53996
54199
|
pluginNeed(typeof item.bindingId === "string" && /^[a-f0-9]{64}$/.test(item.bindingId) && !seen.has(item.bindingId), "Invalid or duplicate managed plugin witness");
|
|
53997
54200
|
seen.add(item.bindingId);
|
|
53998
54201
|
pluginText(item.storeRoot);
|
|
53999
|
-
pluginNeed(
|
|
54202
|
+
pluginNeed(isAbsolute11(item.storeRoot) && resolve12(item.storeRoot) === item.storeRoot, "Invalid plugin receipt store path");
|
|
54000
54203
|
}
|
|
54001
54204
|
}
|
|
54002
54205
|
function safe3(path) {
|
|
54003
54206
|
pluginText(path);
|
|
54004
|
-
pluginNeed(
|
|
54207
|
+
pluginNeed(isAbsolute11(path) && resolve12(path) === path, "Invalid plugin registry path");
|
|
54005
54208
|
for (let at2 = path;; at2 = dirname11(at2)) {
|
|
54006
54209
|
pluginNeed(!lstatSync14(at2, { throwIfNoEntry: false })?.isSymbolicLink(), "Plugin registry path traverses a symlink");
|
|
54007
54210
|
if (at2 === dirname11(at2))
|
|
@@ -54070,7 +54273,7 @@ function hashManagedPluginRegistry(path, managed) {
|
|
|
54070
54273
|
pluginNeed(/^(?:[A-Za-z0-9][A-Za-z0-9._+-]*-)?[a-f0-9]{12}$/.test(row.version) && row.installPath === join27(cacheRoot, row.version), "Managed plugin cache path or version is outside its registration");
|
|
54071
54274
|
const approval = (producer) => {
|
|
54072
54275
|
pluginText(producer);
|
|
54073
|
-
const digest = `sha256:${
|
|
54276
|
+
const digest = `sha256:${basename5(producer)}`;
|
|
54074
54277
|
const receipt2 = readPluginAdmissionReceipt(witness.storeRoot, witness.bindingId, digest);
|
|
54075
54278
|
pluginNeed(receipt2.materializedPath === producer, "Managed producer path is not an approved immutable projection");
|
|
54076
54279
|
if (!verified.has(producer)) {
|
|
@@ -54133,10 +54336,403 @@ var init_plugin_discovery = __esm(() => {
|
|
|
54133
54336
|
init_plugin_projection_store();
|
|
54134
54337
|
});
|
|
54135
54338
|
|
|
54136
|
-
// src/lib/
|
|
54339
|
+
// src/lib/claude-marketplace-registry.ts
|
|
54137
54340
|
import { createHash as createHash11 } from "crypto";
|
|
54138
|
-
import {
|
|
54139
|
-
import {
|
|
54341
|
+
import { closeSync as closeSync9, constants as constants9, fstatSync as fstatSync9, lstatSync as lstatSync15, openSync as openSync9, readSync as readSync7 } from "fs";
|
|
54342
|
+
import { basename as basename6, dirname as dirname12, isAbsolute as isAbsolute12, resolve as resolve13 } from "path";
|
|
54343
|
+
function need2(value, reason) {
|
|
54344
|
+
if (!value)
|
|
54345
|
+
throw new Error(`Claude marketplace registry ${reason}`);
|
|
54346
|
+
}
|
|
54347
|
+
function absolutePath(value) {
|
|
54348
|
+
need2(typeof value === "string" && value.length > 0 && value.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute12(value) && resolve13(value) === value, "requires a normalized absolute path");
|
|
54349
|
+
}
|
|
54350
|
+
function parents(path) {
|
|
54351
|
+
const result2 = [];
|
|
54352
|
+
for (let at2 = dirname12(path);; at2 = dirname12(at2)) {
|
|
54353
|
+
const stat2 = lstatSync15(at2, { bigint: true });
|
|
54354
|
+
need2(stat2.isDirectory() && !stat2.isSymbolicLink(), "path traverses a symlink or non-directory");
|
|
54355
|
+
result2.push([at2, stat2]);
|
|
54356
|
+
if (at2 === dirname12(at2))
|
|
54357
|
+
return result2;
|
|
54358
|
+
}
|
|
54359
|
+
}
|
|
54360
|
+
function readRegistry2(path, budget) {
|
|
54361
|
+
absolutePath(path);
|
|
54362
|
+
need2(basename6(path) === "known_marketplaces.json", "requires known_marketplaces.json");
|
|
54363
|
+
need2(Number.isSafeInteger(budget.remaining) && budget.remaining >= 0, "has an invalid byte budget");
|
|
54364
|
+
const ancestors2 = parents(path), initial2 = lstatSync15(path, { bigint: true });
|
|
54365
|
+
need2(initial2.isFile() && !initial2.isSymbolicLink() && initial2.size <= BigInt(CLAUDE_MARKETPLACE_REGISTRY_LIMITS.bytes), "is not a bounded regular file");
|
|
54366
|
+
need2(initial2.size <= BigInt(budget.remaining), "exceeds its aggregate byte limit");
|
|
54367
|
+
const fd = openSync9(path, constants9.O_RDONLY | constants9.O_NOFOLLOW | constants9.O_NONBLOCK);
|
|
54368
|
+
try {
|
|
54369
|
+
const opened = fstatSync9(fd, { bigint: true });
|
|
54370
|
+
need2(opened.isFile() && sameFile(initial2, opened), "changed during open");
|
|
54371
|
+
const bytes = Buffer.alloc(Number(opened.size) + 1);
|
|
54372
|
+
let length = 0;
|
|
54373
|
+
while (length < bytes.length) {
|
|
54374
|
+
const count = readSync7(fd, bytes, length, bytes.length - length, null);
|
|
54375
|
+
if (!count)
|
|
54376
|
+
break;
|
|
54377
|
+
length += count;
|
|
54378
|
+
}
|
|
54379
|
+
const after2 = fstatSync9(fd, { bigint: true }), current = lstatSync15(path, { bigint: true });
|
|
54380
|
+
need2(current.isFile() && sameFile(opened, after2) && sameFile(after2, current) && BigInt(length) === opened.size, "changed during read");
|
|
54381
|
+
for (const [ancestor, before2] of ancestors2) {
|
|
54382
|
+
const now3 = lstatSync15(ancestor, { bigint: true });
|
|
54383
|
+
need2(now3.isDirectory() && before2.dev === now3.dev && before2.ino === now3.ino && before2.mode === now3.mode, "parent changed during read");
|
|
54384
|
+
}
|
|
54385
|
+
budget.remaining -= length;
|
|
54386
|
+
try {
|
|
54387
|
+
return new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes.subarray(0, length));
|
|
54388
|
+
} catch {
|
|
54389
|
+
throw new Error("Claude marketplace registry is not strict UTF-8");
|
|
54390
|
+
}
|
|
54391
|
+
} finally {
|
|
54392
|
+
closeSync9(fd);
|
|
54393
|
+
}
|
|
54394
|
+
}
|
|
54395
|
+
function parse5(text2) {
|
|
54396
|
+
let at2 = 0, nodes = 0;
|
|
54397
|
+
const numberPattern = /-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?/y;
|
|
54398
|
+
const space = () => {
|
|
54399
|
+
while (at2 < text2.length && /[\x20\t\r\n]/.test(text2[at2]))
|
|
54400
|
+
at2++;
|
|
54401
|
+
};
|
|
54402
|
+
function string() {
|
|
54403
|
+
need2(text2[at2] === '"', "contains invalid JSON");
|
|
54404
|
+
const start = at2++;
|
|
54405
|
+
while (at2 < text2.length) {
|
|
54406
|
+
const character = text2[at2++];
|
|
54407
|
+
if (character === '"') {
|
|
54408
|
+
let value2;
|
|
54409
|
+
try {
|
|
54410
|
+
value2 = JSON.parse(text2.slice(start, at2));
|
|
54411
|
+
} catch {
|
|
54412
|
+
throw new Error("Claude marketplace registry contains invalid JSON string");
|
|
54413
|
+
}
|
|
54414
|
+
need2(value2.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.stringCharacters, "exceeds its string limit");
|
|
54415
|
+
return value2;
|
|
54416
|
+
}
|
|
54417
|
+
if (character === "\\")
|
|
54418
|
+
at2++;
|
|
54419
|
+
}
|
|
54420
|
+
throw new Error("Claude marketplace registry contains an unterminated JSON string");
|
|
54421
|
+
}
|
|
54422
|
+
function value(depth) {
|
|
54423
|
+
need2(depth <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.depth && ++nodes <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.nodes, "exceeds its nesting or node limit");
|
|
54424
|
+
space();
|
|
54425
|
+
const character = text2[at2];
|
|
54426
|
+
if (character === '"')
|
|
54427
|
+
return { kind: "string", value: string() };
|
|
54428
|
+
if (character === "{" || character === "[") {
|
|
54429
|
+
at2++;
|
|
54430
|
+
space();
|
|
54431
|
+
const object4 = character === "{", end = object4 ? "}" : "]", entries = [], items = [], keys2 = new Set;
|
|
54432
|
+
if (text2[at2] !== end)
|
|
54433
|
+
while (true) {
|
|
54434
|
+
if (object4) {
|
|
54435
|
+
space();
|
|
54436
|
+
const key = string();
|
|
54437
|
+
need2(!keys2.has(key), "contains a duplicate JSON key");
|
|
54438
|
+
keys2.add(key);
|
|
54439
|
+
space();
|
|
54440
|
+
need2(text2[at2++] === ":", "contains invalid JSON");
|
|
54441
|
+
entries.push([key, value(depth + 1)]);
|
|
54442
|
+
} else
|
|
54443
|
+
items.push(value(depth + 1));
|
|
54444
|
+
space();
|
|
54445
|
+
if (text2[at2] === end)
|
|
54446
|
+
break;
|
|
54447
|
+
need2(text2[at2++] === ",", "contains invalid JSON");
|
|
54448
|
+
}
|
|
54449
|
+
at2++;
|
|
54450
|
+
return object4 ? { kind: "object", entries } : { kind: "array", items };
|
|
54451
|
+
}
|
|
54452
|
+
for (const literal of ["true", "false", "null"])
|
|
54453
|
+
if (text2.startsWith(literal, at2)) {
|
|
54454
|
+
at2 += literal.length;
|
|
54455
|
+
return { kind: "literal", value: literal };
|
|
54456
|
+
}
|
|
54457
|
+
numberPattern.lastIndex = at2;
|
|
54458
|
+
const number = numberPattern.exec(text2);
|
|
54459
|
+
need2(number, "contains invalid JSON");
|
|
54460
|
+
at2 += number[0].length;
|
|
54461
|
+
return { kind: "number", value: number[0] };
|
|
54462
|
+
}
|
|
54463
|
+
const root2 = value(0);
|
|
54464
|
+
space();
|
|
54465
|
+
need2(at2 === text2.length && root2.kind === "object", "requires a JSON object without trailing content");
|
|
54466
|
+
need2(root2.entries.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.rows, "exceeds its marketplace row limit");
|
|
54467
|
+
return root2;
|
|
54468
|
+
}
|
|
54469
|
+
function exactKeys(value, keys2) {
|
|
54470
|
+
return value?.kind === "object" && value.entries.length === keys2.length && value.entries.every(([key]) => keys2.includes(key));
|
|
54471
|
+
}
|
|
54472
|
+
function textField(value) {
|
|
54473
|
+
need2(value?.kind === "string" && value.value.length > 0 && !/[\x00-\x1f\x7f]/.test(value.value), "contains an invalid recognized field");
|
|
54474
|
+
return value.value;
|
|
54475
|
+
}
|
|
54476
|
+
function normalizeRow(row) {
|
|
54477
|
+
if (!exactKeys(row, ["source", "installLocation", "lastUpdated"]))
|
|
54478
|
+
return;
|
|
54479
|
+
const source = field(row, "source");
|
|
54480
|
+
if (source?.kind !== "object")
|
|
54481
|
+
return;
|
|
54482
|
+
const type = field(source, "source");
|
|
54483
|
+
if (type?.kind !== "string" || !["github", "directory"].includes(type.value))
|
|
54484
|
+
return;
|
|
54485
|
+
const location = type.value === "github" ? "repo" : "path";
|
|
54486
|
+
if (!exactKeys(source, ["source", location]))
|
|
54487
|
+
return;
|
|
54488
|
+
const sourceLocation = textField(field(source, location));
|
|
54489
|
+
if (type.value === "directory")
|
|
54490
|
+
absolutePath(sourceLocation);
|
|
54491
|
+
absolutePath(textField(field(row, "installLocation")));
|
|
54492
|
+
const updated = textField(field(row, "lastUpdated"));
|
|
54493
|
+
need2(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(updated), "contains an invalid recognized update timestamp");
|
|
54494
|
+
const millis = Date.parse(updated);
|
|
54495
|
+
need2(Number.isFinite(millis) && new Date(millis).toISOString() === updated, "contains an invalid recognized update timestamp");
|
|
54496
|
+
row.entries = row.entries.map(([key, value]) => [key, key === "lastUpdated" ? { kind: "validated-update-time" } : value]);
|
|
54497
|
+
}
|
|
54498
|
+
function captureClaudeMarketplaceRegistry(path, budget = { remaining: 256 * 1024 * 1024 }) {
|
|
54499
|
+
const value = parse5(readRegistry2(path, budget));
|
|
54500
|
+
for (const [, row] of value.entries)
|
|
54501
|
+
normalizeRow(row);
|
|
54502
|
+
const sha2562 = createHash11("sha256").update("hasna.skills.claude-marketplace-registry.v1\x00").update(JSON.stringify(value)).digest("hex");
|
|
54503
|
+
return { path, hashMode: "claude-marketplace-registry", sha256: sha2562 };
|
|
54504
|
+
}
|
|
54505
|
+
var CLAUDE_MARKETPLACE_REGISTRY_LIMITS, sameFile = (a, b) => a.dev === b.dev && a.ino === b.ino && a.mode === b.mode && a.uid === b.uid && a.gid === b.gid && a.nlink === b.nlink && a.size === b.size && a.mtimeNs === b.mtimeNs && a.ctimeNs === b.ctimeNs, field = (object4, key) => object4.entries.find(([name]) => name === key)?.[1];
|
|
54506
|
+
var init_claude_marketplace_registry = __esm(() => {
|
|
54507
|
+
CLAUDE_MARKETPLACE_REGISTRY_LIMITS = Object.freeze({ bytes: 1024 * 1024, rows: 1024, depth: 32, nodes: 65536, stringCharacters: 16384, pathCharacters: 4096 });
|
|
54508
|
+
});
|
|
54509
|
+
|
|
54510
|
+
// src/lib/claude-settings-witness.ts
|
|
54511
|
+
import { createHash as createHash12 } from "crypto";
|
|
54512
|
+
import { closeSync as closeSync10, constants as constants10, fstatSync as fstatSync10, lstatSync as lstatSync16, openSync as openSync10, readSync as readSync8 } from "fs";
|
|
54513
|
+
import { basename as basename7, dirname as dirname13, isAbsolute as isAbsolute13, resolve as resolve14 } from "path";
|
|
54514
|
+
function need3(value, reason) {
|
|
54515
|
+
if (!value)
|
|
54516
|
+
throw new Error(`Claude settings witness ${reason}`);
|
|
54517
|
+
}
|
|
54518
|
+
function absolutePath2(value) {
|
|
54519
|
+
need3(typeof value === "string" && value.length > 0 && value.length <= CLAUDE_SETTINGS_WITNESS_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute13(value) && resolve14(value) === value, "requires a normalized absolute path");
|
|
54520
|
+
}
|
|
54521
|
+
function parents2(path) {
|
|
54522
|
+
const result2 = [];
|
|
54523
|
+
for (let at2 = dirname13(path);; at2 = dirname13(at2)) {
|
|
54524
|
+
const stat2 = lstatSync16(at2, { bigint: true });
|
|
54525
|
+
need3(stat2.isDirectory() && !stat2.isSymbolicLink(), "path traverses a symlink or non-directory");
|
|
54526
|
+
result2.push([at2, stat2]);
|
|
54527
|
+
if (at2 === dirname13(at2))
|
|
54528
|
+
return result2;
|
|
54529
|
+
}
|
|
54530
|
+
}
|
|
54531
|
+
function readSettings(path, budget) {
|
|
54532
|
+
absolutePath2(path);
|
|
54533
|
+
need3(basename7(path) === "settings.json", "requires settings.json");
|
|
54534
|
+
need3(Number.isSafeInteger(budget.remaining) && budget.remaining >= 0, "has an invalid byte budget");
|
|
54535
|
+
const ancestors2 = parents2(path), initial2 = lstatSync16(path, { bigint: true });
|
|
54536
|
+
need3(initial2.isFile() && !initial2.isSymbolicLink() && initial2.size <= BigInt(CLAUDE_SETTINGS_WITNESS_LIMITS.bytes), "is not a bounded regular file");
|
|
54537
|
+
need3(initial2.size <= BigInt(budget.remaining), "exceeds its aggregate byte limit");
|
|
54538
|
+
const fd = openSync10(path, constants10.O_RDONLY | constants10.O_NOFOLLOW | constants10.O_NONBLOCK);
|
|
54539
|
+
try {
|
|
54540
|
+
const opened = fstatSync10(fd, { bigint: true });
|
|
54541
|
+
need3(opened.isFile() && sameFile2(initial2, opened), "changed during open");
|
|
54542
|
+
const bytes = Buffer.alloc(Number(opened.size) + 1);
|
|
54543
|
+
let length = 0;
|
|
54544
|
+
while (length < bytes.length) {
|
|
54545
|
+
const count = readSync8(fd, bytes, length, bytes.length - length, null);
|
|
54546
|
+
if (!count)
|
|
54547
|
+
break;
|
|
54548
|
+
length += count;
|
|
54549
|
+
}
|
|
54550
|
+
const after2 = fstatSync10(fd, { bigint: true }), current = lstatSync16(path, { bigint: true });
|
|
54551
|
+
need3(current.isFile() && sameFile2(opened, after2) && sameFile2(after2, current) && BigInt(length) === opened.size, "changed during read");
|
|
54552
|
+
for (const [ancestor, before2] of ancestors2) {
|
|
54553
|
+
const now3 = lstatSync16(ancestor, { bigint: true });
|
|
54554
|
+
need3(now3.isDirectory() && before2.dev === now3.dev && before2.ino === now3.ino && before2.mode === now3.mode, "parent changed during read");
|
|
54555
|
+
}
|
|
54556
|
+
budget.remaining -= length;
|
|
54557
|
+
try {
|
|
54558
|
+
return new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes.subarray(0, length));
|
|
54559
|
+
} catch {
|
|
54560
|
+
throw new Error("Claude settings witness is not strict UTF-8");
|
|
54561
|
+
}
|
|
54562
|
+
} finally {
|
|
54563
|
+
closeSync10(fd);
|
|
54564
|
+
}
|
|
54565
|
+
}
|
|
54566
|
+
function parse6(text2) {
|
|
54567
|
+
let at2 = 0, nodes = 0;
|
|
54568
|
+
const numberPattern = /-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?/y;
|
|
54569
|
+
const space = () => {
|
|
54570
|
+
while (at2 < text2.length && /[\x20\t\r\n]/.test(text2[at2]))
|
|
54571
|
+
at2++;
|
|
54572
|
+
};
|
|
54573
|
+
function string() {
|
|
54574
|
+
need3(text2[at2] === '"', "contains invalid JSON");
|
|
54575
|
+
const start = at2++;
|
|
54576
|
+
while (at2 < text2.length) {
|
|
54577
|
+
const character = text2[at2++];
|
|
54578
|
+
if (character === '"') {
|
|
54579
|
+
let value2;
|
|
54580
|
+
try {
|
|
54581
|
+
value2 = JSON.parse(text2.slice(start, at2));
|
|
54582
|
+
} catch {
|
|
54583
|
+
throw new Error("Claude settings witness contains invalid JSON string");
|
|
54584
|
+
}
|
|
54585
|
+
need3(value2.length <= CLAUDE_SETTINGS_WITNESS_LIMITS.stringCharacters, "exceeds its string limit");
|
|
54586
|
+
return value2;
|
|
54587
|
+
}
|
|
54588
|
+
if (character === "\\")
|
|
54589
|
+
at2++;
|
|
54590
|
+
}
|
|
54591
|
+
throw new Error("Claude settings witness contains an unterminated JSON string");
|
|
54592
|
+
}
|
|
54593
|
+
function value(depth) {
|
|
54594
|
+
need3(depth <= CLAUDE_SETTINGS_WITNESS_LIMITS.depth && ++nodes <= CLAUDE_SETTINGS_WITNESS_LIMITS.nodes, "exceeds its nesting or node limit");
|
|
54595
|
+
space();
|
|
54596
|
+
const character = text2[at2];
|
|
54597
|
+
if (character === '"')
|
|
54598
|
+
return { kind: "string", value: string() };
|
|
54599
|
+
if (character === "{" || character === "[") {
|
|
54600
|
+
at2++;
|
|
54601
|
+
space();
|
|
54602
|
+
const object4 = character === "{", end = object4 ? "}" : "]", entries = [], items = [], keys2 = new Set;
|
|
54603
|
+
if (text2[at2] !== end)
|
|
54604
|
+
while (true) {
|
|
54605
|
+
if (object4) {
|
|
54606
|
+
space();
|
|
54607
|
+
const key = string();
|
|
54608
|
+
need3(!keys2.has(key), "contains a duplicate JSON key");
|
|
54609
|
+
keys2.add(key);
|
|
54610
|
+
space();
|
|
54611
|
+
need3(text2[at2++] === ":", "contains invalid JSON");
|
|
54612
|
+
entries.push([key, value(depth + 1)]);
|
|
54613
|
+
} else
|
|
54614
|
+
items.push(value(depth + 1));
|
|
54615
|
+
space();
|
|
54616
|
+
if (text2[at2] === end)
|
|
54617
|
+
break;
|
|
54618
|
+
need3(text2[at2++] === ",", "contains invalid JSON");
|
|
54619
|
+
}
|
|
54620
|
+
at2++;
|
|
54621
|
+
return object4 ? { kind: "object", entries } : { kind: "array", items };
|
|
54622
|
+
}
|
|
54623
|
+
for (const literal of ["true", "false", "null"])
|
|
54624
|
+
if (text2.startsWith(literal, at2)) {
|
|
54625
|
+
at2 += literal.length;
|
|
54626
|
+
return { kind: "literal", value: literal };
|
|
54627
|
+
}
|
|
54628
|
+
numberPattern.lastIndex = at2;
|
|
54629
|
+
const number = numberPattern.exec(text2);
|
|
54630
|
+
need3(number, "contains invalid JSON");
|
|
54631
|
+
at2 += number[0].length;
|
|
54632
|
+
return { kind: "number", value: number[0] };
|
|
54633
|
+
}
|
|
54634
|
+
const root2 = value(0);
|
|
54635
|
+
space();
|
|
54636
|
+
need3(at2 === text2.length && root2.kind === "object", "requires a JSON object without trailing content");
|
|
54637
|
+
need3(root2.entries.length <= CLAUDE_SETTINGS_WITNESS_LIMITS.rows, "exceeds its settings field limit");
|
|
54638
|
+
return root2;
|
|
54639
|
+
}
|
|
54640
|
+
function canonical3(value) {
|
|
54641
|
+
if (value.kind === "object")
|
|
54642
|
+
return { kind: "object", entries: value.entries.map(([key, child]) => [key, canonical3(child)]).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0) };
|
|
54643
|
+
if (value.kind === "array")
|
|
54644
|
+
return { kind: "array", items: value.items.map(canonical3) };
|
|
54645
|
+
return value;
|
|
54646
|
+
}
|
|
54647
|
+
function settingsDigest(text2) {
|
|
54648
|
+
const value = parse6(text2);
|
|
54649
|
+
value.entries = value.entries.filter(([key, child]) => {
|
|
54650
|
+
if (key === "model") {
|
|
54651
|
+
need3(child.kind === "string", "contains an invalid model selection");
|
|
54652
|
+
return !BUILTIN_MODEL_SELECTIONS.has(child.value);
|
|
54653
|
+
}
|
|
54654
|
+
if (BOOLEAN_PREFERENCES.has(key)) {
|
|
54655
|
+
need3(child.kind === "literal" && (child.value === "true" || child.value === "false"), "contains an invalid display preference");
|
|
54656
|
+
return false;
|
|
54657
|
+
}
|
|
54658
|
+
if (Object.hasOwn(ENUM_PREFERENCES, key)) {
|
|
54659
|
+
need3(child.kind === "string" && ENUM_PREFERENCES[key].includes(child.value), "contains an invalid display preference");
|
|
54660
|
+
return false;
|
|
54661
|
+
}
|
|
54662
|
+
return true;
|
|
54663
|
+
});
|
|
54664
|
+
return createHash12("sha256").update("hasna.skills.claude-settings.v1\x00").update(JSON.stringify(canonical3(value))).digest("hex");
|
|
54665
|
+
}
|
|
54666
|
+
function hashClaudeSettingsReplacement(text2, budget) {
|
|
54667
|
+
need3(typeof text2 === "string", "requires settings text");
|
|
54668
|
+
const bytes = Buffer.byteLength(text2);
|
|
54669
|
+
need3(bytes <= CLAUDE_SETTINGS_WITNESS_LIMITS.bytes && Number.isSafeInteger(budget.remaining) && budget.remaining >= bytes, "exceeds its byte limit");
|
|
54670
|
+
budget.remaining -= bytes;
|
|
54671
|
+
return settingsDigest(text2);
|
|
54672
|
+
}
|
|
54673
|
+
function captureClaudeSettings(path, budget = { remaining: 256 * 1024 * 1024 }) {
|
|
54674
|
+
return { path, hashMode: "claude-settings-v1", sha256: settingsDigest(readSettings(path, budget)) };
|
|
54675
|
+
}
|
|
54676
|
+
var CLAUDE_SETTINGS_WITNESS_LIMITS, sameFile2 = (a, b) => a.dev === b.dev && a.ino === b.ino && a.mode === b.mode && a.uid === b.uid && a.gid === b.gid && a.nlink === b.nlink && a.size === b.size && a.mtimeNs === b.mtimeNs && a.ctimeNs === b.ctimeNs, BOOLEAN_PREFERENCES, ENUM_PREFERENCES, BUILTIN_MODEL_SELECTIONS;
|
|
54677
|
+
var init_claude_settings_witness = __esm(() => {
|
|
54678
|
+
CLAUDE_SETTINGS_WITNESS_LIMITS = Object.freeze({ bytes: 1024 * 1024, rows: 1024, depth: 32, nodes: 65536, stringCharacters: 16384, pathCharacters: 4096 });
|
|
54679
|
+
BOOLEAN_PREFERENCES = new Set([
|
|
54680
|
+
"autoScrollEnabled",
|
|
54681
|
+
"axScreenReader",
|
|
54682
|
+
"emojiCompletionEnabled",
|
|
54683
|
+
"prefersReducedMotion",
|
|
54684
|
+
"showTurnDuration",
|
|
54685
|
+
"spinnerTipsEnabled",
|
|
54686
|
+
"syntaxHighlightingDisabled",
|
|
54687
|
+
"terminalProgressBarEnabled",
|
|
54688
|
+
"terminalTitleFromRename",
|
|
54689
|
+
"verbose",
|
|
54690
|
+
"wheelScrollAccelerationEnabled"
|
|
54691
|
+
]);
|
|
54692
|
+
ENUM_PREFERENCES = Object.freeze({
|
|
54693
|
+
editorMode: ["normal", "vim"],
|
|
54694
|
+
tui: ["default", "fullscreen"],
|
|
54695
|
+
viewMode: ["default", "verbose", "focus"]
|
|
54696
|
+
});
|
|
54697
|
+
BUILTIN_MODEL_SELECTIONS = new Set([
|
|
54698
|
+
"default",
|
|
54699
|
+
"best",
|
|
54700
|
+
"fable",
|
|
54701
|
+
"fable[1m]",
|
|
54702
|
+
"sonnet",
|
|
54703
|
+
"sonnet[1m]",
|
|
54704
|
+
"opus",
|
|
54705
|
+
"opus[1m]",
|
|
54706
|
+
"haiku",
|
|
54707
|
+
"opusplan",
|
|
54708
|
+
"claude-fable-5-1",
|
|
54709
|
+
"claude-fable-5",
|
|
54710
|
+
"claude-fable-5[1m]",
|
|
54711
|
+
"claude-opus-5",
|
|
54712
|
+
"claude-sonnet-5",
|
|
54713
|
+
"claude-haiku-4-5-20251001",
|
|
54714
|
+
"claude-opus-4-6",
|
|
54715
|
+
"claude-sonnet-4-5",
|
|
54716
|
+
"claude-sonnet-4-5-20250929",
|
|
54717
|
+
"claude-opus-4-8",
|
|
54718
|
+
"claude-opus-4-8[1m]",
|
|
54719
|
+
"claude-opus-4-7",
|
|
54720
|
+
"claude-sonnet-4-6",
|
|
54721
|
+
"claude-opus-4-5-20251101",
|
|
54722
|
+
"claude-opus-4-5",
|
|
54723
|
+
"claude-haiku-4-5",
|
|
54724
|
+
"claude-fable-5-1[1m]",
|
|
54725
|
+
"claude-opus-5[1m]",
|
|
54726
|
+
"claude-opus-4-7[1m]",
|
|
54727
|
+
"claude-opus-4-6[1m]",
|
|
54728
|
+
"claude-sonnet-4-6[1m]"
|
|
54729
|
+
]);
|
|
54730
|
+
});
|
|
54731
|
+
|
|
54732
|
+
// src/lib/agent-discovery.ts
|
|
54733
|
+
import { createHash as createHash13 } from "crypto";
|
|
54734
|
+
import { lstatSync as lstatSync17, readFileSync as readFileSync14, readdirSync as readdirSync9, realpathSync as realpathSync4 } from "fs";
|
|
54735
|
+
import { basename as basename8, dirname as dirname14, isAbsolute as isAbsolute14, join as join28, resolve as resolve15, sep as sep5 } from "path";
|
|
54140
54736
|
function parseConfig(text2, path, toml = false) {
|
|
54141
54737
|
try {
|
|
54142
54738
|
const value = toml ? Bun.TOML.parse(text2) : JSON.parse(text2);
|
|
@@ -54148,12 +54744,12 @@ function parseConfig(text2, path, toml = false) {
|
|
|
54148
54744
|
}
|
|
54149
54745
|
}
|
|
54150
54746
|
function safe4(path) {
|
|
54151
|
-
if (!
|
|
54747
|
+
if (!isAbsolute14(path) || path.includes("\x00"))
|
|
54152
54748
|
throw new Error("Expected an absolute native discovery path");
|
|
54153
|
-
for (let cursor = path;; cursor =
|
|
54154
|
-
if (
|
|
54749
|
+
for (let cursor = path;; cursor = dirname14(cursor)) {
|
|
54750
|
+
if (lstatSync17(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
54155
54751
|
throw new Error(`Refusing symlink native discovery input: ${cursor}`);
|
|
54156
|
-
if (
|
|
54752
|
+
if (dirname14(cursor) === cursor)
|
|
54157
54753
|
break;
|
|
54158
54754
|
}
|
|
54159
54755
|
}
|
|
@@ -54161,7 +54757,7 @@ function read2(path, changes) {
|
|
|
54161
54757
|
safe4(path);
|
|
54162
54758
|
if (changes?.has(path))
|
|
54163
54759
|
return changes.get(path);
|
|
54164
|
-
const stat2 =
|
|
54760
|
+
const stat2 = lstatSync17(path, { throwIfNoEntry: false });
|
|
54165
54761
|
if (!stat2)
|
|
54166
54762
|
return null;
|
|
54167
54763
|
if (!stat2.isFile() || stat2.size > 16 * 1024 * 1024)
|
|
@@ -54169,6 +54765,22 @@ function read2(path, changes) {
|
|
|
54169
54765
|
return readFileSync14(path, "utf8");
|
|
54170
54766
|
}
|
|
54171
54767
|
function projected(source, changes, budget = discoveryByteBudget()) {
|
|
54768
|
+
if (source.hashMode === "claude-settings-v1") {
|
|
54769
|
+
if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256))
|
|
54770
|
+
throw new Error("Claude settings witnesses require exact typed metadata");
|
|
54771
|
+
const current = captureClaudeSettings(source.path, budget).sha256;
|
|
54772
|
+
if (current !== source.sha256)
|
|
54773
|
+
throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
54774
|
+
return changes?.has(source.path) ? hashClaudeSettingsReplacement(changes.get(source.path), budget) : current;
|
|
54775
|
+
}
|
|
54776
|
+
if (source.hashMode === "claude-marketplace-registry") {
|
|
54777
|
+
if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256) || changes?.has(source.path))
|
|
54778
|
+
throw new Error("Claude marketplace witnesses require an exact reviewed registry without synthetic changes");
|
|
54779
|
+
const sha2562 = captureClaudeMarketplaceRegistry(source.path, budget).sha256;
|
|
54780
|
+
if (sha2562 !== source.sha256)
|
|
54781
|
+
throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
|
|
54782
|
+
return sha2562;
|
|
54783
|
+
}
|
|
54172
54784
|
if (source.hashMode === "claude-plugin-registry") {
|
|
54173
54785
|
if (source.format !== undefined || source.fields !== undefined || !source.managedPlugins || changes?.has(source.path))
|
|
54174
54786
|
throw new Error("Managed plugin registry witnesses require verified native registrations");
|
|
@@ -54193,7 +54805,7 @@ function projected(source, changes, budget = discoveryByteBudget()) {
|
|
|
54193
54805
|
const object4 = source.format === "yaml" ? parseHermesConfig(text2) : parseConfig(text2, source.path, source.format === "toml");
|
|
54194
54806
|
if (!object4 || typeof object4 !== "object" || Array.isArray(object4))
|
|
54195
54807
|
throw new Error("Expected native discovery configuration object");
|
|
54196
|
-
return digest(JSON.stringify(Object.fromEntries((source.fields ?? []).map((
|
|
54808
|
+
return digest(JSON.stringify(Object.fromEntries((source.fields ?? []).map((field2) => [field2, object4[field2] ?? null]))));
|
|
54197
54809
|
}
|
|
54198
54810
|
function verifyAgentDiscovery(binding) {
|
|
54199
54811
|
if (!binding || !Array.isArray(binding.sources) || !Array.isArray(binding.roots) || binding.sources.length > AGENT_POLICY_LIMITS.discoverySources || binding.roots.length > AGENT_POLICY_LIMITS.discoveryRoots)
|
|
@@ -54204,9 +54816,10 @@ function verifyAgentDiscovery(binding) {
|
|
|
54204
54816
|
verifyDiscoveryDirectories(binding.directories);
|
|
54205
54817
|
const budget = discoveryByteBudget();
|
|
54206
54818
|
for (const source of binding.sources) {
|
|
54819
|
+
assertMarketplaceBinding(binding, source);
|
|
54207
54820
|
if (source.hashMode === "claude-plugin-registry" && binding.agent !== "claude")
|
|
54208
54821
|
throw new Error("Managed Claude registry witnesses cannot apply to another agent");
|
|
54209
|
-
if (source.format !== undefined && (!["json", "toml", "yaml"].includes(source.format) || !Array.isArray(source.fields) || !source.fields.length || source.fields.length > 64 || source.fields.some((
|
|
54822
|
+
if (source.format !== undefined && (!["json", "toml", "yaml"].includes(source.format) || !Array.isArray(source.fields) || !source.fields.length || source.fields.length > 64 || source.fields.some((field2) => typeof field2 !== "string" || !field2)))
|
|
54210
54823
|
throw new Error("Invalid native discovery projection");
|
|
54211
54824
|
if (source.sha256 !== null && !/^[a-f0-9]{64}$/.test(source.sha256))
|
|
54212
54825
|
throw new Error("Invalid native discovery digest");
|
|
@@ -54216,13 +54829,22 @@ function verifyAgentDiscovery(binding) {
|
|
|
54216
54829
|
for (const root2 of binding.roots)
|
|
54217
54830
|
safe4(root2);
|
|
54218
54831
|
}
|
|
54832
|
+
function assertMarketplaceBinding(binding, source) {
|
|
54833
|
+
if (source.hashMode === "claude-settings-v1" && (binding.agent !== "claude" || binding.method !== "reviewed" || basename8(source.path) !== "settings.json"))
|
|
54834
|
+
throw new Error("Claude settings witnesses require explicit reviewed Claude configuration");
|
|
54835
|
+
if (source.hashMode === "claude-marketplace-registry" && (binding.agent !== "claude" || binding.method !== "reviewed"))
|
|
54836
|
+
throw new Error("Claude marketplace witnesses require explicit reviewed Claude discovery");
|
|
54837
|
+
}
|
|
54219
54838
|
function rebindAgentDiscovery(binding, changes) {
|
|
54220
54839
|
const budget = discoveryByteBudget();
|
|
54221
|
-
return { ...binding, sources: binding.sources.map((source) =>
|
|
54840
|
+
return { ...binding, sources: binding.sources.map((source) => {
|
|
54841
|
+
assertMarketplaceBinding(binding, source);
|
|
54842
|
+
return { ...source, sha256: projected(source, changes, budget) };
|
|
54843
|
+
}) };
|
|
54222
54844
|
}
|
|
54223
|
-
function assertProjectDiscovery(agent, directories, home,
|
|
54845
|
+
function assertProjectDiscovery(agent, directories, home, canonical4 = resolve15, reviewed) {
|
|
54224
54846
|
for (const directory of directories) {
|
|
54225
|
-
const isHome =
|
|
54847
|
+
const isHome = resolve15(directory) === resolve15(home);
|
|
54226
54848
|
if (agent === "hermes") {
|
|
54227
54849
|
assertHermesEnvironment(home);
|
|
54228
54850
|
continue;
|
|
@@ -54231,7 +54853,7 @@ function assertProjectDiscovery(agent, directories, home, canonical3 = resolve12
|
|
|
54231
54853
|
continue;
|
|
54232
54854
|
const paths = agent === "claude" ? [...isHome ? [] : [".claude/settings.json"], ".claude/settings.local.json"] : agent === "codex" ? [".codex/config.toml"] : agent === "gemini" ? [".gemini/settings.json"] : agent === "opencode" ? ["opencode.json", "opencode.jsonc", ".opencode/opencode.json", ".opencode/opencode.jsonc"] : [".cursor/hooks.json"];
|
|
54233
54855
|
for (const suffix of paths) {
|
|
54234
|
-
const path =
|
|
54856
|
+
const path = canonical4(join28(directory, suffix)), raw = read2(path);
|
|
54235
54857
|
if (raw === null)
|
|
54236
54858
|
continue;
|
|
54237
54859
|
if (suffix.endsWith(".jsonc"))
|
|
@@ -54244,25 +54866,25 @@ function assertProjectDiscovery(agent, directories, home, canonical3 = resolve12
|
|
|
54244
54866
|
const managed = reviewed.sources.flatMap((source) => source.hashMode === "claude-plugin-registry" ? source.managedPlugins ?? [] : []);
|
|
54245
54867
|
if (exact && projected(exact) === exact.sha256 && managed.length) {
|
|
54246
54868
|
const bindings = managed.map((item) => readPluginBinding(item.storeRoot, item.bindingId));
|
|
54247
|
-
admittedPlugins = Object.entries(config.enabledPlugins).every(([id, enabled]) => typeof enabled === "boolean" && bindings.some((binding) => binding.target.pluginId === id && binding.target.registrations.some((scope) => scope.scope === "project" && scope.projectPath ===
|
|
54869
|
+
admittedPlugins = Object.entries(config.enabledPlugins).every(([id, enabled]) => typeof enabled === "boolean" && bindings.some((binding) => binding.target.pluginId === id && binding.target.registrations.some((scope) => scope.scope === "project" && scope.projectPath === canonical4(directory))));
|
|
54248
54870
|
}
|
|
54249
54871
|
}
|
|
54250
54872
|
if (keys2.some((key) => config[key] !== undefined && !(key === "enabledPlugins" && admittedPlugins)) || config.disableAllHooks === true || config.disableBundledSkills === false || config.hooksConfig?.enabled === false || config.permission?.skill !== undefined || config.permissions?.deny?.some((rule) => typeof rule === "string" && /^Skill(?:\(|$)/.test(rule)))
|
|
54251
54873
|
throw new Error(`NATIVE_SKILL_DRIFT: higher-precedence project skill or hook configuration requires review: ${path}`);
|
|
54252
54874
|
}
|
|
54253
54875
|
if (agent === "claude") {
|
|
54254
|
-
const commands =
|
|
54876
|
+
const commands = canonical4(join28(directory, ".claude/commands"));
|
|
54255
54877
|
safe4(commands);
|
|
54256
|
-
if (
|
|
54878
|
+
if (lstatSync17(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync9(commands).length)
|
|
54257
54879
|
throw new Error("NATIVE_SKILL_DRIFT: legacy project command discovery requires a dedicated format adapter");
|
|
54258
54880
|
}
|
|
54259
54881
|
}
|
|
54260
54882
|
}
|
|
54261
54883
|
function resolveAgentDiscovery(options) {
|
|
54262
|
-
const
|
|
54884
|
+
const canonical4 = options.canonical ?? resolve15, home = resolve15(options.home), agent = options.agent;
|
|
54263
54885
|
const sources = [], roots = new Set, builtinNames = [];
|
|
54264
54886
|
const witness = (path, format, fields) => {
|
|
54265
|
-
const source = { path:
|
|
54887
|
+
const source = { path: canonical4(path), sha256: null, ...format ? { format, fields } : {} };
|
|
54266
54888
|
source.sha256 = projected(source);
|
|
54267
54889
|
sources.push(source);
|
|
54268
54890
|
return read2(source.path);
|
|
@@ -54290,7 +54912,7 @@ function resolveAgentDiscovery(options) {
|
|
|
54290
54912
|
continue;
|
|
54291
54913
|
if (normalized.startsWith("~") && normalized !== "~" && !normalized.startsWith("~/"))
|
|
54292
54914
|
unresolved("user-specific tilde expansion requires a separate discovery adapter");
|
|
54293
|
-
const path = normalized === "~" ? home : normalized.startsWith("~/") ? join28(home, normalized.slice(2)) :
|
|
54915
|
+
const path = normalized === "~" ? home : normalized.startsWith("~/") ? join28(home, normalized.slice(2)) : resolve15(home, ".hermes", normalized);
|
|
54294
54916
|
safe4(path);
|
|
54295
54917
|
roots.add(path);
|
|
54296
54918
|
}
|
|
@@ -54299,21 +54921,21 @@ function resolveAgentDiscovery(options) {
|
|
|
54299
54921
|
const executable = Bun.which("gemini");
|
|
54300
54922
|
if (executable) {
|
|
54301
54923
|
let packageRoot;
|
|
54302
|
-
for (let directory =
|
|
54924
|
+
for (let directory = dirname14(realpathSync4(executable)), depth = 0;depth < 8; directory = dirname14(directory), depth++) {
|
|
54303
54925
|
const path = join28(directory, "package.json"), raw = read2(path);
|
|
54304
54926
|
if (raw !== null && parseConfig(raw, path).name === "@google/gemini-cli") {
|
|
54305
54927
|
packageRoot = directory;
|
|
54306
54928
|
witness(path);
|
|
54307
54929
|
break;
|
|
54308
54930
|
}
|
|
54309
|
-
if (
|
|
54931
|
+
if (dirname14(directory) === directory)
|
|
54310
54932
|
break;
|
|
54311
54933
|
}
|
|
54312
54934
|
if (!packageRoot)
|
|
54313
54935
|
unresolved("installed Gemini package layout is not recognized");
|
|
54314
54936
|
const builtinRoot = join28(packageRoot, "bundle/builtin");
|
|
54315
54937
|
safe4(builtinRoot);
|
|
54316
|
-
if (!
|
|
54938
|
+
if (!lstatSync17(builtinRoot, { throwIfNoEntry: false })?.isDirectory())
|
|
54317
54939
|
unresolved("installed Gemini builtin root is missing");
|
|
54318
54940
|
for (const name of readdirSync9(builtinRoot).sort()) {
|
|
54319
54941
|
const text2 = witness(join28(builtinRoot, name, "SKILL.md"));
|
|
@@ -54334,12 +54956,14 @@ function resolveAgentDiscovery(options) {
|
|
|
54334
54956
|
if (review.sources.some((source) => source.format !== undefined || source.fields !== undefined))
|
|
54335
54957
|
throw new Error("Explicit discovery reviews require full source-file hashes");
|
|
54336
54958
|
verifyAgentDiscovery(supplied);
|
|
54337
|
-
if (
|
|
54959
|
+
if (review.sources.some((source) => source.hashMode === "claude-settings-v1" && source.path !== canonical4(configPath)))
|
|
54960
|
+
throw new Error("Semantic settings witnesses must name the configured Claude configuration source");
|
|
54961
|
+
if (!review.sources.some((source) => source.path === canonical4(configPath)))
|
|
54338
54962
|
throw new Error("Discovery review must include the agent configuration source");
|
|
54339
54963
|
return { ...supplied, roots: [...new Set([...roots, ...supplied.roots])].sort(), sources: [...sources, ...review.sources], ...agent === "gemini" ? { builtinNames } : {} };
|
|
54340
54964
|
}
|
|
54341
54965
|
function plugin(root2) {
|
|
54342
|
-
root2 =
|
|
54966
|
+
root2 = canonical4(root2);
|
|
54343
54967
|
safe4(root2);
|
|
54344
54968
|
const manifestPath = join28(root2, agent === "claude" ? ".claude-plugin/plugin.json" : ".codex-plugin/plugin.json");
|
|
54345
54969
|
const raw = witness(manifestPath);
|
|
@@ -54351,7 +54975,7 @@ function resolveAgentDiscovery(options) {
|
|
|
54351
54975
|
unresolved("plugin hooks require a separate no-skill-injection review");
|
|
54352
54976
|
const commands = join28(root2, "commands");
|
|
54353
54977
|
safe4(commands);
|
|
54354
|
-
if (agent === "claude" && (manifest.commands !== undefined ||
|
|
54978
|
+
if (agent === "claude" && (manifest.commands !== undefined || lstatSync17(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync9(commands).length))
|
|
54355
54979
|
unresolved("legacy command discovery requires retirement or a dedicated format adapter");
|
|
54356
54980
|
const rootSkill = witness(join28(root2, "SKILL.md"));
|
|
54357
54981
|
if (rootSkill !== null)
|
|
@@ -54362,18 +54986,18 @@ function resolveAgentDiscovery(options) {
|
|
|
54362
54986
|
if (agent === "claude")
|
|
54363
54987
|
roots.add(join28(root2, "skills"));
|
|
54364
54988
|
for (const value of declared) {
|
|
54365
|
-
const path =
|
|
54989
|
+
const path = resolve15(root2, value);
|
|
54366
54990
|
if (path !== root2 && !path.startsWith(root2 + sep5))
|
|
54367
54991
|
unresolved("plugin skill path escapes its root");
|
|
54368
|
-
roots.add(path.endsWith(`${sep5}SKILL.md`) ?
|
|
54992
|
+
roots.add(path.endsWith(`${sep5}SKILL.md`) ? dirname14(path) : path);
|
|
54369
54993
|
}
|
|
54370
54994
|
}
|
|
54371
54995
|
if (agent === "claude") {
|
|
54372
54996
|
const registrations = witness(join28(home, ".claude/plugins/installed_plugins.json"));
|
|
54373
54997
|
const installed = registrations === null ? {} : parseConfig(registrations, join28(home, ".claude/plugins/installed_plugins.json")).plugins;
|
|
54374
|
-
const commands =
|
|
54998
|
+
const commands = canonical4(join28(home, ".claude/commands"));
|
|
54375
54999
|
safe4(commands);
|
|
54376
|
-
if (
|
|
55000
|
+
if (lstatSync17(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync9(commands).length)
|
|
54377
55001
|
unresolved("legacy home command discovery requires a dedicated format adapter");
|
|
54378
55002
|
for (const [id, enabled] of Object.entries(config.enabledPlugins ?? {})) {
|
|
54379
55003
|
if (enabled === false)
|
|
@@ -54393,7 +55017,7 @@ function resolveAgentDiscovery(options) {
|
|
|
54393
55017
|
unresolved("unsupported plugin enablement");
|
|
54394
55018
|
const split2 = id.lastIndexOf("@"), name = id.slice(0, split2), marketplace = id.slice(split2 + 1);
|
|
54395
55019
|
const market = config.marketplaces?.[marketplace] ?? (marketplace === "personal" ? { source_type: "local", source: home } : undefined);
|
|
54396
|
-
if (split2 < 1 || market?.source_type !== "local" || typeof market.source !== "string" || !
|
|
55020
|
+
if (split2 < 1 || market?.source_type !== "local" || typeof market.source !== "string" || !isAbsolute14(market.source))
|
|
54397
55021
|
unresolved("enabled plugin marketplace is not an explicit local source");
|
|
54398
55022
|
const catalogText = witness(join28(market.source, ".agents/plugins/marketplace.json"));
|
|
54399
55023
|
if (catalogText === null)
|
|
@@ -54401,7 +55025,7 @@ function resolveAgentDiscovery(options) {
|
|
|
54401
55025
|
const catalog = parseConfig(catalogText, join28(market.source, ".agents/plugins/marketplace.json")), matches2 = Array.isArray(catalog.plugins) ? catalog.plugins.filter((item) => item.name === name) : [];
|
|
54402
55026
|
if (matches2.length !== 1 || matches2[0]?.source?.source !== "local" || typeof matches2[0]?.source?.path !== "string")
|
|
54403
55027
|
unresolved("plugin catalog source is missing or ambiguous");
|
|
54404
|
-
plugin(
|
|
55028
|
+
plugin(resolve15(market.source, matches2[0].source.path));
|
|
54405
55029
|
}
|
|
54406
55030
|
} else if (agent === "opencode") {
|
|
54407
55031
|
if (witness(join28(home, ".config/opencode/opencode.jsonc")) !== null || witness(join28(home, ".config/opencode/config.json")) !== null)
|
|
@@ -54409,18 +55033,18 @@ function resolveAgentDiscovery(options) {
|
|
|
54409
55033
|
if ((config.plugin?.length ?? 0) > 0 || config.skills?.urls?.length)
|
|
54410
55034
|
unresolved("external plugin or remote skill source");
|
|
54411
55035
|
for (const path of config.skills?.paths ?? []) {
|
|
54412
|
-
if (typeof path !== "string" || !
|
|
55036
|
+
if (typeof path !== "string" || !isAbsolute14(path))
|
|
54413
55037
|
unresolved("relative or malformed added skill root");
|
|
54414
55038
|
roots.add(path);
|
|
54415
55039
|
}
|
|
54416
55040
|
const localPlugins = join28(home, ".config/opencode/plugins");
|
|
54417
55041
|
safe4(localPlugins);
|
|
54418
|
-
if (
|
|
55042
|
+
if (lstatSync17(localPlugins, { throwIfNoEntry: false }) && readdirSync9(localPlugins).some((name) => name !== "skills-cli.js"))
|
|
54419
55043
|
unresolved("additional local plugin hooks require review");
|
|
54420
55044
|
} else if (agent === "hermes") {
|
|
54421
55045
|
for (const directory of [join28(home, ".hermes/plugins"), join28(home, ".hermes/hermes-agent")]) {
|
|
54422
55046
|
safe4(directory);
|
|
54423
|
-
if (
|
|
55047
|
+
if (lstatSync17(directory, { throwIfNoEntry: false }))
|
|
54424
55048
|
unresolved("installed runtime/plugin discovery requires reviewed source bindings");
|
|
54425
55049
|
}
|
|
54426
55050
|
if (Bun.which("hermes") || Object.keys(config.plugins ?? {}).length)
|
|
@@ -54430,11 +55054,11 @@ function resolveAgentDiscovery(options) {
|
|
|
54430
55054
|
unresolved("custom extension or skill paths");
|
|
54431
55055
|
const directory = join28(home, ".gemini/extensions");
|
|
54432
55056
|
safe4(directory);
|
|
54433
|
-
if (
|
|
55057
|
+
if (lstatSync17(directory, { throwIfNoEntry: false }))
|
|
54434
55058
|
for (const name of readdirSync9(directory)) {
|
|
54435
55059
|
const root2 = join28(directory, name);
|
|
54436
55060
|
safe4(root2);
|
|
54437
|
-
if (!
|
|
55061
|
+
if (!lstatSync17(root2)?.isDirectory())
|
|
54438
55062
|
continue;
|
|
54439
55063
|
const raw = witness(join28(root2, "gemini-extension.json"));
|
|
54440
55064
|
if (raw === null)
|
|
@@ -54445,9 +55069,9 @@ function resolveAgentDiscovery(options) {
|
|
|
54445
55069
|
roots.add(join28(root2, "skills"));
|
|
54446
55070
|
}
|
|
54447
55071
|
}
|
|
54448
|
-
return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([join28(home, ".hermes/plugins"), join28(home, ".hermes/hermes-agent")].map((path) =>
|
|
55072
|
+
return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([join28(home, ".hermes/plugins"), join28(home, ".hermes/hermes-agent")].map((path) => canonical4(path))) } : {} };
|
|
54449
55073
|
}
|
|
54450
|
-
var digest = (text2) =>
|
|
55074
|
+
var digest = (text2) => createHash13("sha256").update(text2).digest("hex");
|
|
54451
55075
|
var init_agent_discovery = __esm(() => {
|
|
54452
55076
|
init_agent_policy_limits();
|
|
54453
55077
|
init_agent_hermes();
|
|
@@ -54456,6 +55080,8 @@ var init_agent_discovery = __esm(() => {
|
|
|
54456
55080
|
init_agent_discovery_path_bytes();
|
|
54457
55081
|
init_plugin_discovery();
|
|
54458
55082
|
init_plugin_admission();
|
|
55083
|
+
init_claude_marketplace_registry();
|
|
55084
|
+
init_claude_settings_witness();
|
|
54459
55085
|
init_agent_discovery_directories();
|
|
54460
55086
|
});
|
|
54461
55087
|
|
|
@@ -54540,7 +55166,7 @@ var init_agent_adapters = __esm(() => {
|
|
|
54540
55166
|
});
|
|
54541
55167
|
|
|
54542
55168
|
// src/lib/agent-codex.ts
|
|
54543
|
-
import { isDeepStrictEqual as
|
|
55169
|
+
import { isDeepStrictEqual as isDeepStrictEqual3 } from "util";
|
|
54544
55170
|
function assertCodexPathConfigEditable(text2) {
|
|
54545
55171
|
const before2 = Bun.TOML.parse(text2);
|
|
54546
55172
|
if (before2.skills?.config === undefined)
|
|
@@ -54549,7 +55175,7 @@ function assertCodexPathConfigEditable(text2) {
|
|
|
54549
55175
|
delete expected.skills.config;
|
|
54550
55176
|
try {
|
|
54551
55177
|
const withoutSections = Bun.TOML.parse(text2.replace(CODEX_SKILL_CONFIG_SECTIONS, ""));
|
|
54552
|
-
if (
|
|
55178
|
+
if (isDeepStrictEqual3(withoutSections, expected))
|
|
54553
55179
|
return;
|
|
54554
55180
|
} catch {}
|
|
54555
55181
|
throw new Error("Codex skill path controls require ordinary [[skills.config]] TOML tables; preserve and convert inline or dotted config arrays before running skills hook install");
|
|
@@ -54587,7 +55213,7 @@ function disableCodexBundledSkills(text2) {
|
|
|
54587
55213
|
const candidates = new Set;
|
|
54588
55214
|
const consider = (candidate2) => {
|
|
54589
55215
|
try {
|
|
54590
|
-
if (
|
|
55216
|
+
if (isDeepStrictEqual3(Bun.TOML.parse(candidate2), expected))
|
|
54591
55217
|
candidates.add(candidate2);
|
|
54592
55218
|
} catch {}
|
|
54593
55219
|
};
|
|
@@ -54617,16 +55243,16 @@ var init_agent_codex = __esm(() => {
|
|
|
54617
55243
|
});
|
|
54618
55244
|
|
|
54619
55245
|
// src/lib/agent-integration.ts
|
|
54620
|
-
import { createHash as
|
|
54621
|
-
import { existsSync as existsSync15, lstatSync as
|
|
54622
|
-
import { dirname as
|
|
55246
|
+
import { createHash as createHash14, randomUUID as randomUUID6 } from "crypto";
|
|
55247
|
+
import { existsSync as existsSync15, lstatSync as lstatSync18, statSync as statSync8, mkdirSync as mkdirSync7, readFileSync as readFileSync15, readdirSync as readdirSync10, opendirSync as opendirSync5, readlinkSync as readlinkSync2, realpathSync as realpathSync5, renameSync as renameSync4, rmdirSync as rmdirSync3, writeFileSync as writeFileSync5, unlinkSync as unlinkSync4, chmodSync, openSync as openSync11, closeSync as closeSync11, fsyncSync as fsyncSync3, fstatSync as fstatSync11, readSync as readSync9, constants as constants11, linkSync as linkSync2 } from "fs";
|
|
55248
|
+
import { dirname as dirname15, join as join29, resolve as resolve16, relative as relative5, isAbsolute as isAbsolute15, sep as sep6 } from "path";
|
|
54623
55249
|
import { homedir as homedir4 } from "os";
|
|
54624
55250
|
function assertSafePath(path) {
|
|
54625
|
-
let cursor =
|
|
55251
|
+
let cursor = resolve16(path);
|
|
54626
55252
|
while (true) {
|
|
54627
|
-
if (
|
|
55253
|
+
if (lstatSync18(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
|
|
54628
55254
|
throw new Error(`Refusing symlink path: ${cursor}`);
|
|
54629
|
-
const parent =
|
|
55255
|
+
const parent = dirname15(cursor);
|
|
54630
55256
|
if (parent === cursor)
|
|
54631
55257
|
return;
|
|
54632
55258
|
cursor = parent;
|
|
@@ -54635,16 +55261,16 @@ function assertSafePath(path) {
|
|
|
54635
55261
|
function readRootAlias(home, agent) {
|
|
54636
55262
|
assertSafePath(home);
|
|
54637
55263
|
const realHome = realpathSync5(home), alias = join29(realHome, `.${agent}`);
|
|
54638
|
-
const stat2 =
|
|
55264
|
+
const stat2 = lstatSync18(alias, { throwIfNoEntry: false, bigint: true });
|
|
54639
55265
|
if (!stat2?.isSymbolicLink())
|
|
54640
55266
|
throw new Error(`Agent root alias changed after planning: ${alias}`);
|
|
54641
|
-
const link2 = readlinkSync2(alias), targetPath =
|
|
55267
|
+
const link2 = readlinkSync2(alias), targetPath = resolve16(dirname15(alias), link2);
|
|
54642
55268
|
assertSafePath(targetPath);
|
|
54643
|
-
const targetStat =
|
|
55269
|
+
const targetStat = lstatSync18(targetPath, { throwIfNoEntry: false });
|
|
54644
55270
|
if (!targetStat?.isDirectory())
|
|
54645
55271
|
throw new Error(`Agent root alias must target an existing directory: ${alias}`);
|
|
54646
55272
|
const target = realpathSync5(targetPath), inside = relative5(realHome, target);
|
|
54647
|
-
if (!inside || inside === ".." || inside.startsWith(`..${sep6}`) ||
|
|
55273
|
+
if (!inside || inside === ".." || inside.startsWith(`..${sep6}`) || isAbsolute15(inside))
|
|
54648
55274
|
throw new Error(`Agent root alias target must be inside the real home: ${alias}`);
|
|
54649
55275
|
return { agent, home: realHome, alias, target, link: link2, aliasIdentity: `${stat2.dev}:${stat2.ino}:${stat2.ctimeNs}`, targetIdentity: `${targetStat.dev}:${targetStat.ino}` };
|
|
54650
55276
|
}
|
|
@@ -54653,14 +55279,14 @@ function rootAliases(home, allowed = false) {
|
|
|
54653
55279
|
return [];
|
|
54654
55280
|
const result2 = [];
|
|
54655
55281
|
for (const agent of ["claude", "codex"])
|
|
54656
|
-
if (
|
|
55282
|
+
if (lstatSync18(join29(home, `.${agent}`), { throwIfNoEntry: false })?.isSymbolicLink())
|
|
54657
55283
|
result2.push(readRootAlias(home, agent));
|
|
54658
55284
|
if (result2.some((item, index) => result2.slice(index + 1).some((other) => item.target === other.target || item.target.startsWith(other.target + sep6) || other.target.startsWith(item.target + sep6))))
|
|
54659
55285
|
throw new Error("Agent root alias targets must not overlap");
|
|
54660
55286
|
return result2;
|
|
54661
55287
|
}
|
|
54662
55288
|
function canonicalAgentPath(path, aliases) {
|
|
54663
|
-
const absolute =
|
|
55289
|
+
const absolute = resolve16(path), binding = aliases.find((item) => absolute === item.alias || absolute.startsWith(item.alias + sep6));
|
|
54664
55290
|
return binding ? join29(binding.target, relative5(binding.alias, absolute)) : absolute;
|
|
54665
55291
|
}
|
|
54666
55292
|
function recheckRootAliases(aliases) {
|
|
@@ -54674,35 +55300,35 @@ function recheckRootAliases(aliases) {
|
|
|
54674
55300
|
}
|
|
54675
55301
|
function readNativeBytes(path, maximum = 64 * 1024 * 1024) {
|
|
54676
55302
|
assertSafePath(path);
|
|
54677
|
-
const before2 =
|
|
55303
|
+
const before2 = lstatSync18(path);
|
|
54678
55304
|
if (!before2.isFile() || before2.size > maximum)
|
|
54679
55305
|
throw new Error("Unsupported or oversized native skill file");
|
|
54680
|
-
const descriptor =
|
|
55306
|
+
const descriptor = openSync11(path, constants11.O_RDONLY | constants11.O_NOFOLLOW | constants11.O_NONBLOCK);
|
|
54681
55307
|
try {
|
|
54682
|
-
const opened =
|
|
55308
|
+
const opened = fstatSync11(descriptor);
|
|
54683
55309
|
if (!opened.isFile() || opened.dev !== before2.dev || opened.ino !== before2.ino || opened.size !== before2.size)
|
|
54684
55310
|
throw new Error("Native skill file changed while reading");
|
|
54685
55311
|
const bytes = Buffer.allocUnsafe(before2.size + 1);
|
|
54686
55312
|
let length = 0;
|
|
54687
55313
|
while (length < bytes.length) {
|
|
54688
|
-
const count =
|
|
55314
|
+
const count = readSync9(descriptor, bytes, length, bytes.length - length, null);
|
|
54689
55315
|
if (!count)
|
|
54690
55316
|
break;
|
|
54691
55317
|
length += count;
|
|
54692
55318
|
}
|
|
54693
|
-
const after2 =
|
|
55319
|
+
const after2 = fstatSync11(descriptor);
|
|
54694
55320
|
if (length !== before2.size || after2.size !== before2.size || after2.mtimeMs !== opened.mtimeMs || after2.ctimeMs !== opened.ctimeMs)
|
|
54695
55321
|
throw new Error("Native skill file changed while reading");
|
|
54696
55322
|
return bytes.subarray(0, length);
|
|
54697
55323
|
} finally {
|
|
54698
|
-
|
|
55324
|
+
closeSync11(descriptor);
|
|
54699
55325
|
}
|
|
54700
55326
|
}
|
|
54701
55327
|
function treeHash(root2) {
|
|
54702
|
-
const hash2 =
|
|
55328
|
+
const hash2 = createHash14("sha256");
|
|
54703
55329
|
let bytes = 0, files = 0;
|
|
54704
55330
|
function visit2(path) {
|
|
54705
|
-
const stat2 =
|
|
55331
|
+
const stat2 = lstatSync18(path);
|
|
54706
55332
|
if (stat2.isSymbolicLink())
|
|
54707
55333
|
throw new Error(`Refusing symlink in skill: ${path}`);
|
|
54708
55334
|
const rel = relative5(root2, path);
|
|
@@ -54728,11 +55354,11 @@ function treeHash(root2) {
|
|
|
54728
55354
|
function projectAncestorDirectories(projects) {
|
|
54729
55355
|
const directories = new Set;
|
|
54730
55356
|
for (const project of projects) {
|
|
54731
|
-
for (let path =
|
|
55357
|
+
for (let path = resolve16(project), depth = 0;; depth++) {
|
|
54732
55358
|
if (depth >= 100)
|
|
54733
55359
|
throw new Error("NATIVE_SKILL_DRIFT: project ancestor discovery limit exceeded");
|
|
54734
55360
|
directories.add(path);
|
|
54735
|
-
const parent =
|
|
55361
|
+
const parent = dirname15(path);
|
|
54736
55362
|
if (parent === path)
|
|
54737
55363
|
break;
|
|
54738
55364
|
path = parent;
|
|
@@ -54759,10 +55385,10 @@ function inventoryNativeSkills(home = homedir4(), options = {}) {
|
|
|
54759
55385
|
throw new Error("Native skill discovery metadata limit exceeded");
|
|
54760
55386
|
}
|
|
54761
55387
|
function emptySiblingCacheAlias(path, parent) {
|
|
54762
|
-
const link2 = readlinkSync2(path), target =
|
|
54763
|
-
if (
|
|
55388
|
+
const link2 = readlinkSync2(path), target = resolve16(parent, link2);
|
|
55389
|
+
if (dirname15(target) !== parent || (isAbsolute15(link2) ? link2 !== target : dirname15(link2) !== "."))
|
|
54764
55390
|
return false;
|
|
54765
|
-
if (!
|
|
55391
|
+
if (!lstatSync18(target, { throwIfNoEntry: false })?.isDirectory())
|
|
54766
55392
|
return false;
|
|
54767
55393
|
const scan = cacheScans.get(target);
|
|
54768
55394
|
return Boolean(scan?.complete && !scan.hasSkills && scan.entries <= maxAliasProofEntries);
|
|
@@ -54774,7 +55400,7 @@ function inventoryNativeSkills(home = homedir4(), options = {}) {
|
|
|
54774
55400
|
assertSafePath(path);
|
|
54775
55401
|
if (!existsSync15(path))
|
|
54776
55402
|
return scan;
|
|
54777
|
-
const stat2 =
|
|
55403
|
+
const stat2 = lstatSync18(path);
|
|
54778
55404
|
if (stat2.isFile())
|
|
54779
55405
|
return scan;
|
|
54780
55406
|
if (!stat2.isDirectory())
|
|
@@ -54793,7 +55419,7 @@ function inventoryNativeSkills(home = homedir4(), options = {}) {
|
|
|
54793
55419
|
}
|
|
54794
55420
|
const bridge = !vendor && isOwnedCliBridge(path, bridgePaths);
|
|
54795
55421
|
const rootAlias = aliases.find((item) => path === item.target || path.startsWith(item.target + sep6));
|
|
54796
|
-
entries.push({ agent, path, hash: treeHash(path), managed, vendor, ...agent === "codex" && path.startsWith(canonicalAgentPath(join29(home, ".codex", "skills", ".system"), aliases) + sep6) ? { system: true } : {}, ...bridge ? { bridge: true, bridgeHome:
|
|
55422
|
+
entries.push({ agent, path, hash: treeHash(path), managed, vendor, ...agent === "codex" && path.startsWith(canonicalAgentPath(join29(home, ".codex", "skills", ".system"), aliases) + sep6) ? { system: true } : {}, ...bridge ? { bridge: true, bridgeHome: resolve16(home) } : {}, ...rootAlias ? { rootAlias } : {} });
|
|
54797
55423
|
return scan;
|
|
54798
55424
|
}
|
|
54799
55425
|
if (depth > (vendor ? 32 : 3))
|
|
@@ -54820,7 +55446,7 @@ function inventoryNativeSkills(home = homedir4(), options = {}) {
|
|
|
54820
55446
|
if (isVendor && !options.includeVendor)
|
|
54821
55447
|
continue;
|
|
54822
55448
|
const child = join29(path, name);
|
|
54823
|
-
if (isVendor &&
|
|
55449
|
+
if (isVendor && lstatSync18(child, { throwIfNoEntry: false })?.isSymbolicLink()) {
|
|
54824
55450
|
const target = statSync8(child, { throwIfNoEntry: false });
|
|
54825
55451
|
if (target?.isFile() || pluginCache && target?.isDirectory() && emptySiblingCacheAlias(child, path)) {
|
|
54826
55452
|
scan.entries++;
|
|
@@ -54942,7 +55568,7 @@ function configureHooks(config, agent, command, profileId, nativeReady) {
|
|
|
54942
55568
|
function disableCodexSkills(text2, skills, aliases, bridgePath) {
|
|
54943
55569
|
const bundled = disableCodexBundledSkills(text2);
|
|
54944
55570
|
let result2 = bundled;
|
|
54945
|
-
const bridgeSelector = (entry) => typeof entry.name === "string" && entry.name.trim() === CLI_BRIDGE_NAME || typeof entry.path === "string" && [
|
|
55571
|
+
const bridgeSelector = (entry) => typeof entry.name === "string" && entry.name.trim() === CLI_BRIDGE_NAME || typeof entry.path === "string" && [resolve16(bridgePath), resolve16(join29(bridgePath, "SKILL.md"))].includes(canonicalAgentPath(entry.path, aliases));
|
|
54946
55572
|
const previousConfig = Bun.TOML.parse(bundled).skills?.config;
|
|
54947
55573
|
if (previousConfig !== undefined && (!Array.isArray(previousConfig) || previousConfig.some((entry) => !entry || typeof entry !== "object" || entry.path !== undefined && entry.name !== undefined)))
|
|
54948
55574
|
throw new Error("Codex skill controls require one path or name selector per [[skills.config]] entry; review ambiguous entries before running skills hook install");
|
|
@@ -54954,7 +55580,7 @@ function disableCodexSkills(text2, skills, aliases, bridgePath) {
|
|
|
54954
55580
|
result2 = result2.replace(CODEX_SKILL_CONFIG_SECTIONS, (section) => {
|
|
54955
55581
|
const parsed = Bun.TOML.parse(section);
|
|
54956
55582
|
const declared = parsed.skills?.config?.[0];
|
|
54957
|
-
if (!declared || !(skill.enabled && bridgeSelector(declared)) && !(typeof declared.path === "string" && [
|
|
55583
|
+
if (!declared || !(skill.enabled && bridgeSelector(declared)) && !(typeof declared.path === "string" && [resolve16(path), resolve16(skill.path)].includes(canonicalAgentPath(declared.path, aliases))))
|
|
54958
55584
|
return section;
|
|
54959
55585
|
found = true;
|
|
54960
55586
|
return /^\s*enabled\s*=/m.test(section) ? section.replace(/^\s*enabled\s*=.*$/m, `enabled = ${skill.enabled}`) : `${section.trimEnd()}
|
|
@@ -54984,9 +55610,9 @@ function planAgentIntegration(options) {
|
|
|
54984
55610
|
throw new Error("Invalid existing Skills bridge policy");
|
|
54985
55611
|
if (policy.bridge?.agents !== undefined && (!Array.isArray(policy.bridge.agents) || policy.bridge.agents.some((agent) => !INTEGRATION_AGENTS.includes(agent))))
|
|
54986
55612
|
throw new Error("Invalid existing bridge agent inventory");
|
|
54987
|
-
for (const
|
|
54988
|
-
if (policy.bridge?.[
|
|
54989
|
-
throw new Error(`Invalid existing bridge ${
|
|
55613
|
+
for (const field2 of ["commands", "profiles"])
|
|
55614
|
+
if (policy.bridge?.[field2] !== undefined && (!policy.bridge[field2] || typeof policy.bridge[field2] !== "object" || Array.isArray(policy.bridge[field2]) || Object.entries(policy.bridge[field2]).some(([key, value]) => !INTEGRATION_AGENTS.includes(key) || typeof value !== "string" || !value || value.includes("\x00"))))
|
|
55615
|
+
throw new Error(`Invalid existing bridge ${field2} binding`);
|
|
54990
55616
|
const priorAgents = policy.bridge?.agents ?? [];
|
|
54991
55617
|
const profileId = options.profileId ?? policy.profileId ?? "default";
|
|
54992
55618
|
const validateProfile = (value) => {
|
|
@@ -55072,7 +55698,7 @@ function planAgentIntegration(options) {
|
|
|
55072
55698
|
version: CLI_BRIDGE_VERSION,
|
|
55073
55699
|
digest: CLI_BRIDGE_DIGEST,
|
|
55074
55700
|
agents: [...new Set([...priorAgents, ...options.agents])].sort(),
|
|
55075
|
-
home:
|
|
55701
|
+
home: resolve16(home),
|
|
55076
55702
|
includeVendor: true,
|
|
55077
55703
|
...options.agents.includes("hermes") ? { supervisors: { ...policy.bridge?.supervisors, hermes: { path: join29(dataDir3, "agent-hooks", "hermes.js"), runtime: process.execPath, sha256: sha(renderHermesSupervisor(bindings.get("hermes").command, bindings.get("hermes").profileId)) } } } : {},
|
|
55078
55704
|
commands: { ...policy.bridge?.commands, ...Object.fromEntries([...bindings].map(([agent, binding]) => [agent, binding.command])) },
|
|
@@ -55089,7 +55715,7 @@ function planAgentIntegration(options) {
|
|
|
55089
55715
|
}
|
|
55090
55716
|
function atomicWrite2(path, content) {
|
|
55091
55717
|
assertSafePath(path);
|
|
55092
|
-
mkdirSync7(
|
|
55718
|
+
mkdirSync7(dirname15(path), { recursive: true, mode: 448 });
|
|
55093
55719
|
const temporary = `${path}.skills-${randomUUID6()}`;
|
|
55094
55720
|
try {
|
|
55095
55721
|
writeFileSync5(temporary, content, { mode: 384, flag: "wx" });
|
|
@@ -55102,10 +55728,10 @@ function atomicWrite2(path, content) {
|
|
|
55102
55728
|
function applyAgentIntegration(plan) {
|
|
55103
55729
|
const policyPath = join29(plan.dataDir, "agent-policy.json");
|
|
55104
55730
|
assertSafePath(policyPath);
|
|
55105
|
-
const currentText = (path) =>
|
|
55731
|
+
const currentText = (path) => resolve16(path) === resolve16(policyPath) ? readManagedSkillPolicySnapshot(plan.dataDir)?.text ?? null : readOptional(path);
|
|
55106
55732
|
readManagedSkillPolicySnapshot(plan.dataDir);
|
|
55107
55733
|
for (const change of plan.changes)
|
|
55108
|
-
if (
|
|
55734
|
+
if (resolve16(change.path) === resolve16(policyPath))
|
|
55109
55735
|
parseManagedSkillPolicy(change.after);
|
|
55110
55736
|
const aliases = plan.rootAliases ?? [];
|
|
55111
55737
|
recheckRootAliases(aliases);
|
|
@@ -55135,7 +55761,7 @@ function applyAgentIntegration(plan) {
|
|
|
55135
55761
|
recheckRootAliases(aliases);
|
|
55136
55762
|
if (currentText(change.path) !== change.before)
|
|
55137
55763
|
throw new Error(`Configuration changed after planning: ${change.path}`);
|
|
55138
|
-
for (let directory =
|
|
55764
|
+
for (let directory = dirname15(change.path);!existsSync15(directory); directory = dirname15(directory))
|
|
55139
55765
|
createdDirectories.add(directory);
|
|
55140
55766
|
const after2 = change.after;
|
|
55141
55767
|
atomicWrite2(change.path, after2);
|
|
@@ -55175,11 +55801,11 @@ function applyAgentIntegration(plan) {
|
|
|
55175
55801
|
}
|
|
55176
55802
|
function syncArchiveDirectory(path) {
|
|
55177
55803
|
assertSafePath(path);
|
|
55178
|
-
const descriptor =
|
|
55804
|
+
const descriptor = openSync11(path, constants11.O_RDONLY | constants11.O_DIRECTORY | constants11.O_NOFOLLOW | constants11.O_NONBLOCK);
|
|
55179
55805
|
try {
|
|
55180
|
-
|
|
55806
|
+
fsyncSync3(descriptor);
|
|
55181
55807
|
} finally {
|
|
55182
|
-
|
|
55808
|
+
closeSync11(descriptor);
|
|
55183
55809
|
}
|
|
55184
55810
|
}
|
|
55185
55811
|
function writeArchiveJournal(path, value) {
|
|
@@ -55187,18 +55813,18 @@ function writeArchiveJournal(path, value) {
|
|
|
55187
55813
|
const temporary = `${path}.skills-${randomUUID6()}`;
|
|
55188
55814
|
let descriptor;
|
|
55189
55815
|
try {
|
|
55190
|
-
descriptor =
|
|
55816
|
+
descriptor = openSync11(temporary, constants11.O_WRONLY | constants11.O_CREAT | constants11.O_EXCL | constants11.O_NOFOLLOW, 384);
|
|
55191
55817
|
writeFileSync5(descriptor, `${JSON.stringify(value)}
|
|
55192
55818
|
`);
|
|
55193
|
-
|
|
55194
|
-
|
|
55819
|
+
fsyncSync3(descriptor);
|
|
55820
|
+
closeSync11(descriptor);
|
|
55195
55821
|
descriptor = undefined;
|
|
55196
55822
|
renameSync4(temporary, path);
|
|
55197
|
-
syncArchiveDirectory(
|
|
55823
|
+
syncArchiveDirectory(dirname15(path));
|
|
55198
55824
|
} finally {
|
|
55199
55825
|
if (descriptor !== undefined)
|
|
55200
|
-
|
|
55201
|
-
if (
|
|
55826
|
+
closeSync11(descriptor);
|
|
55827
|
+
if (lstatSync18(temporary, { throwIfNoEntry: false }))
|
|
55202
55828
|
unlinkSync4(temporary);
|
|
55203
55829
|
}
|
|
55204
55830
|
}
|
|
@@ -55231,7 +55857,7 @@ function archiveNativeSkills(inventory, options) {
|
|
|
55231
55857
|
const moved = [];
|
|
55232
55858
|
const verifyArchive = (entry) => {
|
|
55233
55859
|
assertSafePath(entry.archive);
|
|
55234
|
-
const stat2 =
|
|
55860
|
+
const stat2 = lstatSync18(entry.archive);
|
|
55235
55861
|
if (entry.discoveryOnly ? !stat2.isFile() : !stat2.isDirectory())
|
|
55236
55862
|
throw new Error("Archive type changed");
|
|
55237
55863
|
if ((entry.discoveryOnly ? sha(readNativeBytes(entry.archive)) : treeHash(entry.archive)) !== entry.hash)
|
|
@@ -55239,14 +55865,14 @@ function archiveNativeSkills(inventory, options) {
|
|
|
55239
55865
|
};
|
|
55240
55866
|
assertSafePath(archiveRoot);
|
|
55241
55867
|
const created = [];
|
|
55242
|
-
for (let path = archiveRoot;!existsSync15(path); path =
|
|
55868
|
+
for (let path = archiveRoot;!existsSync15(path); path = dirname15(path))
|
|
55243
55869
|
created.push(path);
|
|
55244
55870
|
mkdirSync7(archiveRoot, { recursive: true, mode: 448 });
|
|
55245
55871
|
try {
|
|
55246
55872
|
for (const directory of created)
|
|
55247
55873
|
syncArchiveDirectory(directory);
|
|
55248
55874
|
if (created.length)
|
|
55249
|
-
syncArchiveDirectory(
|
|
55875
|
+
syncArchiveDirectory(dirname15(created.at(-1)));
|
|
55250
55876
|
writeArchiveJournal(receiptPath, journal);
|
|
55251
55877
|
for (const [index, entry] of selected.entries()) {
|
|
55252
55878
|
recheckRootAliases(aliases);
|
|
@@ -55258,7 +55884,7 @@ function archiveNativeSkills(inventory, options) {
|
|
|
55258
55884
|
writeArchiveJournal(receiptPath, journal);
|
|
55259
55885
|
renameSync4(move.source, move.archive);
|
|
55260
55886
|
moved.push(move);
|
|
55261
|
-
syncArchiveDirectory(
|
|
55887
|
+
syncArchiveDirectory(dirname15(move.source));
|
|
55262
55888
|
syncArchiveDirectory(archiveRoot);
|
|
55263
55889
|
verifyArchive(move);
|
|
55264
55890
|
move.status = "archived";
|
|
@@ -55279,7 +55905,7 @@ function archiveNativeSkills(inventory, options) {
|
|
|
55279
55905
|
recheckRootAliases(aliases);
|
|
55280
55906
|
assertSafePath(entry.source);
|
|
55281
55907
|
assertSafePath(entry.archive);
|
|
55282
|
-
if (
|
|
55908
|
+
if (lstatSync18(entry.source, { throwIfNoEntry: false })) {
|
|
55283
55909
|
entry.status = "recovery-required";
|
|
55284
55910
|
entry.conflict = "source-occupied";
|
|
55285
55911
|
continue;
|
|
@@ -55293,10 +55919,10 @@ function archiveNativeSkills(inventory, options) {
|
|
|
55293
55919
|
}
|
|
55294
55920
|
if (entry.discoveryOnly) {
|
|
55295
55921
|
linkSync2(entry.archive, entry.source);
|
|
55296
|
-
syncArchiveDirectory(
|
|
55922
|
+
syncArchiveDirectory(dirname15(entry.source));
|
|
55297
55923
|
unlinkSync4(entry.archive);
|
|
55298
55924
|
} else {
|
|
55299
|
-
if (
|
|
55925
|
+
if (lstatSync18(entry.source, { throwIfNoEntry: false })) {
|
|
55300
55926
|
entry.status = "recovery-required";
|
|
55301
55927
|
entry.conflict = "source-occupied";
|
|
55302
55928
|
continue;
|
|
@@ -55304,7 +55930,7 @@ function archiveNativeSkills(inventory, options) {
|
|
|
55304
55930
|
renameSync4(entry.archive, entry.source);
|
|
55305
55931
|
}
|
|
55306
55932
|
entry.status = "restored";
|
|
55307
|
-
syncArchiveDirectory(
|
|
55933
|
+
syncArchiveDirectory(dirname15(entry.source));
|
|
55308
55934
|
syncArchiveDirectory(archiveRoot);
|
|
55309
55935
|
} catch {
|
|
55310
55936
|
entry.status = "recovery-required";
|
|
@@ -55324,7 +55950,7 @@ function archiveNativeSkills(inventory, options) {
|
|
|
55324
55950
|
return { entries: entries.map(({ status, conflict, ...entry }) => entry), receiptPath, ...aliases.length ? { rootAliases: aliases } : {} };
|
|
55325
55951
|
}
|
|
55326
55952
|
function assertManagedAgentBridge(agent, options = {}) {
|
|
55327
|
-
const home =
|
|
55953
|
+
const home = resolve16(options.home ?? homedir4()), dataDir3 = options.dataDir ?? getDataDirReadOnly();
|
|
55328
55954
|
assertSafePath(join29(dataDir3, "agent-policy.json"));
|
|
55329
55955
|
const snapshot = readManagedSkillPolicySnapshot(dataDir3);
|
|
55330
55956
|
if (!snapshot)
|
|
@@ -55447,7 +56073,7 @@ function assertNativeExportAllowed(dataDir3 = getDataDirReadOnly()) {
|
|
|
55447
56073
|
if (requiresCliSkillLoading(dataDir3))
|
|
55448
56074
|
throw new Error("NATIVE_SKILL_EXPORT_DISABLED: this station loads skills through the Skills CLI; use skills sync --selection-profile <id>");
|
|
55449
56075
|
}
|
|
55450
|
-
var sha = (data) =>
|
|
56076
|
+
var sha = (data) => createHash14("sha256").update(data).digest("hex"), HOOK_EVENTS, ROOTS, SKILLS_LOADING_POLICY = "Skills loading policy: discover skills with `skills list` or `skills search`, and read selected instructions with `skills load <slug>`. Use `skills sync` to refresh the shared profile. The only native skill is the owned skills-cli bridge. Create and edit payload skills in the Skills authoring workspace; do not copy payload instructions into native discovery folders. Context loading does not authorize execution; use `skills run` only when the task calls for running a skill.";
|
|
55451
56077
|
var init_agent_integration = __esm(() => {
|
|
55452
56078
|
init_config();
|
|
55453
56079
|
init_managed_policy();
|
|
@@ -55615,7 +56241,7 @@ var init_home_migration = __esm(() => {
|
|
|
55615
56241
|
import {
|
|
55616
56242
|
cpSync as cpSync2,
|
|
55617
56243
|
existsSync as existsSync17,
|
|
55618
|
-
lstatSync as
|
|
56244
|
+
lstatSync as lstatSync19,
|
|
55619
56245
|
mkdirSync as mkdirSync9,
|
|
55620
56246
|
mkdtempSync as mkdtempSync2,
|
|
55621
56247
|
readFileSync as readFileSync16,
|
|
@@ -55626,14 +56252,14 @@ import {
|
|
|
55626
56252
|
writeFileSync as writeFileSync7
|
|
55627
56253
|
} from "fs";
|
|
55628
56254
|
import { homedir as homedir5 } from "os";
|
|
55629
|
-
import { basename as
|
|
56255
|
+
import { basename as basename9, dirname as dirname16, join as join31 } from "path";
|
|
55630
56256
|
function isSkillsOwnershipMarker(marker) {
|
|
55631
56257
|
return typeof marker === "object" && marker !== null && Object.hasOwn(marker, "managedBy") && marker.managedBy === SYNC_MARKER_MANAGED_BY;
|
|
55632
56258
|
}
|
|
55633
56259
|
function hasSkillsOwnershipMarker(dir) {
|
|
55634
56260
|
const path = join31(dir, SYNC_MARKER_FILE);
|
|
55635
56261
|
try {
|
|
55636
|
-
if (!
|
|
56262
|
+
if (!lstatSync19(path).isFile())
|
|
55637
56263
|
return false;
|
|
55638
56264
|
const marker = JSON.parse(readFileSync16(path, "utf8"));
|
|
55639
56265
|
return isSkillsOwnershipMarker(marker);
|
|
@@ -55858,9 +56484,9 @@ function writeManagedSkillDir(dir, skillMd, options) {
|
|
|
55858
56484
|
const action = dirExists ? "update" : "create";
|
|
55859
56485
|
if (options.dryRun)
|
|
55860
56486
|
return { action, path: skillMdPath };
|
|
55861
|
-
const parentDir =
|
|
56487
|
+
const parentDir = dirname16(dir);
|
|
55862
56488
|
mkdirSync9(parentDir, { recursive: true });
|
|
55863
|
-
const transactionDir = mkdtempSync2(join31(parentDir, `.hasna-skills-write-${
|
|
56489
|
+
const transactionDir = mkdtempSync2(join31(parentDir, `.hasna-skills-write-${basename9(dir)}-`));
|
|
55864
56490
|
const candidateDir = join31(transactionDir, "candidate");
|
|
55865
56491
|
const backupDir = join31(transactionDir, "backup");
|
|
55866
56492
|
const candidateSkillMdPath = join31(candidateDir, "SKILL.md");
|
|
@@ -57710,7 +58336,7 @@ var _parse = (_Err) => {
|
|
|
57710
58336
|
return result2.value;
|
|
57711
58337
|
};
|
|
57712
58338
|
return fn;
|
|
57713
|
-
},
|
|
58339
|
+
}, parse7, _parseAsync = (_Err) => {
|
|
57714
58340
|
const fn = async (schema, value, _ctx, params) => {
|
|
57715
58341
|
const ctx = _ctx ? { ..._ctx, async: true } : { async: true };
|
|
57716
58342
|
let result2 = schema._zod.run({ value, issues: [] }, ctx);
|
|
@@ -57755,16 +58381,16 @@ var _parse = (_Err) => {
|
|
|
57755
58381
|
result2 = await result2;
|
|
57756
58382
|
return result2.issues.length === 0;
|
|
57757
58383
|
}, _encode = (_Err) => {
|
|
57758
|
-
const
|
|
58384
|
+
const parse8 = _parse(_Err);
|
|
57759
58385
|
const fn = (schema, value, _ctx, _params) => {
|
|
57760
58386
|
const ctx = _ctx ? { ..._ctx, direction: "backward" } : { direction: "backward" };
|
|
57761
|
-
return
|
|
58387
|
+
return parse8(schema, value, ctx, finalizeParams(fn, _params));
|
|
57762
58388
|
};
|
|
57763
58389
|
return fn;
|
|
57764
58390
|
}, encode, _decode = (_Err) => {
|
|
57765
|
-
const
|
|
58391
|
+
const parse8 = _parse(_Err);
|
|
57766
58392
|
const fn = (schema, value, _ctx, _params) => {
|
|
57767
|
-
return
|
|
58393
|
+
return parse8(schema, value, _ctx, finalizeParams(fn, _params));
|
|
57768
58394
|
};
|
|
57769
58395
|
return fn;
|
|
57770
58396
|
}, decode, _encodeAsync = (_Err) => {
|
|
@@ -57795,7 +58421,7 @@ var init_parse = __esm(() => {
|
|
|
57795
58421
|
init_core();
|
|
57796
58422
|
init_errors();
|
|
57797
58423
|
init_util();
|
|
57798
|
-
|
|
58424
|
+
parse7 = /* @__PURE__ */ _parse($ZodRealError);
|
|
57799
58425
|
parseAsync = /* @__PURE__ */ _parseAsync($ZodRealError);
|
|
57800
58426
|
safeParse = /* @__PURE__ */ _safeParse($ZodRealError);
|
|
57801
58427
|
safeParseAsync = /* @__PURE__ */ _safeParseAsync($ZodRealError);
|
|
@@ -59758,14 +60384,14 @@ var init_schemas = __esm(() => {
|
|
|
59758
60384
|
const shape = zod.def.shape;
|
|
59759
60385
|
const propValues = {};
|
|
59760
60386
|
for (const key in shape) {
|
|
59761
|
-
const
|
|
59762
|
-
if (
|
|
60387
|
+
const field2 = shape[key]._zod;
|
|
60388
|
+
if (field2.values) {
|
|
59763
60389
|
if (!Object.prototype.hasOwnProperty.call(propValues, key)) {
|
|
59764
60390
|
assignProp(propValues, key, new Set);
|
|
59765
60391
|
}
|
|
59766
|
-
for (const v of
|
|
60392
|
+
for (const v of field2.values)
|
|
59767
60393
|
propValues[key].add(v);
|
|
59768
|
-
if (
|
|
60394
|
+
if (field2.optin !== undefined)
|
|
59769
60395
|
propValues[key].add(undefined);
|
|
59770
60396
|
}
|
|
59771
60397
|
}
|
|
@@ -60720,10 +61346,10 @@ var init_schemas = __esm(() => {
|
|
|
60720
61346
|
throw new Error("implement() must be called with a function");
|
|
60721
61347
|
}
|
|
60722
61348
|
return Object.defineProperty(function(...args) {
|
|
60723
|
-
const parsedArgs = inst._def.input ?
|
|
61349
|
+
const parsedArgs = inst._def.input ? parse7(inst._def.input, args) : args;
|
|
60724
61350
|
const result2 = Reflect.apply(func, this, parsedArgs);
|
|
60725
61351
|
if (inst._def.output) {
|
|
60726
|
-
return
|
|
61352
|
+
return parse7(inst._def.output, result2);
|
|
60727
61353
|
}
|
|
60728
61354
|
return result2;
|
|
60729
61355
|
}, "_zod", { value: inst._zod, enumerable: false });
|
|
@@ -72040,11 +72666,11 @@ var formatMap, stringProcessor = (schema, ctx, _json, _params) => {
|
|
|
72040
72666
|
}
|
|
72041
72667
|
const allKeys = new Set(Object.keys(shape));
|
|
72042
72668
|
const requiredKeys = new Set([...allKeys].filter((key) => {
|
|
72043
|
-
const
|
|
72669
|
+
const field2 = def.shape[key];
|
|
72044
72670
|
if (ctx.io === "input") {
|
|
72045
|
-
return inputOptin(
|
|
72671
|
+
return inputOptin(field2) === undefined;
|
|
72046
72672
|
} else {
|
|
72047
|
-
return
|
|
72673
|
+
return field2._zod.optout === undefined;
|
|
72048
72674
|
}
|
|
72049
72675
|
}));
|
|
72050
72676
|
if (requiredKeys.size > 0) {
|
|
@@ -72424,7 +73050,7 @@ __export(exports_core2, {
|
|
|
72424
73050
|
prettifyError: () => prettifyError,
|
|
72425
73051
|
parseURLObject: () => parseURLObject,
|
|
72426
73052
|
parseAsync: () => parseAsync,
|
|
72427
|
-
parse: () =>
|
|
73053
|
+
parse: () => parse7,
|
|
72428
73054
|
meta: () => meta,
|
|
72429
73055
|
mergeValues: () => mergeValues,
|
|
72430
73056
|
memoizer: () => memoizer,
|
|
@@ -72814,12 +73440,12 @@ var init_errors2 = __esm(() => {
|
|
|
72814
73440
|
});
|
|
72815
73441
|
|
|
72816
73442
|
// node_modules/zod/v4/classic/parse.js
|
|
72817
|
-
var
|
|
73443
|
+
var parse9, parseAsync2, safeParse2, safeParseAsync2, encode2, decode2, encodeAsync2, decodeAsync2, safeEncode2, safeDecode2, safeEncodeAsync2, safeDecodeAsync2;
|
|
72818
73444
|
var init_parse2 = __esm(() => {
|
|
72819
73445
|
init_core2();
|
|
72820
73446
|
init_errors2();
|
|
72821
73447
|
init_core2();
|
|
72822
|
-
|
|
73448
|
+
parse9 = /* @__PURE__ */ _parse(ZodRealError);
|
|
72823
73449
|
parseAsync2 = /* @__PURE__ */ _parseAsync(ZodRealError);
|
|
72824
73450
|
safeParse2 = /* @__PURE__ */ _safeParse(ZodRealError);
|
|
72825
73451
|
safeParseAsync2 = /* @__PURE__ */ _safeParseAsync(ZodRealError);
|
|
@@ -73620,7 +74246,7 @@ var init_schemas2 = __esm(() => {
|
|
|
73620
74246
|
exports_util.own(this, "~standard", value);
|
|
73621
74247
|
},
|
|
73622
74248
|
parse: function _parse2(data, params) {
|
|
73623
|
-
return
|
|
74249
|
+
return parse9(this, data, params, { callee: _parse2 });
|
|
73624
74250
|
},
|
|
73625
74251
|
parseAsync: async function _parseAsync2(data, params) {
|
|
73626
74252
|
return await parseAsync2(this, data, params, { callee: _parseAsync2 });
|
|
@@ -75313,7 +75939,7 @@ __export(exports_external, {
|
|
|
75313
75939
|
pipe: () => pipe,
|
|
75314
75940
|
partialRecord: () => partialRecord,
|
|
75315
75941
|
parseAsync: () => parseAsync2,
|
|
75316
|
-
parse: () =>
|
|
75942
|
+
parse: () => parse9,
|
|
75317
75943
|
overwrite: () => _overwrite,
|
|
75318
75944
|
output: () => output,
|
|
75319
75945
|
optional: () => optional,
|
|
@@ -75794,7 +76420,7 @@ var init_v4 = __esm(() => {
|
|
|
75794
76420
|
});
|
|
75795
76421
|
|
|
75796
76422
|
// src/lib/canonical-json.ts
|
|
75797
|
-
import { createHash as
|
|
76423
|
+
import { createHash as createHash15 } from "crypto";
|
|
75798
76424
|
function canonicalJson2(value, maximumBytes = 2 * 1024 * 1024) {
|
|
75799
76425
|
return canonicalJsonAtDepth(value, maximumBytes, 64);
|
|
75800
76426
|
}
|
|
@@ -75838,7 +76464,7 @@ function canonicalJsonAtDepth(value, maximumBytes, maximumDepth) {
|
|
|
75838
76464
|
return visit3(value, 0);
|
|
75839
76465
|
}
|
|
75840
76466
|
function canonicalJsonSha256(value, maximumBytes) {
|
|
75841
|
-
return
|
|
76467
|
+
return createHash15("sha256").update(canonicalJson2(value, maximumBytes)).digest("hex");
|
|
75842
76468
|
}
|
|
75843
76469
|
var init_canonical_json = () => {};
|
|
75844
76470
|
|
|
@@ -76592,13 +77218,13 @@ var init_remote_workspace_leave = __esm(() => {
|
|
|
76592
77218
|
|
|
76593
77219
|
// src/lib/auth-store.ts
|
|
76594
77220
|
import { chmodSync as chmodSync2, existsSync as existsSync20, mkdirSync as mkdirSync11, readFileSync as readFileSync19, renameSync as renameSync7, statSync as statSync11, unlinkSync as unlinkSync5, writeFileSync as writeFileSync9 } from "fs";
|
|
76595
|
-
import { basename as
|
|
77221
|
+
import { basename as basename10, dirname as dirname17, join as join34 } from "path";
|
|
76596
77222
|
function getAuthFilePath(env3 = process.env) {
|
|
76597
77223
|
return skillsCredentialFilePath(env3);
|
|
76598
77224
|
}
|
|
76599
77225
|
function getIdentityFilePath(env3 = process.env) {
|
|
76600
77226
|
const file2 = skillsCredentialFilePath(env3);
|
|
76601
|
-
return join34(
|
|
77227
|
+
return join34(dirname17(file2), basename10(file2).replace(/^credentials/, "identity") + ".json");
|
|
76602
77228
|
}
|
|
76603
77229
|
function getAuthIdentity(env3 = process.env) {
|
|
76604
77230
|
return readIdentity(env3);
|
|
@@ -76614,10 +77240,10 @@ function readIdentity(env3 = process.env) {
|
|
|
76614
77240
|
if (selected && normalizeSkillsApiOrigin(bound) !== selected)
|
|
76615
77241
|
return {};
|
|
76616
77242
|
const identity4 = {};
|
|
76617
|
-
for (const
|
|
76618
|
-
const value = record6[
|
|
77243
|
+
for (const field2 of ["email", "orgId", "orgSlug", "userId"]) {
|
|
77244
|
+
const value = record6[field2];
|
|
76619
77245
|
if (typeof value === "string" && value.length > 0)
|
|
76620
|
-
identity4[
|
|
77246
|
+
identity4[field2] = value;
|
|
76621
77247
|
}
|
|
76622
77248
|
return identity4;
|
|
76623
77249
|
} catch {
|
|
@@ -76632,7 +77258,7 @@ function getAuthConfig(env3 = process.env, options = {}) {
|
|
|
76632
77258
|
}
|
|
76633
77259
|
function writeCredentialValues(values2, env3 = process.env) {
|
|
76634
77260
|
const file2 = skillsCredentialFilePath(env3);
|
|
76635
|
-
mkdirSync11(
|
|
77261
|
+
mkdirSync11(dirname17(file2), { recursive: true, mode: 448 });
|
|
76636
77262
|
const lines = [];
|
|
76637
77263
|
const written = new Set;
|
|
76638
77264
|
if (existsSync20(file2)) {
|
|
@@ -76700,10 +77326,10 @@ function saveAuthConfig(config2, env3 = process.env, authenticatedOrigin) {
|
|
|
76700
77326
|
const apiUrl = authenticatedOrigin ? normalizeSkillsApiOrigin(authenticatedOrigin) : resolveSkillsApiOrigin(env3)?.origin ?? defaultFleetGatewayBaseUrl("skills");
|
|
76701
77327
|
const file2 = writeCredentialValues({ SKILLS_API_KEY: null, SKILLS_API_URL: null, [SKILLS_API_KEY_REF]: null, [SKILLS_API_KEY_ENV]: apiKey, [SKILLS_BOUND_API_URL]: apiUrl, [SKILLS_API_URL_ENV]: apiUrl }, env3);
|
|
76702
77328
|
const identity4 = {};
|
|
76703
|
-
for (const
|
|
76704
|
-
const value = config2[
|
|
77329
|
+
for (const field2 of ["email", "orgId", "orgSlug", "userId"]) {
|
|
77330
|
+
const value = config2[field2];
|
|
76705
77331
|
if (typeof value === "string" && value.length > 0)
|
|
76706
|
-
identity4[
|
|
77332
|
+
identity4[field2] = value;
|
|
76707
77333
|
}
|
|
76708
77334
|
const identityFile = getIdentityFilePath(env3);
|
|
76709
77335
|
if (Object.keys(identity4).length > 0) {
|
|
@@ -76896,15 +77522,44 @@ var init_remote_account = __esm(() => {
|
|
|
76896
77522
|
};
|
|
76897
77523
|
});
|
|
76898
77524
|
|
|
77525
|
+
// src/lib/remote-credit-checkout.ts
|
|
77526
|
+
function creditCheckoutRequestKey(value) {
|
|
77527
|
+
if (value === undefined)
|
|
77528
|
+
return crypto.randomUUID();
|
|
77529
|
+
if (typeof value !== "string" || !creditCheckoutKeyPattern.test(value))
|
|
77530
|
+
throw new Error("Checkout idempotency key must be 8-255 URL-safe characters");
|
|
77531
|
+
return value;
|
|
77532
|
+
}
|
|
77533
|
+
function creditCheckoutFailure(value, status, key) {
|
|
77534
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
77535
|
+
return { code: "CREDIT_CHECKOUT_UNCONFIRMED" };
|
|
77536
|
+
const row = value;
|
|
77537
|
+
if (row.requestIdempotencyKey !== undefined && row.requestIdempotencyKey !== key)
|
|
77538
|
+
return { code: "CREDIT_CHECKOUT_UNCONFIRMED" };
|
|
77539
|
+
const code = status === 409 && row.error === "credit checkout in_progress" ? "CREDIT_CHECKOUT_IN_PROGRESS" : status === 409 && row.error === "credit checkout expired" && row.requestIdempotencyKey === key ? "CREDIT_CHECKOUT_EXPIRED" : status === 409 && row.error === "credit checkout fulfilled" && row.requestIdempotencyKey === key ? "CREDIT_CHECKOUT_FULFILLED" : "CREDIT_CHECKOUT_UNCONFIRMED";
|
|
77540
|
+
const delay2 = row.retryAfterSeconds;
|
|
77541
|
+
return { code, ...code === "CREDIT_CHECKOUT_IN_PROGRESS" || status === 503 && row.error === "credit checkout creation unresolved" ? typeof delay2 === "number" && Number.isSafeInteger(delay2) && delay2 > 0 && delay2 <= 3600 ? { retryAfterSeconds: delay2 } : {} : {} };
|
|
77542
|
+
}
|
|
77543
|
+
var creditCheckoutKeyPattern, creditCheckoutMessages;
|
|
77544
|
+
var init_remote_credit_checkout = __esm(() => {
|
|
77545
|
+
creditCheckoutKeyPattern = /^[A-Za-z0-9._:-]{8,255}$/;
|
|
77546
|
+
creditCheckoutMessages = {
|
|
77547
|
+
CREDIT_CHECKOUT_UNCONFIRMED: "Checkout creation could not be confirmed. Keep the request idempotency key, inspect billing, and use the same key for an explicit retry on the same server, account and pack. No automatic retry was made.",
|
|
77548
|
+
CREDIT_CHECKOUT_IN_PROGRESS: "This checkout is still being created. Wait before explicitly retrying the same server, account and pack with the same request idempotency key. No automatic retry was made.",
|
|
77549
|
+
CREDIT_CHECKOUT_EXPIRED: "This checkout has expired. Inspect billing before deliberately starting a new purchase with a new request idempotency key. Do not retry this checkout automatically.",
|
|
77550
|
+
CREDIT_CHECKOUT_FULFILLED: "This checkout is already fulfilled. Inspect the account balance; do not create another checkout to recover this purchase."
|
|
77551
|
+
};
|
|
77552
|
+
});
|
|
77553
|
+
|
|
76899
77554
|
// src/lib/remote-profile.ts
|
|
76900
|
-
function customerNamePatch(input2,
|
|
76901
|
-
if (!isRecord4(input2) || Object.keys(input2).length !== 1 || !Object.hasOwn(input2,
|
|
77555
|
+
function customerNamePatch(input2, field2) {
|
|
77556
|
+
if (!isRecord4(input2) || Object.keys(input2).length !== 1 || !Object.hasOwn(input2, field2))
|
|
76902
77557
|
throw new Error("Provide only the requested name field.");
|
|
76903
|
-
const value = input2[
|
|
77558
|
+
const value = input2[field2];
|
|
76904
77559
|
if (typeof value !== "string" || /[\p{Cc}\p{Cs}\u2028\u2029]/u.test(value) || !value.trim() || [...value.trim()].length > 100) {
|
|
76905
77560
|
throw new Error("Use a name of 1\u2013100 characters without control characters or newlines.");
|
|
76906
77561
|
}
|
|
76907
|
-
return { [
|
|
77562
|
+
return { [field2]: value.trim() };
|
|
76908
77563
|
}
|
|
76909
77564
|
function isRecord4(value) {
|
|
76910
77565
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
@@ -76941,10 +77596,10 @@ async function readQuoteUnavailableCode(response) {
|
|
|
76941
77596
|
let timer;
|
|
76942
77597
|
let deadlineExceeded = false;
|
|
76943
77598
|
const expired = Symbol("quote body deadline");
|
|
76944
|
-
const deadline = new Promise((
|
|
77599
|
+
const deadline = new Promise((resolve17) => {
|
|
76945
77600
|
timer = setTimeout(() => {
|
|
76946
77601
|
deadlineExceeded = true;
|
|
76947
|
-
|
|
77602
|
+
resolve17(expired);
|
|
76948
77603
|
reader.cancel().catch(() => {});
|
|
76949
77604
|
}, 1500);
|
|
76950
77605
|
});
|
|
@@ -77059,6 +77714,7 @@ __export(exports_remote_client, {
|
|
|
77059
77714
|
RemoteRouteUnsupportedError: () => RemoteRouteUnsupportedError,
|
|
77060
77715
|
RemoteRequestError: () => RemoteRequestError,
|
|
77061
77716
|
RemoteQuoteUnavailableError: () => RemoteQuoteUnavailableError,
|
|
77717
|
+
RemoteCreditCheckoutError: () => RemoteCreditCheckoutError,
|
|
77062
77718
|
RemoteCapabilityUnavailableError: () => RemoteCapabilityUnavailableError
|
|
77063
77719
|
});
|
|
77064
77720
|
|
|
@@ -77509,14 +78165,43 @@ class RemoteSkillsClient {
|
|
|
77509
78165
|
async listCreditPacks() {
|
|
77510
78166
|
return parseRemoteCreditPacks(await (await this.requestNewRoute("/api/v1/billing/credits")).json());
|
|
77511
78167
|
}
|
|
77512
|
-
async createCreditCheckout(packId) {
|
|
78168
|
+
async createCreditCheckout(packId, options = {}) {
|
|
78169
|
+
const requestIdempotencyKey = creditCheckoutRequestKey(options.idempotencyKey);
|
|
77513
78170
|
const packs = await this.listCreditPacks();
|
|
77514
78171
|
if (!packs.some((pack) => pack.id === packId))
|
|
77515
78172
|
throw new Error("Choose a credit pack returned by skills credits packs");
|
|
77516
|
-
|
|
77517
|
-
|
|
77518
|
-
|
|
77519
|
-
|
|
78173
|
+
let response;
|
|
78174
|
+
try {
|
|
78175
|
+
response = await this.request("/api/v1/billing/credits", {
|
|
78176
|
+
method: "POST",
|
|
78177
|
+
body: JSON.stringify({ packId, idempotencyKey: requestIdempotencyKey })
|
|
78178
|
+
});
|
|
78179
|
+
} catch {
|
|
78180
|
+
throw new RemoteCreditCheckoutError("CREDIT_CHECKOUT_UNCONFIRMED", 0, requestIdempotencyKey);
|
|
78181
|
+
}
|
|
78182
|
+
if (response.status === 404 || response.status === 405) {
|
|
78183
|
+
response.body?.cancel().catch(() => {});
|
|
78184
|
+
throw new RemoteRouteUnsupportedError("/api/v1/billing/credits", response.status, this.apiUrl);
|
|
78185
|
+
}
|
|
78186
|
+
let value;
|
|
78187
|
+
try {
|
|
78188
|
+
value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(await readBoundedResponse(response, 4096)));
|
|
78189
|
+
} catch {
|
|
78190
|
+
throw new RemoteCreditCheckoutError("CREDIT_CHECKOUT_UNCONFIRMED", response.status, requestIdempotencyKey);
|
|
78191
|
+
}
|
|
78192
|
+
if (!response.ok) {
|
|
78193
|
+
const failure = creditCheckoutFailure(value, response.status, requestIdempotencyKey);
|
|
78194
|
+
throw new RemoteCreditCheckoutError(failure.code, response.status, requestIdempotencyKey, failure.retryAfterSeconds);
|
|
78195
|
+
}
|
|
78196
|
+
try {
|
|
78197
|
+
const checkout = parseRemoteCheckout(value);
|
|
78198
|
+
const echo = value.requestIdempotencyKey;
|
|
78199
|
+
if (echo !== undefined && echo !== requestIdempotencyKey)
|
|
78200
|
+
throw new Error("checkout request key changed");
|
|
78201
|
+
return { ...checkout, requestIdempotencyKey };
|
|
78202
|
+
} catch {
|
|
78203
|
+
throw new RemoteCreditCheckoutError("CREDIT_CHECKOUT_UNCONFIRMED", response.status, requestIdempotencyKey);
|
|
78204
|
+
}
|
|
77520
78205
|
}
|
|
77521
78206
|
async getUsage() {
|
|
77522
78207
|
return this.arrayResponse("/api/v1/billing/usage");
|
|
@@ -77749,13 +78434,13 @@ class RemoteSkillsClient {
|
|
|
77749
78434
|
return normalizeUpdatedSincePage(await response.json());
|
|
77750
78435
|
}
|
|
77751
78436
|
}
|
|
77752
|
-
function requireOptionalString(record7,
|
|
77753
|
-
if (record7[
|
|
78437
|
+
function requireOptionalString(record7, field2) {
|
|
78438
|
+
if (record7[field2] === undefined)
|
|
77754
78439
|
return;
|
|
77755
|
-
if (typeof record7[
|
|
77756
|
-
throw new Error(`Remote payload did not match the expected contract (${
|
|
78440
|
+
if (typeof record7[field2] !== "string") {
|
|
78441
|
+
throw new Error(`Remote payload did not match the expected contract (${field2} must be a string when present)`);
|
|
77757
78442
|
}
|
|
77758
|
-
return record7[
|
|
78443
|
+
return record7[field2];
|
|
77759
78444
|
}
|
|
77760
78445
|
function isVersionRecord(value) {
|
|
77761
78446
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
@@ -77886,7 +78571,7 @@ async function createRemoteSkillsClient(env3 = process.env) {
|
|
|
77886
78571
|
function createRemoteSkillsClientReadOnly(env3 = process.env) {
|
|
77887
78572
|
return createRemoteSkillsClient(env3);
|
|
77888
78573
|
}
|
|
77889
|
-
var RemoteRouteUnsupportedError, RemoteRequestError, RemoteQuoteUnavailableError, RemoteWorkspaceMemberError, RemoteWorkspaceSelectionError, RemoteCapabilityUnavailableError, INVALID_SKILL_VERSION_RESPONSE = "Remote skill version payload did not match the expected contract.";
|
|
78574
|
+
var RemoteRouteUnsupportedError, RemoteRequestError, RemoteCreditCheckoutError, RemoteQuoteUnavailableError, RemoteWorkspaceMemberError, RemoteWorkspaceSelectionError, RemoteCapabilityUnavailableError, INVALID_SKILL_VERSION_RESPONSE = "Remote skill version payload did not match the expected contract.";
|
|
77890
78575
|
var init_remote_client = __esm(() => {
|
|
77891
78576
|
init_remote_recurring();
|
|
77892
78577
|
init_remote_invitations();
|
|
@@ -77898,6 +78583,7 @@ var init_remote_client = __esm(() => {
|
|
|
77898
78583
|
init_fleet_credentials();
|
|
77899
78584
|
init_remote_account();
|
|
77900
78585
|
init_remote_files();
|
|
78586
|
+
init_remote_credit_checkout();
|
|
77901
78587
|
init_remote_quote_errors();
|
|
77902
78588
|
init_remote_permissions();
|
|
77903
78589
|
RemoteRouteUnsupportedError = class RemoteRouteUnsupportedError extends Error {
|
|
@@ -77922,6 +78608,19 @@ var init_remote_client = __esm(() => {
|
|
|
77922
78608
|
this.name = "RemoteRequestError";
|
|
77923
78609
|
}
|
|
77924
78610
|
};
|
|
78611
|
+
RemoteCreditCheckoutError = class RemoteCreditCheckoutError extends RemoteRequestError {
|
|
78612
|
+
code;
|
|
78613
|
+
requestIdempotencyKey;
|
|
78614
|
+
retryAfterSeconds;
|
|
78615
|
+
constructor(code, status, requestIdempotencyKey, retryAfterSeconds) {
|
|
78616
|
+
super("/api/v1/billing/credits", status);
|
|
78617
|
+
this.code = code;
|
|
78618
|
+
this.requestIdempotencyKey = requestIdempotencyKey;
|
|
78619
|
+
this.retryAfterSeconds = retryAfterSeconds;
|
|
78620
|
+
this.name = "RemoteCreditCheckoutError";
|
|
78621
|
+
this.message = creditCheckoutMessages[code];
|
|
78622
|
+
}
|
|
78623
|
+
};
|
|
77925
78624
|
RemoteQuoteUnavailableError = class RemoteQuoteUnavailableError extends RemoteRequestError {
|
|
77926
78625
|
code;
|
|
77927
78626
|
constructor(path, code) {
|
|
@@ -77962,9 +78661,9 @@ var init_remote_client = __esm(() => {
|
|
|
77962
78661
|
});
|
|
77963
78662
|
|
|
77964
78663
|
// src/lib/revision.ts
|
|
77965
|
-
import { createHash as
|
|
78664
|
+
import { createHash as createHash16 } from "crypto";
|
|
77966
78665
|
function revisionIdOf(content) {
|
|
77967
|
-
const
|
|
78666
|
+
const canonical4 = JSON.stringify({
|
|
77968
78667
|
slug: content.slug,
|
|
77969
78668
|
displayName: content.displayName,
|
|
77970
78669
|
description: content.description,
|
|
@@ -77977,7 +78676,7 @@ function revisionIdOf(content) {
|
|
|
77977
78676
|
bundleSha256: content.bundleSha256 ?? null,
|
|
77978
78677
|
bundleByteSize: content.bundleByteSize ?? null
|
|
77979
78678
|
});
|
|
77980
|
-
return
|
|
78679
|
+
return createHash16("sha256").update(canonical4).digest("hex");
|
|
77981
78680
|
}
|
|
77982
78681
|
var REVISION_ID_PATTERN;
|
|
77983
78682
|
var init_revision = __esm(() => {
|
|
@@ -78007,7 +78706,7 @@ var init_skill_bundles = __esm(() => {
|
|
|
78007
78706
|
|
|
78008
78707
|
// src/lib/pull.ts
|
|
78009
78708
|
import { existsSync as existsSync21, mkdirSync as mkdirSync12, mkdtempSync as mkdtempSync3, readFileSync as readFileSync20, renameSync as renameSync8, rmSync as rmSync6, writeFileSync as writeFileSync10 } from "fs";
|
|
78010
|
-
import { dirname as
|
|
78709
|
+
import { dirname as dirname18, join as join35 } from "path";
|
|
78011
78710
|
async function pullSkills(options = {}) {
|
|
78012
78711
|
const client2 = options.client !== undefined ? options.client : await createRemoteSkillsClient();
|
|
78013
78712
|
if (!client2) {
|
|
@@ -78311,7 +79010,7 @@ function installBundleAtomically(name, entries, options = {}, marker = {}) {
|
|
|
78311
79010
|
try {
|
|
78312
79011
|
for (const entry of entries) {
|
|
78313
79012
|
const destination = join35(staging, entry.path);
|
|
78314
|
-
mkdirSync12(
|
|
79013
|
+
mkdirSync12(dirname18(destination), { recursive: true });
|
|
78315
79014
|
writeFileSync10(destination, entry.bytes, { mode: entry.mode });
|
|
78316
79015
|
}
|
|
78317
79016
|
writePullMarker(staging, {
|
|
@@ -78426,8 +79125,8 @@ var init_pull = __esm(() => {
|
|
|
78426
79125
|
});
|
|
78427
79126
|
|
|
78428
79127
|
// src/lib/skill-context.ts
|
|
78429
|
-
import { createHash as
|
|
78430
|
-
import { resolve as
|
|
79128
|
+
import { createHash as createHash17 } from "crypto";
|
|
79129
|
+
import { resolve as resolve17 } from "path";
|
|
78431
79130
|
function words2(value) {
|
|
78432
79131
|
return new Set(value.toLowerCase().match(/[a-z0-9]+/g) ?? []);
|
|
78433
79132
|
}
|
|
@@ -78462,7 +79161,7 @@ async function buildSkillContext(input2, options = {}) {
|
|
|
78462
79161
|
const promptWords = words2(prompt);
|
|
78463
79162
|
const promptNames = new Set(prompt.toLowerCase().match(/[a-z0-9]+(?:-[a-z0-9]+)*/g) ?? []);
|
|
78464
79163
|
const loaded = new Set(resolved.session?.loaded ?? []);
|
|
78465
|
-
const paths = [...input2.paths ?? [], ...input2.cwd ? [input2.cwd,
|
|
79164
|
+
const paths = [...input2.paths ?? [], ...input2.cwd ? [input2.cwd, resolve17(input2.cwd)] : []];
|
|
78466
79165
|
const candidates = profile.selections.map((selection) => {
|
|
78467
79166
|
const key = selectionKey(selection);
|
|
78468
79167
|
if (input2.restore && loaded.has(key))
|
|
@@ -78515,7 +79214,7 @@ ${content}`;
|
|
|
78515
79214
|
`);
|
|
78516
79215
|
const receipt = {
|
|
78517
79216
|
schemaVersion: 1,
|
|
78518
|
-
id:
|
|
79217
|
+
id: createHash17("sha256").update(JSON.stringify({ profile: profile.profileRevision, sessionId, selections, omitted })).digest("hex"),
|
|
78519
79218
|
profileId: profile.profileId,
|
|
78520
79219
|
profileRevision: profile.profileRevision,
|
|
78521
79220
|
authority: profile.authority,
|
|
@@ -78527,7 +79226,7 @@ ${content}`;
|
|
|
78527
79226
|
selections
|
|
78528
79227
|
};
|
|
78529
79228
|
if (sessionId)
|
|
78530
|
-
|
|
79229
|
+
writeSkillSession({ ...resolved.receipt, sessionId, loaded: [...loaded] }, { current: resolved.sessionSnapshot, parent: resolved.parentSnapshot }, options);
|
|
78531
79230
|
return { context, selections, omitted, receipt };
|
|
78532
79231
|
}
|
|
78533
79232
|
var init_skill_context = __esm(() => {
|
|
@@ -78536,6 +79235,107 @@ var init_skill_context = __esm(() => {
|
|
|
78536
79235
|
init_selected_document();
|
|
78537
79236
|
});
|
|
78538
79237
|
|
|
79238
|
+
// src/lib/session-reconciliation.ts
|
|
79239
|
+
import { createHash as createHash18 } from "crypto";
|
|
79240
|
+
function exactTimestamp(value) {
|
|
79241
|
+
const parsed = value === undefined ? Number.NaN : Date.parse(value);
|
|
79242
|
+
if (!Number.isFinite(parsed) || new Date(parsed).toISOString() !== value) {
|
|
79243
|
+
throw new SkillSelectionError("SESSION_PLAN_WINDOW_INVALID", "The reviewed plan must include its exact canonical issuedAt and expiresAt timestamps.");
|
|
79244
|
+
}
|
|
79245
|
+
return parsed;
|
|
79246
|
+
}
|
|
79247
|
+
function assertPlanWindow(issuedAt, expiresAt, now3) {
|
|
79248
|
+
const issued = exactTimestamp(issuedAt), expires = exactTimestamp(expiresAt);
|
|
79249
|
+
if (expires - issued !== SESSION_RECONCILIATION_PLAN_TTL_MS) {
|
|
79250
|
+
throw new SkillSelectionError("SESSION_PLAN_WINDOW_INVALID", "A session reconciliation approval is valid for exactly five minutes and cannot be extended by the caller.");
|
|
79251
|
+
}
|
|
79252
|
+
if (now3 < issued || now3 >= expires) {
|
|
79253
|
+
throw new SkillSelectionError("SESSION_PLAN_EXPIRED", "The reviewed session reconciliation plan is not currently valid; inspect the receipt and prepare a new plan.");
|
|
79254
|
+
}
|
|
79255
|
+
}
|
|
79256
|
+
function inspectSkillSession(sessionId, options = {}) {
|
|
79257
|
+
const snapshot = readSkillSessionSnapshot(sessionId, options), { receipt } = snapshot;
|
|
79258
|
+
return {
|
|
79259
|
+
sessionId,
|
|
79260
|
+
path: snapshot.path,
|
|
79261
|
+
receiptSha256: snapshot.sha256,
|
|
79262
|
+
generation: snapshot.generation,
|
|
79263
|
+
verifiedAt: receipt.verifiedAt,
|
|
79264
|
+
authority: receipt.profile.authority,
|
|
79265
|
+
workspaceId: receipt.profile.workspaceId,
|
|
79266
|
+
profileId: receipt.profile.profileId,
|
|
79267
|
+
profileRevision: receipt.profile.profileRevision,
|
|
79268
|
+
selectionCount: receipt.profile.selections.length,
|
|
79269
|
+
loadedCount: receipt.loaded.length
|
|
79270
|
+
};
|
|
79271
|
+
}
|
|
79272
|
+
async function reconcileSkillSession(input2, options = {}) {
|
|
79273
|
+
if (![input2.fromProfile, input2.fromRevision, input2.selectionProfile, input2.profileRevision].every((value) => typeof value === "string" && value.trim()) || !/^[a-f0-9]{64}$/.test(input2.receiptSha256)) {
|
|
79274
|
+
throw new SkillSelectionError("INVALID_SESSION_RECONCILIATION", "Name the exact old receipt SHA256, old profile/revision and intended target profile/revision.");
|
|
79275
|
+
}
|
|
79276
|
+
if (input2.apply && (!input2.planDigest || !input2.planIssuedAt || !input2.planExpiresAt)) {
|
|
79277
|
+
throw new SkillSelectionError("SESSION_PLAN_REQUIRED", "Review the session reconciliation plan and provide its exact digest, issuedAt and expiresAt before applying it.");
|
|
79278
|
+
}
|
|
79279
|
+
if (!input2.apply && (input2.planDigest !== undefined || input2.planIssuedAt !== undefined || input2.planExpiresAt !== undefined)) {
|
|
79280
|
+
throw new SkillSelectionError("SESSION_PLAN_WINDOW_INVALID", "Plan timestamps are minted by the planner and may only be replayed with --apply.");
|
|
79281
|
+
}
|
|
79282
|
+
const now3 = (options.now ?? Date.now)();
|
|
79283
|
+
const issuedAt = input2.apply ? input2.planIssuedAt : new Date(now3).toISOString();
|
|
79284
|
+
const expiresAt = input2.apply ? input2.planExpiresAt : new Date(now3 + SESSION_RECONCILIATION_PLAN_TTL_MS).toISOString();
|
|
79285
|
+
if (input2.apply)
|
|
79286
|
+
assertPlanWindow(issuedAt, expiresAt, now3);
|
|
79287
|
+
const snapshot = readSkillSessionSnapshot(input2.sessionId, options), old = snapshot.receipt;
|
|
79288
|
+
if (snapshot.sha256 !== input2.receiptSha256 || old.profile.profileId !== input2.fromProfile || old.profile.profileRevision !== input2.fromRevision) {
|
|
79289
|
+
throw new SkillSelectionError("SESSION_RECEIPT_CHANGED", "The current session receipt does not match the reviewed old bytes, profile and revision.");
|
|
79290
|
+
}
|
|
79291
|
+
const client2 = options.client ?? await createProfileClient();
|
|
79292
|
+
const target = structuredClone(await client2.resolveProfile(input2.selectionProfile));
|
|
79293
|
+
validateResolvedProfile(target, client2.authority);
|
|
79294
|
+
if (target.profileId !== input2.selectionProfile || target.profileRevision !== input2.profileRevision) {
|
|
79295
|
+
throw new SkillSelectionError("SESSION_TARGET_CHANGED", "The API selection profile does not match the intended target revision; review the current selection before proceeding.");
|
|
79296
|
+
}
|
|
79297
|
+
if (old.profile.authority !== target.authority || old.profile.workspaceId !== target.workspaceId) {
|
|
79298
|
+
throw new SkillSelectionError("PROFILE_IDENTITY_MISMATCH", "A session reconciliation cannot change its Skills authority or workspace.");
|
|
79299
|
+
}
|
|
79300
|
+
const targetKeys = new Set(target.selections.map(selectionKey));
|
|
79301
|
+
const loaded = old.loaded.filter((key) => targetKeys.has(key));
|
|
79302
|
+
const replacementGeneration = nextSkillSessionGeneration(snapshot.generation);
|
|
79303
|
+
const plan = {
|
|
79304
|
+
schemaVersion: 1,
|
|
79305
|
+
issuedAt,
|
|
79306
|
+
expiresAt,
|
|
79307
|
+
sessionId: input2.sessionId,
|
|
79308
|
+
sessionPath: snapshot.path,
|
|
79309
|
+
before: { receiptSha256: snapshot.sha256, generation: snapshot.generation, profileId: old.profile.profileId, profileRevision: old.profile.profileRevision, selectionCount: old.profile.selections.length },
|
|
79310
|
+
target: { authority: target.authority, workspaceId: target.workspaceId, profileId: target.profileId, profileRevision: target.profileRevision, profileSha256: digest3(target), selectionCount: target.selections.length },
|
|
79311
|
+
replacementGeneration,
|
|
79312
|
+
retainedLoadedCount: loaded.length,
|
|
79313
|
+
retiredLoadedCount: old.loaded.length - loaded.length,
|
|
79314
|
+
scope: "Only this receipt; existing child sessions, project locks, shared profiles, hooks and running processes are unchanged."
|
|
79315
|
+
};
|
|
79316
|
+
const planDigest = digest3(plan);
|
|
79317
|
+
if (input2.planDigest !== undefined && input2.planDigest !== planDigest)
|
|
79318
|
+
throw new SkillSelectionError("SESSION_PLAN_CHANGED", "The session reconciliation plan differs from the reviewed plan.");
|
|
79319
|
+
if (!input2.apply)
|
|
79320
|
+
return { applied: false, plan, planDigest, archivePath: undefined, receiptPath: undefined, beforeSha256: snapshot.sha256, afterSha256: undefined };
|
|
79321
|
+
assertPlanWindow(issuedAt, expiresAt, (options.now ?? Date.now)());
|
|
79322
|
+
const replacement = {
|
|
79323
|
+
...old,
|
|
79324
|
+
generation: replacementGeneration,
|
|
79325
|
+
verifiedAt: new Date((options.now ?? Date.now)()).toISOString(),
|
|
79326
|
+
profile: target,
|
|
79327
|
+
loaded
|
|
79328
|
+
};
|
|
79329
|
+
const result2 = replaceSkillSession(skillSessionSnapshotBinding(snapshot), replacement, { ...plan, planDigest }, options, () => assertPlanWindow(issuedAt, expiresAt, (options.now ?? Date.now)()));
|
|
79330
|
+
return { applied: true, plan, planDigest, ...result2 };
|
|
79331
|
+
}
|
|
79332
|
+
var SESSION_RECONCILIATION_PLAN_TTL_MS, digest3 = (value) => createHash18("sha256").update(JSON.stringify(value)).digest("hex");
|
|
79333
|
+
var init_session_reconciliation = __esm(() => {
|
|
79334
|
+
init_profile_client();
|
|
79335
|
+
init_selection_cache();
|
|
79336
|
+
SESSION_RECONCILIATION_PLAN_TTL_MS = 5 * 60 * 1000;
|
|
79337
|
+
});
|
|
79338
|
+
|
|
78539
79339
|
// src/cli/commands/context.ts
|
|
78540
79340
|
var exports_context = {};
|
|
78541
79341
|
__export(exports_context, {
|
|
@@ -78545,7 +79345,7 @@ __export(exports_context, {
|
|
|
78545
79345
|
parseSkillContextInput: () => parseSkillContextInput,
|
|
78546
79346
|
contextResolverOptions: () => contextResolverOptions
|
|
78547
79347
|
});
|
|
78548
|
-
import { readSync as
|
|
79348
|
+
import { readSync as readSync10 } from "fs";
|
|
78549
79349
|
function selectedProfileId(explicit) {
|
|
78550
79350
|
return explicit ?? process.env.HASNA_SKILLS_SELECTION_PROFILE ?? readManagedSkillPolicy()?.profileId ?? "default";
|
|
78551
79351
|
}
|
|
@@ -78559,6 +79359,25 @@ function contextResolverOptions(options) {
|
|
|
78559
79359
|
return { cached: true, authority };
|
|
78560
79360
|
}
|
|
78561
79361
|
function registerContextCommands(parent) {
|
|
79362
|
+
const sessions = parent.command("sessions").description("Inspect exact session pins and explicitly reconcile one reviewed receipt");
|
|
79363
|
+
sessions.command("show <id>").option("--json", "Return metadata as JSON", false).description("Inspect one session receipt without displaying payloads or changing its pin").action(async (id, options) => {
|
|
79364
|
+
try {
|
|
79365
|
+
const result2 = inspectSkillSession(id);
|
|
79366
|
+
await writeCliOutput(options.json ? JSON.stringify(result2) : `${JSON.stringify(id)}: ${result2.profileId} at ${result2.profileRevision}
|
|
79367
|
+
Receipt SHA256: ${result2.receiptSha256}`);
|
|
79368
|
+
} catch (error61) {
|
|
79369
|
+
reportContextError(error61, options.json);
|
|
79370
|
+
}
|
|
79371
|
+
});
|
|
79372
|
+
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; ordinary hooks never migrate pins").action(async (id, options) => {
|
|
79373
|
+
try {
|
|
79374
|
+
const result2 = await reconcileSkillSession({ ...options, sessionId: id });
|
|
79375
|
+
await writeCliOutput(options.json ? JSON.stringify(result2) : result2.applied ? `Reconciled ${JSON.stringify(id)} to ${result2.plan.target.profileId} at ${result2.plan.target.profileRevision}.
|
|
79376
|
+
Preserved original receipt: ${result2.archivePath}` : `Planned one session reconciliation. Review --json output, then use --apply --plan-digest ${result2.planDigest} --plan-issued-at ${result2.plan.issuedAt} --plan-expires-at ${result2.plan.expiresAt}.`);
|
|
79377
|
+
} catch (error61) {
|
|
79378
|
+
reportContextError(error61, options.json);
|
|
79379
|
+
}
|
|
79380
|
+
});
|
|
78562
79381
|
parent.command("load <skill>").description("Load an exact API-selected skill and return its version/digest receipt").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>", "Pin this load to a session").option("--file <path>", "Read an exact bundle file (default: SKILL.md, README.md, then CLAUDE.md)").option("--json", "Return content and provenance as JSON", false).action(async (skill, options) => {
|
|
78563
79382
|
try {
|
|
78564
79383
|
const result2 = await loadSelectedSkill(skill, selectedProfileId(options.selectionProfile), {
|
|
@@ -78604,7 +79423,7 @@ async function readContextStdin() {
|
|
|
78604
79423
|
let size2 = 0;
|
|
78605
79424
|
while (true) {
|
|
78606
79425
|
const chunk2 = Buffer.allocUnsafe(8192);
|
|
78607
|
-
const count =
|
|
79426
|
+
const count = readSync10(0, chunk2, 0, chunk2.length, null);
|
|
78608
79427
|
if (count === 0)
|
|
78609
79428
|
break;
|
|
78610
79429
|
size2 += count;
|
|
@@ -78662,6 +79481,7 @@ var init_context = __esm(() => {
|
|
|
78662
79481
|
init_selection_resolver();
|
|
78663
79482
|
init_selection_cache();
|
|
78664
79483
|
init_managed_policy();
|
|
79484
|
+
init_session_reconciliation();
|
|
78665
79485
|
});
|
|
78666
79486
|
|
|
78667
79487
|
// src/cli/commands/profile-sync.ts
|
|
@@ -79080,12 +79900,12 @@ function handleBrowseError(error61) {
|
|
|
79080
79900
|
async function writeJson(value, space) {
|
|
79081
79901
|
const text3 = `${JSON.stringify(value, null, space)}
|
|
79082
79902
|
`;
|
|
79083
|
-
await new Promise((
|
|
79903
|
+
await new Promise((resolve18, reject2) => {
|
|
79084
79904
|
process.stdout.write(text3, (error61) => {
|
|
79085
79905
|
if (error61)
|
|
79086
79906
|
reject2(error61);
|
|
79087
79907
|
else
|
|
79088
|
-
|
|
79908
|
+
resolve18();
|
|
79089
79909
|
});
|
|
79090
79910
|
});
|
|
79091
79911
|
}
|
|
@@ -79617,7 +80437,7 @@ function handleDiff(name, options) {
|
|
|
79617
80437
|
const sourcePath = getSkillPath(bare);
|
|
79618
80438
|
const canonicalDir = join36(resolveCorpusRoot(), normalized);
|
|
79619
80439
|
const canonicalSkillMd = join36(canonicalDir, "SKILL.md");
|
|
79620
|
-
const
|
|
80440
|
+
const canonical4 = {
|
|
79621
80441
|
present: existsSync22(canonicalSkillMd),
|
|
79622
80442
|
path: canonicalDir,
|
|
79623
80443
|
...existsSync22(canonicalSkillMd) ? { hash: hashSkillMarkdownFile(canonicalSkillMd) } : {},
|
|
@@ -79649,7 +80469,7 @@ function handleDiff(name, options) {
|
|
|
79649
80469
|
stub = undefined;
|
|
79650
80470
|
}
|
|
79651
80471
|
}
|
|
79652
|
-
const diverged = present &&
|
|
80472
|
+
const diverged = present && canonical4.present && managed && hash3 !== canonical4.hash;
|
|
79653
80473
|
homes.push({
|
|
79654
80474
|
agent,
|
|
79655
80475
|
path: dir,
|
|
@@ -79664,7 +80484,7 @@ function handleDiff(name, options) {
|
|
|
79664
80484
|
if (options.json) {
|
|
79665
80485
|
console.log(JSON.stringify({
|
|
79666
80486
|
name: bare,
|
|
79667
|
-
canonical:
|
|
80487
|
+
canonical: canonical4,
|
|
79668
80488
|
pinned,
|
|
79669
80489
|
installedVersion,
|
|
79670
80490
|
registryVersion,
|
|
@@ -79672,10 +80492,10 @@ function handleDiff(name, options) {
|
|
|
79672
80492
|
homes
|
|
79673
80493
|
}, null, 2));
|
|
79674
80494
|
} else {
|
|
79675
|
-
if (!
|
|
80495
|
+
if (!canonical4.present) {
|
|
79676
80496
|
console.log(source_default.yellow(`${bare}: no canonical corpus entry`));
|
|
79677
80497
|
} else {
|
|
79678
|
-
console.log(source_default.dim(`${bare} canonical: ${
|
|
80498
|
+
console.log(source_default.dim(`${bare} canonical: ${canonical4.hash?.slice(0, 12)}\u2026`));
|
|
79679
80499
|
}
|
|
79680
80500
|
if (pinned) {
|
|
79681
80501
|
console.log(upToDate ? source_default.green(`\u2713 pin is up to date (${installedVersion})`) : source_default.yellow(`pin metadata differs: ${installedVersion} \u2192 ${registryVersion}`));
|
|
@@ -79686,14 +80506,14 @@ function handleDiff(name, options) {
|
|
|
79686
80506
|
} else if (!home.managed) {
|
|
79687
80507
|
console.log(`${source_default.dim("\u2022")} ${home.agent}: ${source_default.yellow("unmarked (adoption candidate)")}`);
|
|
79688
80508
|
} else if (home.diverged) {
|
|
79689
|
-
const stubNote = home.stub === true ? " (home is a pointer stub; canonical holds content)" :
|
|
79690
|
-
console.log(`${source_default.red("\u2717")} ${home.agent}: ${source_default.red("diverged")} ${source_default.dim(home.hash?.slice(0, 12))} \u2260 ${source_default.dim(
|
|
80509
|
+
const stubNote = home.stub === true ? " (home is a pointer stub; canonical holds content)" : canonical4.stub === true ? " (home holds content; canonical renders a pointer stub \u2014 sync refuses to replace it)" : "";
|
|
80510
|
+
console.log(`${source_default.red("\u2717")} ${home.agent}: ${source_default.red("diverged")} ${source_default.dim(home.hash?.slice(0, 12))} \u2260 ${source_default.dim(canonical4.hash?.slice(0, 12))}${stubNote}`);
|
|
79691
80511
|
} else {
|
|
79692
80512
|
console.log(`${source_default.green("\u2713")} ${home.agent}: ${source_default.green("matches canonical")}`);
|
|
79693
80513
|
}
|
|
79694
80514
|
}
|
|
79695
80515
|
}
|
|
79696
|
-
if (divergedHomes.length > 0 || homes.length > 0 && !
|
|
80516
|
+
if (divergedHomes.length > 0 || homes.length > 0 && !canonical4.present)
|
|
79697
80517
|
process.exitCode = 1;
|
|
79698
80518
|
}
|
|
79699
80519
|
var init_introspect = __esm(() => {
|
|
@@ -80429,7 +81249,7 @@ var init_init = __esm(() => {
|
|
|
80429
81249
|
});
|
|
80430
81250
|
|
|
80431
81251
|
// src/lib/home-adoption.ts
|
|
80432
|
-
import { constants as
|
|
81252
|
+
import { constants as constants12, closeSync as closeSync12, fstatSync as fstatSync12, lstatSync as lstatSync20, openSync as openSync12, readSync as readSync11, existsSync as existsSync24, mkdirSync as mkdirSync13, readdirSync as readdirSync13, readFileSync as readFileSync25, rmSync as rmSync7, statSync as statSync12, writeFileSync as writeFileSync12 } from "fs";
|
|
80433
81253
|
import { homedir as homedir7 } from "os";
|
|
80434
81254
|
import { join as join38 } from "path";
|
|
80435
81255
|
function indexCanonicalCorpus(corpusRoot) {
|
|
@@ -80584,25 +81404,25 @@ function adoptUnmarkedHomes(options = {}) {
|
|
|
80584
81404
|
function pruneOwnership(dir) {
|
|
80585
81405
|
let descriptor;
|
|
80586
81406
|
try {
|
|
80587
|
-
const directory =
|
|
81407
|
+
const directory = lstatSync20(dir);
|
|
80588
81408
|
if (!directory.isDirectory())
|
|
80589
81409
|
return;
|
|
80590
|
-
const markerPath = join38(dir, SYNC_MARKER_FILE), markerPathBefore =
|
|
81410
|
+
const markerPath = join38(dir, SYNC_MARKER_FILE), markerPathBefore = lstatSync20(markerPath);
|
|
80591
81411
|
if (!markerPathBefore.isFile())
|
|
80592
81412
|
return;
|
|
80593
|
-
descriptor =
|
|
80594
|
-
const before2 =
|
|
81413
|
+
descriptor = openSync12(markerPath, constants12.O_RDONLY | constants12.O_NOFOLLOW | constants12.O_NONBLOCK);
|
|
81414
|
+
const before2 = fstatSync12(descriptor);
|
|
80595
81415
|
if (!before2.isFile() || before2.dev !== markerPathBefore.dev || before2.ino !== markerPathBefore.ino || before2.size !== markerPathBefore.size || before2.mtimeMs !== markerPathBefore.mtimeMs || before2.ctimeMs !== markerPathBefore.ctimeMs || before2.size < 1 || before2.size > 65536)
|
|
80596
81416
|
return;
|
|
80597
81417
|
const bytes = Buffer.alloc(before2.size + 1);
|
|
80598
81418
|
let length = 0;
|
|
80599
81419
|
while (length < bytes.length) {
|
|
80600
|
-
const count =
|
|
81420
|
+
const count = readSync11(descriptor, bytes, length, bytes.length - length, length);
|
|
80601
81421
|
if (!count)
|
|
80602
81422
|
break;
|
|
80603
81423
|
length += count;
|
|
80604
81424
|
}
|
|
80605
|
-
const after2 =
|
|
81425
|
+
const after2 = fstatSync12(descriptor), current = lstatSync20(dir), markerPathAfter = lstatSync20(markerPath);
|
|
80606
81426
|
if (!markerPathAfter.isFile() || markerPathAfter.dev !== before2.dev || markerPathAfter.ino !== before2.ino || markerPathAfter.size !== before2.size || markerPathAfter.mtimeMs !== before2.mtimeMs || markerPathAfter.ctimeMs !== before2.ctimeMs || length !== before2.size || after2.size !== before2.size || after2.mtimeMs !== before2.mtimeMs || after2.ctimeMs !== before2.ctimeMs || !current.isDirectory() || current.dev !== directory.dev || current.ino !== directory.ino)
|
|
80607
81427
|
return;
|
|
80608
81428
|
const text3 = bytes.subarray(0, length).toString("utf8"), marker = JSON.parse(text3);
|
|
@@ -80613,7 +81433,7 @@ function pruneOwnership(dir) {
|
|
|
80613
81433
|
return;
|
|
80614
81434
|
} finally {
|
|
80615
81435
|
if (descriptor !== undefined)
|
|
80616
|
-
|
|
81436
|
+
closeSync12(descriptor);
|
|
80617
81437
|
}
|
|
80618
81438
|
}
|
|
80619
81439
|
function pruneStrayHomes(options = {}) {
|
|
@@ -80798,7 +81618,7 @@ var init_home_census = __esm(() => {
|
|
|
80798
81618
|
});
|
|
80799
81619
|
|
|
80800
81620
|
// src/cli/env-assignment.ts
|
|
80801
|
-
import { closeSync as
|
|
81621
|
+
import { closeSync as closeSync13, constants as constants13, fstatSync as fstatSync13, ftruncateSync as ftruncateSync2, lstatSync as lstatSync21, openSync as openSync13, readFileSync as readFileSync27, writeSync as writeSync3 } from "fs";
|
|
80802
81622
|
function serializeValue(value) {
|
|
80803
81623
|
if (controls.test(value))
|
|
80804
81624
|
throw new EnvAssignmentError("Environment values cannot contain control characters or newlines.");
|
|
@@ -80877,7 +81697,7 @@ function setEnvAssignment(path, assignment) {
|
|
|
80877
81697
|
try {
|
|
80878
81698
|
const previous = (() => {
|
|
80879
81699
|
try {
|
|
80880
|
-
return
|
|
81700
|
+
return lstatSync21(path);
|
|
80881
81701
|
} catch (error61) {
|
|
80882
81702
|
if (error61.code === "ENOENT")
|
|
80883
81703
|
return;
|
|
@@ -80886,8 +81706,8 @@ function setEnvAssignment(path, assignment) {
|
|
|
80886
81706
|
})();
|
|
80887
81707
|
if (previous && !previous.isFile())
|
|
80888
81708
|
throw new EnvAssignmentError("The project .env must be a regular file, not a symlink or special file.");
|
|
80889
|
-
descriptor =
|
|
80890
|
-
const opened =
|
|
81709
|
+
descriptor = openSync13(path, previous ? constants13.O_RDWR | constants13.O_NOFOLLOW | constants13.O_NONBLOCK : constants13.O_WRONLY | constants13.O_CREAT | constants13.O_EXCL | constants13.O_NOFOLLOW, 384);
|
|
81710
|
+
const opened = fstatSync13(descriptor);
|
|
80891
81711
|
if (!opened.isFile() || previous && (opened.ino !== previous.ino || opened.dev !== previous.dev)) {
|
|
80892
81712
|
throw new EnvAssignmentError("The project .env changed while opening it; retry with a regular file.");
|
|
80893
81713
|
}
|
|
@@ -80914,7 +81734,7 @@ function setEnvAssignment(path, assignment) {
|
|
|
80914
81734
|
throw new EnvAssignmentError("Cannot safely read or write the project .env file.");
|
|
80915
81735
|
} finally {
|
|
80916
81736
|
if (descriptor !== undefined)
|
|
80917
|
-
|
|
81737
|
+
closeSync13(descriptor);
|
|
80918
81738
|
}
|
|
80919
81739
|
}
|
|
80920
81740
|
var INVALID_LAYOUT = "Cannot safely update .env with multiline or unsupported assignments. Use single-line KEY=VALUE entries or edit the file manually.", controls, EnvAssignmentError;
|
|
@@ -81397,12 +82217,12 @@ function parseExecution(value) {
|
|
|
81397
82217
|
].includes(v.status) || typeof v.skill !== "string" || typeof v.version !== "string" || !Array.isArray(v.artifacts))
|
|
81398
82218
|
throw Error("Unsupported cloud execution response");
|
|
81399
82219
|
runId(v.id);
|
|
81400
|
-
for (const
|
|
82220
|
+
for (const field2 of [
|
|
81401
82221
|
"bundleDigest",
|
|
81402
82222
|
"inputDigest",
|
|
81403
82223
|
"runtimeImageDigest"
|
|
81404
82224
|
])
|
|
81405
|
-
if (typeof v[
|
|
82225
|
+
if (typeof v[field2] !== "string" || !/^(sha256:)?[a-f0-9]{64}$/.test(v[field2]))
|
|
81406
82226
|
throw Error("Invalid cloud execution integrity receipt");
|
|
81407
82227
|
return v;
|
|
81408
82228
|
}
|
|
@@ -81423,11 +82243,11 @@ var init_cloud_executions = __esm(() => {
|
|
|
81423
82243
|
// node_modules/@hasna/secrets/dist/sdk.js
|
|
81424
82244
|
import { isIP as isIP3 } from "net";
|
|
81425
82245
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
81426
|
-
import { closeSync as
|
|
82246
|
+
import { closeSync as closeSync14, fstatSync as fstatSync14, openSync as openSync14, readFileSync as readFileSync29 } from "fs";
|
|
81427
82247
|
import { O_NOFOLLOW as O_NOFOLLOW3, O_NONBLOCK as O_NONBLOCK3, O_RDONLY as O_RDONLY3 } from "constants";
|
|
81428
82248
|
import { createRequire as createRequire2 } from "module";
|
|
81429
82249
|
import { hostname as osHostname2 } from "os";
|
|
81430
|
-
import { isAbsolute as
|
|
82250
|
+
import { isAbsolute as isAbsolute16, join as join41 } from "path";
|
|
81431
82251
|
import { createRequire as createRequire22 } from "module";
|
|
81432
82252
|
function envToken2(name) {
|
|
81433
82253
|
return name.toUpperCase().replace(/-/g, "_");
|
|
@@ -81451,7 +82271,7 @@ function homeDir2(env3) {
|
|
|
81451
82271
|
}
|
|
81452
82272
|
function absoluteOverride2(env3, key) {
|
|
81453
82273
|
const value = env3[key]?.trim();
|
|
81454
|
-
return value &&
|
|
82274
|
+
return value && isAbsolute16(value) ? value : null;
|
|
81455
82275
|
}
|
|
81456
82276
|
function hasnaHomeDir2(env3) {
|
|
81457
82277
|
const override = absoluteOverride2(env3, HASNA_HOME_ENV_KEY2);
|
|
@@ -81528,7 +82348,7 @@ function readAppConfigFile2(path) {
|
|
|
81528
82348
|
};
|
|
81529
82349
|
let fd = -1;
|
|
81530
82350
|
try {
|
|
81531
|
-
fd =
|
|
82351
|
+
fd = openSync14(path, O_RDONLY3 | O_NOFOLLOW3 | O_NONBLOCK3);
|
|
81532
82352
|
} catch (error61) {
|
|
81533
82353
|
const code = error61.code;
|
|
81534
82354
|
if (code === "ENOENT" || code === "ENOTDIR")
|
|
@@ -81538,7 +82358,7 @@ function readAppConfigFile2(path) {
|
|
|
81538
82358
|
unsafe(`the path could not be opened (${code ?? "unknown error"})`);
|
|
81539
82359
|
}
|
|
81540
82360
|
try {
|
|
81541
|
-
const before2 =
|
|
82361
|
+
const before2 = fstatSync14(fd);
|
|
81542
82362
|
if (!before2.isFile())
|
|
81543
82363
|
unsafe("the path is not a regular file");
|
|
81544
82364
|
if (!configFileModeAllowed2(before2.mode)) {
|
|
@@ -81550,14 +82370,14 @@ function readAppConfigFile2(path) {
|
|
|
81550
82370
|
if (before2.size > MAX_CREDENTIAL_FILE_BYTES2)
|
|
81551
82371
|
unsafe("the file exceeds the size limit");
|
|
81552
82372
|
const bytes = readFileSync29(fd);
|
|
81553
|
-
const after2 =
|
|
82373
|
+
const after2 = fstatSync14(fd);
|
|
81554
82374
|
if (!configFileReadsCoherent2(before2, after2)) {
|
|
81555
82375
|
unsafe("the file changed while being read");
|
|
81556
82376
|
}
|
|
81557
82377
|
return parseEnvFile2(bytes.toString("utf8"));
|
|
81558
82378
|
} finally {
|
|
81559
82379
|
if (fd !== -1)
|
|
81560
|
-
|
|
82380
|
+
closeSync14(fd);
|
|
81561
82381
|
}
|
|
81562
82382
|
}
|
|
81563
82383
|
function readCredentialFile2(path, apiKeyKeys) {
|
|
@@ -82588,7 +83408,7 @@ function createSecretsClientFromEnv(env3 = process.env, overrides = {}) {
|
|
|
82588
83408
|
});
|
|
82589
83409
|
return new SecretsClient({ ...clientOverrides, baseUrl, apiKey });
|
|
82590
83410
|
}
|
|
82591
|
-
var __esm2 = (fn, res) => () => (fn && (res = fn(fn = 0)), res), CREDENTIAL_PROFILE_ENV_KEY2 = "HASNA_PROFILE", CredentialResolutionError2, CredentialFileUnsafeError2, HASNA_HOME_ENV_KEY2 = "HASNA_HOME", HASNA_CONFIG_HOME_ENV_KEY2 = "HASNA_CONFIG_HOME", KEYCHAIN_STATION_ENV_KEY2 = "HASNA_STATION", HASNA_HOME_DIR2 = ".hasna", CONFIG_SUBDIR2 = "config", CREDENTIALS_FILE2 = "credentials", KEYCHAIN_SECURITY_BIN2 = "/usr/bin/security", KEYCHAIN_SERVICE_PREFIX2 = "hasna.credentials", KEYCHAIN_ITEM_NOT_FOUND_STATUS2 = 44, KEYCHAIN_SPAWN_TIMEOUT_MS2 = 1e4, MAX_CREDENTIAL_FILE_BYTES2, SAFE_APP_SLUG2, SAFE_PROFILE2, ILLEGAL_IN_HEADER_VALUE2, VAULT_POINTER_SHAPE2, CREDENTIAL_SHAPED_KEY2, INSPECT_CUSTOM2, CREDENTIAL_SEAL2, CALLER_SUPPLIED_CREDENTIAL_PROVIDER_SOURCE = "caller-supplied CredentialProvider", AMBIENT_ENVIRONMENT2, SECRETS_PACKAGE_SPECIFIER, requireSecretsSdk2, DEFAULT_FLEET_GATEWAY_ORIGIN2 = "https://api.hasna.com", DEFAULT_AUTHORITY_SOURCE = "default", ASCII_CONTROL_PATTERN2, DNS_LABEL_PATTERN2, ClientTransportConfigurationError2, HasnaHttpError, DEFAULT_RETRY_STATUSES, IDEMPOTENT_METHODS2, AUTHORITY_OVERRIDE_HEADERS2, defaultSleep = (ms) => new Promise((
|
|
83411
|
+
var __esm2 = (fn, res) => () => (fn && (res = fn(fn = 0)), res), CREDENTIAL_PROFILE_ENV_KEY2 = "HASNA_PROFILE", CredentialResolutionError2, CredentialFileUnsafeError2, HASNA_HOME_ENV_KEY2 = "HASNA_HOME", HASNA_CONFIG_HOME_ENV_KEY2 = "HASNA_CONFIG_HOME", KEYCHAIN_STATION_ENV_KEY2 = "HASNA_STATION", HASNA_HOME_DIR2 = ".hasna", CONFIG_SUBDIR2 = "config", CREDENTIALS_FILE2 = "credentials", KEYCHAIN_SECURITY_BIN2 = "/usr/bin/security", KEYCHAIN_SERVICE_PREFIX2 = "hasna.credentials", KEYCHAIN_ITEM_NOT_FOUND_STATUS2 = 44, KEYCHAIN_SPAWN_TIMEOUT_MS2 = 1e4, MAX_CREDENTIAL_FILE_BYTES2, SAFE_APP_SLUG2, SAFE_PROFILE2, ILLEGAL_IN_HEADER_VALUE2, VAULT_POINTER_SHAPE2, CREDENTIAL_SHAPED_KEY2, INSPECT_CUSTOM2, CREDENTIAL_SEAL2, CALLER_SUPPLIED_CREDENTIAL_PROVIDER_SOURCE = "caller-supplied CredentialProvider", AMBIENT_ENVIRONMENT2, SECRETS_PACKAGE_SPECIFIER, requireSecretsSdk2, DEFAULT_FLEET_GATEWAY_ORIGIN2 = "https://api.hasna.com", DEFAULT_AUTHORITY_SOURCE = "default", ASCII_CONTROL_PATTERN2, DNS_LABEL_PATTERN2, ClientTransportConfigurationError2, HasnaHttpError, DEFAULT_RETRY_STATUSES, IDEMPOTENT_METHODS2, AUTHORITY_OVERRIDE_HEADERS2, defaultSleep = (ms) => new Promise((resolve18) => setTimeout(resolve18, ms)), init_transport2, MAX_CREDENTIAL_FILE_BYTES22, INSPECT_CUSTOM22, CREDENTIAL_SEAL22, AMBIENT_ENVIRONMENT22, SECRETS_PACKAGE_SPECIFIER2, requireSecretsSdk22, IDEMPOTENT_METHODS22, AUTHORITY_OVERRIDE_HEADERS22, init_storage, PATHS_RESOLVER_APP_SLUG_RE3, SQLITE_SIDECAR_FILES, LEGACY_SERVICE_FILES, init_data_dir, SecretsTestIsolationError, TEST_ENTRYPOINT_RE, init_test_isolation, init_client, ApiError;
|
|
82592
83412
|
var init_sdk = __esm(() => {
|
|
82593
83413
|
init_transport2 = __esm2(() => {
|
|
82594
83414
|
CredentialResolutionError2 = class CredentialResolutionError3 extends Error {
|
|
@@ -82723,7 +83543,7 @@ var init_sdk = __esm(() => {
|
|
|
82723
83543
|
});
|
|
82724
83544
|
|
|
82725
83545
|
// src/lib/execution-secrets.ts
|
|
82726
|
-
import { constants as
|
|
83546
|
+
import { constants as constants14, closeSync as closeSync15, fstatSync as fstatSync15, openSync as openSync15, readSync as readSync12, realpathSync as realpathSync6 } from "fs";
|
|
82727
83547
|
import { hostname as stationHostname } from "os";
|
|
82728
83548
|
function selectedSecretBindingsTemplate(scope, names, createClient2 = createSecretsClientFromEnv) {
|
|
82729
83549
|
let secretsAuthority;
|
|
@@ -82747,7 +83567,7 @@ function refuse(code, message) {
|
|
|
82747
83567
|
function record7(value) {
|
|
82748
83568
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
82749
83569
|
}
|
|
82750
|
-
function
|
|
83570
|
+
function exactKeys2(value, keys2) {
|
|
82751
83571
|
return Object.keys(value).length === keys2.length && keys2.every((key) => Object.hasOwn(value, key));
|
|
82752
83572
|
}
|
|
82753
83573
|
function identifier2(value) {
|
|
@@ -82767,13 +83587,13 @@ function declaredSecretNames(value) {
|
|
|
82767
83587
|
function readSelectedSecretBindings(path) {
|
|
82768
83588
|
let fd;
|
|
82769
83589
|
try {
|
|
82770
|
-
fd =
|
|
82771
|
-
const stat2 =
|
|
83590
|
+
fd = openSync15(path, constants14.O_RDONLY | constants14.O_NOFOLLOW | constants14.O_NONBLOCK);
|
|
83591
|
+
const stat2 = fstatSync15(fd);
|
|
82772
83592
|
if (!stat2.isFile() || stat2.size > 65536)
|
|
82773
83593
|
throw new Error;
|
|
82774
83594
|
const bytes = Buffer.alloc(65537);
|
|
82775
83595
|
let size2 = 0, count;
|
|
82776
|
-
while ((count =
|
|
83596
|
+
while ((count = readSync12(fd, bytes, size2, bytes.length - size2, null)) > 0) {
|
|
82777
83597
|
size2 += count;
|
|
82778
83598
|
if (size2 > 65536)
|
|
82779
83599
|
throw new Error;
|
|
@@ -82783,11 +83603,11 @@ function readSelectedSecretBindings(path) {
|
|
|
82783
83603
|
return refuse("INVALID_SECRET_BINDINGS", "Secret bindings must be a regular JSON file of at most 64 KiB, containing reference names only.");
|
|
82784
83604
|
} finally {
|
|
82785
83605
|
if (fd !== undefined)
|
|
82786
|
-
|
|
83606
|
+
closeSync15(fd);
|
|
82787
83607
|
}
|
|
82788
83608
|
}
|
|
82789
83609
|
function validateSelectedSecretBindings(value, scope, names) {
|
|
82790
|
-
if (!record7(value) || !
|
|
83610
|
+
if (!record7(value) || !exactKeys2(value, ["schema", "selection", "consumer", "secretsAuthority", "bindings"]) || value.schema !== "hasna.skills-secret-bindings.v1" || !record7(value.selection) || !exactKeys2(value.selection, ["authority", "workspaceId", "profileId", "profileRevision", "slug", "version", "bundleDigest"]) || !record7(value.consumer) || !exactKeys2(value.consumer, ["stationId", "workspaceDirectory"]) || !record7(value.bindings)) {
|
|
82791
83611
|
return refuse("INVALID_SECRET_BINDINGS", "Secret bindings do not match the hasna.skills-secret-bindings.v1 contract.");
|
|
82792
83612
|
}
|
|
82793
83613
|
for (const [key, expected] of Object.entries({ authority: scope.selection.authority, workspaceId: scope.selection.workspaceId, profileId: scope.profileId, profileRevision: scope.selection.profileRevision, slug: scope.selection.slug, version: scope.selection.version, bundleDigest: scope.selection.bundleDigest })) {
|
|
@@ -82812,7 +83632,7 @@ function validateSelectedSecretBindings(value, scope, names) {
|
|
|
82812
83632
|
} catch {
|
|
82813
83633
|
return refuse("INVALID_SECRET_BINDINGS", "Secret bindings require a canonical HTTPS Secrets /v1 authority (loopback HTTP is allowed).");
|
|
82814
83634
|
}
|
|
82815
|
-
if (!
|
|
83635
|
+
if (!exactKeys2(value.bindings, names) || Object.values(value.bindings).some((key) => !identifier2(key) || !/^[A-Za-z0-9][A-Za-z0-9._/-]*$/.test(key) || key.split("/").some((part) => !part || part === "." || part === ".."))) {
|
|
82816
83636
|
return refuse("INVALID_SECRET_BINDINGS", "Bind every declared environment name exactly once to a vault key; undeclared bindings and values are refused.");
|
|
82817
83637
|
}
|
|
82818
83638
|
return structuredClone(value);
|
|
@@ -82990,7 +83810,7 @@ var init_execution_grants = __esm(() => {
|
|
|
82990
83810
|
});
|
|
82991
83811
|
|
|
82992
83812
|
// src/lib/execution-grant-client.ts
|
|
82993
|
-
import { isDeepStrictEqual as
|
|
83813
|
+
import { isDeepStrictEqual as isDeepStrictEqual4 } from "util";
|
|
82994
83814
|
function id(value) {
|
|
82995
83815
|
if (!grantIdentifier(value))
|
|
82996
83816
|
throw new Error("Invalid execution grant profile or revision identifier.");
|
|
@@ -83042,7 +83862,7 @@ async function saveExecutionGrantPolicy(profileId, grants, revision) {
|
|
|
83042
83862
|
headers: revision === undefined ? { "If-None-Match": "*" } : { "If-Match": `"${revision}"` },
|
|
83043
83863
|
body: JSON.stringify({ grants: snapshot })
|
|
83044
83864
|
}));
|
|
83045
|
-
if (policy.profileId !== profileId || policy.previousRevision !== (revision ?? null) || !
|
|
83865
|
+
if (policy.profileId !== profileId || policy.previousRevision !== (revision ?? null) || !isDeepStrictEqual4(policy.grants, snapshot)) {
|
|
83046
83866
|
throw new Error("The API did not preserve the reviewed execution grant policy; read it before retrying.");
|
|
83047
83867
|
}
|
|
83048
83868
|
return policy;
|
|
@@ -83053,7 +83873,7 @@ async function resolveExecutionGrant(input2) {
|
|
|
83053
83873
|
if (!grantRecord(value) || Object.keys(value).length !== 3 || !grantIdentifier(value.policyRevision) || !grantIdentifier(value.grantId) || !grantRecord(value.bindings)) {
|
|
83054
83874
|
throw new SkillSelectionError("INVALID_EXECUTION_GRANT", "The Skills API returned an invalid execution grant.");
|
|
83055
83875
|
}
|
|
83056
|
-
if (!
|
|
83876
|
+
if (!isDeepStrictEqual4(value.bindings.selection, snapshot.selection) || !isDeepStrictEqual4(value.bindings.consumer, snapshot.consumer)) {
|
|
83057
83877
|
throw new SkillSelectionError("EXECUTION_GRANT_SCOPE_MISMATCH", "The Skills API returned a grant for a different selection or consumer.");
|
|
83058
83878
|
}
|
|
83059
83879
|
return value;
|
|
@@ -83072,10 +83892,10 @@ __export(exports_selected_run, {
|
|
|
83072
83892
|
prepareSelectedSecretBindings: () => prepareSelectedSecretBindings,
|
|
83073
83893
|
executeSelectedLocal: () => executeSelectedLocal
|
|
83074
83894
|
});
|
|
83075
|
-
import { createHash as
|
|
83895
|
+
import { createHash as createHash19 } from "crypto";
|
|
83076
83896
|
import { spawn as spawn2 } from "child_process";
|
|
83077
83897
|
import { mkdirSync as mkdirSync14, mkdtempSync as mkdtempSync4, writeFileSync as writeFileSync13, realpathSync as realpathSync7 } from "fs";
|
|
83078
|
-
import { dirname as
|
|
83898
|
+
import { dirname as dirname19, join as join42, resolve as resolve18 } from "path";
|
|
83079
83899
|
import { tmpdir, hostname as stationHostname2 } from "os";
|
|
83080
83900
|
async function resolveSelectedRun(spec, profileId, options = {}) {
|
|
83081
83901
|
const context = await resolveSelectionContext(profileId, options);
|
|
@@ -83164,11 +83984,11 @@ async function executeSelectedLocal(selected, options = {}) {
|
|
|
83164
83984
|
throw new SkillSelectionError("INVALID_BUNDLE_PATH", "The execution bundle path exceeds its limit.");
|
|
83165
83985
|
});
|
|
83166
83986
|
const destination = join42(runDirectory, entry.path);
|
|
83167
|
-
mkdirSync14(
|
|
83987
|
+
mkdirSync14(dirname19(destination), { recursive: true, mode: 448 });
|
|
83168
83988
|
writeFileSync13(destination, entry.bytes, { flag: "wx", mode: entry.mode & 511 });
|
|
83169
83989
|
}
|
|
83170
83990
|
env3.SKILLS_INPUT_JSON = input2;
|
|
83171
|
-
env3.SKILLS_WORKSPACE_DIR =
|
|
83991
|
+
env3.SKILLS_WORKSPACE_DIR = resolve18(options.cwd ?? process.cwd());
|
|
83172
83992
|
env3.SKILLS_RUN_DIR = runDirectory;
|
|
83173
83993
|
if (runtime.version) {
|
|
83174
83994
|
const version2 = await subprocess([executable, ...runtimeName === "bun" ? ["--no-env-file"] : [], "--version"], runDirectory, env3, "", Math.min(timeoutMs, 5000));
|
|
@@ -83198,7 +84018,7 @@ async function executeSelectedLocal(selected, options = {}) {
|
|
|
83198
84018
|
selection: selection2,
|
|
83199
84019
|
target: "local",
|
|
83200
84020
|
runtime: runtimeName,
|
|
83201
|
-
inputDigest: `sha256:${
|
|
84021
|
+
inputDigest: `sha256:${createHash19("sha256").update(input2).digest("hex")}`,
|
|
83202
84022
|
runDirectory,
|
|
83203
84023
|
...executionGrant ? { executionGrant } : {},
|
|
83204
84024
|
...bindings ? { secretBinding: { schema: bindings.schema, selection: bindings.selection, consumer: bindings.consumer, secretsAuthority: bindings.secretsAuthority, bindings: bindings.bindings } } : {},
|
|
@@ -87415,7 +88235,7 @@ var init_runs = __esm(() => {
|
|
|
87415
88235
|
});
|
|
87416
88236
|
|
|
87417
88237
|
// src/lib/run-state.ts
|
|
87418
|
-
import { createHash as
|
|
88238
|
+
import { createHash as createHash20, randomBytes } from "crypto";
|
|
87419
88239
|
import { existsSync as existsSync27, mkdirSync as mkdirSync15, readFileSync as readFileSync30, readdirSync as readdirSync16, statSync as statSync15, writeFileSync as writeFileSync14 } from "fs";
|
|
87420
88240
|
import { extname, join as join43, relative as relative6 } from "path";
|
|
87421
88241
|
function createSkillRun(params, targetDir = process.cwd()) {
|
|
@@ -87552,7 +88372,7 @@ function collectRunArtifacts(context) {
|
|
|
87552
88372
|
artifacts.push({
|
|
87553
88373
|
path: toProjectRelative(context.targetDir, path),
|
|
87554
88374
|
mime: mimeForPath(path),
|
|
87555
|
-
sha256:
|
|
88375
|
+
sha256: createHash20("sha256").update(bytes).digest("hex"),
|
|
87556
88376
|
sizeBytes: stat2.size
|
|
87557
88377
|
});
|
|
87558
88378
|
}
|
|
@@ -88555,12 +89375,12 @@ class StdioServerTransport {
|
|
|
88555
89375
|
this.onclose?.();
|
|
88556
89376
|
}
|
|
88557
89377
|
send(message) {
|
|
88558
|
-
return new Promise((
|
|
89378
|
+
return new Promise((resolve19) => {
|
|
88559
89379
|
const json2 = serializeMessage(message);
|
|
88560
89380
|
if (this._stdout.write(json2)) {
|
|
88561
|
-
|
|
89381
|
+
resolve19();
|
|
88562
89382
|
} else {
|
|
88563
|
-
this._stdout.once("drain",
|
|
89383
|
+
this._stdout.once("drain", resolve19);
|
|
88564
89384
|
}
|
|
88565
89385
|
});
|
|
88566
89386
|
}
|
|
@@ -88602,7 +89422,7 @@ var init_schemas3 = __esm(() => {
|
|
|
88602
89422
|
own(this, "with", value);
|
|
88603
89423
|
},
|
|
88604
89424
|
parse(data, params) {
|
|
88605
|
-
return
|
|
89425
|
+
return parse7(this, data, params, { callee: this.parse });
|
|
88606
89426
|
},
|
|
88607
89427
|
parseAsync(data, params) {
|
|
88608
89428
|
return parseAsync(this, data, params, { callee: this.parseAsync });
|
|
@@ -90746,7 +91566,7 @@ class Protocol {
|
|
|
90746
91566
|
return;
|
|
90747
91567
|
}
|
|
90748
91568
|
const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1000;
|
|
90749
|
-
await new Promise((
|
|
91569
|
+
await new Promise((resolve19) => setTimeout(resolve19, pollInterval));
|
|
90750
91570
|
options?.signal?.throwIfAborted();
|
|
90751
91571
|
}
|
|
90752
91572
|
} catch (error61) {
|
|
@@ -90758,7 +91578,7 @@ class Protocol {
|
|
|
90758
91578
|
}
|
|
90759
91579
|
request(request2, resultSchema, options) {
|
|
90760
91580
|
const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
|
|
90761
|
-
return new Promise((
|
|
91581
|
+
return new Promise((resolve19, reject2) => {
|
|
90762
91582
|
const earlyReject = (error61) => {
|
|
90763
91583
|
reject2(error61);
|
|
90764
91584
|
};
|
|
@@ -90836,7 +91656,7 @@ class Protocol {
|
|
|
90836
91656
|
if (!parseResult.success) {
|
|
90837
91657
|
reject2(parseResult.error);
|
|
90838
91658
|
} else {
|
|
90839
|
-
|
|
91659
|
+
resolve19(parseResult.data);
|
|
90840
91660
|
}
|
|
90841
91661
|
} catch (error61) {
|
|
90842
91662
|
reject2(error61);
|
|
@@ -91027,12 +91847,12 @@ class Protocol {
|
|
|
91027
91847
|
interval = task.pollInterval;
|
|
91028
91848
|
}
|
|
91029
91849
|
} catch {}
|
|
91030
|
-
return new Promise((
|
|
91850
|
+
return new Promise((resolve19, reject2) => {
|
|
91031
91851
|
if (signal.aborted) {
|
|
91032
91852
|
reject2(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
91033
91853
|
return;
|
|
91034
91854
|
}
|
|
91035
|
-
const timeoutId = setTimeout(
|
|
91855
|
+
const timeoutId = setTimeout(resolve19, interval);
|
|
91036
91856
|
signal.addEventListener("abort", () => {
|
|
91037
91857
|
clearTimeout(timeoutId);
|
|
91038
91858
|
reject2(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
@@ -91509,11 +92329,11 @@ var require_codegen = __commonJS((exports) => {
|
|
|
91509
92329
|
const rhs = this.rhs === undefined ? "" : ` = ${this.rhs}`;
|
|
91510
92330
|
return `${varKind} ${this.name}${rhs};` + _n;
|
|
91511
92331
|
}
|
|
91512
|
-
optimizeNames(names,
|
|
92332
|
+
optimizeNames(names, constants15) {
|
|
91513
92333
|
if (!names[this.name.str])
|
|
91514
92334
|
return;
|
|
91515
92335
|
if (this.rhs)
|
|
91516
|
-
this.rhs = optimizeExpr(this.rhs, names,
|
|
92336
|
+
this.rhs = optimizeExpr(this.rhs, names, constants15);
|
|
91517
92337
|
return this;
|
|
91518
92338
|
}
|
|
91519
92339
|
get names() {
|
|
@@ -91531,10 +92351,10 @@ var require_codegen = __commonJS((exports) => {
|
|
|
91531
92351
|
render({ _n }) {
|
|
91532
92352
|
return `${this.lhs} = ${this.rhs};` + _n;
|
|
91533
92353
|
}
|
|
91534
|
-
optimizeNames(names,
|
|
92354
|
+
optimizeNames(names, constants15) {
|
|
91535
92355
|
if (this.lhs instanceof code_1.Name && !names[this.lhs.str] && !this.sideEffects)
|
|
91536
92356
|
return;
|
|
91537
|
-
this.rhs = optimizeExpr(this.rhs, names,
|
|
92357
|
+
this.rhs = optimizeExpr(this.rhs, names, constants15);
|
|
91538
92358
|
return this;
|
|
91539
92359
|
}
|
|
91540
92360
|
get names() {
|
|
@@ -91600,8 +92420,8 @@ var require_codegen = __commonJS((exports) => {
|
|
|
91600
92420
|
optimizeNodes() {
|
|
91601
92421
|
return `${this.code}` ? this : undefined;
|
|
91602
92422
|
}
|
|
91603
|
-
optimizeNames(names,
|
|
91604
|
-
this.code = optimizeExpr(this.code, names,
|
|
92423
|
+
optimizeNames(names, constants15) {
|
|
92424
|
+
this.code = optimizeExpr(this.code, names, constants15);
|
|
91605
92425
|
return this;
|
|
91606
92426
|
}
|
|
91607
92427
|
get names() {
|
|
@@ -91631,12 +92451,12 @@ var require_codegen = __commonJS((exports) => {
|
|
|
91631
92451
|
}
|
|
91632
92452
|
return nodes.length > 0 ? this : undefined;
|
|
91633
92453
|
}
|
|
91634
|
-
optimizeNames(names,
|
|
92454
|
+
optimizeNames(names, constants15) {
|
|
91635
92455
|
const { nodes } = this;
|
|
91636
92456
|
let i = nodes.length;
|
|
91637
92457
|
while (i--) {
|
|
91638
92458
|
const n2 = nodes[i];
|
|
91639
|
-
if (n2.optimizeNames(names,
|
|
92459
|
+
if (n2.optimizeNames(names, constants15))
|
|
91640
92460
|
continue;
|
|
91641
92461
|
subtractNames(names, n2.names);
|
|
91642
92462
|
nodes.splice(i, 1);
|
|
@@ -91693,12 +92513,12 @@ var require_codegen = __commonJS((exports) => {
|
|
|
91693
92513
|
return;
|
|
91694
92514
|
return this;
|
|
91695
92515
|
}
|
|
91696
|
-
optimizeNames(names,
|
|
92516
|
+
optimizeNames(names, constants15) {
|
|
91697
92517
|
var _a3;
|
|
91698
|
-
this.else = (_a3 = this.else) === null || _a3 === undefined ? undefined : _a3.optimizeNames(names,
|
|
91699
|
-
if (!(super.optimizeNames(names,
|
|
92518
|
+
this.else = (_a3 = this.else) === null || _a3 === undefined ? undefined : _a3.optimizeNames(names, constants15);
|
|
92519
|
+
if (!(super.optimizeNames(names, constants15) || this.else))
|
|
91700
92520
|
return;
|
|
91701
|
-
this.condition = optimizeExpr(this.condition, names,
|
|
92521
|
+
this.condition = optimizeExpr(this.condition, names, constants15);
|
|
91702
92522
|
return this;
|
|
91703
92523
|
}
|
|
91704
92524
|
get names() {
|
|
@@ -91723,10 +92543,10 @@ var require_codegen = __commonJS((exports) => {
|
|
|
91723
92543
|
render(opts) {
|
|
91724
92544
|
return `for(${this.iteration})` + super.render(opts);
|
|
91725
92545
|
}
|
|
91726
|
-
optimizeNames(names,
|
|
91727
|
-
if (!super.optimizeNames(names,
|
|
92546
|
+
optimizeNames(names, constants15) {
|
|
92547
|
+
if (!super.optimizeNames(names, constants15))
|
|
91728
92548
|
return;
|
|
91729
|
-
this.iteration = optimizeExpr(this.iteration, names,
|
|
92549
|
+
this.iteration = optimizeExpr(this.iteration, names, constants15);
|
|
91730
92550
|
return this;
|
|
91731
92551
|
}
|
|
91732
92552
|
get names() {
|
|
@@ -91764,10 +92584,10 @@ var require_codegen = __commonJS((exports) => {
|
|
|
91764
92584
|
render(opts) {
|
|
91765
92585
|
return `for(${this.varKind} ${this.name} ${this.loop} ${this.iterable})` + super.render(opts);
|
|
91766
92586
|
}
|
|
91767
|
-
optimizeNames(names,
|
|
91768
|
-
if (!super.optimizeNames(names,
|
|
92587
|
+
optimizeNames(names, constants15) {
|
|
92588
|
+
if (!super.optimizeNames(names, constants15))
|
|
91769
92589
|
return;
|
|
91770
|
-
this.iterable = optimizeExpr(this.iterable, names,
|
|
92590
|
+
this.iterable = optimizeExpr(this.iterable, names, constants15);
|
|
91771
92591
|
return this;
|
|
91772
92592
|
}
|
|
91773
92593
|
get names() {
|
|
@@ -91812,11 +92632,11 @@ var require_codegen = __commonJS((exports) => {
|
|
|
91812
92632
|
(_b = this.finally) === null || _b === undefined || _b.optimizeNodes();
|
|
91813
92633
|
return this;
|
|
91814
92634
|
}
|
|
91815
|
-
optimizeNames(names,
|
|
92635
|
+
optimizeNames(names, constants15) {
|
|
91816
92636
|
var _a3, _b;
|
|
91817
|
-
super.optimizeNames(names,
|
|
91818
|
-
(_a3 = this.catch) === null || _a3 === undefined || _a3.optimizeNames(names,
|
|
91819
|
-
(_b = this.finally) === null || _b === undefined || _b.optimizeNames(names,
|
|
92637
|
+
super.optimizeNames(names, constants15);
|
|
92638
|
+
(_a3 = this.catch) === null || _a3 === undefined || _a3.optimizeNames(names, constants15);
|
|
92639
|
+
(_b = this.finally) === null || _b === undefined || _b.optimizeNames(names, constants15);
|
|
91820
92640
|
return this;
|
|
91821
92641
|
}
|
|
91822
92642
|
get names() {
|
|
@@ -92090,7 +92910,7 @@ var require_codegen = __commonJS((exports) => {
|
|
|
92090
92910
|
function addExprNames(names, from) {
|
|
92091
92911
|
return from instanceof code_1._CodeOrName ? addNames(names, from.names) : names;
|
|
92092
92912
|
}
|
|
92093
|
-
function optimizeExpr(expr, names,
|
|
92913
|
+
function optimizeExpr(expr, names, constants15) {
|
|
92094
92914
|
if (expr instanceof code_1.Name)
|
|
92095
92915
|
return replaceName(expr);
|
|
92096
92916
|
if (!canOptimize(expr))
|
|
@@ -92105,14 +92925,14 @@ var require_codegen = __commonJS((exports) => {
|
|
|
92105
92925
|
return items;
|
|
92106
92926
|
}, []));
|
|
92107
92927
|
function replaceName(n2) {
|
|
92108
|
-
const c =
|
|
92928
|
+
const c = constants15[n2.str];
|
|
92109
92929
|
if (c === undefined || names[n2.str] !== 1)
|
|
92110
92930
|
return n2;
|
|
92111
92931
|
delete names[n2.str];
|
|
92112
92932
|
return c;
|
|
92113
92933
|
}
|
|
92114
92934
|
function canOptimize(e2) {
|
|
92115
|
-
return e2 instanceof code_1._Code && e2._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 &&
|
|
92935
|
+
return e2 instanceof code_1._Code && e2._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 && constants15[c.str] !== undefined);
|
|
92116
92936
|
}
|
|
92117
92937
|
}
|
|
92118
92938
|
function subtractNames(names, from) {
|
|
@@ -94017,7 +94837,7 @@ var require_compile = __commonJS((exports) => {
|
|
|
94017
94837
|
const schOrFunc = root2.refs[ref];
|
|
94018
94838
|
if (schOrFunc)
|
|
94019
94839
|
return schOrFunc;
|
|
94020
|
-
let _sch =
|
|
94840
|
+
let _sch = resolve19.call(this, root2, ref);
|
|
94021
94841
|
if (_sch === undefined) {
|
|
94022
94842
|
const schema = (_a3 = root2.localRefs) === null || _a3 === undefined ? undefined : _a3[ref];
|
|
94023
94843
|
const { schemaId } = this.opts;
|
|
@@ -94044,7 +94864,7 @@ var require_compile = __commonJS((exports) => {
|
|
|
94044
94864
|
function sameSchemaEnv(s1, s2) {
|
|
94045
94865
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
94046
94866
|
}
|
|
94047
|
-
function
|
|
94867
|
+
function resolve19(root2, ref) {
|
|
94048
94868
|
let sch;
|
|
94049
94869
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
94050
94870
|
ref = sch;
|
|
@@ -94842,11 +95662,11 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
94842
95662
|
if (typeof uri === "string") {
|
|
94843
95663
|
uri = normalizeString(uri, options);
|
|
94844
95664
|
} else if (typeof uri === "object") {
|
|
94845
|
-
uri =
|
|
95665
|
+
uri = parse12(serialize(uri, options), options);
|
|
94846
95666
|
}
|
|
94847
95667
|
return uri;
|
|
94848
95668
|
}
|
|
94849
|
-
function
|
|
95669
|
+
function resolve19(baseURI, relativeURI, options) {
|
|
94850
95670
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
94851
95671
|
const {
|
|
94852
95672
|
parsed: baseParsed,
|
|
@@ -94882,8 +95702,8 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
94882
95702
|
function resolveComponent(base2, relative7, options, skipNormalization) {
|
|
94883
95703
|
const target = {};
|
|
94884
95704
|
if (!skipNormalization) {
|
|
94885
|
-
base2 =
|
|
94886
|
-
relative7 =
|
|
95705
|
+
base2 = parse12(serialize(base2, options), options);
|
|
95706
|
+
relative7 = parse12(serialize(relative7, options), options);
|
|
94887
95707
|
}
|
|
94888
95708
|
options = options || {};
|
|
94889
95709
|
if (!options.tolerant && relative7.scheme) {
|
|
@@ -95183,7 +96003,7 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
95183
96003
|
}
|
|
95184
96004
|
return { parsed, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme };
|
|
95185
96005
|
}
|
|
95186
|
-
function
|
|
96006
|
+
function parse12(uri, opts) {
|
|
95187
96007
|
return parseWithStatus(uri, opts).parsed;
|
|
95188
96008
|
}
|
|
95189
96009
|
function normalizeString(uri, opts) {
|
|
@@ -95216,11 +96036,11 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
95216
96036
|
var fastUri = {
|
|
95217
96037
|
SCHEMES,
|
|
95218
96038
|
normalize: normalize3,
|
|
95219
|
-
resolve:
|
|
96039
|
+
resolve: resolve19,
|
|
95220
96040
|
resolveComponent,
|
|
95221
96041
|
equal,
|
|
95222
96042
|
serialize,
|
|
95223
|
-
parse:
|
|
96043
|
+
parse: parse12
|
|
95224
96044
|
};
|
|
95225
96045
|
module.exports = fastUri;
|
|
95226
96046
|
module.exports.default = fastUri;
|
|
@@ -99002,7 +99822,7 @@ class McpServer {
|
|
|
99002
99822
|
let task = createTaskResult.task;
|
|
99003
99823
|
const pollInterval = task.pollInterval ?? 5000;
|
|
99004
99824
|
while (task.status !== "completed" && task.status !== "failed" && task.status !== "cancelled") {
|
|
99005
|
-
await new Promise((
|
|
99825
|
+
await new Promise((resolve19) => setTimeout(resolve19, pollInterval));
|
|
99006
99826
|
const updatedTask = await extra.taskStore.getTask(taskId);
|
|
99007
99827
|
if (!updatedTask) {
|
|
99008
99828
|
throw new McpError(ErrorCode.InternalError, `Task ${taskId} not found during polling`);
|
|
@@ -99045,11 +99865,11 @@ class McpServer {
|
|
|
99045
99865
|
return EMPTY_COMPLETION_RESULT;
|
|
99046
99866
|
}
|
|
99047
99867
|
const promptShape = getObjectShape(prompt.argsSchema);
|
|
99048
|
-
const
|
|
99049
|
-
if (!isCompletable(
|
|
99868
|
+
const field2 = promptShape?.[request2.params.argument.name];
|
|
99869
|
+
if (!isCompletable(field2)) {
|
|
99050
99870
|
return EMPTY_COMPLETION_RESULT;
|
|
99051
99871
|
}
|
|
99052
|
-
const completer = getCompleter(
|
|
99872
|
+
const completer = getCompleter(field2);
|
|
99053
99873
|
if (!completer) {
|
|
99054
99874
|
return EMPTY_COMPLETION_RESULT;
|
|
99055
99875
|
}
|
|
@@ -99321,8 +100141,8 @@ class McpServer {
|
|
|
99321
100141
|
};
|
|
99322
100142
|
this._registeredPrompts[name] = registeredPrompt;
|
|
99323
100143
|
if (argsSchema) {
|
|
99324
|
-
const hasCompletable = Object.values(argsSchema).some((
|
|
99325
|
-
const inner =
|
|
100144
|
+
const hasCompletable = Object.values(argsSchema).some((field2) => {
|
|
100145
|
+
const inner = field2 instanceof ZodOptional ? field2._def?.innerType : field2;
|
|
99326
100146
|
return isCompletable(inner);
|
|
99327
100147
|
});
|
|
99328
100148
|
if (hasCompletable) {
|
|
@@ -99514,9 +100334,9 @@ function promptArgumentsFromSchema(schema) {
|
|
|
99514
100334
|
const shape = getObjectShape(schema);
|
|
99515
100335
|
if (!shape)
|
|
99516
100336
|
return [];
|
|
99517
|
-
return Object.entries(shape).map(([name,
|
|
99518
|
-
const description = getSchemaDescription(
|
|
99519
|
-
const isOptional = isSchemaOptional(
|
|
100337
|
+
return Object.entries(shape).map(([name, field2]) => {
|
|
100338
|
+
const description = getSchemaDescription(field2);
|
|
100339
|
+
const isOptional = isSchemaOptional(field2);
|
|
99520
100340
|
return {
|
|
99521
100341
|
name,
|
|
99522
100342
|
description,
|
|
@@ -99575,7 +100395,7 @@ var init_remote_customer_operations = __esm(() => {
|
|
|
99575
100395
|
{ name: "list_remote_skills", title: "List Remote Skills", parameter: null, mutates: false, invoke: (client2) => client2.listSkills() },
|
|
99576
100396
|
{ name: "get_billing_status", title: "Get Billing Status", parameter: null, mutates: false, invoke: (client2) => client2.getBillingStatus() },
|
|
99577
100397
|
{ name: "list_credit_packs", title: "List Credit Packs", parameter: null, mutates: false, invoke: (client2) => client2.listCreditPacks() },
|
|
99578
|
-
{ name: "create_credit_checkout", title: "Create Credit Checkout", parameter: "pack_id", mutates: true, invoke: (client2, value) => client2.createCreditCheckout(value) },
|
|
100398
|
+
{ name: "create_credit_checkout", title: "Create Credit Checkout", parameter: "pack_id", mutates: true, invoke: (client2, value, options) => client2.createCreditCheckout(value, options) },
|
|
99579
100399
|
{ name: "get_billing_usage", title: "Get Billing Usage", parameter: null, mutates: false, invoke: (client2) => client2.getUsage() },
|
|
99580
100400
|
{ name: "list_invoices", title: "List Invoices", parameter: null, mutates: false, invoke: (client2) => client2.listInvoices() },
|
|
99581
100401
|
{ name: "create_billing_checkout", title: "Create Billing Checkout", parameter: null, mutates: true, invoke: (client2) => client2.createBillingCheckout() },
|
|
@@ -99689,7 +100509,7 @@ var init_remote_invitation_recovery = __esm(() => {
|
|
|
99689
100509
|
});
|
|
99690
100510
|
|
|
99691
100511
|
// src/lib/remote-private-publications.ts
|
|
99692
|
-
import { createHash as
|
|
100512
|
+
import { createHash as createHash21 } from "crypto";
|
|
99693
100513
|
function checkedPublicationDeclaration(value) {
|
|
99694
100514
|
if (!exact(value, ["idempotencyKey", "version", "expectedCurrentVersionId", "manifestText", "archiveSha256", "archiveByteSize"]) || !publicationUuid(value.idempotencyKey) || !(value.expectedCurrentVersionId === null || publicationUuid(value.expectedCurrentVersionId)) || typeof value.version !== "string" || !value.version || value.version.length > 128 || /[\p{Cc}\p{Cs}]/u.test(value.version) || typeof value.manifestText !== "string" || Buffer.byteLength(value.manifestText) > 16384 || !hash3(value.archiveSha256) || !Number.isSafeInteger(value.archiveByteSize) || Number(value.archiveByteSize) < 1 || Number(value.archiveByteSize) > PRIVATE_PUBLICATION_MAX_BYTES)
|
|
99695
100515
|
return bad();
|
|
@@ -99934,12 +100754,12 @@ class RemotePrivatePublicationsClient {
|
|
|
99934
100754
|
previous = view;
|
|
99935
100755
|
if (!["queued", "verifying"].includes(view.state) || Date.now() >= until)
|
|
99936
100756
|
return view;
|
|
99937
|
-
await new Promise((
|
|
100757
|
+
await new Promise((resolve19) => {
|
|
99938
100758
|
const timer = setTimeout(done, Math.min(1000, until - Date.now()));
|
|
99939
100759
|
function done() {
|
|
99940
100760
|
clearTimeout(timer);
|
|
99941
100761
|
options.signal?.removeEventListener("abort", done);
|
|
99942
|
-
|
|
100762
|
+
resolve19();
|
|
99943
100763
|
}
|
|
99944
100764
|
options.signal?.addEventListener("abort", done, { once: true });
|
|
99945
100765
|
});
|
|
@@ -99950,7 +100770,7 @@ var PRIVATE_PUBLICATION_MAX_BYTES, failures2, PrivatePublicationError, bad = ()
|
|
|
99950
100770
|
throw new PrivatePublicationError("INVALID_PUBLICATION_INPUT", "Invalid publication input or recovery data.");
|
|
99951
100771
|
}, invalid5 = () => {
|
|
99952
100772
|
throw new PrivatePublicationError("INVALID_PUBLICATION_RESPONSE", "The server returned an invalid publication result.");
|
|
99953
|
-
}, publicationUuid = (v) => typeof v === "string" && /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(v), hash3 = (v) => typeof v === "string" && /^[a-f0-9]{64}$/.test(v), record10 = (v) => !!v && typeof v === "object" && !Array.isArray(v), exact = (v, keys3) => record10(v) && Object.keys(v).sort().join(",") === keys3.sort().join(","), date6 = (v) => typeof v === "string" && /^\d{4}-\d\d-\d\dT[0-9:.]+(?:Z|[+-](?:[01]\d|2[0-3]):[0-5]\d)$/.test(v) && Number.isFinite(Date.parse(v)), publicationSha256 = (bytes) =>
|
|
100773
|
+
}, publicationUuid = (v) => typeof v === "string" && /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(v), hash3 = (v) => typeof v === "string" && /^[a-f0-9]{64}$/.test(v), record10 = (v) => !!v && typeof v === "object" && !Array.isArray(v), exact = (v, keys3) => record10(v) && Object.keys(v).sort().join(",") === keys3.sort().join(","), date6 = (v) => typeof v === "string" && /^\d{4}-\d\d-\d\dT[0-9:.]+(?:Z|[+-](?:[01]\d|2[0-3]):[0-5]\d)$/.test(v) && Number.isFinite(Date.parse(v)), publicationSha256 = (bytes) => createHash21("sha256").update(bytes).digest("hex");
|
|
99954
100774
|
var init_remote_private_publications = __esm(() => {
|
|
99955
100775
|
init_fleet_credentials();
|
|
99956
100776
|
init_remote_workspace_selection();
|
|
@@ -100227,11 +101047,11 @@ var init_remote_auth = __esm(() => {
|
|
|
100227
101047
|
});
|
|
100228
101048
|
|
|
100229
101049
|
// src/lib/workspace-profile.ts
|
|
100230
|
-
import { constants as
|
|
100231
|
-
import { dirname as
|
|
101050
|
+
import { constants as constants15, closeSync as closeSync16, fstatSync as fstatSync16, lstatSync as lstatSync22, mkdirSync as mkdirSync16, mkdtempSync as mkdtempSync5, openSync as openSync16, readFileSync as readFileSync31, renameSync as renameSync9, rmSync as rmSync8, writeFileSync as writeFileSync15 } from "fs";
|
|
101051
|
+
import { dirname as dirname20, join as join44 } from "path";
|
|
100232
101052
|
function stat2(path) {
|
|
100233
101053
|
try {
|
|
100234
|
-
return
|
|
101054
|
+
return lstatSync22(path);
|
|
100235
101055
|
} catch (error61) {
|
|
100236
101056
|
if (error61.code === "ENOENT")
|
|
100237
101057
|
return null;
|
|
@@ -100241,14 +101061,14 @@ function stat2(path) {
|
|
|
100241
101061
|
function safeText(file2) {
|
|
100242
101062
|
if (stat2(file2) === null)
|
|
100243
101063
|
return null;
|
|
100244
|
-
const fd =
|
|
101064
|
+
const fd = openSync16(file2, constants15.O_RDONLY | constants15.O_NOFOLLOW | constants15.O_NONBLOCK);
|
|
100245
101065
|
try {
|
|
100246
|
-
const s =
|
|
101066
|
+
const s = fstatSync16(fd);
|
|
100247
101067
|
if (!s.isFile() || s.size > 65536 || ![256, 384].includes(s.mode & 4095) || process.getuid && s.uid !== process.getuid())
|
|
100248
101068
|
return fail2("The selected profile must use bounded owner-only regular files.");
|
|
100249
101069
|
return readFileSync31(fd, "utf8");
|
|
100250
101070
|
} finally {
|
|
100251
|
-
|
|
101071
|
+
closeSync16(fd);
|
|
100252
101072
|
}
|
|
100253
101073
|
}
|
|
100254
101074
|
function checkIdentityMetadata(file2, identity4) {
|
|
@@ -100313,18 +101133,18 @@ async function prepareWorkspaceEnrollment(membershipId, source = process.env) {
|
|
|
100313
101133
|
`);
|
|
100314
101134
|
if (Buffer.byteLength(credentialBody("x".repeat(8192)), "utf8") > 65536)
|
|
100315
101135
|
return fail2("The selected profile has insufficient space for a bounded credential. Reduce its unrelated configuration before signing in.");
|
|
100316
|
-
const
|
|
100317
|
-
for (let path =
|
|
101136
|
+
const parents3 = [];
|
|
101137
|
+
for (let path = dirname20(file2);; path = dirname20(path)) {
|
|
100318
101138
|
const before2 = stat2(path);
|
|
100319
101139
|
if (before2 && (!before2.isDirectory() || before2.isSymbolicLink()))
|
|
100320
101140
|
return fail2("The profile directory must not be a symbolic link.");
|
|
100321
|
-
|
|
100322
|
-
if (path ===
|
|
101141
|
+
parents3.push([path, before2]);
|
|
101142
|
+
if (path === dirname20(path))
|
|
100323
101143
|
break;
|
|
100324
101144
|
}
|
|
100325
101145
|
const unchanged2 = () => {
|
|
100326
101146
|
unchangedFiles();
|
|
100327
|
-
for (const [path, before2] of
|
|
101147
|
+
for (const [path, before2] of parents3) {
|
|
100328
101148
|
const now3 = stat2(path);
|
|
100329
101149
|
if (!before2 ? now3 !== null : !now3 || !now3.isDirectory() || before2.dev !== now3.dev || before2.ino !== now3.ino)
|
|
100330
101150
|
changed();
|
|
@@ -100378,14 +101198,14 @@ async function prepareWorkspaceEnrollment(membershipId, source = process.env) {
|
|
|
100378
101198
|
return fail2("The new profile exceeds the credential reader size limit.");
|
|
100379
101199
|
const identity4 = JSON.stringify({ email: verified.user.email, userId: verified.user.id, orgId: verified.organization.id, orgSlug: verified.organization.slug, apiUrl: origin }, null, 2) + `
|
|
100380
101200
|
`;
|
|
100381
|
-
mkdirSync16(
|
|
100382
|
-
const temp = mkdtempSync5(join44(
|
|
101201
|
+
mkdirSync16(dirname20(file2), { recursive: true, mode: 448 });
|
|
101202
|
+
const temp = mkdtempSync5(join44(dirname20(file2), ".workspace-login-"));
|
|
100383
101203
|
let identityInstalled = false;
|
|
100384
101204
|
try {
|
|
100385
101205
|
writeFileSync15(join44(temp, "credentials"), body, { mode: 384, flag: "wx" });
|
|
100386
101206
|
writeFileSync15(join44(temp, "identity"), identity4, { mode: 384, flag: "wx" });
|
|
100387
101207
|
unchangedFiles();
|
|
100388
|
-
for (const [path, before2] of
|
|
101208
|
+
for (const [path, before2] of parents3) {
|
|
100389
101209
|
const now3 = stat2(path);
|
|
100390
101210
|
if (!now3 || !now3.isDirectory() || now3.isSymbolicLink() || before2 && (before2.dev !== now3.dev || before2.ino !== now3.ino))
|
|
100391
101211
|
changed();
|
|
@@ -100595,8 +101415,8 @@ var init_recurring_customer = __esm(() => {
|
|
|
100595
101415
|
});
|
|
100596
101416
|
|
|
100597
101417
|
// src/lib/recurring-recovery.ts
|
|
100598
|
-
import { constants as
|
|
100599
|
-
import { dirname as
|
|
101418
|
+
import { constants as constants16, closeSync as closeSync17, fsyncSync as fsyncSync4, fstatSync as fstatSync17, lstatSync as lstatSync23, mkdirSync as mkdirSync17, openSync as openSync17, readSync as readSync13, realpathSync as realpathSync8, renameSync as renameSync10, unlinkSync as unlinkSync6, writeFileSync as writeFileSync16 } from "fs";
|
|
101419
|
+
import { dirname as dirname21, isAbsolute as isAbsolute17, join as join45, resolve as resolve19 } from "path";
|
|
100600
101420
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
100601
101421
|
|
|
100602
101422
|
class RecoveryOwner {
|
|
@@ -100604,14 +101424,14 @@ class RecoveryOwner {
|
|
|
100604
101424
|
parents = [];
|
|
100605
101425
|
constructor(directory) {
|
|
100606
101426
|
this.directory = directory;
|
|
100607
|
-
if (!
|
|
101427
|
+
if (!isAbsolute17(directory) || resolve19(directory) !== directory || realpathSync8(directory) !== directory)
|
|
100608
101428
|
invalid6();
|
|
100609
|
-
for (let path = directory;; path =
|
|
100610
|
-
const stat3 =
|
|
101429
|
+
for (let path = directory;; path = dirname21(path)) {
|
|
101430
|
+
const stat3 = lstatSync23(path);
|
|
100611
101431
|
if (!stat3.isDirectory() || stat3.isSymbolicLink())
|
|
100612
101432
|
invalid6();
|
|
100613
101433
|
this.parents.push({ path, dev: stat3.dev, ino: stat3.ino });
|
|
100614
|
-
if (path ===
|
|
101434
|
+
if (path === dirname21(path))
|
|
100615
101435
|
break;
|
|
100616
101436
|
}
|
|
100617
101437
|
this.assert();
|
|
@@ -100620,59 +101440,59 @@ class RecoveryOwner {
|
|
|
100620
101440
|
if (realpathSync8(this.directory) !== this.directory)
|
|
100621
101441
|
invalid6();
|
|
100622
101442
|
for (const prior of this.parents) {
|
|
100623
|
-
const now3 =
|
|
101443
|
+
const now3 = lstatSync23(prior.path);
|
|
100624
101444
|
if (!now3.isDirectory() || now3.isSymbolicLink() || now3.dev !== prior.dev || now3.ino !== prior.ino)
|
|
100625
101445
|
invalid6();
|
|
100626
101446
|
}
|
|
100627
|
-
const own2 =
|
|
101447
|
+
const own2 = lstatSync23(this.directory);
|
|
100628
101448
|
if ((own2.mode & 511) !== 448 || (own2.mode & 3584) !== 0 || process.getuid && own2.uid !== process.getuid())
|
|
100629
101449
|
invalid6();
|
|
100630
101450
|
}
|
|
100631
101451
|
read(name) {
|
|
100632
101452
|
this.assert();
|
|
100633
|
-
const fd =
|
|
101453
|
+
const fd = openSync17(join45(this.directory, name), constants16.O_RDONLY | constants16.O_NOFOLLOW | constants16.O_NONBLOCK);
|
|
100634
101454
|
try {
|
|
100635
|
-
const before2 =
|
|
101455
|
+
const before2 = fstatSync17(fd);
|
|
100636
101456
|
if (!before2.isFile() || before2.nlink !== 1 || (before2.mode & 4095) !== 384 || before2.size < 1 || before2.size > 8192 || process.getuid && before2.uid !== process.getuid())
|
|
100637
101457
|
invalid6();
|
|
100638
101458
|
const bytes = Buffer.alloc(before2.size + 1);
|
|
100639
101459
|
let size2 = 0;
|
|
100640
101460
|
while (size2 < bytes.length) {
|
|
100641
|
-
const n2 =
|
|
101461
|
+
const n2 = readSync13(fd, bytes, size2, bytes.length - size2, size2);
|
|
100642
101462
|
if (!n2)
|
|
100643
101463
|
break;
|
|
100644
101464
|
size2 += n2;
|
|
100645
101465
|
}
|
|
100646
|
-
const after2 =
|
|
101466
|
+
const after2 = fstatSync17(fd), path = lstatSync23(join45(this.directory, name));
|
|
100647
101467
|
if (size2 !== before2.size || after2.size !== before2.size || before2.mtimeMs !== after2.mtimeMs || before2.ctimeMs !== after2.ctimeMs || path.dev !== before2.dev || path.ino !== before2.ino || !path.isFile() || path.isSymbolicLink())
|
|
100648
101468
|
invalid6();
|
|
100649
101469
|
this.assert();
|
|
100650
101470
|
return new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(0, size2));
|
|
100651
101471
|
} finally {
|
|
100652
|
-
|
|
101472
|
+
closeSync17(fd);
|
|
100653
101473
|
}
|
|
100654
101474
|
}
|
|
100655
101475
|
write(name, value) {
|
|
100656
101476
|
this.assert();
|
|
100657
101477
|
const bytes = canonicalJson2(value, 8192) + `
|
|
100658
101478
|
`;
|
|
100659
|
-
const fd =
|
|
101479
|
+
const fd = openSync17(join45(this.directory, name), constants16.O_WRONLY | constants16.O_CREAT | constants16.O_EXCL | constants16.O_NOFOLLOW, 384);
|
|
100660
101480
|
try {
|
|
100661
101481
|
writeFileSync16(fd, bytes);
|
|
100662
|
-
|
|
101482
|
+
fsyncSync4(fd);
|
|
100663
101483
|
} finally {
|
|
100664
|
-
|
|
101484
|
+
closeSync17(fd);
|
|
100665
101485
|
}
|
|
100666
101486
|
this.assert();
|
|
100667
101487
|
this.sync();
|
|
100668
101488
|
}
|
|
100669
101489
|
sync() {
|
|
100670
101490
|
this.assert();
|
|
100671
|
-
const fd =
|
|
101491
|
+
const fd = openSync17(this.directory, constants16.O_RDONLY | constants16.O_NOFOLLOW);
|
|
100672
101492
|
try {
|
|
100673
|
-
|
|
101493
|
+
fsyncSync4(fd);
|
|
100674
101494
|
} finally {
|
|
100675
|
-
|
|
101495
|
+
closeSync17(fd);
|
|
100676
101496
|
}
|
|
100677
101497
|
}
|
|
100678
101498
|
saveState(state, expected) {
|
|
@@ -100690,20 +101510,20 @@ class RecoveryOwner {
|
|
|
100690
101510
|
this.assert();
|
|
100691
101511
|
let fd;
|
|
100692
101512
|
try {
|
|
100693
|
-
fd =
|
|
101513
|
+
fd = openSync17(join45(this.directory, "operation.lock"), constants16.O_WRONLY | constants16.O_CREAT | constants16.O_EXCL | constants16.O_NOFOLLOW, 384);
|
|
100694
101514
|
} catch {
|
|
100695
101515
|
throw new RecurringCustomerError("RECURRING_RECOVERY_BUSY", "Recovery is locked. Confirm the original process has stopped before explicitly reconciling the retained lock; no request was retried.");
|
|
100696
101516
|
}
|
|
100697
|
-
const owner2 =
|
|
101517
|
+
const owner2 = fstatSync17(fd);
|
|
100698
101518
|
try {
|
|
100699
101519
|
writeFileSync16(fd, JSON.stringify({ pid: process.pid }));
|
|
100700
|
-
|
|
101520
|
+
fsyncSync4(fd);
|
|
100701
101521
|
this.sync();
|
|
100702
101522
|
return await action();
|
|
100703
101523
|
} finally {
|
|
100704
|
-
|
|
101524
|
+
closeSync17(fd);
|
|
100705
101525
|
this.assert();
|
|
100706
|
-
const now3 =
|
|
101526
|
+
const now3 = lstatSync23(join45(this.directory, "operation.lock"));
|
|
100707
101527
|
if (owner2.dev !== now3.dev || owner2.ino !== now3.ino || !now3.isFile() || now3.isSymbolicLink())
|
|
100708
101528
|
invalid6();
|
|
100709
101529
|
unlinkSync6(join45(this.directory, "operation.lock"));
|
|
@@ -100739,7 +101559,7 @@ function base2(customer, organizationId) {
|
|
|
100739
101559
|
};
|
|
100740
101560
|
}
|
|
100741
101561
|
function create3(directory, intent) {
|
|
100742
|
-
if (!
|
|
101562
|
+
if (!isAbsolute17(directory) || resolve19(directory) !== directory || realpathSync8(dirname21(directory)) !== dirname21(directory))
|
|
100743
101563
|
invalid6();
|
|
100744
101564
|
mkdirSync17(directory, { mode: 448 });
|
|
100745
101565
|
const owner2 = new RecoveryOwner(directory), checked = intentSchema.parse(intent), intentSha256 = canonicalJsonSha256(checked);
|
|
@@ -100902,7 +101722,7 @@ var init_recurring_recovery = __esm(() => {
|
|
|
100902
101722
|
});
|
|
100903
101723
|
|
|
100904
101724
|
// src/lib/recurring-surface.ts
|
|
100905
|
-
import { isAbsolute as
|
|
101725
|
+
import { isAbsolute as isAbsolute18 } from "path";
|
|
100906
101726
|
function recurringMcpSchema(action) {
|
|
100907
101727
|
return action === "activate" ? recurringSurfaceSchemas.activate.extend({ code, confirm: exports_external.literal(true) }) : recurringSurfaceSchemas[action];
|
|
100908
101728
|
}
|
|
@@ -101007,7 +101827,7 @@ var init_recurring_surface = __esm(() => {
|
|
|
101007
101827
|
uuid13 = exports_external.string().regex(/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/);
|
|
101008
101828
|
context = { userId: uuid13.optional(), membershipId: uuid13.optional() };
|
|
101009
101829
|
page2 = { limit: exports_external.number().int().min(1).max(100).optional(), cursor: exports_external.string().min(1).max(2048).optional() };
|
|
101010
|
-
directory = exports_external.string().max(4096).refine(
|
|
101830
|
+
directory = exports_external.string().max(4096).refine(isAbsolute18, "Use an absolute recovery directory");
|
|
101011
101831
|
email4 = exports_external.string().trim().toLowerCase().email().max(254);
|
|
101012
101832
|
code = exports_external.string().regex(/^\d{6}$/);
|
|
101013
101833
|
recurringSurfaceSchemas = {
|
|
@@ -101976,11 +102796,11 @@ var init_mcp_contracts = __esm(() => {
|
|
|
101976
102796
|
name: operation.name,
|
|
101977
102797
|
title: operation.title,
|
|
101978
102798
|
description: `${operation.title} on the configured server; unavailable capabilities fail explicitly.`,
|
|
101979
|
-
params: operation.parameter ? [operation.parameter] : [],
|
|
102799
|
+
params: operation.parameter ? [operation.parameter, ...operation.name === "create_credit_checkout" ? ["idempotency_key?"] : []] : [],
|
|
101980
102800
|
category: "execution",
|
|
101981
102801
|
sideEffects: operation.mutates ? "local-process-or-remote-run" : "none",
|
|
101982
102802
|
stable: true,
|
|
101983
|
-
inputSchema: objectSchema(operation.parameter ? { [operation.parameter]: stringSchema("Server resource identifier.") } : {}, operation.parameter ? [operation.parameter] : []),
|
|
102803
|
+
inputSchema: objectSchema(operation.parameter ? { [operation.parameter]: stringSchema("Server resource identifier."), ...operation.name === "create_credit_checkout" ? { idempotency_key: { type: "string", pattern: "^[A-Za-z0-9._:-]{8,255}$", description: "Caller-owned key retained before submission; reuse only for explicit recovery of the same server/account/pack." } } : {} } : {}, operation.parameter ? [operation.parameter] : []),
|
|
101984
102804
|
outputSchema: { oneOf: [objectSchema({}, [], "Server response.", true), { type: "array", items: objectSchema({}, [], "Server record.", true) }] }
|
|
101985
102805
|
}));
|
|
101986
102806
|
remoteCustomerContracts.push({
|
|
@@ -102913,14 +103733,14 @@ var init_operation_tools = __esm(() => {
|
|
|
102913
103733
|
|
|
102914
103734
|
// src/lib/feedback.ts
|
|
102915
103735
|
import { appendFileSync as appendFileSync2, existsSync as existsSync29, mkdirSync as mkdirSync18 } from "fs";
|
|
102916
|
-
import { dirname as
|
|
103736
|
+
import { dirname as dirname22, join as join47 } from "path";
|
|
102917
103737
|
import { Database } from "bun:sqlite";
|
|
102918
103738
|
function getFeedbackDbPath() {
|
|
102919
103739
|
return join47(getDataDir(), "skills.db");
|
|
102920
103740
|
}
|
|
102921
103741
|
function getFeedbackDb() {
|
|
102922
103742
|
const dbPath = getFeedbackDbPath();
|
|
102923
|
-
const dir =
|
|
103743
|
+
const dir = dirname22(dbPath);
|
|
102924
103744
|
if (!existsSync29(dir))
|
|
102925
103745
|
mkdirSync18(dir, { recursive: true });
|
|
102926
103746
|
const db = new Database(dbPath);
|
|
@@ -102949,7 +103769,7 @@ function saveFeedback(input2) {
|
|
|
102949
103769
|
const category = input2.category ?? "general";
|
|
102950
103770
|
if (isApiMode()) {
|
|
102951
103771
|
const path = join47(getDataDir(), "feedback.jsonl");
|
|
102952
|
-
const dir =
|
|
103772
|
+
const dir = dirname22(path);
|
|
102953
103773
|
if (!existsSync29(dir))
|
|
102954
103774
|
mkdirSync18(dir, { recursive: true });
|
|
102955
103775
|
appendFileSync2(path, JSON.stringify({ message, category, email: input2.email ?? null, agent: input2.agent ?? null, version: input2.version ?? null, createdAt: new Date().toISOString() }) + `
|
|
@@ -103427,7 +104247,7 @@ var init_schedule_tools = __esm(() => {
|
|
|
103427
104247
|
});
|
|
103428
104248
|
|
|
103429
104249
|
// src/lib/native-storage.ts
|
|
103430
|
-
import { createHash as
|
|
104250
|
+
import { createHash as createHash22, createHmac as createHmac3 } from "crypto";
|
|
103431
104251
|
import {
|
|
103432
104252
|
existsSync as existsSync31,
|
|
103433
104253
|
mkdirSync as mkdirSync20,
|
|
@@ -103436,7 +104256,7 @@ import {
|
|
|
103436
104256
|
statSync as statSync17,
|
|
103437
104257
|
writeFileSync as writeFileSync18
|
|
103438
104258
|
} from "fs";
|
|
103439
|
-
import { dirname as
|
|
104259
|
+
import { dirname as dirname23, join as join49, normalize as normalize3, relative as relative7, sep as sep7 } from "path";
|
|
103440
104260
|
function resolveSkillsNativeStorageConfig(env3 = process.env) {
|
|
103441
104261
|
assertNoRetiredModeEnvVars(env3, {
|
|
103442
104262
|
app: SKILLS_ENV_NAMESPACE,
|
|
@@ -103504,7 +104324,7 @@ function exportSkillsLocalSnapshot(targetDir = process.cwd(), options = {}) {
|
|
|
103504
104324
|
files.push({
|
|
103505
104325
|
path: relativePath,
|
|
103506
104326
|
sizeBytes: bytes.byteLength,
|
|
103507
|
-
sha256:
|
|
104327
|
+
sha256: createHash22("sha256").update(bytes).digest("hex"),
|
|
103508
104328
|
...options.includeFileContents ? { contentBase64: Buffer.from(bytes).toString("base64") } : {}
|
|
103509
104329
|
});
|
|
103510
104330
|
}
|
|
@@ -103796,20 +104616,20 @@ var init_private_publication_customer = __esm(() => {
|
|
|
103796
104616
|
});
|
|
103797
104617
|
|
|
103798
104618
|
// src/lib/private-publication-recovery.ts
|
|
103799
|
-
import { constants as
|
|
103800
|
-
import { dirname as
|
|
104619
|
+
import { constants as constants17, closeSync as closeSync18, fsyncSync as fsyncSync5, fstatSync as fstatSync18, lstatSync as lstatSync24, mkdirSync as mkdirSync21, openSync as openSync18, readSync as readSync14, realpathSync as realpathSync9, renameSync as renameSync11, unlinkSync as unlinkSync7, writeFileSync as writeFileSync19 } from "fs";
|
|
104620
|
+
import { dirname as dirname24, isAbsolute as isAbsolute19, join as join50, resolve as resolve20 } from "path";
|
|
103801
104621
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
103802
104622
|
function safeDirectory(directory2) {
|
|
103803
|
-
if (!
|
|
104623
|
+
if (!isAbsolute19(directory2) || directory2 !== resolve20(directory2) || realpathSync9(directory2) !== directory2)
|
|
103804
104624
|
return fail3();
|
|
103805
|
-
for (let path = directory2;; path =
|
|
103806
|
-
const stat3 =
|
|
104625
|
+
for (let path = directory2;; path = dirname24(path)) {
|
|
104626
|
+
const stat3 = lstatSync24(path);
|
|
103807
104627
|
if (!stat3.isDirectory() || stat3.isSymbolicLink())
|
|
103808
104628
|
return fail3();
|
|
103809
|
-
if (path ===
|
|
104629
|
+
if (path === dirname24(path))
|
|
103810
104630
|
break;
|
|
103811
104631
|
}
|
|
103812
|
-
const own2 =
|
|
104632
|
+
const own2 = lstatSync24(directory2);
|
|
103813
104633
|
if ((own2.mode & 63) !== 0 || process.getuid && own2.uid !== process.getuid())
|
|
103814
104634
|
return fail3();
|
|
103815
104635
|
return { dev: own2.dev, ino: own2.ino };
|
|
@@ -103821,35 +104641,35 @@ function unchangedDirectory(directory2, identity4) {
|
|
|
103821
104641
|
}
|
|
103822
104642
|
function readOwned(directory2, name, max2) {
|
|
103823
104643
|
const identity4 = safeDirectory(directory2), file2 = join50(directory2, name);
|
|
103824
|
-
const fd =
|
|
104644
|
+
const fd = openSync18(file2, constants17.O_RDONLY | constants17.O_NOFOLLOW);
|
|
103825
104645
|
try {
|
|
103826
|
-
const stat3 =
|
|
104646
|
+
const stat3 = fstatSync18(fd);
|
|
103827
104647
|
if (!stat3.isFile() || stat3.nlink !== 1 || stat3.size > max2 || stat3.size < 1 || (stat3.mode & 63) !== 0 || process.getuid && stat3.uid !== process.getuid())
|
|
103828
104648
|
return fail3();
|
|
103829
104649
|
const buffer = Buffer.alloc(Math.min(max2, stat3.size) + 1);
|
|
103830
104650
|
let length = 0;
|
|
103831
104651
|
while (length < buffer.length) {
|
|
103832
|
-
const count =
|
|
104652
|
+
const count = readSync14(fd, buffer, length, buffer.length - length, length);
|
|
103833
104653
|
if (count === 0)
|
|
103834
104654
|
break;
|
|
103835
104655
|
length += count;
|
|
103836
104656
|
}
|
|
103837
|
-
const bytes = buffer.subarray(0, length), after2 =
|
|
104657
|
+
const bytes = buffer.subarray(0, length), after2 = fstatSync18(fd);
|
|
103838
104658
|
unchangedDirectory(directory2, identity4);
|
|
103839
104659
|
if (bytes.length !== stat3.size || stat3.size !== after2.size || stat3.mtimeMs !== after2.mtimeMs || stat3.ctimeMs !== after2.ctimeMs)
|
|
103840
104660
|
return fail3();
|
|
103841
104661
|
return bytes;
|
|
103842
104662
|
} finally {
|
|
103843
|
-
|
|
104663
|
+
closeSync18(fd);
|
|
103844
104664
|
}
|
|
103845
104665
|
}
|
|
103846
104666
|
function writeOwned(directory2, name, bytes) {
|
|
103847
|
-
const fd =
|
|
104667
|
+
const fd = openSync18(join50(directory2, name), constants17.O_WRONLY | constants17.O_CREAT | constants17.O_EXCL | constants17.O_NOFOLLOW, 384);
|
|
103848
104668
|
try {
|
|
103849
104669
|
writeFileSync19(fd, bytes);
|
|
103850
|
-
|
|
104670
|
+
fsyncSync5(fd);
|
|
103851
104671
|
} finally {
|
|
103852
|
-
|
|
104672
|
+
closeSync18(fd);
|
|
103853
104673
|
}
|
|
103854
104674
|
}
|
|
103855
104675
|
function save(directory2, value) {
|
|
@@ -103858,11 +104678,11 @@ function save(directory2, value) {
|
|
|
103858
104678
|
`);
|
|
103859
104679
|
unchangedDirectory(directory2, identity4);
|
|
103860
104680
|
renameSync11(join50(directory2, temporary), join50(directory2, "receipt.json"));
|
|
103861
|
-
const fd =
|
|
104681
|
+
const fd = openSync18(directory2, constants17.O_RDONLY | constants17.O_NOFOLLOW);
|
|
103862
104682
|
try {
|
|
103863
|
-
|
|
104683
|
+
fsyncSync5(fd);
|
|
103864
104684
|
} finally {
|
|
103865
|
-
|
|
104685
|
+
closeSync18(fd);
|
|
103866
104686
|
}
|
|
103867
104687
|
}
|
|
103868
104688
|
function bind2(client2, receipt) {
|
|
@@ -103873,20 +104693,20 @@ async function locked(directory2, action) {
|
|
|
103873
104693
|
const identity4 = safeDirectory(directory2), file2 = join50(directory2, "operation.lock");
|
|
103874
104694
|
let fd;
|
|
103875
104695
|
try {
|
|
103876
|
-
fd =
|
|
104696
|
+
fd = openSync18(file2, constants17.O_WRONLY | constants17.O_CREAT | constants17.O_EXCL | constants17.O_NOFOLLOW, 384);
|
|
103877
104697
|
} catch {
|
|
103878
104698
|
throw new PrivatePublicationError("PUBLICATION_RECOVERY_BUSY", "Another operation holds this recovery directory. If it crashed, confirm that process has stopped before explicitly removing operation.lock and resuming.");
|
|
103879
104699
|
}
|
|
103880
|
-
const lock =
|
|
104700
|
+
const lock = fstatSync18(fd);
|
|
103881
104701
|
try {
|
|
103882
104702
|
writeFileSync19(fd, JSON.stringify({ pid: process.pid }) + `
|
|
103883
104703
|
`);
|
|
103884
|
-
|
|
104704
|
+
fsyncSync5(fd);
|
|
103885
104705
|
return await action();
|
|
103886
104706
|
} finally {
|
|
103887
|
-
|
|
104707
|
+
closeSync18(fd);
|
|
103888
104708
|
unchangedDirectory(directory2, identity4);
|
|
103889
|
-
const now3 =
|
|
104709
|
+
const now3 = lstatSync24(file2);
|
|
103890
104710
|
if (now3.dev !== lock.dev || now3.ino !== lock.ino || !now3.isFile() || now3.isSymbolicLink())
|
|
103891
104711
|
fail3();
|
|
103892
104712
|
unlinkSync7(file2);
|
|
@@ -103938,15 +104758,15 @@ async function preparePrivatePublication(client2, sourceDirectory, recoveryDirec
|
|
|
103938
104758
|
phase: "prepared",
|
|
103939
104759
|
intent: null
|
|
103940
104760
|
};
|
|
103941
|
-
if (!
|
|
104761
|
+
if (!isAbsolute19(recoveryDirectory) || resolve20(recoveryDirectory) !== recoveryDirectory || realpathSync9(dirname24(recoveryDirectory)) !== dirname24(recoveryDirectory))
|
|
103942
104762
|
return fail3();
|
|
103943
104763
|
mkdirSync21(recoveryDirectory, { mode: 448 });
|
|
103944
104764
|
safeDirectory(recoveryDirectory);
|
|
103945
|
-
const parent =
|
|
104765
|
+
const parent = openSync18(dirname24(recoveryDirectory), constants17.O_RDONLY | constants17.O_NOFOLLOW);
|
|
103946
104766
|
try {
|
|
103947
|
-
|
|
104767
|
+
fsyncSync5(parent);
|
|
103948
104768
|
} finally {
|
|
103949
|
-
|
|
104769
|
+
closeSync18(parent);
|
|
103950
104770
|
}
|
|
103951
104771
|
writeOwned(recoveryDirectory, "bundle.tgz", packed.bytes);
|
|
103952
104772
|
save(recoveryDirectory, receipt);
|
|
@@ -104039,10 +104859,10 @@ var init_private_publication_recovery = __esm(() => {
|
|
|
104039
104859
|
});
|
|
104040
104860
|
|
|
104041
104861
|
// src/mcp/private-publication-tools.ts
|
|
104042
|
-
import { isAbsolute as
|
|
104862
|
+
import { isAbsolute as isAbsolute20 } from "path";
|
|
104043
104863
|
function registerPrivatePublicationTools(server) {
|
|
104044
104864
|
const uuid9 = exports_external.string().regex(/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/);
|
|
104045
|
-
const directory2 = exports_external.string().max(4096).refine(
|
|
104865
|
+
const directory2 = exports_external.string().max(4096).refine(isAbsolute20, "Use an absolute local directory");
|
|
104046
104866
|
const verification2 = { email: exports_external.string().email().max(254), code: exports_external.string().regex(/^\d{6}$/), userId: uuid9, membershipId: uuid9, recoveryDirectory: directory2 };
|
|
104047
104867
|
const description = "Manage a private source publication using fresh workspace-bound verification and a host-local recovery directory. Publishing requires explicit UUID current-version comparison and upload consent. Resume reuses immutable saved bytes and intent; an uncertain PUT is finalized for server verification, never uploaded twice. Sessions and signed URLs are not returned or persisted. Private execution is unavailable. Host request history may contain the supplied verification code.";
|
|
104048
104868
|
const handler = (action) => async (value) => {
|
|
@@ -104197,6 +105017,14 @@ function registerRemoteCustomerTools(server) {
|
|
|
104197
105017
|
});
|
|
104198
105018
|
}
|
|
104199
105019
|
for (const operation of REMOTE_CUSTOMER_OPERATIONS) {
|
|
105020
|
+
if (operation.name === "create_credit_checkout") {
|
|
105021
|
+
server.registerTool(operation.name, {
|
|
105022
|
+
title: operation.title,
|
|
105023
|
+
description: "Create one external checkout link on the selected Skills server. Retain an idempotency_key before calling and reuse it only for explicit recovery on the same server, account and pack. No automatic retries; payment requires customer confirmation.",
|
|
105024
|
+
inputSchema: { pack_id: exports_external.string().min(1), idempotency_key: exports_external.string().regex(/^[A-Za-z0-9._:-]{8,255}$/).optional() }
|
|
105025
|
+
}, ({ pack_id, idempotency_key }) => callRemote((client2) => operation.invoke(client2, pack_id, { idempotencyKey: idempotency_key })));
|
|
105026
|
+
continue;
|
|
105027
|
+
}
|
|
104200
105028
|
const inputSchema = {};
|
|
104201
105029
|
if (operation.parameter)
|
|
104202
105030
|
inputSchema[operation.parameter] = exports_external.string().min(1);
|
|
@@ -104273,6 +105101,15 @@ async function callRemote(action) {
|
|
|
104273
105101
|
return mcpError("AUTH_REQUIRED", "Configure a Skills API and sign in with skills auth login");
|
|
104274
105102
|
return mcpJson(await action(client2));
|
|
104275
105103
|
} catch (error61) {
|
|
105104
|
+
if (error61 instanceof RemoteCreditCheckoutError) {
|
|
105105
|
+
return { ...mcpJson({
|
|
105106
|
+
code: error61.code,
|
|
105107
|
+
message: error61.message,
|
|
105108
|
+
status: error61.status,
|
|
105109
|
+
requestIdempotencyKey: error61.requestIdempotencyKey,
|
|
105110
|
+
...error61.retryAfterSeconds === undefined ? {} : { retryAfterSeconds: error61.retryAfterSeconds }
|
|
105111
|
+
}), isError: true };
|
|
105112
|
+
}
|
|
104276
105113
|
if (error61 instanceof RemoteCapabilityUnavailableError) {
|
|
104277
105114
|
return { ...mcpJson({ code: error61.code, message: error61.message, status: error61.status }), isError: true };
|
|
104278
105115
|
}
|
|
@@ -104385,7 +105222,7 @@ var init_mcp2 = __esm(() => {
|
|
|
104385
105222
|
// src/cli/commands/runtime-mcp.ts
|
|
104386
105223
|
import { existsSync as existsSync32, mkdirSync as mkdirSync22, readFileSync as readFileSync34, writeFileSync as writeFileSync20 } from "fs";
|
|
104387
105224
|
import { homedir as homedir9 } from "os";
|
|
104388
|
-
import { dirname as
|
|
105225
|
+
import { dirname as dirname25, join as join51 } from "path";
|
|
104389
105226
|
async function handleMcp(options) {
|
|
104390
105227
|
if (options.register) {
|
|
104391
105228
|
let agents;
|
|
@@ -104559,7 +105396,7 @@ function writeJsonObject(path, data) {
|
|
|
104559
105396
|
`);
|
|
104560
105397
|
}
|
|
104561
105398
|
function writeTextFile(path, content) {
|
|
104562
|
-
mkdirSync22(
|
|
105399
|
+
mkdirSync22(dirname25(path), { recursive: true });
|
|
104563
105400
|
writeFileSync20(path, content.endsWith(`
|
|
104564
105401
|
`) ? content : `${content}
|
|
104565
105402
|
`);
|
|
@@ -104622,7 +105459,7 @@ function registerRemoteAccount(parent) {
|
|
|
104622
105459
|
billing.command("portal").option("--json", "Output as JSON", false).description("Create an external customer billing portal link").action((options) => execute(options, (client2) => client2.createBillingPortal()));
|
|
104623
105460
|
const credits = parent.command("credits").description("Inspect and purchase credits from the configured server");
|
|
104624
105461
|
credits.command("packs").option("--json", "Output as JSON", false).action((options) => execute(options, (client2) => client2.listCreditPacks()));
|
|
104625
|
-
credits.command("buy").argument("<pack-id>", "An ID returned by credits packs").option("--json", "Output as JSON", false).description("Create an external checkout link; payment is confirmed in the browser").action((packId, options) => execute(options, (client2) => client2.createCreditCheckout(packId)));
|
|
105462
|
+
credits.command("buy").argument("<pack-id>", "An ID returned by credits packs").option("--json", "Output as JSON", false).option("--idempotency-key <key>", "Retain and reuse this request key for explicit checkout recovery").description("Create an external checkout link; payment is confirmed in the browser. No automatic retries.").action((packId, options) => execute(options, (client2) => client2.createCreditCheckout(packId, { idempotencyKey: options.idempotencyKey })));
|
|
104626
105463
|
}
|
|
104627
105464
|
async function execute(options, action) {
|
|
104628
105465
|
try {
|
|
@@ -104633,6 +105470,23 @@ async function execute(options, action) {
|
|
|
104633
105470
|
console.log(JSON.stringify(result2, null, 2));
|
|
104634
105471
|
} catch (error61) {
|
|
104635
105472
|
const message = error61 instanceof Error ? error61.message : "The Skills server request failed";
|
|
105473
|
+
if (error61 instanceof RemoteCreditCheckoutError) {
|
|
105474
|
+
const result2 = {
|
|
105475
|
+
error: error61.message,
|
|
105476
|
+
code: error61.code,
|
|
105477
|
+
status: error61.status,
|
|
105478
|
+
requestIdempotencyKey: error61.requestIdempotencyKey,
|
|
105479
|
+
...error61.retryAfterSeconds === undefined ? {} : { retryAfterSeconds: error61.retryAfterSeconds }
|
|
105480
|
+
};
|
|
105481
|
+
if (options.json)
|
|
105482
|
+
console.log(JSON.stringify(result2));
|
|
105483
|
+
else
|
|
105484
|
+
console.error(`${error61.message}
|
|
105485
|
+
Request key: ${error61.requestIdempotencyKey}` + (error61.code === "CREDIT_CHECKOUT_UNCONFIRMED" || error61.code === "CREDIT_CHECKOUT_IN_PROGRESS" ? `
|
|
105486
|
+
For explicit recovery, pass this key with --idempotency-key. Keep the same server, account and pack.` : ""));
|
|
105487
|
+
process.exitCode = 1;
|
|
105488
|
+
return;
|
|
105489
|
+
}
|
|
104636
105490
|
if (options.json)
|
|
104637
105491
|
console.log(JSON.stringify({
|
|
104638
105492
|
error: message,
|
|
@@ -104652,9 +105506,9 @@ var exports_runtime = {};
|
|
|
104652
105506
|
__export(exports_runtime, {
|
|
104653
105507
|
registerRuntime: () => registerRuntime
|
|
104654
105508
|
});
|
|
104655
|
-
import { createHash as
|
|
104656
|
-
import { lstatSync as
|
|
104657
|
-
import { basename as
|
|
105509
|
+
import { createHash as createHash23, randomUUID as randomUUID9 } from "crypto";
|
|
105510
|
+
import { lstatSync as lstatSync25, mkdirSync as mkdirSync23, readFileSync as readFileSync35, realpathSync as realpathSync10, writeFileSync as writeFileSync21 } from "fs";
|
|
105511
|
+
import { basename as basename11, isAbsolute as isAbsolute21, join as join52 } from "path";
|
|
104658
105512
|
import { createInterface } from "readline";
|
|
104659
105513
|
function registerRuntime(parent) {
|
|
104660
105514
|
parent.command("run").argument("<skill>", "Skill name").argument("[args...]", "Arguments to pass to the skill; use -- to end Skills options").allowUnknownOption(true).passThroughOptions(true).option("--json", "Output result as JSON", false).option("--remote", "Run on the configured server, using its catalog and quote", false).option("--target <target>", "Execution target: local or cloud").option("--secret-bindings <path>", "Reviewed, exact-selection local execution vault bindings (JSON file)").option("--secret-bindings-template", "Print a scoped bindings template without resolving secrets or running the skill", false).option("--input <json>", "Structured cloud execution input").option("--skill-version <version>", "Exact selected skill version").option("--selection-profile <id>", "Selected Skills profile").option("--session <id>", "Pinned Skills session").option("--cached", "Use the explicit verified selected cache", false).option("--yes", "Approve the server's quoted credit cost for this run", false).option("--idempotency-key <key>", "Reuse this key when retrying the same remote submission").option("--file <path>", "Attach a local input file to a remote run (repeatable)", (value, prior) => [...prior, value], []).option("--wait", "Poll remote runs until a terminal status", false).option("--poll-interval-ms <ms>", "Remote polling interval in milliseconds", "1000").option("--poll-timeout-ms <ms>", "Maximum time to wait for a remote run", "300000").description("Run a skill directly").action(async (name, args2, options, command) => {
|
|
@@ -104684,7 +105538,7 @@ function registerRuntime(parent) {
|
|
|
104684
105538
|
if (!expected)
|
|
104685
105539
|
throw new Error("Cloud artifact not found");
|
|
104686
105540
|
const bytes = await client2.download(id2, name);
|
|
104687
|
-
if (bytes.length !== expected.byteSize ||
|
|
105541
|
+
if (bytes.length !== expected.byteSize || createHash23("sha256").update(bytes).digest("hex") !== expected.sha256)
|
|
104688
105542
|
throw new Error("Cloud artifact integrity verification failed");
|
|
104689
105543
|
writeFileSync21(options.output, bytes, { flag: "wx", mode: 384 });
|
|
104690
105544
|
console.log(JSON.stringify({ path: options.output, sha256: expected.sha256, byteSize: bytes.length }));
|
|
@@ -104772,7 +105626,7 @@ Updating ${name}...
|
|
|
104772
105626
|
async function readUpdatedVersion(bunExecutable) {
|
|
104773
105627
|
const output2 = await readUpdateCommand([bunExecutable, "pm", "bin", "-g"]);
|
|
104774
105628
|
const globalBin = output2.replace(/\r?\n$/, "");
|
|
104775
|
-
if (!globalBin || !
|
|
105629
|
+
if (!globalBin || !isAbsolute21(globalBin) || /[\r\n\0]/.test(globalBin))
|
|
104776
105630
|
throw new Error("Update bin discovery failed");
|
|
104777
105631
|
const installed = Bun.which("skills", { PATH: globalBin, cwd: globalBin });
|
|
104778
105632
|
const selected = Bun.which("skills");
|
|
@@ -104908,14 +105762,14 @@ function requireHttpUrl(value) {
|
|
|
104908
105762
|
}
|
|
104909
105763
|
function promptLine(question) {
|
|
104910
105764
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
104911
|
-
return new Promise((
|
|
105765
|
+
return new Promise((resolve21) => {
|
|
104912
105766
|
let settled = false;
|
|
104913
105767
|
const finish = (answer) => {
|
|
104914
105768
|
if (settled)
|
|
104915
105769
|
return;
|
|
104916
105770
|
settled = true;
|
|
104917
105771
|
rl.close();
|
|
104918
|
-
|
|
105772
|
+
resolve21(answer);
|
|
104919
105773
|
};
|
|
104920
105774
|
rl.once("SIGINT", () => finish(null));
|
|
104921
105775
|
rl.once("close", () => finish(null));
|
|
@@ -105092,10 +105946,10 @@ async function handleRun(name, args2, options, separatorBeforeSkill) {
|
|
|
105092
105946
|
try {
|
|
105093
105947
|
parsePollingOptions(options);
|
|
105094
105948
|
inputFiles = (options.file ?? []).map((path) => {
|
|
105095
|
-
const info =
|
|
105949
|
+
const info = lstatSync25(path);
|
|
105096
105950
|
if (!info.isFile() || info.size > 20 * 1024 * 1024)
|
|
105097
105951
|
throw new Error("Input must be a regular file no larger than 20 MiB");
|
|
105098
|
-
return { name:
|
|
105952
|
+
return { name: basename11(path), bytes: new Uint8Array(readFileSync35(path)) };
|
|
105099
105953
|
});
|
|
105100
105954
|
describeRemoteFiles(inputFiles);
|
|
105101
105955
|
client2 = new RemoteSkillsClient(routing.apiKey, routing.apiOrigin);
|
|
@@ -105522,7 +106376,7 @@ function ensureSafeExportParent(root2, relativePath) {
|
|
|
105522
106376
|
if (part)
|
|
105523
106377
|
parent = join52(parent, part);
|
|
105524
106378
|
try {
|
|
105525
|
-
if (!
|
|
106379
|
+
if (!lstatSync25(parent).isDirectory() || lstatSync25(parent).isSymbolicLink())
|
|
105526
106380
|
throw new Error("Unsafe artifact directory");
|
|
105527
106381
|
} catch (error61) {
|
|
105528
106382
|
if (error61.code !== "ENOENT")
|
|
@@ -105560,7 +106414,7 @@ async function pollRemoteRun(client2, runId2, options) {
|
|
|
105560
106414
|
const remaining = deadline - Date.now();
|
|
105561
106415
|
if (remaining <= 0)
|
|
105562
106416
|
break;
|
|
105563
|
-
await new Promise((
|
|
106417
|
+
await new Promise((resolve21) => setTimeout(resolve21, Math.min(options.intervalMs, remaining)));
|
|
105564
106418
|
}
|
|
105565
106419
|
return {
|
|
105566
106420
|
run: current ?? { id: runId2, status: "queued" },
|
|
@@ -105752,7 +106606,7 @@ async function readCode() {
|
|
|
105752
106606
|
function promptCode() {
|
|
105753
106607
|
const { stdin, stderr: output2 } = process;
|
|
105754
106608
|
const { isRaw: wasRaw, readableFlowing: wasFlowing } = stdin;
|
|
105755
|
-
return new Promise((
|
|
106609
|
+
return new Promise((resolve21) => {
|
|
105756
106610
|
let value = "", settled = false;
|
|
105757
106611
|
const finish = (answer) => {
|
|
105758
106612
|
if (settled)
|
|
@@ -105769,7 +106623,7 @@ function promptCode() {
|
|
|
105769
106623
|
`);
|
|
105770
106624
|
if (answer === null)
|
|
105771
106625
|
process.exitCode = 130;
|
|
105772
|
-
|
|
106626
|
+
resolve21(answer);
|
|
105773
106627
|
};
|
|
105774
106628
|
const cancel = () => finish(null);
|
|
105775
106629
|
const keypress = (text3, key) => {
|
|
@@ -105814,37 +106668,37 @@ var exports_recurring = {};
|
|
|
105814
106668
|
__export(exports_recurring, {
|
|
105815
106669
|
registerRecurringCommands: () => registerRecurringCommands
|
|
105816
106670
|
});
|
|
105817
|
-
import { constants as
|
|
106671
|
+
import { constants as constants18, closeSync as closeSync19, fstatSync as fstatSync19, lstatSync as lstatSync26, openSync as openSync19, readSync as readSync15 } from "fs";
|
|
105818
106672
|
import { createInterface as createInterface2 } from "readline";
|
|
105819
106673
|
function readRequest(path) {
|
|
105820
|
-
const fd =
|
|
106674
|
+
const fd = openSync19(path, constants18.O_RDONLY | constants18.O_NOFOLLOW | constants18.O_NONBLOCK);
|
|
105821
106675
|
try {
|
|
105822
|
-
const before2 =
|
|
106676
|
+
const before2 = fstatSync19(fd);
|
|
105823
106677
|
if (!before2.isFile() || before2.size > 1048576 || before2.size < 1)
|
|
105824
106678
|
throw new RecurringInputError;
|
|
105825
106679
|
const bytes = Buffer.alloc(before2.size + 1);
|
|
105826
106680
|
let length = 0;
|
|
105827
106681
|
while (length < bytes.length) {
|
|
105828
|
-
const n2 =
|
|
106682
|
+
const n2 = readSync15(fd, bytes, length, bytes.length - length, length);
|
|
105829
106683
|
if (!n2)
|
|
105830
106684
|
break;
|
|
105831
106685
|
length += n2;
|
|
105832
106686
|
}
|
|
105833
|
-
const after2 =
|
|
106687
|
+
const after2 = fstatSync19(fd), current = lstatSync26(path);
|
|
105834
106688
|
if (length !== before2.size || after2.size !== before2.size || before2.mtimeMs !== after2.mtimeMs || before2.ctimeMs !== after2.ctimeMs || current.dev !== before2.dev || current.ino !== before2.ino || !current.isFile() || current.isSymbolicLink())
|
|
105835
106689
|
throw new RecurringInputError;
|
|
105836
106690
|
return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(0, length)));
|
|
105837
106691
|
} catch {
|
|
105838
106692
|
throw new RecurringInputError;
|
|
105839
106693
|
} finally {
|
|
105840
|
-
|
|
106694
|
+
closeSync19(fd);
|
|
105841
106695
|
}
|
|
105842
106696
|
}
|
|
105843
106697
|
async function acceptAtTerminal(draft) {
|
|
105844
|
-
await new Promise((
|
|
106698
|
+
await new Promise((resolve21, reject2) => process.stderr.write(`${jsonText(draft)}
|
|
105845
106699
|
This grants an additional recurring budget. Each occurrence reprices within the approved ceilings. Revocation prevents new authority; an already-authorized attempt may finish, and cancellation is separate.
|
|
105846
|
-
`, (error61) => error61 ? reject2(error61) :
|
|
105847
|
-
return new Promise((
|
|
106700
|
+
`, (error61) => error61 ? reject2(error61) : resolve21()));
|
|
106701
|
+
return new Promise((resolve21) => {
|
|
105848
106702
|
const rl = createInterface2({ input: process.stdin, output: process.stderr });
|
|
105849
106703
|
let settled = false;
|
|
105850
106704
|
const finish = (accepted) => {
|
|
@@ -105855,7 +106709,7 @@ This grants an additional recurring budget. Each occurrence reprices within the
|
|
|
105855
106709
|
rl.close();
|
|
105856
106710
|
if (!accepted)
|
|
105857
106711
|
process.exitCode = 130;
|
|
105858
|
-
|
|
106712
|
+
resolve21(accepted);
|
|
105859
106713
|
};
|
|
105860
106714
|
const timer = setTimeout(() => finish(false), 5 * 60 * 1000);
|
|
105861
106715
|
rl.once("SIGINT", () => finish(false));
|
|
@@ -106263,7 +107117,7 @@ var init_portable_snapshot_filter = __esm(() => {
|
|
|
106263
107117
|
});
|
|
106264
107118
|
|
|
106265
107119
|
// src/lib/station-snapshot.ts
|
|
106266
|
-
import { createHash as
|
|
107120
|
+
import { createHash as createHash24 } from "crypto";
|
|
106267
107121
|
import {
|
|
106268
107122
|
copyFileSync,
|
|
106269
107123
|
mkdirSync as mkdirSync24,
|
|
@@ -106271,14 +107125,14 @@ import {
|
|
|
106271
107125
|
statSync as statSync19,
|
|
106272
107126
|
writeFileSync as writeFileSync22
|
|
106273
107127
|
} from "fs";
|
|
106274
|
-
import { dirname as
|
|
107128
|
+
import { dirname as dirname27, isAbsolute as isAbsolute22, relative as relative8, resolve as resolve21, sep as sep9 } from "path";
|
|
106275
107129
|
function validateStationId(stationId) {
|
|
106276
107130
|
if (!/^[a-z0-9-]+$/.test(stationId)) {
|
|
106277
107131
|
throw new StationSnapshotError("INVALID_STATION", `station id must be a slug, got: ${stationId}`);
|
|
106278
107132
|
}
|
|
106279
107133
|
}
|
|
106280
107134
|
function sha256File(filePath) {
|
|
106281
|
-
return
|
|
107135
|
+
return createHash24("sha256").update(readFileSync36(filePath)).digest("hex");
|
|
106282
107136
|
}
|
|
106283
107137
|
function scanHome(definition, homesRoot) {
|
|
106284
107138
|
const homePath = homePathFor(definition, homesRoot);
|
|
@@ -106349,7 +107203,7 @@ function humanHomes(scanned) {
|
|
|
106349
107203
|
}));
|
|
106350
107204
|
}
|
|
106351
107205
|
function writeStationSnapshot(options) {
|
|
106352
|
-
const repoRoot =
|
|
107206
|
+
const repoRoot = resolve21(options.repoRoot ?? process.cwd());
|
|
106353
107207
|
const { scanned, plans, totalBytes } = planStationSnapshot(options);
|
|
106354
107208
|
const manifestFiles = plans.map((plan) => ({
|
|
106355
107209
|
relativePath: plan.source.relativePath,
|
|
@@ -106375,9 +107229,9 @@ function writeStationSnapshot(options) {
|
|
|
106375
107229
|
const conflicts = [];
|
|
106376
107230
|
const untouched = [];
|
|
106377
107231
|
for (const plan of plans) {
|
|
106378
|
-
const destination =
|
|
107232
|
+
const destination = resolve21(repoRoot, plan.destination);
|
|
106379
107233
|
const destinationRelative = relative8(repoRoot, destination);
|
|
106380
|
-
if (destinationRelative.startsWith("..") || destinationRelative.startsWith(sep9) ||
|
|
107234
|
+
if (destinationRelative.startsWith("..") || destinationRelative.startsWith(sep9) || isAbsolute22(destinationRelative)) {
|
|
106381
107235
|
throw new StationSnapshotError("DESTINATION_ESCAPE", `destination escapes repo root: ${plan.destination}`);
|
|
106382
107236
|
}
|
|
106383
107237
|
let existingDigest = null;
|
|
@@ -106398,8 +107252,8 @@ function writeStationSnapshot(options) {
|
|
|
106398
107252
|
}
|
|
106399
107253
|
let written = 0;
|
|
106400
107254
|
for (const plan of untouched) {
|
|
106401
|
-
const destination =
|
|
106402
|
-
mkdirSync24(
|
|
107255
|
+
const destination = resolve21(repoRoot, plan.destination);
|
|
107256
|
+
mkdirSync24(dirname27(destination), { recursive: true });
|
|
106403
107257
|
copyFileSync(plan.source.fullPath, destination);
|
|
106404
107258
|
written += 1;
|
|
106405
107259
|
}
|
|
@@ -106417,8 +107271,8 @@ function writeStationSnapshot(options) {
|
|
|
106417
107271
|
},
|
|
106418
107272
|
files: manifestFiles
|
|
106419
107273
|
};
|
|
106420
|
-
const manifestPath =
|
|
106421
|
-
mkdirSync24(
|
|
107274
|
+
const manifestPath = resolve21(repoRoot, "resources", options.stationId, "skills", "sync-manifest.json");
|
|
107275
|
+
mkdirSync24(dirname27(manifestPath), { recursive: true });
|
|
106422
107276
|
writeFileSync22(manifestPath, `${JSON.stringify(manifest, null, 2)}
|
|
106423
107277
|
`);
|
|
106424
107278
|
return {
|
|
@@ -106852,10 +107706,10 @@ var init_create_sync_config = __esm(() => {
|
|
|
106852
107706
|
// src/lib/codex-hook-rpc.ts
|
|
106853
107707
|
import { execFile, spawn as spawn3 } from "child_process";
|
|
106854
107708
|
import { realpathSync as realpathSync11, statSync as statSync20 } from "fs";
|
|
106855
|
-
import { isAbsolute as
|
|
107709
|
+
import { isAbsolute as isAbsolute23 } from "path";
|
|
106856
107710
|
import { promisify } from "util";
|
|
106857
107711
|
async function connectCodexHookRpc(options) {
|
|
106858
|
-
const found =
|
|
107712
|
+
const found = isAbsolute23(options.command) ? options.command : Bun.which(options.command, { PATH: process.env.PATH });
|
|
106859
107713
|
if (!found)
|
|
106860
107714
|
throw new Error("CODEX_HOOK_TRUST_NATIVE_UNAVAILABLE: install Codex or pass --codex-command");
|
|
106861
107715
|
const binary = realpathSync11(found), stat3 = statSync20(binary);
|
|
@@ -106941,13 +107795,13 @@ async function connectCodexHookRpc(options) {
|
|
|
106941
107795
|
request(method2, params) {
|
|
106942
107796
|
if (stopped)
|
|
106943
107797
|
return Promise.reject(new Error("CODEX_HOOK_TRUST_NATIVE_RPC_CLOSED"));
|
|
106944
|
-
return new Promise((
|
|
107798
|
+
return new Promise((resolve22, reject2) => {
|
|
106945
107799
|
const id2 = nextId++;
|
|
106946
107800
|
const timer = setTimeout(() => {
|
|
106947
107801
|
fail4();
|
|
106948
107802
|
child.kill();
|
|
106949
107803
|
}, 20000);
|
|
106950
|
-
pending.set(id2, { resolve:
|
|
107804
|
+
pending.set(id2, { resolve: resolve22, reject: reject2, timer });
|
|
106951
107805
|
child.stdin.write(JSON.stringify({ id: id2, method: method2, params }) + `
|
|
106952
107806
|
`);
|
|
106953
107807
|
});
|
|
@@ -106957,14 +107811,14 @@ async function connectCodexHookRpc(options) {
|
|
|
106957
107811
|
child.stdin.end();
|
|
106958
107812
|
if (child.exitCode !== null || child.signalCode !== null)
|
|
106959
107813
|
return;
|
|
106960
|
-
await new Promise((
|
|
107814
|
+
await new Promise((resolve22) => {
|
|
106961
107815
|
const timer = setTimeout(() => {
|
|
106962
107816
|
child.kill();
|
|
106963
|
-
|
|
107817
|
+
resolve22();
|
|
106964
107818
|
}, 1000);
|
|
106965
107819
|
child.once("exit", () => {
|
|
106966
107820
|
clearTimeout(timer);
|
|
106967
|
-
|
|
107821
|
+
resolve22();
|
|
106968
107822
|
});
|
|
106969
107823
|
});
|
|
106970
107824
|
}
|
|
@@ -106985,7 +107839,7 @@ var init_codex_hook_rpc = __esm(() => {
|
|
|
106985
107839
|
});
|
|
106986
107840
|
|
|
106987
107841
|
// src/lib/codex-hook-trust-layout.ts
|
|
106988
|
-
import { isDeepStrictEqual as
|
|
107842
|
+
import { isDeepStrictEqual as isDeepStrictEqual5 } from "util";
|
|
106989
107843
|
function codexTrustTextWitness(text3, keys3) {
|
|
106990
107844
|
const parsed = Bun.TOML.parse(text3), wanted = new Set(keys3);
|
|
106991
107845
|
const headers = [...text3.matchAll(/^[ \t]*(\[[^\r\n]+\])[ \t]*(#[^\r\n]*)?(?:\r?\n|$)/gm)];
|
|
@@ -107032,11 +107886,11 @@ function codexTrustTextWitness(text3, keys3) {
|
|
|
107032
107886
|
comments.push(line);
|
|
107033
107887
|
continue;
|
|
107034
107888
|
}
|
|
107035
|
-
const
|
|
107036
|
-
if (!
|
|
107889
|
+
const field2 = /^[ \t]*(?:enabled|trusted_hash)[ \t]*=[ \t]*(?:true|false|"(?:[^"\\]|\\.)*"|'[^']*')[ \t]*(#[^\r\n]*)?$/.exec(line);
|
|
107890
|
+
if (!field2)
|
|
107037
107891
|
throw fail4();
|
|
107038
|
-
if (
|
|
107039
|
-
comments.push(
|
|
107892
|
+
if (field2[1])
|
|
107893
|
+
comments.push(field2[1]);
|
|
107040
107894
|
}
|
|
107041
107895
|
replacements2.push({ start, end, comments: comments.join(`
|
|
107042
107896
|
`) + `
|
|
@@ -107050,7 +107904,7 @@ function codexTrustTextWitness(text3, keys3) {
|
|
|
107050
107904
|
if (expected.hooks)
|
|
107051
107905
|
delete expected.hooks.state;
|
|
107052
107906
|
try {
|
|
107053
|
-
if (!
|
|
107907
|
+
if (!isDeepStrictEqual5(prune(Bun.TOML.parse(noState)), prune(expected)))
|
|
107054
107908
|
throw fail4();
|
|
107055
107909
|
} catch {
|
|
107056
107910
|
throw fail4();
|
|
@@ -107071,59 +107925,59 @@ var fail4 = () => new Error('CODEX_HOOK_TRUST_UNSUPPORTED_LAYOUT: preserve and c
|
|
|
107071
107925
|
var init_codex_hook_trust_layout = () => {};
|
|
107072
107926
|
|
|
107073
107927
|
// src/lib/codex-hook-trust-files.ts
|
|
107074
|
-
import { closeSync as
|
|
107075
|
-
import { createHash as
|
|
107076
|
-
import { dirname as
|
|
107077
|
-
function
|
|
107928
|
+
import { closeSync as closeSync20, constants as constants19, fstatSync as fstatSync20, fsyncSync as fsyncSync6, lstatSync as lstatSync27, openSync as openSync20, readSync as readSync16, writeFileSync as writeFileSync23 } from "fs";
|
|
107929
|
+
import { createHash as createHash25 } from "crypto";
|
|
107930
|
+
import { dirname as dirname28 } from "path";
|
|
107931
|
+
function need4(value, code2) {
|
|
107078
107932
|
if (!value)
|
|
107079
107933
|
throw new Error(`CODEX_HOOK_TRUST_${code2}`);
|
|
107080
107934
|
}
|
|
107081
107935
|
function safeParents(file2) {
|
|
107082
|
-
for (let p =
|
|
107083
|
-
const s =
|
|
107084
|
-
|
|
107085
|
-
|
|
107086
|
-
if (
|
|
107936
|
+
for (let p = dirname28(file2);; p = dirname28(p)) {
|
|
107937
|
+
const s = lstatSync27(p);
|
|
107938
|
+
need4(s.isDirectory() && !s.isSymbolicLink(), "UNSAFE_PARENT");
|
|
107939
|
+
need4((s.mode & 18) === 0 || s.uid === 0 && (s.mode & 512) !== 0, "UNSAFE_PARENT");
|
|
107940
|
+
if (dirname28(p) === p)
|
|
107087
107941
|
break;
|
|
107088
107942
|
}
|
|
107089
107943
|
}
|
|
107090
107944
|
function snapshot(file2, privateFile = false, options = {}) {
|
|
107091
107945
|
const readOnlyPackage = options.readOnlyPackage === true && !privateFile;
|
|
107092
107946
|
safeParents(file2);
|
|
107093
|
-
const initial2 =
|
|
107094
|
-
|
|
107095
|
-
|
|
107096
|
-
const fd =
|
|
107947
|
+
const initial2 = lstatSync27(file2, { bigint: true });
|
|
107948
|
+
need4(initial2.isFile() && initial2.uid === BigInt(process.getuid()) && (initial2.nlink === 1n || readOnlyPackage && initial2.nlink > 1n) && (initial2.mode & 0o022n) === 0n && (!privateFile || (initial2.mode & 0o777n) === 0o600n), "UNSAFE_FILE");
|
|
107949
|
+
need4(initial2.size <= 8n * 1024n * 1024n, "FILE_BOUND");
|
|
107950
|
+
const fd = openSync20(file2, constants19.O_RDONLY | constants19.O_NOFOLLOW | constants19.O_NONBLOCK);
|
|
107097
107951
|
try {
|
|
107098
|
-
const before2 =
|
|
107099
|
-
|
|
107952
|
+
const before2 = fstatSync20(fd, { bigint: true });
|
|
107953
|
+
need4(sameStat(initial2, before2), "INPUT_CHANGED");
|
|
107100
107954
|
const bytes = Buffer.alloc(Number(before2.size) + 1);
|
|
107101
107955
|
let length = 0;
|
|
107102
107956
|
while (length < bytes.length) {
|
|
107103
|
-
const n2 =
|
|
107957
|
+
const n2 = readSync16(fd, bytes, length, bytes.length - length, null);
|
|
107104
107958
|
if (!n2)
|
|
107105
107959
|
break;
|
|
107106
107960
|
length += n2;
|
|
107107
107961
|
}
|
|
107108
|
-
|
|
107962
|
+
need4(length === Number(before2.size) && sameStat(before2, fstatSync20(fd, { bigint: true })) && sameStat(before2, lstatSync27(file2, { bigint: true })), "INPUT_CHANGED");
|
|
107109
107963
|
const content = bytes.subarray(0, length), text3 = new TextDecoder("utf-8", { fatal: true }).decode(content);
|
|
107110
|
-
return { file: file2, privateFile, readOnlyPackage, text: text3, bytes: content, stat: before2, sha256:
|
|
107964
|
+
return { file: file2, privateFile, readOnlyPackage, text: text3, bytes: content, stat: before2, sha256: createHash25("sha256").update(content).digest("hex") };
|
|
107111
107965
|
} finally {
|
|
107112
|
-
|
|
107966
|
+
closeSync20(fd);
|
|
107113
107967
|
}
|
|
107114
107968
|
}
|
|
107115
107969
|
function unchanged2(before2) {
|
|
107116
107970
|
const after2 = snapshot(before2.file, before2.privateFile, before2.readOnlyPackage ? { readOnlyPackage: true } : {});
|
|
107117
|
-
|
|
107971
|
+
need4(sameStat(before2.stat, after2.stat) && after2.sha256 === before2.sha256, "INPUT_CHANGED");
|
|
107118
107972
|
}
|
|
107119
107973
|
function save2(file2, content) {
|
|
107120
107974
|
safeParents(file2);
|
|
107121
|
-
const fd =
|
|
107975
|
+
const fd = openSync20(file2, constants19.O_WRONLY | constants19.O_CREAT | constants19.O_EXCL | constants19.O_NOFOLLOW, 384);
|
|
107122
107976
|
try {
|
|
107123
107977
|
writeFileSync23(fd, content);
|
|
107124
|
-
|
|
107978
|
+
fsyncSync6(fd);
|
|
107125
107979
|
} finally {
|
|
107126
|
-
|
|
107980
|
+
closeSync20(fd);
|
|
107127
107981
|
}
|
|
107128
107982
|
}
|
|
107129
107983
|
var sameStat = (a, b) => ["dev", "ino", "uid", "nlink", "mode", "size", "mtimeNs", "ctimeNs"].every((key) => a[key] === b[key]);
|
|
@@ -107131,26 +107985,26 @@ var init_codex_hook_trust_files = () => {};
|
|
|
107131
107985
|
|
|
107132
107986
|
// src/lib/codex-hook-trust-identity.ts
|
|
107133
107987
|
import { realpathSync as realpathSync12 } from "fs";
|
|
107134
|
-
import { dirname as
|
|
107988
|
+
import { dirname as dirname29, isAbsolute as isAbsolute24, join as join55 } from "path";
|
|
107135
107989
|
function bindSkillsCli(command, reviewed) {
|
|
107136
107990
|
const normal = Bun.which("skills", { PATH: process.env.PATH });
|
|
107137
|
-
|
|
107991
|
+
need4(normal, "SKILLS_COMMAND_UNAVAILABLE");
|
|
107138
107992
|
const resolved = realpathSync12(normal);
|
|
107139
|
-
const bound =
|
|
107140
|
-
|
|
107993
|
+
const bound = isAbsolute24(command) ? command : command === "skills" ? normal : undefined;
|
|
107994
|
+
need4(bound && realpathSync12(bound) === resolved, "SKILLS_COMMAND_MISMATCH");
|
|
107141
107995
|
const entrypoint = reviewed?.path ?? process.argv[1];
|
|
107142
|
-
|
|
107996
|
+
need4(entrypoint && realpathSync12(entrypoint) === resolved, "SKILLS_ENTRYPOINT_MISMATCH");
|
|
107143
107997
|
const cli = snapshot(resolved, false, { readOnlyPackage: true });
|
|
107144
|
-
const manifest = snapshot(join55(
|
|
107998
|
+
const manifest = snapshot(join55(dirname29(dirname29(resolved)), "package.json"), false, { readOnlyPackage: true });
|
|
107145
107999
|
const pkg = JSON.parse(manifest.text);
|
|
107146
|
-
|
|
108000
|
+
need4(pkg.name === "@hasna/skills" && /^\d+\.\d+\.\d+$/.test(pkg.version) && pkg.bin?.skills === "bin/index.js" && resolved === join55(dirname29(manifest.file), "bin/index.js"), "SKILLS_PACKAGE_MISMATCH");
|
|
107147
108001
|
if (reviewed)
|
|
107148
|
-
|
|
107149
|
-
|
|
108002
|
+
need4(/^[a-f0-9]{64}$/.test(reviewed.sha256) && reviewed.sha256 === cli.sha256 && reviewed.version === pkg.version, "SKILLS_RELEASE_MISMATCH");
|
|
108003
|
+
need4((cli.stat.mode & 0o100n) !== 0n, "SKILLS_COMMAND_NOT_EXECUTABLE");
|
|
107150
108004
|
return {
|
|
107151
108005
|
receipt: { path: resolved, version: pkg.version, sha256: cli.sha256, manifestSha256: manifest.sha256 },
|
|
107152
108006
|
recheck() {
|
|
107153
|
-
|
|
108007
|
+
need4(Bun.which("skills", { PATH: process.env.PATH }) === normal && realpathSync12(normal) === resolved && realpathSync12(bound) === resolved && realpathSync12(entrypoint) === resolved, "SKILLS_COMMAND_CHANGED");
|
|
107154
108008
|
unchanged2(cli);
|
|
107155
108009
|
unchanged2(manifest);
|
|
107156
108010
|
}
|
|
@@ -107161,15 +108015,15 @@ var init_codex_hook_trust_identity = __esm(() => {
|
|
|
107161
108015
|
});
|
|
107162
108016
|
|
|
107163
108017
|
// src/lib/agent-codex-trust.ts
|
|
107164
|
-
import { lstatSync as
|
|
107165
|
-
import { createHash as
|
|
107166
|
-
import { join as join56, resolve as
|
|
108018
|
+
import { lstatSync as lstatSync28, mkdirSync as mkdirSync25, readdirSync as readdirSync20 } from "fs";
|
|
108019
|
+
import { createHash as createHash26, randomUUID as randomUUID10 } from "crypto";
|
|
108020
|
+
import { join as join56, resolve as resolve22 } from "path";
|
|
107167
108021
|
import { homedir as homedir11 } from "os";
|
|
107168
|
-
import { isDeepStrictEqual as
|
|
108022
|
+
import { isDeepStrictEqual as isDeepStrictEqual6 } from "util";
|
|
107169
108023
|
async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRpc) {
|
|
107170
108024
|
let rpc, journal;
|
|
107171
108025
|
try {
|
|
107172
|
-
const home =
|
|
108026
|
+
const home = resolve22(options.home ?? homedir11()), dataDir3 = resolve22(options.dataDir ?? getDataDirReadOnly());
|
|
107173
108027
|
assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home });
|
|
107174
108028
|
const policyFile = snapshot(join56(dataDir3, "agent-policy.json"), true), policy = parseManagedSkillPolicy(policyFile.text);
|
|
107175
108029
|
const binding = policy.bridge, alias = binding.rootAliases?.find((item) => item.agent === "codex");
|
|
@@ -107180,35 +108034,35 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
|
|
|
107180
108034
|
for (const [event, [nativeEvent, label]] of Object.entries(eventNames)) {
|
|
107181
108035
|
const command = renderAgentHookCommand(binding.commands.codex, "codex", binding.profiles.codex, event);
|
|
107182
108036
|
const groups = declarations[event];
|
|
107183
|
-
|
|
108037
|
+
need4(Array.isArray(groups), "DECLARATION_CHANGED");
|
|
107184
108038
|
const matches2 = groups.flatMap((group, gi) => (group.hooks ?? []).flatMap((entry, hi) => entry.command === command ? [{ group, entry, gi, hi }] : []));
|
|
107185
|
-
|
|
108039
|
+
need4(matches2.length === 1 && isDeepStrictEqual6(matches2[0].group, { hooks: [{ type: "command", command, timeout: 15 }] }), "DECLARATION_CHANGED");
|
|
107186
108040
|
expected.push({ event: nativeEvent, key: `${join56(home, ".codex/hooks.json")}:${label}:${matches2[0].gi}:${matches2[0].hi}`, command });
|
|
107187
108041
|
}
|
|
107188
108042
|
codexTrustTextWitness(configFile.text, expected.map((h) => h.key));
|
|
107189
108043
|
rpc = await connect({ command: options.codexCommand ?? "codex", home, codexHome });
|
|
107190
|
-
|
|
108044
|
+
need4(SUPPORTED_CODEX_HOOK_VERSIONS.includes(rpc.version), "NATIVE_UNSUPPORTED_VERSION");
|
|
107191
108045
|
const list2 = async () => {
|
|
107192
108046
|
const response = await rpc.request("hooks/list", { cwds: [home] });
|
|
107193
|
-
|
|
108047
|
+
need4(Array.isArray(response?.data) && response.data.length === 1 && response.data[0].cwd === home && Array.isArray(response.data[0].hooks) && response.data[0].hooks.length <= 1e4 && !response.data[0].errors?.length && !response.data[0].warnings?.length, "NATIVE_DISCOVERY_REFUSED");
|
|
107194
108048
|
return response.data[0].hooks;
|
|
107195
108049
|
};
|
|
107196
108050
|
const admit = (hooks) => expected.map((wanted) => {
|
|
107197
108051
|
const canonicalKey = wanted.key.replace(join56(home, ".codex/hooks.json"), hooksPath);
|
|
107198
108052
|
const matches2 = hooks.filter((h2) => h2.key === wanted.key || h2.key === canonicalKey);
|
|
107199
|
-
|
|
108053
|
+
need4(matches2.length === 1, "AMBIGUOUS_IDENTITY");
|
|
107200
108054
|
const h = matches2[0];
|
|
107201
|
-
|
|
107202
|
-
|
|
107203
|
-
|
|
108055
|
+
need4(h.eventName === wanted.event && h.handlerType === "command" && h.command === wanted.command && h.matcher === null && h.timeoutSec === 15 && h.async === false && h.statusMessage === null && h.additionalContextLimit === null && [hooksPath, join56(home, ".codex/hooks.json")].includes(h.sourcePath) && h.source === "user" && h.pluginId === null && h.isManaged === false && /^sha256:[a-f0-9]{64}$/.test(h.currentHash) && typeof h.enabled === "boolean", "NATIVE_IDENTITY_CHANGED");
|
|
108056
|
+
need4(hooks.filter((other) => other.command === wanted.command).length === 1, "AMBIGUOUS_IDENTITY");
|
|
108057
|
+
need4(["trusted", "untrusted", "modified"].includes(h.trustStatus), "UNKNOWN_TRUST_STATUS");
|
|
107204
108058
|
return { key: h.key, event: wanted.event, command: wanted.command, handlerType: h.handlerType, timeoutSec: h.timeoutSec, sourcePath: h.sourcePath, currentHash: h.currentHash, enabled: h.enabled, trustStatus: h.trustStatus };
|
|
107205
108059
|
});
|
|
107206
108060
|
const discovered = await list2(), admitted = admit(discovered);
|
|
107207
108061
|
const config2 = await rpc.request("config/read", { includeLayers: true, cwd: home });
|
|
107208
108062
|
const layers = config2?.layers?.filter((layer) => layer.name?.type === "user" && layer.name.file === configPath && !layer.name.profile);
|
|
107209
|
-
|
|
107210
|
-
|
|
107211
|
-
|
|
108063
|
+
need4(layers?.length === 1 && /^sha256:[a-f0-9]{64}$/.test(layers[0].version) && !layers[0].disabledReason && isDeepStrictEqual6(layers[0].config, original), "NATIVE_CONFIG_MISMATCH");
|
|
108064
|
+
need4(config2.config && config2.config.features?.hooks !== false, "NATIVE_HOOKS_DISABLED");
|
|
108065
|
+
need4(config2.layers.slice(0, config2.layers.indexOf(layers[0])).every((layer) => layer.config?.hooks === undefined && layer.config?.features?.hooks === undefined), "NATIVE_CONFIG_OVERRIDDEN");
|
|
107212
108066
|
const keys3 = admitted.map((h) => h.key), planned = admitted.filter((h) => !h.enabled || h.trustStatus !== "trusted");
|
|
107213
108067
|
const preservationText = codexTrustTextWitness(configFile.text, keys3);
|
|
107214
108068
|
const checkInputs = () => {
|
|
@@ -107219,19 +108073,19 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
|
|
|
107219
108073
|
unchanged2(configFile);
|
|
107220
108074
|
};
|
|
107221
108075
|
checkInputs();
|
|
107222
|
-
const planDigest =
|
|
108076
|
+
const planDigest = createHash26("sha256").update(json2({ version: 1, home, configPath, configSha256: configFile.sha256, configVersion: layers[0].version, policySha256: policyFile.sha256, hooksSha256: hooksFile.sha256, skillsCli: skillsCli.receipt, nativeVersion: rpc.version, declarations: expected, admitted })).digest("hex");
|
|
107223
108077
|
const baseReceipt = { planDigest, skillsCli: skillsCli.receipt, nativeVersion: rpc.version, ownedNativeProcessId: rpc.processId, agent: "codex", applied: false, planned, nativeEligible: planned.length === 0, transport: "owned-stdio-process", existingSessionsReloaded: false, nativeExecutionVerified: false };
|
|
107224
108078
|
if (options.apply)
|
|
107225
|
-
|
|
108079
|
+
need4(options.reviewedPlanDigest === planDigest, "PLAN_CHANGED: run the dry-run again and pass its reviewed --plan-digest with --apply");
|
|
107226
108080
|
const parent = join56(dataDir3, "native-hook-trust");
|
|
107227
|
-
const st =
|
|
108081
|
+
const st = lstatSync28(parent, { throwIfNoEntry: false });
|
|
107228
108082
|
if (st) {
|
|
107229
|
-
|
|
108083
|
+
need4(st.isDirectory() && !st.isSymbolicLink() && st.uid === process.getuid() && (st.mode & 511) === 448, "UNSAFE_JOURNAL");
|
|
107230
108084
|
const priorJournals = readdirSync20(parent);
|
|
107231
|
-
|
|
108085
|
+
need4(priorJournals.length < 1000, "JOURNAL_BOUND");
|
|
107232
108086
|
for (const name of priorJournals) {
|
|
107233
|
-
|
|
107234
|
-
|
|
108087
|
+
need4(/^[a-f0-9-]{36}$/.test(name), "UNSAFE_JOURNAL");
|
|
108088
|
+
need4(lstatSync28(join56(parent, name, "receipt.json"), { throwIfNoEntry: false })?.isFile(), "RECONCILE_REQUIRED: inspect the incomplete private journal before applying again");
|
|
107235
108089
|
}
|
|
107236
108090
|
}
|
|
107237
108091
|
if (!options.apply || !planned.length)
|
|
@@ -107244,7 +108098,7 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
|
|
|
107244
108098
|
save2(join56(journal, "hooks.before.json"), hooksFile.bytes);
|
|
107245
108099
|
save2(join56(journal, "policy.before.json"), policyFile.bytes);
|
|
107246
108100
|
save2(join56(journal, "intent.json"), json2({ version: 1, planDigest, skillsCli: skillsCli.receipt, nativeVersion: rpc.version, configPath, beforeSha256: configFile.sha256, hooksSha256: hooksFile.sha256, policySha256: policyFile.sha256, expectedVersion: layers[0].version, hooks: planned }));
|
|
107247
|
-
|
|
108101
|
+
need4(isDeepStrictEqual6(admit(await list2()), admitted), "NATIVE_DISCOVERY_CHANGED");
|
|
107248
108102
|
checkInputs();
|
|
107249
108103
|
let result2;
|
|
107250
108104
|
try {
|
|
@@ -107252,19 +108106,19 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
|
|
|
107252
108106
|
} catch {
|
|
107253
108107
|
throw new Error("CODEX_HOOK_TRUST_NATIVE_WRITE_FAILED: reconcile the private journal before retrying");
|
|
107254
108108
|
}
|
|
107255
|
-
|
|
108109
|
+
need4(result2?.status === "ok" && result2.filePath === configPath && /^sha256:[a-f0-9]{64}$/.test(result2.version), "NATIVE_WRITE_OVERRIDDEN");
|
|
107256
108110
|
const after2 = snapshot(configPath, true), expectedConfig = structuredClone(original);
|
|
107257
108111
|
expectedConfig.hooks ??= {};
|
|
107258
108112
|
expectedConfig.hooks.state ??= {};
|
|
107259
108113
|
for (const h of planned)
|
|
107260
108114
|
expectedConfig.hooks.state[h.key] = { ...expectedConfig.hooks.state[h.key], enabled: true, trusted_hash: h.currentHash };
|
|
107261
|
-
|
|
108115
|
+
need4(isDeepStrictEqual6(structure(after2.text), expectedConfig) && codexTrustTextWitness(after2.text, keys3) === preservationText, "PRESERVATION_FAILED");
|
|
107262
108116
|
unchanged2(policyFile);
|
|
107263
108117
|
unchanged2(hooksFile);
|
|
107264
108118
|
assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home });
|
|
107265
108119
|
const current = await list2(), confirmed = admit(current);
|
|
107266
|
-
|
|
107267
|
-
|
|
108120
|
+
need4(confirmed.every((h) => h.enabled && h.trustStatus === "trusted") && isDeepStrictEqual6(confirmed.map((h) => [h.key, h.currentHash]), admitted.map((h) => [h.key, h.currentHash])), "NATIVE_NOT_ELIGIBLE");
|
|
108121
|
+
need4(isDeepStrictEqual6(current.filter((h) => !keys3.includes(h.key)), discovered.filter((h) => !keys3.includes(h.key))), "UNRELATED_HOOK_CHANGED");
|
|
107268
108122
|
unchanged2(after2);
|
|
107269
108123
|
unchanged2(hooksFile);
|
|
107270
108124
|
unchanged2(policyFile);
|
|
@@ -107298,39 +108152,142 @@ var init_agent_codex_trust = __esm(() => {
|
|
|
107298
108152
|
eventNames = { UserPromptSubmit: ["userPromptSubmit", "user_prompt_submit"], SessionStart: ["sessionStart", "session_start"], SubagentStart: ["subagentStart", "subagent_start"] };
|
|
107299
108153
|
});
|
|
107300
108154
|
|
|
108155
|
+
// src/lib/hook-diagnostics.ts
|
|
108156
|
+
function hookChildError(stdout, stage) {
|
|
108157
|
+
let code2;
|
|
108158
|
+
if (stdout.length <= 16 * 1024) {
|
|
108159
|
+
try {
|
|
108160
|
+
code2 = JSON.parse(stdout)?.error?.code;
|
|
108161
|
+
} catch {}
|
|
108162
|
+
}
|
|
108163
|
+
return new HookDiagnosticError(typeof code2 === "string" && CONTEXT_ERROR_CODES.has(code2) ? code2 : "SKILLS_CONTEXT_FAILED", stage);
|
|
108164
|
+
}
|
|
108165
|
+
function hookFailureReason(error61, profileId) {
|
|
108166
|
+
const owned = error61 instanceof HookDiagnosticError;
|
|
108167
|
+
const code2 = owned && (CONTEXT_ERROR_CODES.has(error61.code) || ["SKILLS_HOOK_TIMEOUT", "SKILLS_HOOK_INVALID_RESPONSE"].includes(error61.code)) ? error61.code : "SKILLS_HOOK_FAILED";
|
|
108168
|
+
const profile = typeof profileId === "string" && /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(profileId) && !profileId.includes("..") ? profileId : undefined;
|
|
108169
|
+
const identity4 = [profile ? `profile=${profile}` : undefined, owned ? `stage=${error61.stage}` : undefined].filter(Boolean).join(", ");
|
|
108170
|
+
const prefix = `Skills context is unavailable [${code2}]${identity4 ? ` (${identity4})` : ""}.`;
|
|
108171
|
+
if (code2 === "PROFILE_LOCK_MISMATCH") {
|
|
108172
|
+
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.`;
|
|
108173
|
+
}
|
|
108174
|
+
if (code2.startsWith("SESSION_")) {
|
|
108175
|
+
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.`;
|
|
108176
|
+
}
|
|
108177
|
+
if (["PROFILE_IDENTITY_MISMATCH", "BUNDLE_DIGEST_MISMATCH", "BUNDLE_IDENTITY_MISMATCH", "INVALID_RECEIPT", "INVALID_CACHE_FILE", "UNSAFE_CACHE_PATH"].includes(code2)) {
|
|
108178
|
+
return `${prefix} Verify the selected authority and receipt integrity before repairing the profile; do not bypass verification or substitute another cache.`;
|
|
108179
|
+
}
|
|
108180
|
+
const selected = profile ?? "<id>";
|
|
108181
|
+
return `${prefix} Run skills sync --selection-profile ${selected} --json, then diagnose with skills context --stdin --json --cached --selection-profile ${selected} using the same hook session and working-directory fields. Do not include credentials in diagnostic input.`;
|
|
108182
|
+
}
|
|
108183
|
+
var CONTEXT_ERROR_CODES, HookDiagnosticError;
|
|
108184
|
+
var init_hook_diagnostics = __esm(() => {
|
|
108185
|
+
CONTEXT_ERROR_CODES = new Set([
|
|
108186
|
+
"SKILLS_CONTEXT_FAILED",
|
|
108187
|
+
"PROFILE_LOCK_MISMATCH",
|
|
108188
|
+
"PROFILE_IDENTITY_MISMATCH",
|
|
108189
|
+
"PROFILE_APPLIED_REPORT_FAILED",
|
|
108190
|
+
"CACHED_AUTHORITY_REQUIRED",
|
|
108191
|
+
"CACHED_PROFILE_EXPIRED",
|
|
108192
|
+
"CACHED_PROFILE_MISSING",
|
|
108193
|
+
"CACHED_BUNDLE_MISSING",
|
|
108194
|
+
"INVALID_CONTEXT_INPUT",
|
|
108195
|
+
"CONTEXT_INPUT_TOO_LARGE",
|
|
108196
|
+
"INVALID_CONTEXT_BUDGET",
|
|
108197
|
+
"INVALID_SELECTION",
|
|
108198
|
+
"INVALID_SELECTION_ALIASES",
|
|
108199
|
+
"INVALID_RECEIPT",
|
|
108200
|
+
"INVALID_CACHE_FILE",
|
|
108201
|
+
"UNSAFE_CACHE_PATH",
|
|
108202
|
+
"RECEIPT_TOO_LARGE",
|
|
108203
|
+
"BUNDLE_DIGEST_MISMATCH",
|
|
108204
|
+
"BUNDLE_IDENTITY_MISMATCH",
|
|
108205
|
+
"BUNDLE_UNAVAILABLE",
|
|
108206
|
+
"BUNDLE_TOO_LARGE",
|
|
108207
|
+
"SKILL_NOT_SELECTED",
|
|
108208
|
+
"INVALID_SESSION",
|
|
108209
|
+
"SESSION_PARENT_NOT_FOUND",
|
|
108210
|
+
"SESSION_NOT_FOUND",
|
|
108211
|
+
"SESSION_GENERATION_CHANGED",
|
|
108212
|
+
"SESSION_GENERATION_EXHAUSTED",
|
|
108213
|
+
"SESSION_PARENT_CHANGED",
|
|
108214
|
+
"SESSION_RECEIPT_CHANGED",
|
|
108215
|
+
"SESSION_RECONCILIATION_INCOMPLETE",
|
|
108216
|
+
"SESSION_WRITE_LOCKED",
|
|
108217
|
+
"SESSION_WRITE_LOCK_CHANGED"
|
|
108218
|
+
]);
|
|
108219
|
+
HookDiagnosticError = class HookDiagnosticError extends Error {
|
|
108220
|
+
code;
|
|
108221
|
+
stage;
|
|
108222
|
+
constructor(code2, stage) {
|
|
108223
|
+
super("Skills hook operation failed");
|
|
108224
|
+
this.code = code2;
|
|
108225
|
+
this.stage = stage;
|
|
108226
|
+
}
|
|
108227
|
+
};
|
|
108228
|
+
});
|
|
108229
|
+
|
|
107301
108230
|
// src/cli/commands/agent-integration.ts
|
|
107302
108231
|
var exports_agent_integration = {};
|
|
107303
108232
|
__export(exports_agent_integration, {
|
|
107304
108233
|
registerAgentIntegration: () => registerAgentIntegration
|
|
107305
108234
|
});
|
|
107306
108235
|
import { readFileSync as readFileSync37 } from "fs";
|
|
107307
|
-
import { isAbsolute as
|
|
108236
|
+
import { isAbsolute as isAbsolute25 } from "path";
|
|
108237
|
+
function pinnedHookProfile(input3, configuredProfile) {
|
|
108238
|
+
try {
|
|
108239
|
+
const parsed = parseSkillContextInput(JSON.stringify(input3));
|
|
108240
|
+
if (!parsed.sessionId)
|
|
108241
|
+
return configuredProfile;
|
|
108242
|
+
const sessionId = parsed.agentId ? `${parsed.sessionId}:${parsed.agentId}` : parsed.sessionId;
|
|
108243
|
+
const session = readSkillSessionSnapshotIfExists(sessionId);
|
|
108244
|
+
const parent = !session && parsed.agentId ? readSkillSessionSnapshotIfExists(parsed.sessionId) : null;
|
|
108245
|
+
return session?.receipt.profile.profileId ?? parent?.receipt.profile.profileId ?? configuredProfile;
|
|
108246
|
+
} catch (error61) {
|
|
108247
|
+
if (error61 instanceof SkillSelectionError)
|
|
108248
|
+
throw new HookDiagnosticError(error61.code, "context");
|
|
108249
|
+
throw error61;
|
|
108250
|
+
}
|
|
108251
|
+
}
|
|
107308
108252
|
async function contextForHook(input3, profileId, cached2, deadline) {
|
|
107309
108253
|
const remaining = deadline - Date.now();
|
|
107310
108254
|
if (remaining <= 0)
|
|
107311
|
-
throw new
|
|
108255
|
+
throw new HookDiagnosticError("SKILLS_HOOK_TIMEOUT", "context");
|
|
107312
108256
|
const args2 = [process.execPath, process.argv[1], "context", "--stdin", "--json", "--selection-profile", profileId];
|
|
107313
108257
|
if (cached2)
|
|
107314
108258
|
args2.push("--cached");
|
|
107315
108259
|
const child = Bun.spawn(args2, { stdin: new Blob([JSON.stringify(input3)]), stdout: "pipe", stderr: "pipe", env: { ...process.env, NO_COLOR: "1" } });
|
|
107316
|
-
|
|
108260
|
+
let timedOut = false;
|
|
108261
|
+
const timer = setTimeout(() => {
|
|
108262
|
+
timedOut = true;
|
|
108263
|
+
child.kill("SIGKILL");
|
|
108264
|
+
}, Math.min(6500, remaining));
|
|
107317
108265
|
let result2;
|
|
107318
108266
|
let status;
|
|
108267
|
+
let output2;
|
|
107319
108268
|
try {
|
|
107320
108269
|
const [stdout, , exitCode] = await Promise.all([new Response(child.stdout).text(), new Response(child.stderr).text(), child.exited]);
|
|
108270
|
+
if (timedOut)
|
|
108271
|
+
throw new HookDiagnosticError("SKILLS_HOOK_TIMEOUT", "context");
|
|
107321
108272
|
status = exitCode;
|
|
107322
|
-
|
|
108273
|
+
output2 = stdout;
|
|
107323
108274
|
} finally {
|
|
107324
108275
|
clearTimeout(timer);
|
|
107325
108276
|
}
|
|
107326
108277
|
if (status !== 0) {
|
|
107327
|
-
|
|
108278
|
+
const failure = hookChildError(output2, "context");
|
|
108279
|
+
if (cached2 && RECOVERABLE_CONTEXT_CACHE_ERRORS.has(failure.code)) {
|
|
107328
108280
|
return contextForHook(input3, profileId, false, deadline);
|
|
107329
108281
|
}
|
|
107330
|
-
throw
|
|
108282
|
+
throw failure;
|
|
108283
|
+
}
|
|
108284
|
+
try {
|
|
108285
|
+
result2 = JSON.parse(output2);
|
|
108286
|
+
} catch {
|
|
108287
|
+
throw new HookDiagnosticError("SKILLS_HOOK_INVALID_RESPONSE", "context");
|
|
107331
108288
|
}
|
|
107332
108289
|
if (typeof result2?.context !== "string")
|
|
107333
|
-
throw new
|
|
108290
|
+
throw new HookDiagnosticError("SKILLS_HOOK_INVALID_RESPONSE", "context");
|
|
107334
108291
|
return result2;
|
|
107335
108292
|
}
|
|
107336
108293
|
function agents(value) {
|
|
@@ -107377,6 +108334,7 @@ function registerAgentIntegration(parent) {
|
|
|
107377
108334
|
hook.command("user-prompt").requiredOption("--agent <agent>", `Native payload/output adapter: ${INTEGRATION_AGENTS.join(", ")}`).option("--event <event>", "Native lifecycle event supplied by the installed adapter").option("--selection-profile <id>", "Selection profile to load").description("Read native lifecycle JSON on stdin and return selected context").action(async (options) => {
|
|
107378
108335
|
const deadline = Date.now() + 12000;
|
|
107379
108336
|
let event = options.agent === "hermes" && options.event === "pre_tool_call" ? "pre_tool_call" : "UserPromptSubmit";
|
|
108337
|
+
let selectionProfile;
|
|
107380
108338
|
try {
|
|
107381
108339
|
if (agents(options.agent).length !== 1)
|
|
107382
108340
|
throw new Error("A hook invocation requires one agent");
|
|
@@ -107393,18 +108351,18 @@ function registerAgentIntegration(parent) {
|
|
|
107393
108351
|
input3.hook_event_name = event;
|
|
107394
108352
|
const projects = [process.cwd()];
|
|
107395
108353
|
if (input3.cwd !== undefined) {
|
|
107396
|
-
if (typeof input3.cwd !== "string" || !
|
|
108354
|
+
if (typeof input3.cwd !== "string" || !isAbsolute25(input3.cwd) || input3.cwd.includes("\x00"))
|
|
107397
108355
|
throw new Error("Invalid native hook working directory");
|
|
107398
108356
|
projects.push(input3.cwd);
|
|
107399
108357
|
}
|
|
107400
108358
|
if (options.agent === "cursor") {
|
|
107401
|
-
if (!Array.isArray(input3.workspace_roots) || input3.workspace_roots.length > 32 || input3.workspace_roots.some((path) => typeof path !== "string" || !
|
|
108359
|
+
if (!Array.isArray(input3.workspace_roots) || input3.workspace_roots.length > 32 || input3.workspace_roots.some((path) => typeof path !== "string" || !isAbsolute25(path) || path.includes("\x00")))
|
|
107402
108360
|
throw new Error("Invalid Cursor workspace roots");
|
|
107403
108361
|
projects.push(...input3.workspace_roots);
|
|
107404
108362
|
input3.cwd ??= input3.workspace_roots[0] ?? process.cwd();
|
|
107405
108363
|
input3.session_id ??= input3.conversation_id;
|
|
107406
108364
|
}
|
|
107407
|
-
|
|
108365
|
+
selectionProfile = selectedProfileId(options.selectionProfile);
|
|
107408
108366
|
if (options.agent === "hermes" && event === "pre_tool_call") {
|
|
107409
108367
|
assertManagedAgentBridge("hermes", { projectDirs: projects, profileId: selectionProfile });
|
|
107410
108368
|
assertHermesTool(input3);
|
|
@@ -107426,17 +108384,24 @@ function registerAgentIntegration(parent) {
|
|
|
107426
108384
|
if (event === "SessionStart") {
|
|
107427
108385
|
const remaining = deadline - Date.now();
|
|
107428
108386
|
if (remaining <= 0)
|
|
107429
|
-
throw new
|
|
108387
|
+
throw new HookDiagnosticError("SKILLS_HOOK_TIMEOUT", "sync");
|
|
107430
108388
|
const refresh = Bun.spawn([process.execPath, process.argv[1], "sync", "--selection-profile", selectionProfile, "--json"], { stdin: "ignore", stdout: "pipe", stderr: "pipe", env: { ...process.env, NO_COLOR: "1" } });
|
|
107431
|
-
|
|
108389
|
+
let timedOut = false;
|
|
108390
|
+
const timer = setTimeout(() => {
|
|
108391
|
+
timedOut = true;
|
|
108392
|
+
refresh.kill("SIGKILL");
|
|
108393
|
+
}, Math.min(6500, remaining));
|
|
107432
108394
|
try {
|
|
107433
|
-
const [, , status] = await Promise.all([new Response(refresh.stdout).text(), new Response(refresh.stderr).text(), refresh.exited]);
|
|
108395
|
+
const [stdout, , status] = await Promise.all([new Response(refresh.stdout).text(), new Response(refresh.stderr).text(), refresh.exited]);
|
|
108396
|
+
if (timedOut)
|
|
108397
|
+
throw new HookDiagnosticError("SKILLS_HOOK_TIMEOUT", "sync");
|
|
107434
108398
|
if (status !== 0)
|
|
107435
|
-
throw
|
|
108399
|
+
throw hookChildError(stdout, "sync");
|
|
107436
108400
|
} finally {
|
|
107437
108401
|
clearTimeout(timer);
|
|
107438
108402
|
}
|
|
107439
108403
|
}
|
|
108404
|
+
selectionProfile = pinnedHookProfile(input3, selectionProfile);
|
|
107440
108405
|
const result2 = await contextForHook(input3, selectionProfile, true, deadline);
|
|
107441
108406
|
const output2 = hookContextOutput(event, result2);
|
|
107442
108407
|
if (options.agent === "hermes") {
|
|
@@ -107449,7 +108414,7 @@ function registerAgentIntegration(parent) {
|
|
|
107449
108414
|
await writeCliOutput(JSON.stringify(output2));
|
|
107450
108415
|
}
|
|
107451
108416
|
} catch (error61) {
|
|
107452
|
-
const reason = error61 instanceof Error && error61.message.startsWith("NATIVE_SKILL_DRIFT:") ? error61.message :
|
|
108417
|
+
const reason = error61 instanceof Error && error61.message.startsWith("NATIVE_SKILL_DRIFT:") ? error61.message : hookFailureReason(error61, selectionProfile);
|
|
107453
108418
|
if (options.agent === "hermes") {
|
|
107454
108419
|
await writeCliOutput(JSON.stringify(event === "pre_tool_call" ? { action: "block", message: reason } : { context: `Required Skills context is unavailable. ${reason} Do not substitute native skill payloads; stop and repair the bridge before task actions.` }));
|
|
107455
108420
|
} else if (options.agent === "claude" && event === "PreToolUse")
|
|
@@ -107489,6 +108454,8 @@ var init_agent_integration2 = __esm(() => {
|
|
|
107489
108454
|
init_agent_adapters();
|
|
107490
108455
|
init_agent_integration();
|
|
107491
108456
|
init_agent_codex_trust();
|
|
108457
|
+
init_hook_diagnostics();
|
|
108458
|
+
init_selection_cache();
|
|
107492
108459
|
RECOVERABLE_CONTEXT_CACHE_ERRORS = new Set(["CACHED_PROFILE_EXPIRED", "CACHED_PROFILE_MISSING", "CACHED_BUNDLE_MISSING"]);
|
|
107493
108460
|
});
|
|
107494
108461
|
|
|
@@ -107627,17 +108594,17 @@ var exports_profiles = {};
|
|
|
107627
108594
|
__export(exports_profiles, {
|
|
107628
108595
|
registerProfiles: () => registerProfiles
|
|
107629
108596
|
});
|
|
107630
|
-
import { closeSync as
|
|
108597
|
+
import { closeSync as closeSync21, constants as constants20, fstatSync as fstatSync21, openSync as openSync21, readSync as readSync17, writeFileSync as writeFileSync24 } from "fs";
|
|
107631
108598
|
function readProfileInput(path) {
|
|
107632
|
-
const fd =
|
|
108599
|
+
const fd = openSync21(path, constants20.O_RDONLY | constants20.O_NONBLOCK);
|
|
107633
108600
|
try {
|
|
107634
|
-
const stat3 =
|
|
108601
|
+
const stat3 = fstatSync21(fd);
|
|
107635
108602
|
if (!stat3.isFile() || stat3.size > MAX_PROFILE_DOCUMENT_BYTES)
|
|
107636
108603
|
throw new Error("Profile input exceeds the size limit or is not a regular file");
|
|
107637
108604
|
const bytes = Buffer.alloc(MAX_PROFILE_DOCUMENT_BYTES + 1);
|
|
107638
108605
|
let size2 = 0;
|
|
107639
108606
|
while (size2 < bytes.length) {
|
|
107640
|
-
const read3 =
|
|
108607
|
+
const read3 = readSync17(fd, bytes, size2, bytes.length - size2, null);
|
|
107641
108608
|
if (!read3)
|
|
107642
108609
|
break;
|
|
107643
108610
|
size2 += read3;
|
|
@@ -107646,7 +108613,7 @@ function readProfileInput(path) {
|
|
|
107646
108613
|
throw new Error("Profile input exceeds the size limit");
|
|
107647
108614
|
return new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(0, size2));
|
|
107648
108615
|
} finally {
|
|
107649
|
-
|
|
108616
|
+
closeSync21(fd);
|
|
107650
108617
|
}
|
|
107651
108618
|
}
|
|
107652
108619
|
function registerProfiles(parent) {
|
|
@@ -107697,23 +108664,23 @@ __export(exports_grants, {
|
|
|
107697
108664
|
registerGrants: () => registerGrants
|
|
107698
108665
|
});
|
|
107699
108666
|
import {
|
|
107700
|
-
constants as
|
|
107701
|
-
closeSync as
|
|
107702
|
-
fstatSync as
|
|
107703
|
-
openSync as
|
|
107704
|
-
readSync as
|
|
108667
|
+
constants as constants21,
|
|
108668
|
+
closeSync as closeSync23,
|
|
108669
|
+
fstatSync as fstatSync23,
|
|
108670
|
+
openSync as openSync23,
|
|
108671
|
+
readSync as readSync18,
|
|
107705
108672
|
writeFileSync as writeFileSync25
|
|
107706
108673
|
} from "fs";
|
|
107707
108674
|
function readInput(path) {
|
|
107708
|
-
const fd =
|
|
108675
|
+
const fd = openSync23(path, constants21.O_RDONLY | constants21.O_NONBLOCK);
|
|
107709
108676
|
try {
|
|
107710
|
-
const stat3 =
|
|
108677
|
+
const stat3 = fstatSync23(fd);
|
|
107711
108678
|
if (!stat3.isFile() || stat3.size > MAX_EXECUTION_GRANT_BYTES)
|
|
107712
108679
|
throw new Error("Grant input must be a regular file within the policy size limit.");
|
|
107713
108680
|
const bytes = Buffer.alloc(MAX_EXECUTION_GRANT_BYTES + 1);
|
|
107714
108681
|
let size2 = 0;
|
|
107715
108682
|
while (size2 < bytes.length) {
|
|
107716
|
-
const count =
|
|
108683
|
+
const count = readSync18(fd, bytes, size2, bytes.length - size2, null);
|
|
107717
108684
|
if (!count)
|
|
107718
108685
|
break;
|
|
107719
108686
|
size2 += count;
|
|
@@ -107726,7 +108693,7 @@ function readInput(path) {
|
|
|
107726
108693
|
throw new Error("Grant input must be a JSON document containing a grants array.");
|
|
107727
108694
|
}
|
|
107728
108695
|
} finally {
|
|
107729
|
-
|
|
108696
|
+
closeSync23(fd);
|
|
107730
108697
|
}
|
|
107731
108698
|
}
|
|
107732
108699
|
function registerGrants(parent) {
|
|
@@ -107762,7 +108729,7 @@ var init_grants = __esm(() => {
|
|
|
107762
108729
|
});
|
|
107763
108730
|
|
|
107764
108731
|
// src/lib/station-hydrate.ts
|
|
107765
|
-
import { createHash as
|
|
108732
|
+
import { createHash as createHash27 } from "crypto";
|
|
107766
108733
|
import {
|
|
107767
108734
|
copyFileSync as copyFileSync2,
|
|
107768
108735
|
mkdirSync as mkdirSync26,
|
|
@@ -107771,7 +108738,7 @@ import {
|
|
|
107771
108738
|
statSync as statSync21,
|
|
107772
108739
|
writeFileSync as writeFileSync26
|
|
107773
108740
|
} from "fs";
|
|
107774
|
-
import { dirname as
|
|
108741
|
+
import { dirname as dirname30, join as join57, resolve as resolve23, sep as sep10 } from "path";
|
|
107775
108742
|
function fail5(code2, message, detail = []) {
|
|
107776
108743
|
throw new StationSnapshotError(code2, message, detail);
|
|
107777
108744
|
}
|
|
@@ -107965,12 +108932,12 @@ function skillSha256(skill) {
|
|
|
107965
108932
|
return sha256File(skill.files[0].winner.fullPath);
|
|
107966
108933
|
}
|
|
107967
108934
|
const joined = skill.files.map((file2) => sha256File(file2.winner.fullPath));
|
|
107968
|
-
return
|
|
108935
|
+
return createHash27("sha256").update(joined.sort().join(`
|
|
107969
108936
|
`)).digest("hex");
|
|
107970
108937
|
}
|
|
107971
108938
|
function writeStationHydration(options) {
|
|
107972
|
-
const repoRoot =
|
|
107973
|
-
const cacheRoot =
|
|
108939
|
+
const repoRoot = resolve23(options.repoRoot ?? process.cwd());
|
|
108940
|
+
const cacheRoot = resolve23(options.cacheRoot ?? resolveCorpusRoot());
|
|
107974
108941
|
const plan = planStationHydration(options.stationId, repoRoot);
|
|
107975
108942
|
const resultSkills = plan.winners.map((skill) => ({
|
|
107976
108943
|
ident: skill.ident,
|
|
@@ -108004,13 +108971,13 @@ function writeStationHydration(options) {
|
|
|
108004
108971
|
for (const skill of plan.winners) {
|
|
108005
108972
|
for (const file2 of skill.files) {
|
|
108006
108973
|
const destination = join57(cacheRoot, skill.ident, file2.withinIdent);
|
|
108007
|
-
const
|
|
108974
|
+
const digest4 = sha256File(file2.winner.fullPath);
|
|
108008
108975
|
let existingDigest = null;
|
|
108009
108976
|
try {
|
|
108010
108977
|
existingDigest = sha256File(destination);
|
|
108011
108978
|
} catch {}
|
|
108012
108979
|
if (existingDigest !== null) {
|
|
108013
|
-
if (existingDigest ===
|
|
108980
|
+
if (existingDigest === digest4) {
|
|
108014
108981
|
continue;
|
|
108015
108982
|
}
|
|
108016
108983
|
conflicts.push(`existing destination differs from snapshot winner: ${destination}`);
|
|
@@ -108024,7 +108991,7 @@ function writeStationHydration(options) {
|
|
|
108024
108991
|
}
|
|
108025
108992
|
let written = 0;
|
|
108026
108993
|
for (const entry of toWrite) {
|
|
108027
|
-
mkdirSync26(
|
|
108994
|
+
mkdirSync26(dirname30(entry.destination), { recursive: true });
|
|
108028
108995
|
copyFileSync2(entry.fullPath, entry.destination);
|
|
108029
108996
|
written += 1;
|
|
108030
108997
|
}
|
|
@@ -108045,8 +109012,8 @@ function writeStationHydration(options) {
|
|
|
108045
109012
|
},
|
|
108046
109013
|
skills: resultSkills
|
|
108047
109014
|
};
|
|
108048
|
-
const hydrationManifestPath = join57(
|
|
108049
|
-
mkdirSync26(
|
|
109015
|
+
const hydrationManifestPath = join57(dirname30(cacheRoot), `hydration-${options.stationId}.json`);
|
|
109016
|
+
mkdirSync26(dirname30(hydrationManifestPath), { recursive: true });
|
|
108050
109017
|
writeFileSync26(hydrationManifestPath, `${JSON.stringify(hydration, null, 2)}
|
|
108051
109018
|
`);
|
|
108052
109019
|
return {
|
|
@@ -108122,10 +109089,10 @@ var init_hydrate = __esm(() => {
|
|
|
108122
109089
|
});
|
|
108123
109090
|
|
|
108124
109091
|
// src/lib/prepare-skill.ts
|
|
108125
|
-
import { createHash as
|
|
108126
|
-
import { chmodSync as chmodSync3, existsSync as existsSync34, lstatSync as
|
|
109092
|
+
import { createHash as createHash28, randomUUID as randomUUID11 } from "crypto";
|
|
109093
|
+
import { chmodSync as chmodSync3, existsSync as existsSync34, lstatSync as lstatSync29, mkdirSync as mkdirSync27, mkdtempSync as mkdtempSync6, readFileSync as readFileSync39, readdirSync as readdirSync22, renameSync as renameSync12, rmSync as rmSync9, writeFileSync as writeFileSync27 } from "fs";
|
|
108127
109094
|
import { tmpdir as tmpdir2 } from "os";
|
|
108128
|
-
import { dirname as
|
|
109095
|
+
import { dirname as dirname31, isAbsolute as isAbsolute26, join as join58, relative as relative9, resolve as resolve24, sep as sep11 } from "path";
|
|
108129
109096
|
function prepareSkill(name, options) {
|
|
108130
109097
|
const normalized = normalizePortableSkillName(name);
|
|
108131
109098
|
if (!new RegExp(SEMVER_PATTERN).test(options.version))
|
|
@@ -108170,7 +109137,7 @@ function prepareSkill(name, options) {
|
|
|
108170
109137
|
mkdirSync27(join58(staging, directory2), { recursive: true });
|
|
108171
109138
|
for (const file2 of before2.files) {
|
|
108172
109139
|
const destination = join58(staging, file2.path);
|
|
108173
|
-
mkdirSync27(
|
|
109140
|
+
mkdirSync27(dirname31(destination), { recursive: true });
|
|
108174
109141
|
writeFileSync27(destination, file2.bytes, { mode: file2.mode });
|
|
108175
109142
|
}
|
|
108176
109143
|
const stagedManifest = join58(staging, "skill.json");
|
|
@@ -108230,8 +109197,8 @@ function validateRuntimeEntrypoint(candidate2, root2) {
|
|
|
108230
109197
|
const entry = candidate2.runtime.entrypoint;
|
|
108231
109198
|
if (typeof entry !== "string")
|
|
108232
109199
|
return;
|
|
108233
|
-
const target =
|
|
108234
|
-
if (
|
|
109200
|
+
const target = resolve24(root2, entry), rel = relative9(root2, target);
|
|
109201
|
+
if (isAbsolute26(entry) || /^[a-zA-Z]:/.test(entry) || entry.includes("\\") || !rel || rel === ".." || rel.startsWith(`..${sep11}`) || isAbsolute26(rel) || !existsSync34(target) || !lstatSync29(target).isFile()) {
|
|
108235
109202
|
throw new Error("Executable runtime.entrypoint must name an existing regular file inside the skill directory.");
|
|
108236
109203
|
}
|
|
108237
109204
|
}
|
|
@@ -108239,31 +109206,31 @@ function isRecord6(value) {
|
|
|
108239
109206
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
108240
109207
|
}
|
|
108241
109208
|
function validateRawCandidate(candidate2) {
|
|
108242
|
-
for (const
|
|
108243
|
-
if (typeof candidate2[
|
|
108244
|
-
throw new Error(`skill.json ${
|
|
109209
|
+
for (const field2 of ["standard", "name", "description", "version"]) {
|
|
109210
|
+
if (typeof candidate2[field2] !== "string" || !candidate2[field2].trim())
|
|
109211
|
+
throw new Error(`skill.json ${field2} is required.`);
|
|
108245
109212
|
}
|
|
108246
|
-
for (const
|
|
108247
|
-
if (candidate2[
|
|
108248
|
-
throw new Error(`Invalid skill.json ${
|
|
109213
|
+
for (const field2 of ["displayName", "category"]) {
|
|
109214
|
+
if (candidate2[field2] !== undefined && (typeof candidate2[field2] !== "string" || !candidate2[field2].trim()))
|
|
109215
|
+
throw new Error(`Invalid skill.json ${field2}.`);
|
|
108249
109216
|
}
|
|
108250
109217
|
if (candidate2.tags !== undefined && (!Array.isArray(candidate2.tags) || candidate2.tags.some((tag) => typeof tag !== "string" || !tag.trim())))
|
|
108251
109218
|
throw new Error("Invalid skill.json tags.");
|
|
108252
109219
|
const issues = validatePortableManifestContract(candidate2, { strict: true });
|
|
108253
109220
|
if (issues.length)
|
|
108254
109221
|
throw new Error(`Invalid skill.json: ${issues.map((issue2) => issue2.code).join(", ")}`);
|
|
108255
|
-
for (const
|
|
108256
|
-
const items = candidate2[
|
|
109222
|
+
for (const field2 of ["inputs", "commands"]) {
|
|
109223
|
+
const items = candidate2[field2];
|
|
108257
109224
|
if (items === undefined)
|
|
108258
109225
|
continue;
|
|
108259
109226
|
if (!Array.isArray(items))
|
|
108260
|
-
throw new Error(`skill.json ${
|
|
109227
|
+
throw new Error(`skill.json ${field2} must be an array.`);
|
|
108261
109228
|
for (const item of items) {
|
|
108262
109229
|
if (!isRecord6(item) || typeof item.name !== "string" || !item.name.trim())
|
|
108263
|
-
throw new Error(`Invalid skill.json ${
|
|
108264
|
-
if (
|
|
109230
|
+
throw new Error(`Invalid skill.json ${field2} name.`);
|
|
109231
|
+
if (field2 === "inputs" && (typeof item.type !== "string" || !item.type.trim() || item.required !== undefined && typeof item.required !== "boolean"))
|
|
108265
109232
|
throw new Error("Invalid skill.json input type or required flag.");
|
|
108266
|
-
if (
|
|
109233
|
+
if (field2 === "commands") {
|
|
108267
109234
|
if (!/^[a-z0-9][a-z0-9._-]*$/.test(item.name))
|
|
108268
109235
|
throw new Error("Invalid skill.json command name.");
|
|
108269
109236
|
for (const target of ["entry", "command"])
|
|
@@ -108303,11 +109270,11 @@ function compareVersions(left, right) {
|
|
|
108303
109270
|
return 0;
|
|
108304
109271
|
}
|
|
108305
109272
|
function snapshot2(root2) {
|
|
108306
|
-
const rootStat =
|
|
109273
|
+
const rootStat = lstatSync29(root2);
|
|
108307
109274
|
if (rootStat.isSymbolicLink() || !rootStat.isDirectory())
|
|
108308
109275
|
throw new Error("Skill root must be a real directory, not a symlink.");
|
|
108309
109276
|
const files = [], directories = [];
|
|
108310
|
-
const hash4 =
|
|
109277
|
+
const hash4 = createHash28("sha256").update(`${rootStat.dev}:${rootStat.ino}\x00`);
|
|
108311
109278
|
let count = 0, bytes = 0;
|
|
108312
109279
|
const walk2 = (relative10) => {
|
|
108313
109280
|
for (const name of readdirSync22(join58(root2, relative10)).sort()) {
|
|
@@ -108316,7 +109283,7 @@ function snapshot2(root2) {
|
|
|
108316
109283
|
const path = relative10 ? `${relative10}/${name}` : name;
|
|
108317
109284
|
if (++count > 20000)
|
|
108318
109285
|
throw new Error("Skill exceeds the preparation entry limit (20000).");
|
|
108319
|
-
const absolute = join58(root2, path), stat3 =
|
|
109286
|
+
const absolute = join58(root2, path), stat3 = lstatSync29(absolute);
|
|
108320
109287
|
if (stat3.isSymbolicLink())
|
|
108321
109288
|
throw new Error(`Skill contains a symlink: ${path}. No files were changed.`);
|
|
108322
109289
|
if (stat3.isDirectory() && name === "node_modules")
|
|
@@ -108731,7 +109698,7 @@ var init_schedule = __esm(() => {
|
|
|
108731
109698
|
|
|
108732
109699
|
// src/lib/registry-sync.ts
|
|
108733
109700
|
import { mkdirSync as mkdirSync28, writeFileSync as writeFileSync28 } from "fs";
|
|
108734
|
-
import { dirname as
|
|
109701
|
+
import { dirname as dirname32, relative as relative10 } from "path";
|
|
108735
109702
|
function createRegistrySyncArtifact(options = {}) {
|
|
108736
109703
|
const profile = options.profile ?? "all";
|
|
108737
109704
|
const includeDocs = options.includeDocs ?? true;
|
|
@@ -108788,7 +109755,7 @@ function createRegistrySyncArtifact(options = {}) {
|
|
|
108788
109755
|
};
|
|
108789
109756
|
}
|
|
108790
109757
|
function writeRegistrySyncArtifact(path, artifact) {
|
|
108791
|
-
mkdirSync28(
|
|
109758
|
+
mkdirSync28(dirname32(path), { recursive: true });
|
|
108792
109759
|
writeFileSync28(path, `${JSON.stringify(artifact, null, 2)}
|
|
108793
109760
|
`);
|
|
108794
109761
|
}
|
|
@@ -108821,12 +109788,12 @@ function registerRegistry(parent) {
|
|
|
108821
109788
|
async function writeJson2(value, space) {
|
|
108822
109789
|
const text3 = `${JSON.stringify(value, null, space)}
|
|
108823
109790
|
`;
|
|
108824
|
-
await new Promise((
|
|
109791
|
+
await new Promise((resolve25, reject2) => {
|
|
108825
109792
|
process.stdout.write(text3, (error61) => {
|
|
108826
109793
|
if (error61)
|
|
108827
109794
|
reject2(error61);
|
|
108828
109795
|
else
|
|
108829
|
-
|
|
109796
|
+
resolve25();
|
|
108830
109797
|
});
|
|
108831
109798
|
});
|
|
108832
109799
|
}
|
|
@@ -109283,7 +110250,7 @@ var exports_private_publications = {};
|
|
|
109283
110250
|
__export(exports_private_publications, {
|
|
109284
110251
|
registerPrivatePublications: () => registerPrivatePublications
|
|
109285
110252
|
});
|
|
109286
|
-
import { resolve as
|
|
110253
|
+
import { resolve as resolve25 } from "path";
|
|
109287
110254
|
function verifyOptions(options, action) {
|
|
109288
110255
|
if (options.userId === undefined !== (options.membershipId === undefined) || options.userId !== undefined && (!publicationUuid(options.userId) || !publicationUuid(options.membershipId)))
|
|
109289
110256
|
throw new PrivatePublicationError("PUBLICATION_CONTEXT_REQUIRED", "Provide both observed --user-id and --membership-id UUIDs.");
|
|
@@ -109328,9 +110295,9 @@ function registerPrivatePublications(parent) {
|
|
|
109328
110295
|
if (code2 === null)
|
|
109329
110296
|
return;
|
|
109330
110297
|
const context2 = options.userId ? { userId: options.userId, membershipId: options.membershipId } : undefined;
|
|
109331
|
-
const client2 = await privatePublicationSession(options.email, code2, context2), directory2 =
|
|
110298
|
+
const client2 = await privatePublicationSession(options.email, code2, context2), directory2 = resolve25(options.recoveryDir);
|
|
109332
110299
|
if (action === "publish")
|
|
109333
|
-
await preparePrivatePublication(client2,
|
|
110300
|
+
await preparePrivatePublication(client2, resolve25(args2[0]), directory2, { skillId: options.skillId, expectedCurrentVersionId: options.expectedCurrentVersion ?? null, idempotencyKey: options.idempotencyKey });
|
|
109334
110301
|
const result2 = action === "publish" || action === "resume" ? await continuePrivatePublication(client2, directory2, { confirm: true, waitMs: Number(options.waitSeconds) * 1000 }) : await inspectPrivatePublication(client2, directory2, action === "cancel");
|
|
109335
110302
|
print2(result2, options.json);
|
|
109336
110303
|
} catch (error61) {
|
|
@@ -109431,7 +110398,7 @@ __export(exports_auth, {
|
|
|
109431
110398
|
import { createInterface as createInterface3 } from "readline";
|
|
109432
110399
|
function prompt(question) {
|
|
109433
110400
|
const rl = createInterface3({ input: process.stdin, output: process.stdout });
|
|
109434
|
-
return new Promise((
|
|
110401
|
+
return new Promise((resolve26) => {
|
|
109435
110402
|
let settled = false;
|
|
109436
110403
|
const finish = (answer) => {
|
|
109437
110404
|
if (settled)
|
|
@@ -109440,7 +110407,7 @@ function prompt(question) {
|
|
|
109440
110407
|
rl.close();
|
|
109441
110408
|
if (answer === null)
|
|
109442
110409
|
process.exitCode = 130;
|
|
109443
|
-
|
|
110410
|
+
resolve26(answer);
|
|
109444
110411
|
};
|
|
109445
110412
|
rl.once("SIGINT", () => finish(null));
|
|
109446
110413
|
rl.once("close", () => finish(null));
|
|
@@ -109548,7 +110515,7 @@ function printWhoami(payload) {
|
|
|
109548
110515
|
console.log(source_default.dim("(offline \u2014 showing cached info)"));
|
|
109549
110516
|
}
|
|
109550
110517
|
function sleep(ms) {
|
|
109551
|
-
return new Promise((
|
|
110518
|
+
return new Promise((resolve26) => setTimeout(resolve26, ms));
|
|
109552
110519
|
}
|
|
109553
110520
|
function browserCommand(url2) {
|
|
109554
110521
|
if (process.platform === "darwin")
|
|
@@ -110050,7 +111017,7 @@ function promptInvitationProof(kind) {
|
|
|
110050
111017
|
const label = kind === "token" ? "invitation token" : "recovery code";
|
|
110051
111018
|
const character = kind === "token" ? /^[A-Za-z0-9_-]$/ : /^\d$/;
|
|
110052
111019
|
const { stdin, stderr: output2 } = process, wasRaw = stdin.isRaw, wasFlowing = stdin.readableFlowing;
|
|
110053
|
-
return new Promise((
|
|
111020
|
+
return new Promise((resolve26) => {
|
|
110054
111021
|
let value = "", settled = false, overflow = false;
|
|
110055
111022
|
const finish = (answer) => {
|
|
110056
111023
|
if (settled)
|
|
@@ -110067,7 +111034,7 @@ function promptInvitationProof(kind) {
|
|
|
110067
111034
|
`);
|
|
110068
111035
|
if (answer === null)
|
|
110069
111036
|
process.exitCode = 130;
|
|
110070
|
-
|
|
111037
|
+
resolve26(answer);
|
|
110071
111038
|
};
|
|
110072
111039
|
const cancel = () => finish(null);
|
|
110073
111040
|
const keypress = (text3, key) => {
|
|
@@ -110777,8 +111744,8 @@ async function currentRemoteDigest(client2, slug2) {
|
|
|
110777
111744
|
}
|
|
110778
111745
|
if (!body || typeof body !== "object")
|
|
110779
111746
|
return;
|
|
110780
|
-
const
|
|
110781
|
-
return typeof
|
|
111747
|
+
const digest4 = body.bundleSha256;
|
|
111748
|
+
return typeof digest4 === "string" && digest4 ? digest4 : undefined;
|
|
110782
111749
|
}
|
|
110783
111750
|
async function reconcileRegistry(options = {}) {
|
|
110784
111751
|
const conflict = options.conflict ?? "skip";
|