@hasna/instructions 0.5.4 → 0.5.5
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/dist/cli/index.js +461 -364
- package/dist/lib/app-home.d.ts +9 -0
- package/dist/lib/app-home.d.ts.map +1 -1
- package/dist/mcp/index.js +12 -2
- package/dist/mcp/server.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -1290,8 +1290,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1290
1290
|
args = args.slice();
|
|
1291
1291
|
let launchWithNode = false;
|
|
1292
1292
|
const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
|
|
1293
|
-
function findFile(
|
|
1294
|
-
const localBin = path.resolve(
|
|
1293
|
+
function findFile(baseDir2, baseName) {
|
|
1294
|
+
const localBin = path.resolve(baseDir2, baseName);
|
|
1295
1295
|
if (fs.existsSync(localBin))
|
|
1296
1296
|
return localBin;
|
|
1297
1297
|
if (sourceExt.includes(path.extname(baseName)))
|
|
@@ -2161,91 +2161,91 @@ var init_retired_storage_mode = __esm(() => {
|
|
|
2161
2161
|
});
|
|
2162
2162
|
|
|
2163
2163
|
// ../../node_modules/.bun/@hasna+paths@0.1.0/node_modules/@hasna/paths/dist/index.js
|
|
2164
|
-
import { homedir as
|
|
2165
|
-
import { join as
|
|
2166
|
-
function
|
|
2164
|
+
import { homedir as homedir3 } from "os";
|
|
2165
|
+
import { join as join4 } from "path";
|
|
2166
|
+
function assertApp2(app) {
|
|
2167
2167
|
if (typeof app !== "string" || app.length === 0) {
|
|
2168
2168
|
throw new TypeError("paths: app must be a non-empty string");
|
|
2169
2169
|
}
|
|
2170
|
-
if (!
|
|
2170
|
+
if (!APP_SLUG_RE2.test(app)) {
|
|
2171
2171
|
throw new TypeError(`paths: invalid app slug "${app}" \u2014 expected lowercase kebab-case ([a-z0-9]+(-[a-z0-9]+)*)`);
|
|
2172
2172
|
}
|
|
2173
2173
|
}
|
|
2174
|
-
function
|
|
2174
|
+
function envOf2(options) {
|
|
2175
2175
|
return options.env ?? process.env;
|
|
2176
2176
|
}
|
|
2177
|
-
function
|
|
2178
|
-
const value =
|
|
2177
|
+
function envValue2(options, kind) {
|
|
2178
|
+
const value = envOf2(options)[KIND_ENV2[kind]];
|
|
2179
2179
|
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
2180
2180
|
}
|
|
2181
|
-
function
|
|
2181
|
+
function isMacOS2(platform) {
|
|
2182
2182
|
return platform === "darwin";
|
|
2183
2183
|
}
|
|
2184
|
-
function
|
|
2185
|
-
const override =
|
|
2184
|
+
function baseDir2(kind, options) {
|
|
2185
|
+
const override = envValue2(options, kind);
|
|
2186
2186
|
if (override)
|
|
2187
2187
|
return override;
|
|
2188
|
-
const home = options.home ??
|
|
2188
|
+
const home = options.home ?? homedir3();
|
|
2189
2189
|
const platform = options.platform ?? process.platform;
|
|
2190
|
-
if (
|
|
2190
|
+
if (isMacOS2(platform)) {
|
|
2191
2191
|
switch (kind) {
|
|
2192
2192
|
case "config":
|
|
2193
2193
|
case "data":
|
|
2194
|
-
return
|
|
2194
|
+
return join4(home, "Library", "Application Support", "Hasna");
|
|
2195
2195
|
case "cache":
|
|
2196
|
-
return
|
|
2196
|
+
return join4(home, "Library", "Caches", "Hasna");
|
|
2197
2197
|
case "state":
|
|
2198
|
-
return
|
|
2198
|
+
return join4(home, "Library", "Logs", "Hasna");
|
|
2199
2199
|
}
|
|
2200
2200
|
}
|
|
2201
2201
|
switch (kind) {
|
|
2202
2202
|
case "config":
|
|
2203
|
-
return
|
|
2203
|
+
return join4(home, ".config", "hasna");
|
|
2204
2204
|
case "data":
|
|
2205
|
-
return
|
|
2205
|
+
return join4(home, ".local", "share", "hasna");
|
|
2206
2206
|
case "state":
|
|
2207
|
-
return
|
|
2207
|
+
return join4(home, ".local", "state", "hasna");
|
|
2208
2208
|
case "cache":
|
|
2209
|
-
return
|
|
2209
|
+
return join4(home, ".cache", "hasna");
|
|
2210
2210
|
}
|
|
2211
2211
|
}
|
|
2212
|
-
function
|
|
2213
|
-
|
|
2214
|
-
const appSegment = options.internal === true ?
|
|
2215
|
-
return
|
|
2212
|
+
function resolvePath2(kind, options) {
|
|
2213
|
+
assertApp2(options.app);
|
|
2214
|
+
const appSegment = options.internal === true ? join4("internal", options.app) : options.app;
|
|
2215
|
+
return join4(baseDir2(kind, options), appSegment);
|
|
2216
2216
|
}
|
|
2217
2217
|
function configDir(options) {
|
|
2218
|
-
return
|
|
2218
|
+
return resolvePath2("config", options);
|
|
2219
2219
|
}
|
|
2220
|
-
var
|
|
2220
|
+
var KIND_ENV2, APP_SLUG_RE2;
|
|
2221
2221
|
var init_dist = __esm(() => {
|
|
2222
|
-
|
|
2222
|
+
KIND_ENV2 = {
|
|
2223
2223
|
config: "HASNA_CONFIG_HOME",
|
|
2224
2224
|
data: "HASNA_DATA_HOME",
|
|
2225
2225
|
state: "HASNA_STATE_HOME",
|
|
2226
2226
|
cache: "HASNA_CACHE_HOME"
|
|
2227
2227
|
};
|
|
2228
|
-
|
|
2228
|
+
APP_SLUG_RE2 = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
2229
2229
|
});
|
|
2230
2230
|
|
|
2231
2231
|
// src/lib/app-home.ts
|
|
2232
|
-
import { existsSync as
|
|
2233
|
-
import { homedir as
|
|
2234
|
-
import { join as
|
|
2232
|
+
import { existsSync as existsSync3 } from "fs";
|
|
2233
|
+
import { homedir as homedir5 } from "os";
|
|
2234
|
+
import { join as join6, resolve as resolve2 } from "path";
|
|
2235
2235
|
function homeDir(env = process.env) {
|
|
2236
|
-
return env["HOME"] || env["USERPROFILE"] ||
|
|
2236
|
+
return env["HOME"] || env["USERPROFILE"] || homedir5();
|
|
2237
2237
|
}
|
|
2238
2238
|
function legacyStoreHome(env = process.env) {
|
|
2239
|
-
return
|
|
2239
|
+
return resolve2(join6(homeDir(env), ".hasna", "instructions"));
|
|
2240
2240
|
}
|
|
2241
2241
|
function resolverStoreHome(env = process.env) {
|
|
2242
|
-
return configDir({ app: "configs", env, home: env.HOME || env.USERPROFILE ||
|
|
2242
|
+
return configDir({ app: "configs", env, home: env.HOME || env.USERPROFILE || homedir5() });
|
|
2243
2243
|
}
|
|
2244
2244
|
function adoptResolverStoreHome(resolved, env = process.env) {
|
|
2245
2245
|
const override = env.HASNA_CONFIG_HOME;
|
|
2246
2246
|
if (typeof override === "string" && override.trim().length > 0)
|
|
2247
2247
|
return true;
|
|
2248
|
-
return
|
|
2248
|
+
return existsSync3(join6(resolved, "instructions.db"));
|
|
2249
2249
|
}
|
|
2250
2250
|
function exactStoreHome(env = process.env) {
|
|
2251
2251
|
const v = env[HASNA_CONFIGS_HOME_ENV];
|
|
@@ -2254,9 +2254,9 @@ function exactStoreHome(env = process.env) {
|
|
|
2254
2254
|
function getConfigsStoreHome(env = process.env) {
|
|
2255
2255
|
const exact = exactStoreHome(env);
|
|
2256
2256
|
if (exact)
|
|
2257
|
-
return
|
|
2257
|
+
return resolve2(exact);
|
|
2258
2258
|
const resolved = resolverStoreHome(env);
|
|
2259
|
-
return adoptResolverStoreHome(resolved, env) ?
|
|
2259
|
+
return adoptResolverStoreHome(resolved, env) ? resolve2(resolved) : legacyStoreHome(env);
|
|
2260
2260
|
}
|
|
2261
2261
|
var HASNA_CONFIGS_HOME_ENV = "HASNA_CONFIGS_HOME";
|
|
2262
2262
|
var init_app_home = __esm(() => {
|
|
@@ -2264,9 +2264,9 @@ var init_app_home = __esm(() => {
|
|
|
2264
2264
|
});
|
|
2265
2265
|
|
|
2266
2266
|
// src/lib/raw-store-root.ts
|
|
2267
|
-
import { resolve as
|
|
2267
|
+
import { resolve as resolve3 } from "path";
|
|
2268
2268
|
function getRawStoreRoot(env = process.env) {
|
|
2269
|
-
return
|
|
2269
|
+
return resolve3(getConfigsStoreHome(env));
|
|
2270
2270
|
}
|
|
2271
2271
|
var init_raw_store_root = __esm(() => {
|
|
2272
2272
|
init_app_home();
|
|
@@ -2274,8 +2274,8 @@ var init_raw_store_root = __esm(() => {
|
|
|
2274
2274
|
|
|
2275
2275
|
// src/db/database.ts
|
|
2276
2276
|
import { Database } from "bun:sqlite";
|
|
2277
|
-
import { existsSync as
|
|
2278
|
-
import { join as
|
|
2277
|
+
import { existsSync as existsSync5, mkdirSync, rmSync } from "fs";
|
|
2278
|
+
import { join as join7 } from "path";
|
|
2279
2279
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
2280
2280
|
function getDbPath() {
|
|
2281
2281
|
if (process.env["HASNA_INSTRUCTIONS_DB_PATH"]) {
|
|
@@ -2283,7 +2283,7 @@ function getDbPath() {
|
|
|
2283
2283
|
}
|
|
2284
2284
|
const dir = getRawStoreRoot();
|
|
2285
2285
|
mkdirSync(dir, { recursive: true });
|
|
2286
|
-
return
|
|
2286
|
+
return join7(dir, "instructions.db");
|
|
2287
2287
|
}
|
|
2288
2288
|
function uuid() {
|
|
2289
2289
|
return randomUUID3();
|
|
@@ -2324,7 +2324,7 @@ function resetLocalDatabase() {
|
|
|
2324
2324
|
if (dbPath === ":memory:")
|
|
2325
2325
|
return;
|
|
2326
2326
|
for (const p of [dbPath, `${dbPath}-wal`, `${dbPath}-shm`]) {
|
|
2327
|
-
if (
|
|
2327
|
+
if (existsSync5(p))
|
|
2328
2328
|
rmSync(p);
|
|
2329
2329
|
}
|
|
2330
2330
|
}
|
|
@@ -2761,9 +2761,9 @@ var init_template = __esm(() => {
|
|
|
2761
2761
|
});
|
|
2762
2762
|
|
|
2763
2763
|
// src/lib/machine.ts
|
|
2764
|
-
import { arch as currentArch, homedir as
|
|
2765
|
-
import { existsSync as
|
|
2766
|
-
import { join as
|
|
2764
|
+
import { arch as currentArch, homedir as homedir6, hostname as currentHostname, type as currentOsType } from "os";
|
|
2765
|
+
import { existsSync as existsSync6 } from "fs";
|
|
2766
|
+
import { join as join8 } from "path";
|
|
2767
2767
|
function normalizeOsFamily(os) {
|
|
2768
2768
|
const value = (os ?? "").trim().toLowerCase();
|
|
2769
2769
|
if (value === "darwin" || value === "macos" || value === "mac" || value === "osx")
|
|
@@ -2775,11 +2775,11 @@ function normalizeOsFamily(os) {
|
|
|
2775
2775
|
return value || "unknown";
|
|
2776
2776
|
}
|
|
2777
2777
|
function detectMachineContext(overrides = {}) {
|
|
2778
|
-
const homeDir2 = overrides.home_dir ?? process.env["CONFIGS_HOME"] ?? process.env["HOME"] ??
|
|
2778
|
+
const homeDir2 = overrides.home_dir ?? process.env["CONFIGS_HOME"] ?? process.env["HOME"] ?? homedir6();
|
|
2779
2779
|
const os = overrides.os ?? currentOsType();
|
|
2780
2780
|
const osFamily = normalizeOsFamily(os);
|
|
2781
|
-
const bunBinDir = overrides.bun_bin_dir ??
|
|
2782
|
-
const defaultBunPath = osFamily === "macos" &&
|
|
2781
|
+
const bunBinDir = overrides.bun_bin_dir ?? join8(homeDir2, ".bun", "bin");
|
|
2782
|
+
const defaultBunPath = osFamily === "macos" && existsSync6(BREW_BUN_PATH) ? BREW_BUN_PATH : join8(bunBinDir, "bun");
|
|
2783
2783
|
return {
|
|
2784
2784
|
id: "current-machine",
|
|
2785
2785
|
hostname: overrides.hostname ?? currentHostname(),
|
|
@@ -2789,10 +2789,10 @@ function detectMachineContext(overrides = {}) {
|
|
|
2789
2789
|
created_at: "",
|
|
2790
2790
|
os_family: osFamily,
|
|
2791
2791
|
home_dir: homeDir2,
|
|
2792
|
-
workspace_root: overrides.workspace_root ??
|
|
2792
|
+
workspace_root: overrides.workspace_root ?? join8(homeDir2, osFamily === "macos" ? "Workspace" : "workspace"),
|
|
2793
2793
|
bun_bin_dir: bunBinDir,
|
|
2794
2794
|
bun_path: overrides.bun_path ?? defaultBunPath,
|
|
2795
|
-
path_prefix: overrides.path_prefix ?? (osFamily === "macos" ? `${
|
|
2795
|
+
path_prefix: overrides.path_prefix ?? (osFamily === "macos" ? `${join8("/opt", "homebrew", "bin")}:${bunBinDir}` : bunBinDir)
|
|
2796
2796
|
};
|
|
2797
2797
|
}
|
|
2798
2798
|
function machineContextToVariables(machine) {
|
|
@@ -7427,7 +7427,7 @@ import { dlopen, FFIType } from "bun:ffi";
|
|
|
7427
7427
|
import {
|
|
7428
7428
|
closeSync,
|
|
7429
7429
|
constants,
|
|
7430
|
-
existsSync as
|
|
7430
|
+
existsSync as existsSync7,
|
|
7431
7431
|
fstatSync,
|
|
7432
7432
|
fsyncSync,
|
|
7433
7433
|
lstatSync,
|
|
@@ -7440,7 +7440,7 @@ import {
|
|
|
7440
7440
|
statSync,
|
|
7441
7441
|
writeFileSync
|
|
7442
7442
|
} from "fs";
|
|
7443
|
-
import { basename, dirname, isAbsolute, join as
|
|
7443
|
+
import { basename, dirname, isAbsolute, join as join9, parse, relative, resolve as resolve4 } from "path";
|
|
7444
7444
|
function managedObservationMaxBytes(relativePath) {
|
|
7445
7445
|
return SESSION_MANAGED_OUTPUT_PATHS.includes(relativePath) ? SESSION_MANAGED_OUTPUT_MAX_BYTES : FOREIGN_INPUT_MAX_BYTES;
|
|
7446
7446
|
}
|
|
@@ -7520,7 +7520,7 @@ function planProjectContext(input) {
|
|
|
7520
7520
|
const inlineMarkerOverhead = nativeImports ? 0 : Buffer.byteLength(buildManagedBlock(bundle, "", `
|
|
7521
7521
|
`), "utf8");
|
|
7522
7522
|
const generated = buildCanonicalFragment(bundle, status, ageSeconds, PROJECT_CONTEXT_MAX_RENDERED_BYTES - Math.max(320, inlineMarkerOverhead), PROJECT_CONTEXT_MAX_APPROX_TOKENS - Math.max(80, Math.ceil(inlineMarkerOverhead / 4)));
|
|
7523
|
-
const previousTargetContent =
|
|
7523
|
+
const previousTargetContent = existsSync7(paths.target) ? readUtf8RegularFile(paths.target, workspaceRoot, managedObservationMaxBytes(relativePosix(workspaceRoot, paths.target))) : null;
|
|
7524
7524
|
const markerParse = parseManagedBlock(previousTargetContent ?? "", input.force === true);
|
|
7525
7525
|
if (markerParse.block && markerParse.block.id !== bundle.project.id) {
|
|
7526
7526
|
throw new ProjectContextError("MANAGED_BLOCK_CONFLICT", "managed block belongs to a different project");
|
|
@@ -7571,7 +7571,7 @@ function composeProjectContextSessionRender(input) {
|
|
|
7571
7571
|
return null;
|
|
7572
7572
|
const { runtime, workspace_root: workspaceRoot, observed_hashes: observedHashes } = guard;
|
|
7573
7573
|
const paths = runtimePaths(workspaceRoot, runtime);
|
|
7574
|
-
if (!
|
|
7574
|
+
if (!existsSync7(paths.manifest))
|
|
7575
7575
|
return null;
|
|
7576
7576
|
assertCodewithTargetIsConsumed(workspaceRoot, runtime);
|
|
7577
7577
|
const manifest = readProjectContextManifest(paths.manifest, workspaceRoot);
|
|
@@ -7600,7 +7600,7 @@ function composeProjectContextSessionRender(input) {
|
|
|
7600
7600
|
}
|
|
7601
7601
|
const fragment = readUtf8RegularFile(paths.fragment, workspaceRoot, PROJECT_CONTEXT_MAX_RENDERED_BYTES);
|
|
7602
7602
|
scanGeneratedContent(fragment);
|
|
7603
|
-
if (!
|
|
7603
|
+
if (!existsSync7(paths.target)) {
|
|
7604
7604
|
throw new ProjectContextError("MANAGED_BLOCK_CONFLICT", "project-context provider target is missing while durable context is active");
|
|
7605
7605
|
}
|
|
7606
7606
|
const currentTarget = readUtf8RegularFile(paths.target, workspaceRoot, managedObservationMaxBytes(relativePosix(workspaceRoot, paths.target)));
|
|
@@ -7611,7 +7611,7 @@ function composeProjectContextSessionRender(input) {
|
|
|
7611
7611
|
if (currentMarkers.block.id !== cache.project_id || currentMarkers.block.revision !== cache.revision || currentMarkers.block.hash !== cache.hash) {
|
|
7612
7612
|
throw new ProjectContextError("MANAGED_BLOCK_CONFLICT", "project-context provider markers differ from the durable cache");
|
|
7613
7613
|
}
|
|
7614
|
-
const plannedIndexes = input.files.filter((file) => file.role === "index" &&
|
|
7614
|
+
const plannedIndexes = input.files.filter((file) => file.role === "index" && resolve4(file.path) === paths.target);
|
|
7615
7615
|
if (plannedIndexes.length !== 1) {
|
|
7616
7616
|
throw new ProjectContextError("PROJECT_CONTEXT_MANIFEST_INVALID", "session renderer does not own the selected project-context provider target");
|
|
7617
7617
|
}
|
|
@@ -7669,7 +7669,7 @@ function withProjectContextSessionGuard(guard, action, options = {}) {
|
|
|
7669
7669
|
verify();
|
|
7670
7670
|
return action(null);
|
|
7671
7671
|
}
|
|
7672
|
-
const lockPath =
|
|
7672
|
+
const lockPath = resolve4(validated.workspace_root, ...PROJECT_CONTEXT_LOCK_PATH.split("/"));
|
|
7673
7673
|
const lock = acquireWorkspaceLock(validated.workspace_root, lockPath);
|
|
7674
7674
|
try {
|
|
7675
7675
|
verify();
|
|
@@ -7695,7 +7695,7 @@ function validateProjectContextSessionGuard(guard) {
|
|
|
7695
7695
|
if (!isRecord(observed) || typeof observed.path !== "string") {
|
|
7696
7696
|
throw new ProjectContextError("PROJECT_CONTEXT_SESSION_STALE", "session project-context guard contains malformed hash metadata");
|
|
7697
7697
|
}
|
|
7698
|
-
const path =
|
|
7698
|
+
const path = resolve4(observed.path);
|
|
7699
7699
|
if (!allowedPaths.has(path) || observedPaths.has(path)) {
|
|
7700
7700
|
throw new ProjectContextError("PROJECT_CONTEXT_SESSION_STALE", "session project-context guard contains an unexpected or duplicate path");
|
|
7701
7701
|
}
|
|
@@ -7717,7 +7717,7 @@ function validateProjectContextSessionGuard(guard) {
|
|
|
7717
7717
|
function applyProjectContext(options) {
|
|
7718
7718
|
const workspaceRoot = assertSafeWorkspaceRoot(options.workspace_root);
|
|
7719
7719
|
const now3 = options.now ?? new Date;
|
|
7720
|
-
const lockPath =
|
|
7720
|
+
const lockPath = resolve4(workspaceRoot, ...PROJECT_CONTEXT_LOCK_PATH.split("/"));
|
|
7721
7721
|
const lock = options.dry_run ? null : acquireWorkspaceLock(workspaceRoot, lockPath, options.test_hooks?.after_lock_open, options.test_hooks?.before_stale_lock_remove, options.test_hooks?.process_start_identity);
|
|
7722
7722
|
try {
|
|
7723
7723
|
const resolved = resolveBundleForApply(options, workspaceRoot, now3);
|
|
@@ -7864,7 +7864,7 @@ function resolveBundleForApply(options, workspaceRoot, now3) {
|
|
|
7864
7864
|
if (!options.expected_project_id) {
|
|
7865
7865
|
throw new ProjectContextError("PROJECT_CONTEXT_CACHE_ID_REQUIRED", "expected_project_id is required for stale-cache fallback");
|
|
7866
7866
|
}
|
|
7867
|
-
const cachePath =
|
|
7867
|
+
const cachePath = resolve4(workspaceRoot, ...PROJECT_CONTEXT_CACHE_PATH.split("/"));
|
|
7868
7868
|
const cache = readProjectContextCache(cachePath, workspaceRoot);
|
|
7869
7869
|
if (!cache)
|
|
7870
7870
|
throw new ProjectContextError("PROJECT_CONTEXT_CACHE_MISSING", "no last-known-good project context cache exists");
|
|
@@ -8066,7 +8066,7 @@ function findLegacyCodewithWorkspaceSection(workspaceRoot, runtime, content, bun
|
|
|
8066
8066
|
if (runtime !== "codewith" || !content)
|
|
8067
8067
|
return null;
|
|
8068
8068
|
const sessionManifestPath = runtimePaths(workspaceRoot, runtime).sessionManifest;
|
|
8069
|
-
if (!
|
|
8069
|
+
if (!existsSync7(sessionManifestPath))
|
|
8070
8070
|
return null;
|
|
8071
8071
|
const manifest = readSessionManifestRecord(sessionManifestPath, workspaceRoot);
|
|
8072
8072
|
if (!manifest || manifest["schema"] !== SESSION_RENDER_SCHEMA) {
|
|
@@ -8117,7 +8117,7 @@ function assertRevisionOrdering(plan, force) {
|
|
|
8117
8117
|
const manifest = readProjectContextManifest(plan.manifest_path, plan.workspace_root);
|
|
8118
8118
|
if (manifest) {
|
|
8119
8119
|
const manifestHashHasRecoveryProof = manifest.projectContext.hash === plan.bundle.hash || metadataSnapshotMatchesManifest(plan, manifest);
|
|
8120
|
-
const canonicalStateAlreadyInstalled = cache !== null && canonicalCacheHash === plan.bundle.hash && cache.project_id === plan.bundle.project.id && cache.revision === plan.bundle.revision && plan.marker !== null && plan.marker.id === plan.bundle.project.id && plan.marker.revision === plan.bundle.revision && plan.marker.hash === plan.bundle.hash &&
|
|
8120
|
+
const canonicalStateAlreadyInstalled = cache !== null && canonicalCacheHash === plan.bundle.hash && cache.project_id === plan.bundle.project.id && cache.revision === plan.bundle.revision && plan.marker !== null && plan.marker.id === plan.bundle.project.id && plan.marker.revision === plan.bundle.revision && plan.marker.hash === plan.bundle.hash && existsSync7(plan.fragment_path) && fragmentMatchesBundle(plan.fragment_path, plan.bundle, plan.workspace_root) && manifestHashHasRecoveryProof;
|
|
8121
8121
|
observations.push({
|
|
8122
8122
|
source: "manifest",
|
|
8123
8123
|
id: manifest.projectContext.projectId,
|
|
@@ -8125,7 +8125,7 @@ function assertRevisionOrdering(plan, force) {
|
|
|
8125
8125
|
hash: canonicalStateAlreadyInstalled && manifest.projectContext.projectId === plan.bundle.project.id && manifest.projectContext.revision === plan.bundle.revision ? plan.bundle.hash : normalizePersistedHash(manifest.projectContext.revision, manifest.projectContext.hash)
|
|
8126
8126
|
});
|
|
8127
8127
|
const fragmentEntry = manifest.files.find((file) => file.relativePath === PROJECT_CONTEXT_FRAGMENT_PATH);
|
|
8128
|
-
if (fragmentEntry &&
|
|
8128
|
+
if (fragmentEntry && existsSync7(plan.fragment_path)) {
|
|
8129
8129
|
const actual = currentFileHash(plan.fragment_path, plan.workspace_root);
|
|
8130
8130
|
if (actual !== fragmentEntry.sha256 && !fragmentMatchesBundle(plan.fragment_path, plan.bundle, plan.workspace_root) && !force) {
|
|
8131
8131
|
throw new ProjectContextError("MANAGED_BLOCK_CONFLICT", "canonical project-context fragment changed outside Instructions");
|
|
@@ -8220,9 +8220,9 @@ function buildManifest(plan, now3) {
|
|
|
8220
8220
|
function buildSessionCompatibilityManifest(plan, now3) {
|
|
8221
8221
|
const paths = runtimePaths(plan.workspace_root, plan.runtime);
|
|
8222
8222
|
const tool = manifestTool(plan.runtime);
|
|
8223
|
-
const targetHome = plan.runtime === "codewith" ?
|
|
8223
|
+
const targetHome = plan.runtime === "codewith" ? resolve4(plan.workspace_root, ".codewith") : plan.workspace_root;
|
|
8224
8224
|
const targetRelativePath = sessionTargetRelativePath(plan.runtime);
|
|
8225
|
-
const existing =
|
|
8225
|
+
const existing = existsSync7(paths.sessionManifest) ? readSessionManifestRecord(paths.sessionManifest, plan.workspace_root) : {
|
|
8226
8226
|
schema: SESSION_RENDER_SCHEMA,
|
|
8227
8227
|
tool,
|
|
8228
8228
|
adapterMode: plan.native_imports ? "native-imports" : "flattened-markdown",
|
|
@@ -8242,7 +8242,7 @@ function buildSessionCompatibilityManifest(plan, now3) {
|
|
|
8242
8242
|
throw new ProjectContextError("PROJECT_CONTEXT_MANIFEST_INVALID", "provider session manifest is malformed or incompatible");
|
|
8243
8243
|
}
|
|
8244
8244
|
const existingTargetHome = safeLegacyMetadataString(existing["targetHome"], null);
|
|
8245
|
-
if (existingTargetHome !== null &&
|
|
8245
|
+
if (existingTargetHome !== null && resolve4(existingTargetHome) !== targetHome) {
|
|
8246
8246
|
throw new ProjectContextError("PROJECT_CONTEXT_MANIFEST_INVALID", "provider session manifest targets a different workspace");
|
|
8247
8247
|
}
|
|
8248
8248
|
const sources = sanitizeLegacySources(existing["sources"]).filter((source) => source["id"] !== "project-context-bundle");
|
|
@@ -8528,9 +8528,9 @@ function writeMetadataSnapshot(plan, now3) {
|
|
|
8528
8528
|
const previous = readProjectContextManifest(plan.manifest_path, plan.workspace_root);
|
|
8529
8529
|
if (!previous || previous.projectContext.revision === plan.bundle.revision && previous.projectContext.hash === plan.bundle.hash)
|
|
8530
8530
|
return null;
|
|
8531
|
-
const snapshotDir =
|
|
8531
|
+
const snapshotDir = resolve4(plan.workspace_root, ...PROJECT_CONTEXT_SNAPSHOT_DIR.split("/"));
|
|
8532
8532
|
ensureSafeDirectory(snapshotDir, plan.workspace_root, 448);
|
|
8533
|
-
const snapshotPath =
|
|
8533
|
+
const snapshotPath = resolve4(snapshotDir, `${safeFilename(previous.projectContext.revision)}-${previous.projectContext.hash.slice(-12)}.json`);
|
|
8534
8534
|
const snapshot = {
|
|
8535
8535
|
schema: "hasna.configs.session-render-snapshot/v1",
|
|
8536
8536
|
kind: "project-context-metadata",
|
|
@@ -8546,9 +8546,9 @@ function writeMetadataSnapshot(plan, now3) {
|
|
|
8546
8546
|
return snapshotPath;
|
|
8547
8547
|
}
|
|
8548
8548
|
function metadataSnapshotMatchesManifest(plan, manifest) {
|
|
8549
|
-
const snapshotDir =
|
|
8550
|
-
const snapshotPath =
|
|
8551
|
-
if (!
|
|
8549
|
+
const snapshotDir = resolve4(plan.workspace_root, ...PROJECT_CONTEXT_SNAPSHOT_DIR.split("/"));
|
|
8550
|
+
const snapshotPath = resolve4(snapshotDir, `${safeFilename(manifest.projectContext.revision)}-${manifest.projectContext.hash.slice(-12)}.json`);
|
|
8551
|
+
if (!existsSync7(snapshotPath))
|
|
8552
8552
|
return false;
|
|
8553
8553
|
const record = readJsonRecord(snapshotPath, plan.workspace_root);
|
|
8554
8554
|
const result = projectContextMetadataSnapshotSchema.safeParse(record);
|
|
@@ -8596,10 +8596,10 @@ function writeProjectContextRollbackSnapshot(plan, now3, outputs) {
|
|
|
8596
8596
|
sha256: nextHash
|
|
8597
8597
|
};
|
|
8598
8598
|
});
|
|
8599
|
-
const snapshotDir =
|
|
8599
|
+
const snapshotDir = resolve4(plan.workspace_root, ...SESSION_RENDER_SNAPSHOT_RELATIVE_DIR.split("/"));
|
|
8600
8600
|
ensureSafeDirectory(snapshotDir, plan.workspace_root, 448);
|
|
8601
8601
|
const timestamp = now3.toISOString().replace(/[:.]/g, "-");
|
|
8602
|
-
const snapshotPath =
|
|
8602
|
+
const snapshotPath = resolve4(snapshotDir, `${timestamp}-${randomUUID5()}.json`);
|
|
8603
8603
|
const snapshot = {
|
|
8604
8604
|
schema: "hasna.configs.session-render-snapshot/v2",
|
|
8605
8605
|
createdAt: now3.toISOString(),
|
|
@@ -8617,7 +8617,7 @@ function writeProjectContextRollbackSnapshot(plan, now3, outputs) {
|
|
|
8617
8617
|
return snapshotPath;
|
|
8618
8618
|
}
|
|
8619
8619
|
function readProjectContextManifest(path, workspaceRoot) {
|
|
8620
|
-
if (!
|
|
8620
|
+
if (!existsSync7(path))
|
|
8621
8621
|
return null;
|
|
8622
8622
|
const record = readJsonRecord(path, workspaceRoot);
|
|
8623
8623
|
const result = storedManifestObservationSchema.safeParse(record);
|
|
@@ -8632,7 +8632,7 @@ function readProjectContextManifest(path, workspaceRoot) {
|
|
|
8632
8632
|
};
|
|
8633
8633
|
}
|
|
8634
8634
|
function readProjectContextCache(path, workspaceRoot) {
|
|
8635
|
-
if (!
|
|
8635
|
+
if (!existsSync7(path))
|
|
8636
8636
|
return null;
|
|
8637
8637
|
const record = readJsonRecord(path, workspaceRoot);
|
|
8638
8638
|
const result = projectContextCacheSchema.safeParse(record);
|
|
@@ -8664,7 +8664,7 @@ function readSessionManifestRecord(path, workspaceRoot) {
|
|
|
8664
8664
|
}
|
|
8665
8665
|
}
|
|
8666
8666
|
function atomicWriteFile(path, content, workspaceRoot, defaultMode, expectedHash, afterExchange, atomicExchangeUnavailable = false, beforeInstall, portableCreateOnly = false, maxObservedBytes, allowPortableReplacement = false) {
|
|
8667
|
-
const dir =
|
|
8667
|
+
const dir = resolve4(path, "..");
|
|
8668
8668
|
ensureSafeDirectory(dir, workspaceRoot, 448);
|
|
8669
8669
|
assertNoSymlinkSegments(workspaceRoot, path);
|
|
8670
8670
|
const anchoredOps = portableCreateOnly ? null : resolveAnchoredFsOps();
|
|
@@ -8681,7 +8681,7 @@ function atomicWriteFile(path, content, workspaceRoot, defaultMode, expectedHash
|
|
|
8681
8681
|
const previous = anchoredFileObservation(directory, targetName);
|
|
8682
8682
|
const previousMode = previous?.mode ?? defaultMode;
|
|
8683
8683
|
const tempName = `.project-context-${randomUUID5()}.tmp`;
|
|
8684
|
-
const tempPath =
|
|
8684
|
+
const tempPath = join9(dir, tempName);
|
|
8685
8685
|
let fd = null;
|
|
8686
8686
|
let preserveTemp = false;
|
|
8687
8687
|
let directoryChanged = false;
|
|
@@ -8812,7 +8812,7 @@ function atomicWritePortable(path, content, workspaceRoot, defaultMode, expected
|
|
|
8812
8812
|
}
|
|
8813
8813
|
const dir = dirname(path);
|
|
8814
8814
|
const directoryIdentity = captureManagedDirectoryIdentity(dir, workspaceRoot);
|
|
8815
|
-
const tempPath =
|
|
8815
|
+
const tempPath = join9(dir, `.project-context-${randomUUID5()}.tmp`);
|
|
8816
8816
|
let fd = null;
|
|
8817
8817
|
let tempIdentity = null;
|
|
8818
8818
|
try {
|
|
@@ -8869,7 +8869,7 @@ function atomicWritePortableReplacement(path, content, workspaceRoot, expectedHa
|
|
|
8869
8869
|
}
|
|
8870
8870
|
const dir = dirname(path);
|
|
8871
8871
|
const directoryIdentity = captureManagedDirectoryIdentity(dir, workspaceRoot);
|
|
8872
|
-
const tempPath =
|
|
8872
|
+
const tempPath = join9(dir, `.project-context-${randomUUID5()}.tmp`);
|
|
8873
8873
|
const desiredHash = sha2562(content);
|
|
8874
8874
|
let fd = null;
|
|
8875
8875
|
let tempIdentity = null;
|
|
@@ -8926,7 +8926,7 @@ function portablePreparedHash(tempPath, path, workspaceRoot, maxObservedBytes, s
|
|
|
8926
8926
|
function portableFileHash(path, workspaceRoot, maxObservedBytes) {
|
|
8927
8927
|
if (maxObservedBytes === undefined)
|
|
8928
8928
|
return currentFileHash(path, workspaceRoot);
|
|
8929
|
-
if (!
|
|
8929
|
+
if (!existsSync7(path))
|
|
8930
8930
|
return null;
|
|
8931
8931
|
assertNoSymlinkSegments(workspaceRoot, path);
|
|
8932
8932
|
const stat = lstatSync(path);
|
|
@@ -8938,11 +8938,11 @@ function portableFileHash(path, workspaceRoot, maxObservedBytes) {
|
|
|
8938
8938
|
return createHash2("sha256").update(readFileSync(path)).digest("hex");
|
|
8939
8939
|
}
|
|
8940
8940
|
function writeProjectContextCoordinatedFile(input) {
|
|
8941
|
-
atomicWriteFile(
|
|
8941
|
+
atomicWriteFile(resolve4(input.path), input.content, assertSafeWorkspaceRoot(input.workspace_root), input.default_mode ?? 420, input.expected_hash, undefined, false, input.test_hooks?.before_install, input.force_portable_file_ops ?? false, input.max_observed_bytes, input.allow_portable_replacement ?? false);
|
|
8942
8942
|
}
|
|
8943
8943
|
function removeProjectContextCoordinatedFile(input) {
|
|
8944
8944
|
const workspaceRoot = assertSafeWorkspaceRoot(input.workspace_root);
|
|
8945
|
-
const path =
|
|
8945
|
+
const path = resolve4(input.path);
|
|
8946
8946
|
assertNoSymlinkSegments(workspaceRoot, path);
|
|
8947
8947
|
const dir = dirname(path);
|
|
8948
8948
|
const anchoredOps = input.force_portable_file_ops ? null : resolveAnchoredFsOps();
|
|
@@ -8968,7 +8968,7 @@ function removeProjectContextCoordinatedFile(input) {
|
|
|
8968
8968
|
throw new ProjectContextHashRace(`managed path changed during deletion: ${relativePosix(workspaceRoot, path)}`);
|
|
8969
8969
|
}
|
|
8970
8970
|
displaced = true;
|
|
8971
|
-
input.test_hooks?.after_displace?.(
|
|
8971
|
+
input.test_hooks?.after_displace?.(join9(dir, displacedName));
|
|
8972
8972
|
const moved = anchoredFileObservation(directory, displacedName);
|
|
8973
8973
|
if (!moved || moved.dev !== observed.dev || moved.ino !== observed.ino || moved.hash !== input.expected_hash || anchoredFileObservation(directory, targetName) !== null) {
|
|
8974
8974
|
throw new ProjectContextHashRace(`managed path changed during deletion validation: ${relativePosix(workspaceRoot, path)}`);
|
|
@@ -9014,7 +9014,7 @@ function removePortableCoordinatedFile(path, workspaceRoot, expectedHash, maxObs
|
|
|
9014
9014
|
}
|
|
9015
9015
|
const dir = dirname(path);
|
|
9016
9016
|
const directoryIdentity = captureManagedDirectoryIdentity(dir, workspaceRoot);
|
|
9017
|
-
const displacedPath =
|
|
9017
|
+
const displacedPath = join9(dir, `.project-context-delete-${randomUUID5()}.tmp`);
|
|
9018
9018
|
let displaced = false;
|
|
9019
9019
|
try {
|
|
9020
9020
|
assertManagedDirectoryStable(dir, workspaceRoot, directoryIdentity);
|
|
@@ -9025,7 +9025,7 @@ function removePortableCoordinatedFile(path, workspaceRoot, expectedHash, maxObs
|
|
|
9025
9025
|
displaced = true;
|
|
9026
9026
|
afterDisplace?.(displacedPath);
|
|
9027
9027
|
const moved = lstatSync(displacedPath);
|
|
9028
|
-
if (moved.isSymbolicLink() || !moved.isFile() || moved.dev !== observed.dev || moved.ino !== observed.ino || portableFileHash(displacedPath, workspaceRoot, maxObservedBytes) !== expectedHash ||
|
|
9028
|
+
if (moved.isSymbolicLink() || !moved.isFile() || moved.dev !== observed.dev || moved.ino !== observed.ino || portableFileHash(displacedPath, workspaceRoot, maxObservedBytes) !== expectedHash || existsSync7(path)) {
|
|
9029
9029
|
throw new ProjectContextHashRace(`managed path changed during portable deletion: ${relativePosix(workspaceRoot, path)}`);
|
|
9030
9030
|
}
|
|
9031
9031
|
rmSync2(displacedPath);
|
|
@@ -9085,7 +9085,7 @@ function anchoredOpenExclusive(directory, name, mode) {
|
|
|
9085
9085
|
const requestedMode = mode & 4095;
|
|
9086
9086
|
let fd;
|
|
9087
9087
|
try {
|
|
9088
|
-
fd = openSync(
|
|
9088
|
+
fd = openSync(join9(directory.path, name), constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW, requestedMode);
|
|
9089
9089
|
} catch {
|
|
9090
9090
|
throw new ProjectContextHashRace(`could not create prepared managed file in ${relativePosix(directory.workspaceRoot, directory.path)}`);
|
|
9091
9091
|
}
|
|
@@ -9128,7 +9128,7 @@ function anchoredFileObservation(directory, name) {
|
|
|
9128
9128
|
const stat = fstatSync(fd);
|
|
9129
9129
|
if (!stat.isFile())
|
|
9130
9130
|
throw new ProjectContextHashRace("managed output is not a regular file");
|
|
9131
|
-
const relativePath = relativePosix(directory.workspaceRoot,
|
|
9131
|
+
const relativePath = relativePosix(directory.workspaceRoot, join9(directory.path, name));
|
|
9132
9132
|
const maxBytes = directory.maxObservedBytes === undefined ? managedObservationMaxBytes(relativePath) : directory.maxObservedBytes;
|
|
9133
9133
|
if (maxBytes !== null && stat.size > maxBytes) {
|
|
9134
9134
|
throw new ProjectContextHashRace(`managed output exceeds the safe read limit: ${relativePath}`);
|
|
@@ -9154,7 +9154,7 @@ function anchoredPreparedObservation(directory, name, path, stage) {
|
|
|
9154
9154
|
return observed;
|
|
9155
9155
|
}
|
|
9156
9156
|
function captureManagedDirectoryIdentity(path, workspaceRoot) {
|
|
9157
|
-
assertNoSymlinkSegments(workspaceRoot,
|
|
9157
|
+
assertNoSymlinkSegments(workspaceRoot, join9(path, ".project-context-directory-guard"));
|
|
9158
9158
|
let stat;
|
|
9159
9159
|
try {
|
|
9160
9160
|
stat = lstatSync(path);
|
|
@@ -9167,7 +9167,7 @@ function captureManagedDirectoryIdentity(path, workspaceRoot) {
|
|
|
9167
9167
|
return { dev: stat.dev, ino: stat.ino };
|
|
9168
9168
|
}
|
|
9169
9169
|
function assertManagedDirectoryStable(path, workspaceRoot, expected) {
|
|
9170
|
-
assertNoSymlinkSegments(workspaceRoot,
|
|
9170
|
+
assertNoSymlinkSegments(workspaceRoot, join9(path, ".project-context-directory-guard"));
|
|
9171
9171
|
let current;
|
|
9172
9172
|
try {
|
|
9173
9173
|
current = lstatSync(path);
|
|
@@ -9300,10 +9300,10 @@ function resolveAnchoredFsOps() {
|
|
|
9300
9300
|
return null;
|
|
9301
9301
|
}
|
|
9302
9302
|
function acquireWorkspaceLock(workspaceRoot, lockPath, afterOpen, beforeStaleRemove, processStartIdentityLookup = processStartIdentity) {
|
|
9303
|
-
const lockDirectory =
|
|
9303
|
+
const lockDirectory = resolve4(lockPath, "..");
|
|
9304
9304
|
ensureSafeDirectory(lockDirectory, workspaceRoot, 448);
|
|
9305
9305
|
assertNoSymlinkSegments(workspaceRoot, lockPath);
|
|
9306
|
-
const tempPath =
|
|
9306
|
+
const tempPath = join9(lockDirectory, `.project-context-lock-${randomUUID5()}.tmp`);
|
|
9307
9307
|
let fd = null;
|
|
9308
9308
|
let openedIdentity = null;
|
|
9309
9309
|
let openedContentHash = null;
|
|
@@ -9337,7 +9337,7 @@ function acquireWorkspaceLock(workspaceRoot, lockPath, afterOpen, beforeStaleRem
|
|
|
9337
9337
|
linked = true;
|
|
9338
9338
|
}
|
|
9339
9339
|
fsyncDirectory(lockDirectory);
|
|
9340
|
-
if (
|
|
9340
|
+
if (existsSync7(tempPath)) {
|
|
9341
9341
|
rmSync2(tempPath);
|
|
9342
9342
|
fsyncDirectory(lockDirectory);
|
|
9343
9343
|
}
|
|
@@ -9352,7 +9352,7 @@ function acquireWorkspaceLock(workspaceRoot, lockPath, afterOpen, beforeStaleRem
|
|
|
9352
9352
|
if (linked && openedIdentity && openedContentHash) {
|
|
9353
9353
|
removeOwnedLockByInode(lockPath, openedIdentity, openedContentHash);
|
|
9354
9354
|
}
|
|
9355
|
-
if (!preserveTemp &&
|
|
9355
|
+
if (!preserveTemp && existsSync7(tempPath)) {
|
|
9356
9356
|
try {
|
|
9357
9357
|
rmSync2(tempPath);
|
|
9358
9358
|
} catch {}
|
|
@@ -9367,7 +9367,7 @@ function acquireWorkspaceLock(workspaceRoot, lockPath, afterOpen, beforeStaleRem
|
|
|
9367
9367
|
}
|
|
9368
9368
|
function removeOwnedLockByInode(lockPath, identity, expectedHash) {
|
|
9369
9369
|
try {
|
|
9370
|
-
if (!
|
|
9370
|
+
if (!existsSync7(lockPath))
|
|
9371
9371
|
return;
|
|
9372
9372
|
const current = lstatSync(lockPath);
|
|
9373
9373
|
if (current.isSymbolicLink() || current.dev !== identity.dev || current.ino !== identity.ino)
|
|
@@ -9375,7 +9375,7 @@ function removeOwnedLockByInode(lockPath, identity, expectedHash) {
|
|
|
9375
9375
|
if (expectedHash !== undefined && sha2562(readFileSync(lockPath, "utf8")) !== expectedHash)
|
|
9376
9376
|
return;
|
|
9377
9377
|
rmSync2(lockPath);
|
|
9378
|
-
fsyncDirectory(
|
|
9378
|
+
fsyncDirectory(resolve4(lockPath, ".."));
|
|
9379
9379
|
} catch {}
|
|
9380
9380
|
}
|
|
9381
9381
|
function observeStaleWorkspaceLock(lockPath, workspaceRoot, processStartIdentityLookup = processStartIdentity) {
|
|
@@ -9446,7 +9446,7 @@ function tryTakeoverStaleWorkspaceLock(candidatePath, lockPath, workspaceRoot, c
|
|
|
9446
9446
|
const candidateInstalled = !current.isSymbolicLink() && current.dev === candidateIdentity.dev && current.ino === candidateIdentity.ino && currentFileHash(lockPath, workspaceRoot) === candidateHash;
|
|
9447
9447
|
const staleDisplaced = !displaced.isSymbolicLink() && displaced.dev === stale.identity.dev && displaced.ino === stale.identity.ino && currentFileHash(candidatePath, workspaceRoot) === stale.contentHash;
|
|
9448
9448
|
if (!candidateInstalled || !staleDisplaced) {
|
|
9449
|
-
if (candidateInstalled &&
|
|
9449
|
+
if (candidateInstalled && existsSync7(candidatePath)) {
|
|
9450
9450
|
atomicExchangePaths(candidatePath, lockPath);
|
|
9451
9451
|
exchanged = false;
|
|
9452
9452
|
return false;
|
|
@@ -9454,13 +9454,13 @@ function tryTakeoverStaleWorkspaceLock(candidatePath, lockPath, workspaceRoot, c
|
|
|
9454
9454
|
throw new ProjectContextError("PROJECT_CONTEXT_LOCK_LOST", "workspace lock changed during stale-lock takeover and could not be restored safely");
|
|
9455
9455
|
}
|
|
9456
9456
|
rmSync2(candidatePath);
|
|
9457
|
-
fsyncDirectory(
|
|
9457
|
+
fsyncDirectory(resolve4(lockPath, ".."));
|
|
9458
9458
|
exchanged = false;
|
|
9459
9459
|
return true;
|
|
9460
9460
|
} catch (error) {
|
|
9461
9461
|
if (exchanged) {
|
|
9462
9462
|
try {
|
|
9463
|
-
if (currentFileHash(lockPath, workspaceRoot) === candidateHash &&
|
|
9463
|
+
if (currentFileHash(lockPath, workspaceRoot) === candidateHash && existsSync7(candidatePath)) {
|
|
9464
9464
|
atomicExchangePaths(candidatePath, lockPath);
|
|
9465
9465
|
exchanged = false;
|
|
9466
9466
|
}
|
|
@@ -9473,7 +9473,7 @@ function tryTakeoverStaleWorkspaceLock(candidatePath, lockPath, workspaceRoot, c
|
|
|
9473
9473
|
}
|
|
9474
9474
|
}
|
|
9475
9475
|
function assertWorkspaceLockHeld(lockPath, lock, workspaceRoot) {
|
|
9476
|
-
if (!
|
|
9476
|
+
if (!existsSync7(lockPath)) {
|
|
9477
9477
|
throw new ProjectContextError("PROJECT_CONTEXT_LOCK_LOST", "workspace project-context lock changed during render");
|
|
9478
9478
|
}
|
|
9479
9479
|
const current = lstatSync(lockPath);
|
|
@@ -9533,8 +9533,8 @@ function releaseWorkspaceLock(lockPath, lock, workspaceRoot) {
|
|
|
9533
9533
|
}
|
|
9534
9534
|
return;
|
|
9535
9535
|
}
|
|
9536
|
-
const lockDirectory =
|
|
9537
|
-
const releasePath =
|
|
9536
|
+
const lockDirectory = resolve4(lockPath, "..");
|
|
9537
|
+
const releasePath = join9(lockDirectory, `.project-context-release-${randomUUID5()}.tmp`);
|
|
9538
9538
|
let releaseFd = null;
|
|
9539
9539
|
let releaseIdentity = null;
|
|
9540
9540
|
let releaseHash = null;
|
|
@@ -9563,7 +9563,7 @@ function releaseWorkspaceLock(lockPath, lock, workspaceRoot) {
|
|
|
9563
9563
|
const releaseInstalled = !installed.isSymbolicLink() && installed.dev === releaseIdentity.dev && installed.ino === releaseIdentity.ino && currentFileHash(lockPath, workspaceRoot) === releaseHash;
|
|
9564
9564
|
const ownedDisplaced = !displaced.isSymbolicLink() && displaced.dev === lock.identity.dev && displaced.ino === lock.identity.ino && currentFileHash(releasePath, workspaceRoot) === lock.contentHash;
|
|
9565
9565
|
if (!releaseInstalled || !ownedDisplaced) {
|
|
9566
|
-
if (releaseInstalled &&
|
|
9566
|
+
if (releaseInstalled && existsSync7(releasePath)) {
|
|
9567
9567
|
atomicExchangePaths(releasePath, lockPath);
|
|
9568
9568
|
exchanged = false;
|
|
9569
9569
|
}
|
|
@@ -9576,7 +9576,7 @@ function releaseWorkspaceLock(lockPath, lock, workspaceRoot) {
|
|
|
9576
9576
|
} catch {
|
|
9577
9577
|
if (exchanged) {
|
|
9578
9578
|
try {
|
|
9579
|
-
if (releaseHash && currentFileHash(lockPath, workspaceRoot) === releaseHash &&
|
|
9579
|
+
if (releaseHash && currentFileHash(lockPath, workspaceRoot) === releaseHash && existsSync7(releasePath)) {
|
|
9580
9580
|
atomicExchangePaths(releasePath, lockPath);
|
|
9581
9581
|
exchanged = false;
|
|
9582
9582
|
}
|
|
@@ -9588,7 +9588,7 @@ function releaseWorkspaceLock(lockPath, lock, workspaceRoot) {
|
|
|
9588
9588
|
closeSync(releaseFd);
|
|
9589
9589
|
} catch {}
|
|
9590
9590
|
}
|
|
9591
|
-
if (!exchanged &&
|
|
9591
|
+
if (!exchanged && existsSync7(releasePath)) {
|
|
9592
9592
|
try {
|
|
9593
9593
|
rmSync2(releasePath);
|
|
9594
9594
|
} catch {}
|
|
@@ -9614,15 +9614,15 @@ function ensureSafeDirectory(path, workspaceRoot, mode) {
|
|
|
9614
9614
|
const segments = rel.split(/[\\/]+/).filter(Boolean);
|
|
9615
9615
|
let current = workspaceRoot;
|
|
9616
9616
|
for (const segment of segments) {
|
|
9617
|
-
current =
|
|
9618
|
-
if (
|
|
9617
|
+
current = join9(current, segment);
|
|
9618
|
+
if (existsSync7(current)) {
|
|
9619
9619
|
if (lstatSync(current).isSymbolicLink())
|
|
9620
9620
|
throw new ProjectContextError("PROJECT_CONTEXT_SYMLINK_REJECTED", `managed path uses a symlink: ${current}`);
|
|
9621
9621
|
if (!statSync(current).isDirectory())
|
|
9622
9622
|
throw new ProjectContextError("PROJECT_CONTEXT_PATH_INVALID", `managed path is not a directory: ${current}`);
|
|
9623
9623
|
} else {
|
|
9624
9624
|
mkdirSync2(current, { mode });
|
|
9625
|
-
fsyncDirectory(
|
|
9625
|
+
fsyncDirectory(resolve4(current, ".."));
|
|
9626
9626
|
}
|
|
9627
9627
|
}
|
|
9628
9628
|
}
|
|
@@ -9678,11 +9678,11 @@ function scanGeneratedContent(content) {
|
|
|
9678
9678
|
function runtimePaths(workspaceRoot, runtime) {
|
|
9679
9679
|
const relativeTarget = runtime === "claude" ? "CLAUDE.md" : runtime === "codewith" ? ".codewith/CODEWITH.md" : "AGENTS.md";
|
|
9680
9680
|
return {
|
|
9681
|
-
target:
|
|
9682
|
-
fragment:
|
|
9683
|
-
manifest:
|
|
9684
|
-
cache:
|
|
9685
|
-
sessionManifest: runtime === "codewith" ?
|
|
9681
|
+
target: resolve4(workspaceRoot, ...relativeTarget.split("/")),
|
|
9682
|
+
fragment: resolve4(workspaceRoot, ...PROJECT_CONTEXT_FRAGMENT_PATH.split("/")),
|
|
9683
|
+
manifest: resolve4(workspaceRoot, ...PROJECT_CONTEXT_MANIFEST_PATH.split("/")),
|
|
9684
|
+
cache: resolve4(workspaceRoot, ...PROJECT_CONTEXT_CACHE_PATH.split("/")),
|
|
9685
|
+
sessionManifest: runtime === "codewith" ? resolve4(workspaceRoot, ".codewith", ".hasna", "session-render-manifest.json") : resolve4(workspaceRoot, ".hasna", "session-render-manifest.json")
|
|
9686
9686
|
};
|
|
9687
9687
|
}
|
|
9688
9688
|
function projectContextSessionGuardPaths(paths, runtime) {
|
|
@@ -9692,7 +9692,7 @@ function projectContextSessionGuardPaths(paths, runtime) {
|
|
|
9692
9692
|
paths.fragment,
|
|
9693
9693
|
paths.target,
|
|
9694
9694
|
paths.sessionManifest,
|
|
9695
|
-
...runtime === "codewith" ? [
|
|
9695
|
+
...runtime === "codewith" ? [resolve4(paths.target, "..", "CODEWITH.override.md")] : []
|
|
9696
9696
|
];
|
|
9697
9697
|
}
|
|
9698
9698
|
function sessionTargetRelativePath(runtime) {
|
|
@@ -9712,27 +9712,27 @@ function projectContextRuntimeForSessionTool(tool) {
|
|
|
9712
9712
|
return null;
|
|
9713
9713
|
}
|
|
9714
9714
|
function projectContextWorkspaceForSession(input, runtime) {
|
|
9715
|
-
const targetHome =
|
|
9715
|
+
const targetHome = resolve4(input.target_home);
|
|
9716
9716
|
if (runtime === "codewith") {
|
|
9717
9717
|
const workspaceRoot = basename(targetHome) === ".codewith" ? dirname(targetHome) : null;
|
|
9718
9718
|
if (!workspaceRoot)
|
|
9719
9719
|
return null;
|
|
9720
|
-
if (input.project_root &&
|
|
9720
|
+
if (input.project_root && resolve4(input.project_root) !== workspaceRoot) {
|
|
9721
9721
|
throw new ProjectContextError("PROJECT_CONTEXT_PATH_INVALID", "Codewith project_root must be the parent workspace of target_home");
|
|
9722
9722
|
}
|
|
9723
|
-
if (!
|
|
9723
|
+
if (!existsSync7(workspaceRoot) || !lstatSync(workspaceRoot).isDirectory())
|
|
9724
9724
|
return null;
|
|
9725
9725
|
return assertSafeWorkspaceRoot(workspaceRoot);
|
|
9726
9726
|
}
|
|
9727
|
-
if (!
|
|
9727
|
+
if (!existsSync7(targetHome) || !lstatSync(targetHome).isDirectory())
|
|
9728
9728
|
return null;
|
|
9729
9729
|
return assertSafeWorkspaceRoot(targetHome);
|
|
9730
9730
|
}
|
|
9731
9731
|
function assertCodewithTargetIsConsumed(workspaceRoot, runtime) {
|
|
9732
9732
|
if (runtime !== "codewith")
|
|
9733
9733
|
return;
|
|
9734
|
-
const override =
|
|
9735
|
-
if (!
|
|
9734
|
+
const override = resolve4(workspaceRoot, ".codewith", "CODEWITH.override.md");
|
|
9735
|
+
if (!existsSync7(override))
|
|
9736
9736
|
return;
|
|
9737
9737
|
assertNoSymlinkSegments(workspaceRoot, override);
|
|
9738
9738
|
if (!lstatSync(override).isFile())
|
|
@@ -9742,10 +9742,10 @@ function assertCodewithTargetIsConsumed(workspaceRoot, runtime) {
|
|
|
9742
9742
|
function assertSafeWorkspaceRoot(path) {
|
|
9743
9743
|
if (!isAbsolute(path))
|
|
9744
9744
|
throw new ProjectContextError("PROJECT_CONTEXT_PATH_INVALID", "workspace root must be absolute");
|
|
9745
|
-
const normalized =
|
|
9745
|
+
const normalized = resolve4(path);
|
|
9746
9746
|
if (normalized === parse(normalized).root)
|
|
9747
9747
|
throw new ProjectContextError("PROJECT_CONTEXT_PATH_INVALID", "workspace root cannot be the filesystem root");
|
|
9748
|
-
if (!
|
|
9748
|
+
if (!existsSync7(normalized) || !lstatSync(normalized).isDirectory())
|
|
9749
9749
|
throw new ProjectContextError("PROJECT_CONTEXT_PATH_INVALID", "workspace root must be an existing directory");
|
|
9750
9750
|
assertNoSymlinkAncestors(normalized);
|
|
9751
9751
|
if (lstatSync(normalized).isSymbolicLink())
|
|
@@ -9759,18 +9759,18 @@ function assertNoSymlinkSegments(root, target) {
|
|
|
9759
9759
|
}
|
|
9760
9760
|
let current = root;
|
|
9761
9761
|
for (const segment of rel.split(/[\\/]+/).filter(Boolean)) {
|
|
9762
|
-
current =
|
|
9763
|
-
if (
|
|
9762
|
+
current = join9(current, segment);
|
|
9763
|
+
if (existsSync7(current) && lstatSync(current).isSymbolicLink()) {
|
|
9764
9764
|
throw new ProjectContextError("PROJECT_CONTEXT_SYMLINK_REJECTED", `managed path uses a symlink: ${current}`);
|
|
9765
9765
|
}
|
|
9766
9766
|
}
|
|
9767
9767
|
}
|
|
9768
9768
|
function assertNoSymlinkAncestors(path) {
|
|
9769
|
-
const normalized =
|
|
9769
|
+
const normalized = resolve4(path);
|
|
9770
9770
|
let current = parse(normalized).root;
|
|
9771
9771
|
for (const segment of relative(current, normalized).split(/[\\/]+/).filter(Boolean)) {
|
|
9772
|
-
current =
|
|
9773
|
-
if (!
|
|
9772
|
+
current = join9(current, segment);
|
|
9773
|
+
if (!existsSync7(current))
|
|
9774
9774
|
return;
|
|
9775
9775
|
if (lstatSync(current).isSymbolicLink())
|
|
9776
9776
|
throw new ProjectContextError("PROJECT_CONTEXT_SYMLINK_REJECTED", `workspace ancestor is a symlink: ${current}`);
|
|
@@ -9786,7 +9786,7 @@ function readUtf8RegularFile(path, workspaceRoot, maxBytes = FOREIGN_INPUT_MAX_B
|
|
|
9786
9786
|
return readFileSync(path, "utf8");
|
|
9787
9787
|
}
|
|
9788
9788
|
function currentFileHash(path, workspaceRoot) {
|
|
9789
|
-
if (!
|
|
9789
|
+
if (!existsSync7(path))
|
|
9790
9790
|
return null;
|
|
9791
9791
|
const relativePath = relativePosix(workspaceRoot, path);
|
|
9792
9792
|
return sha2562(readUtf8RegularFile(path, workspaceRoot, managedObservationMaxBytes(relativePath)));
|
|
@@ -9805,10 +9805,10 @@ function fragmentMatchesBundle(path, bundle, workspaceRoot) {
|
|
|
9805
9805
|
}
|
|
9806
9806
|
function durableSourcePath(path, workspaceRoot) {
|
|
9807
9807
|
if (!path || path.startsWith("/dev/fd/"))
|
|
9808
|
-
return
|
|
9809
|
-
const normalized = isAbsolute(path) ?
|
|
9808
|
+
return resolve4(workspaceRoot, ...PROJECT_CONTEXT_CACHE_PATH.split("/"));
|
|
9809
|
+
const normalized = isAbsolute(path) ? resolve4(path) : resolve4(workspaceRoot, path);
|
|
9810
9810
|
if (normalized.startsWith("/dev/fd/"))
|
|
9811
|
-
return
|
|
9811
|
+
return resolve4(workspaceRoot, ...PROJECT_CONTEXT_CACHE_PATH.split("/"));
|
|
9812
9812
|
return normalized;
|
|
9813
9813
|
}
|
|
9814
9814
|
function compareRevisions(incoming, previous) {
|
|
@@ -10368,7 +10368,7 @@ function compareProviderVersions(left, right) {
|
|
|
10368
10368
|
|
|
10369
10369
|
// src/lib/asset-plan.ts
|
|
10370
10370
|
import { createHash as createHash3 } from "crypto";
|
|
10371
|
-
import { isAbsolute as isAbsolute2, posix, resolve as
|
|
10371
|
+
import { isAbsolute as isAbsolute2, posix, resolve as resolve5 } from "path";
|
|
10372
10372
|
function assetCapability(provider, surface, kind, support, strategies, note, providerVersionRange = "*") {
|
|
10373
10373
|
return Object.freeze({
|
|
10374
10374
|
schema: ASSET_CAPABILITY_SCHEMA,
|
|
@@ -10575,8 +10575,8 @@ function resolveAssetDestination(item, roots) {
|
|
|
10575
10575
|
if (!isAbsolute2(root))
|
|
10576
10576
|
throw new Error(`Asset ${item.assetKey} destination root must be absolute.`);
|
|
10577
10577
|
const relativePath = safeRelativePath(item.destination.relativePath);
|
|
10578
|
-
const target =
|
|
10579
|
-
const normalizedRoot =
|
|
10578
|
+
const target = resolve5(root, ...relativePath.split("/"));
|
|
10579
|
+
const normalizedRoot = resolve5(root);
|
|
10580
10580
|
if (target === normalizedRoot)
|
|
10581
10581
|
throw new Error(`Asset ${item.assetKey} destination cannot replace its root.`);
|
|
10582
10582
|
if (!target.startsWith(`${normalizedRoot}/`))
|
|
@@ -10756,13 +10756,13 @@ var init_asset_plan = __esm(() => {
|
|
|
10756
10756
|
// src/lib/cursor-authority.ts
|
|
10757
10757
|
import { createHash as createHash4 } from "crypto";
|
|
10758
10758
|
import { lstatSync as lstatSync2, readFileSync as readFileSync2 } from "fs";
|
|
10759
|
-
import { homedir as
|
|
10760
|
-
import { join as
|
|
10759
|
+
import { homedir as homedir7 } from "os";
|
|
10760
|
+
import { join as join10, resolve as resolve6 } from "path";
|
|
10761
10761
|
function sha2564(content) {
|
|
10762
10762
|
return createHash4("sha256").update(content).digest("hex");
|
|
10763
10763
|
}
|
|
10764
10764
|
function homeDir2() {
|
|
10765
|
-
return process.env["HOME"] ||
|
|
10765
|
+
return process.env["HOME"] || homedir7();
|
|
10766
10766
|
}
|
|
10767
10767
|
function markerPayload(content, markerLine, markerIndex) {
|
|
10768
10768
|
const index = markerIndex ?? content.indexOf(markerLine);
|
|
@@ -10778,12 +10778,12 @@ function baseObservation(path) {
|
|
|
10778
10778
|
};
|
|
10779
10779
|
}
|
|
10780
10780
|
function observeCursorGlobalAuthority(options = {}) {
|
|
10781
|
-
const authorityPath =
|
|
10781
|
+
const authorityPath = resolve6(join10(options.home ?? homeDir2(), CURSOR_GLOBAL_AUTHORITY_RELATIVE_PATH));
|
|
10782
10782
|
const readFile2 = options.readFile ?? ((path) => readFileSync2(path, "utf8"));
|
|
10783
10783
|
return observeCursorGlobalAuthorityPath(authorityPath, readFile2);
|
|
10784
10784
|
}
|
|
10785
10785
|
function observeCursorGlobalAuthorityAtPath(authorityPath) {
|
|
10786
|
-
return observeCursorGlobalAuthorityPath(
|
|
10786
|
+
return observeCursorGlobalAuthorityPath(resolve6(authorityPath), (path) => readFileSync2(path, "utf8"));
|
|
10787
10787
|
}
|
|
10788
10788
|
function observeCursorGlobalAuthorityPath(authorityPath, readFile2) {
|
|
10789
10789
|
const base = baseObservation(authorityPath);
|
|
@@ -10928,7 +10928,7 @@ function observeCursorGlobalAuthorityPath(authorityPath, readFile2) {
|
|
|
10928
10928
|
};
|
|
10929
10929
|
}
|
|
10930
10930
|
function isCursorGlobalAuthorityPath(path) {
|
|
10931
|
-
return
|
|
10931
|
+
return resolve6(path) === resolve6(join10(homeDir2(), CURSOR_GLOBAL_AUTHORITY_RELATIVE_PATH));
|
|
10932
10932
|
}
|
|
10933
10933
|
function stampCursorGlobalAuthorityMarker(content) {
|
|
10934
10934
|
const existing = content.match(CURSOR_GLOBAL_AUTHORITY_MARKER_PATTERN);
|
|
@@ -10984,16 +10984,16 @@ var init_cursor_authority = __esm(() => {
|
|
|
10984
10984
|
// src/lib/session-authority.ts
|
|
10985
10985
|
import { createHash as createHash5 } from "crypto";
|
|
10986
10986
|
import { lstatSync as lstatSync3, readFileSync as readFileSync3, realpathSync, statSync as statSync2 } from "fs";
|
|
10987
|
-
import { homedir as
|
|
10988
|
-
import { join as
|
|
10987
|
+
import { homedir as homedir8 } from "os";
|
|
10988
|
+
import { join as join11, resolve as resolve7 } from "path";
|
|
10989
10989
|
function sha2565(content) {
|
|
10990
10990
|
return createHash5("sha256").update(content).digest("hex");
|
|
10991
10991
|
}
|
|
10992
10992
|
function configHomeDir() {
|
|
10993
|
-
return process.env["CONFIGS_HOME"] || process.env["HOME"] ||
|
|
10993
|
+
return process.env["CONFIGS_HOME"] || process.env["HOME"] || homedir8();
|
|
10994
10994
|
}
|
|
10995
10995
|
function normalizeOwnedTargetPath(p) {
|
|
10996
|
-
const expanded = p.startsWith("~/") ?
|
|
10996
|
+
const expanded = p.startsWith("~/") ? resolve7(configHomeDir(), p.slice(2)) : resolve7(p);
|
|
10997
10997
|
try {
|
|
10998
10998
|
return realpathSync(expanded);
|
|
10999
10999
|
} catch {
|
|
@@ -11001,7 +11001,7 @@ function normalizeOwnedTargetPath(p) {
|
|
|
11001
11001
|
}
|
|
11002
11002
|
}
|
|
11003
11003
|
function detectClaudeAuthorityConflicts(targetHome, ownedAuthorities = []) {
|
|
11004
|
-
const authorityPath =
|
|
11004
|
+
const authorityPath = resolve7(join11(targetHome, CLAUDE_LEGACY_AUTHORITY_RELATIVE_PATH));
|
|
11005
11005
|
let stat;
|
|
11006
11006
|
try {
|
|
11007
11007
|
stat = lstatSync3(authorityPath);
|
|
@@ -11090,9 +11090,9 @@ var init_session_authority = __esm(() => {
|
|
|
11090
11090
|
|
|
11091
11091
|
// src/lib/session-render.ts
|
|
11092
11092
|
import { createHash as createHash6 } from "crypto";
|
|
11093
|
-
import { existsSync as
|
|
11094
|
-
import { homedir as
|
|
11095
|
-
import { basename as basename4, dirname as dirname3, extname as extname2, isAbsolute as isAbsolute3, join as
|
|
11093
|
+
import { existsSync as existsSync9, readFileSync as readFileSync4, realpathSync as realpathSync2, statSync as statSync3 } from "fs";
|
|
11094
|
+
import { homedir as homedir9 } from "os";
|
|
11095
|
+
import { basename as basename4, dirname as dirname3, extname as extname2, isAbsolute as isAbsolute3, join as join12, parse as parse2, posix as posix2, relative as relative2, resolve as resolve8 } from "path";
|
|
11096
11096
|
function normalizeSessionInstructionLayer(value) {
|
|
11097
11097
|
if (value === "provider")
|
|
11098
11098
|
return "tool";
|
|
@@ -11178,13 +11178,13 @@ function yamlQuote2(value) {
|
|
|
11178
11178
|
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`;
|
|
11179
11179
|
}
|
|
11180
11180
|
function defaultTargetHome(tool, profile, sessionId) {
|
|
11181
|
-
const home = process.env["HOME"] ||
|
|
11182
|
-
return
|
|
11181
|
+
const home = process.env["HOME"] || homedir9();
|
|
11182
|
+
return join12(home, ".hasna", "accounts", "profiles", tool, slug(profile));
|
|
11183
11183
|
}
|
|
11184
11184
|
function joinTarget(targetHome, relativePath) {
|
|
11185
11185
|
const safeTargetHome = assertSafeTargetRoot(targetHome);
|
|
11186
11186
|
const safeRelativePath2 = assertSafeRelativePath(relativePath);
|
|
11187
|
-
return
|
|
11187
|
+
return join12(safeTargetHome, ...safeRelativePath2.split("/"));
|
|
11188
11188
|
}
|
|
11189
11189
|
function makeFile(targetHome, relativePath, role, content, sourceIds) {
|
|
11190
11190
|
const safeTargetHome = assertSafeTargetRoot(targetHome);
|
|
@@ -11753,7 +11753,7 @@ function buildOpenCodeFiles(targetHome, adapter, profile, sources, providerConfi
|
|
|
11753
11753
|
...sources.flatMap((source) => source.resolvedRules.map((rule) => rule.id))
|
|
11754
11754
|
]);
|
|
11755
11755
|
const existingConfigPath = joinTarget(targetHome, adapter.configFile);
|
|
11756
|
-
const selectedConfig =
|
|
11756
|
+
const selectedConfig = existsSync9(existingConfigPath) ? readOpenCodeConfig(readFileSync4(existingConfigPath, "utf8"), existingConfigPath) : providerConfig ? readOpenCodeConfig(providerConfig.content, providerConfig.sourceId) : {};
|
|
11757
11757
|
const preservedInstructions = normalizeOpenCodeInstructions(selectedConfig["instructions"]).filter((path) => !pathIsManagedOpenCodeInstruction(path, adapter.managedDir));
|
|
11758
11758
|
const config = {
|
|
11759
11759
|
...selectedConfig,
|
|
@@ -11942,7 +11942,7 @@ function adapterFor(input) {
|
|
|
11942
11942
|
return gatedNativeImports ? CODEWITH_NATIVE_ADAPTER : CODEWITH_FLATTENED_ADAPTER;
|
|
11943
11943
|
}
|
|
11944
11944
|
function getHomeDir() {
|
|
11945
|
-
return process.env["CONFIGS_HOME"] || process.env["HOME"] ||
|
|
11945
|
+
return process.env["CONFIGS_HOME"] || process.env["HOME"] || homedir9();
|
|
11946
11946
|
}
|
|
11947
11947
|
function cleanSessionPathInput(path) {
|
|
11948
11948
|
const trimmed = path.trim();
|
|
@@ -11957,16 +11957,16 @@ function resolveSessionPath(path) {
|
|
|
11957
11957
|
throw new Error("Session render path cannot be empty.");
|
|
11958
11958
|
const home = getHomeDir();
|
|
11959
11959
|
if (cleaned === "~")
|
|
11960
|
-
return
|
|
11960
|
+
return resolve8(home);
|
|
11961
11961
|
if (cleaned.startsWith("~/"))
|
|
11962
|
-
return
|
|
11962
|
+
return resolve8(home, cleaned.slice(2));
|
|
11963
11963
|
if (cleaned === "{{HOME}}" || cleaned === "${HOME}")
|
|
11964
|
-
return
|
|
11964
|
+
return resolve8(home);
|
|
11965
11965
|
if (cleaned.startsWith("{{HOME}}/"))
|
|
11966
|
-
return
|
|
11966
|
+
return resolve8(home, cleaned.slice("{{HOME}}/".length));
|
|
11967
11967
|
if (cleaned.startsWith("${HOME}/"))
|
|
11968
|
-
return
|
|
11969
|
-
return
|
|
11968
|
+
return resolve8(home, cleaned.slice("${HOME}/".length));
|
|
11969
|
+
return resolve8(cleaned);
|
|
11970
11970
|
}
|
|
11971
11971
|
function assertSafeRelativePath(relativePath) {
|
|
11972
11972
|
if (!relativePath.trim())
|
|
@@ -11982,7 +11982,7 @@ function assertSafeRelativePath(relativePath) {
|
|
|
11982
11982
|
function assertSafeTargetRoot(targetHome) {
|
|
11983
11983
|
if (!isAbsolute3(targetHome))
|
|
11984
11984
|
throw new Error(`Session render target must be an absolute path: ${targetHome}`);
|
|
11985
|
-
const normalized =
|
|
11985
|
+
const normalized = resolve8(targetHome);
|
|
11986
11986
|
if (normalized === parse2(normalized).root) {
|
|
11987
11987
|
throw new Error(`Session render target cannot be the filesystem root: ${targetHome}`);
|
|
11988
11988
|
}
|
|
@@ -12218,7 +12218,7 @@ function planSessionRender(input) {
|
|
|
12218
12218
|
sourceId: input.providerConfig.sourceId,
|
|
12219
12219
|
selectedPayloadSha256: sha2566(input.providerConfig.content),
|
|
12220
12220
|
renderedPayloadSha256: files.find((file) => file.relativePath === adapter.configFile)?.sha256 ?? sha2566(input.providerConfig.content),
|
|
12221
|
-
selected: !
|
|
12221
|
+
selected: !existsSync9(joinTarget(targetHome, adapter.configFile))
|
|
12222
12222
|
}
|
|
12223
12223
|
} : {},
|
|
12224
12224
|
...projectContext ? {
|
|
@@ -12479,10 +12479,10 @@ function layerFromIdentityKind(kind, exportShape) {
|
|
|
12479
12479
|
function contentFromIdentitySourcePaths(sourcePaths, exportPath, sourceId) {
|
|
12480
12480
|
if (sourcePaths.length === 0 || !exportPath)
|
|
12481
12481
|
return;
|
|
12482
|
-
const
|
|
12482
|
+
const baseDir3 = dirname3(resolveSessionPath(exportPath));
|
|
12483
12483
|
const contents = [];
|
|
12484
12484
|
for (const sourcePath of sourcePaths) {
|
|
12485
|
-
const content = readIdentitySourcePath(sourcePath,
|
|
12485
|
+
const content = readIdentitySourcePath(sourcePath, baseDir3, sourceId);
|
|
12486
12486
|
if (content !== undefined)
|
|
12487
12487
|
contents.push({ path: sourcePath.path, content });
|
|
12488
12488
|
}
|
|
@@ -12495,9 +12495,9 @@ ${item.content.trimEnd()}`).join(`
|
|
|
12495
12495
|
|
|
12496
12496
|
`));
|
|
12497
12497
|
}
|
|
12498
|
-
function readIdentitySourcePath(sourcePath,
|
|
12499
|
-
const resolvedPath = resolveIdentitySourcePath(sourcePath.path,
|
|
12500
|
-
if (!
|
|
12498
|
+
function readIdentitySourcePath(sourcePath, baseDir3, sourceId) {
|
|
12499
|
+
const resolvedPath = resolveIdentitySourcePath(sourcePath.path, baseDir3, sourceId);
|
|
12500
|
+
if (!existsSync9(resolvedPath)) {
|
|
12501
12501
|
if (sourcePath.required) {
|
|
12502
12502
|
throw new Error(`Required identity instruction source path not found for ${sourceId}: ${sourcePath.path}`);
|
|
12503
12503
|
}
|
|
@@ -12507,27 +12507,27 @@ function readIdentitySourcePath(sourcePath, baseDir2, sourceId) {
|
|
|
12507
12507
|
if (!stat.isFile()) {
|
|
12508
12508
|
throw new Error(`Identity instruction source path is not a file for ${sourceId}: ${sourcePath.path}`);
|
|
12509
12509
|
}
|
|
12510
|
-
const realBase = realpathSync2(
|
|
12510
|
+
const realBase = realpathSync2(baseDir3);
|
|
12511
12511
|
const realPath = realpathSync2(resolvedPath);
|
|
12512
12512
|
if (!pathIsInside(realPath, realBase)) {
|
|
12513
12513
|
throw new Error(`Identity instruction source path escapes export directory for ${sourceId}: ${sourcePath.path}`);
|
|
12514
12514
|
}
|
|
12515
12515
|
return readFileSync4(realPath, "utf-8");
|
|
12516
12516
|
}
|
|
12517
|
-
function resolveIdentitySourcePath(path,
|
|
12517
|
+
function resolveIdentitySourcePath(path, baseDir3, sourceId) {
|
|
12518
12518
|
const cleaned = cleanSessionPathInput(path);
|
|
12519
12519
|
if (!cleaned)
|
|
12520
12520
|
throw new Error(`Identity instruction source path cannot be empty for ${sourceId}.`);
|
|
12521
12521
|
if (cleaned.includes("\\"))
|
|
12522
12522
|
throw new Error(`Identity instruction source path must use POSIX separators for ${sourceId}: ${path}`);
|
|
12523
|
-
const resolvedPath = isAbsolute3(cleaned) ?
|
|
12524
|
-
if (!pathIsInside(resolvedPath,
|
|
12523
|
+
const resolvedPath = isAbsolute3(cleaned) ? resolve8(cleaned) : resolve8(baseDir3, cleaned);
|
|
12524
|
+
if (!pathIsInside(resolvedPath, resolve8(baseDir3))) {
|
|
12525
12525
|
throw new Error(`Identity instruction source path escapes export directory for ${sourceId}: ${path}`);
|
|
12526
12526
|
}
|
|
12527
12527
|
return resolvedPath;
|
|
12528
12528
|
}
|
|
12529
|
-
function pathIsInside(path,
|
|
12530
|
-
const rel = relative2(
|
|
12529
|
+
function pathIsInside(path, baseDir3) {
|
|
12530
|
+
const rel = relative2(baseDir3, path);
|
|
12531
12531
|
return rel === "" || !rel.startsWith("..") && !isAbsolute3(rel);
|
|
12532
12532
|
}
|
|
12533
12533
|
function providerTargetsTool(targets, tool) {
|
|
@@ -14187,8 +14187,8 @@ var init_config_store = __esm(() => {
|
|
|
14187
14187
|
});
|
|
14188
14188
|
|
|
14189
14189
|
// src/lib/session-render-ownership.ts
|
|
14190
|
-
import { existsSync as
|
|
14191
|
-
import { dirname as dirname4, join as
|
|
14190
|
+
import { existsSync as existsSync10, readFileSync as readFileSync5, statSync as statSync4 } from "fs";
|
|
14191
|
+
import { dirname as dirname4, join as join13, parse as parse3, relative as relative3, sep } from "path";
|
|
14192
14192
|
function toSegments(absolutePath2) {
|
|
14193
14193
|
return absolutePath2.replaceAll("\\", "/").split("/").filter(Boolean);
|
|
14194
14194
|
}
|
|
@@ -14207,7 +14207,7 @@ function pathIsSessionRenderManagedDir(absolutePath2) {
|
|
|
14207
14207
|
function readManifestRelativePaths(manifestPath) {
|
|
14208
14208
|
let stats;
|
|
14209
14209
|
try {
|
|
14210
|
-
if (!
|
|
14210
|
+
if (!existsSync10(manifestPath))
|
|
14211
14211
|
return null;
|
|
14212
14212
|
stats = statSync4(manifestPath);
|
|
14213
14213
|
} catch {
|
|
@@ -14236,7 +14236,7 @@ function sessionRenderManifestClaimsPath(absolutePath2) {
|
|
|
14236
14236
|
const root = parse3(absolutePath2).root;
|
|
14237
14237
|
let home = dirname4(absolutePath2);
|
|
14238
14238
|
for (let depth = 0;depth < MANIFEST_ANCESTOR_LIMIT; depth += 1) {
|
|
14239
|
-
const manifestPath =
|
|
14239
|
+
const manifestPath = join13(home, ...SESSION_RENDER_MANIFEST_RELATIVE_PATH.split("/"));
|
|
14240
14240
|
const relativePaths = readManifestRelativePaths(manifestPath);
|
|
14241
14241
|
if (relativePaths) {
|
|
14242
14242
|
const claimed = relative3(home, absolutePath2).split(sep).join("/");
|
|
@@ -14271,17 +14271,17 @@ __export(exports_apply, {
|
|
|
14271
14271
|
applyConfigs: () => applyConfigs,
|
|
14272
14272
|
applyConfig: () => applyConfig
|
|
14273
14273
|
});
|
|
14274
|
-
import { existsSync as
|
|
14275
|
-
import { basename as basename5, dirname as dirname5, join as
|
|
14276
|
-
import { homedir as
|
|
14274
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync3, readFileSync as readFileSync6, realpathSync as realpathSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
14275
|
+
import { basename as basename5, dirname as dirname5, join as join14, resolve as resolve9 } from "path";
|
|
14276
|
+
import { homedir as homedir10 } from "os";
|
|
14277
14277
|
function getConfigHome() {
|
|
14278
|
-
return process.env["CONFIGS_HOME"] || process.env["HOME"] ||
|
|
14278
|
+
return process.env["CONFIGS_HOME"] || process.env["HOME"] || homedir10();
|
|
14279
14279
|
}
|
|
14280
14280
|
function expandPath(p) {
|
|
14281
14281
|
if (p.startsWith("~/")) {
|
|
14282
|
-
return
|
|
14282
|
+
return resolve9(getConfigHome(), p.slice(2));
|
|
14283
14283
|
}
|
|
14284
|
-
return
|
|
14284
|
+
return resolve9(p);
|
|
14285
14285
|
}
|
|
14286
14286
|
function normalizeTargetPath(p) {
|
|
14287
14287
|
const expanded = expandPath(p);
|
|
@@ -14291,9 +14291,9 @@ function normalizeTargetPath(p) {
|
|
|
14291
14291
|
let current = expanded;
|
|
14292
14292
|
const missingSegments = [];
|
|
14293
14293
|
while (true) {
|
|
14294
|
-
if (
|
|
14294
|
+
if (existsSync11(current)) {
|
|
14295
14295
|
try {
|
|
14296
|
-
return
|
|
14296
|
+
return resolve9(realpathSync3(current), ...missingSegments);
|
|
14297
14297
|
} catch {
|
|
14298
14298
|
return expanded;
|
|
14299
14299
|
}
|
|
@@ -14322,11 +14322,11 @@ async function writeConfigResult(config, targetPath, content, opts, meta = {}) {
|
|
|
14322
14322
|
}
|
|
14323
14323
|
const path = expandPath(renderedTargetPath);
|
|
14324
14324
|
const renderedForTarget = isCursorGlobalAuthorityPath(path) ? stampCursorGlobalAuthorityMarker(renderedContent) : renderedContent;
|
|
14325
|
-
const previousContent =
|
|
14325
|
+
const previousContent = existsSync11(path) ? readFileSync6(path, "utf-8") : null;
|
|
14326
14326
|
const changed = previousContent !== renderedForTarget;
|
|
14327
14327
|
if (!opts.dryRun) {
|
|
14328
14328
|
const dir = dirname5(path);
|
|
14329
|
-
if (!
|
|
14329
|
+
if (!existsSync11(dir)) {
|
|
14330
14330
|
mkdirSync3(dir, { recursive: true });
|
|
14331
14331
|
}
|
|
14332
14332
|
if (previousContent !== null && changed) {
|
|
@@ -14360,7 +14360,7 @@ function wouldDestroyACredential(targetPath, renderedContent, format) {
|
|
|
14360
14360
|
let current;
|
|
14361
14361
|
try {
|
|
14362
14362
|
const path = expandPath(targetPath);
|
|
14363
|
-
if (!
|
|
14363
|
+
if (!existsSync11(path))
|
|
14364
14364
|
return [];
|
|
14365
14365
|
current = readFileSync6(path, "utf-8");
|
|
14366
14366
|
} catch {
|
|
@@ -14686,7 +14686,7 @@ function sessionRendererOwnsCanonicalTarget(normalized, opts) {
|
|
|
14686
14686
|
getConfigHome(),
|
|
14687
14687
|
opts.vars?.["HOME_DIR"]
|
|
14688
14688
|
].filter((home) => typeof home === "string" && home.length > 0));
|
|
14689
|
-
if ([...homes].some((home) => SESSION_RENDER_OWNED_CONFIG_TARGETS.some((relativePath) => normalized === normalizeTargetPath(
|
|
14689
|
+
if ([...homes].some((home) => SESSION_RENDER_OWNED_CONFIG_TARGETS.some((relativePath) => normalized === normalizeTargetPath(join14(home, ...relativePath.split("/"))))))
|
|
14690
14690
|
return true;
|
|
14691
14691
|
return sessionRenderOwnsPath(normalized);
|
|
14692
14692
|
}
|
|
@@ -14704,20 +14704,20 @@ var init_apply = __esm(() => {
|
|
|
14704
14704
|
});
|
|
14705
14705
|
|
|
14706
14706
|
// src/lib/sync-dir.ts
|
|
14707
|
-
import { existsSync as
|
|
14708
|
-
import { join as
|
|
14709
|
-
import { homedir as
|
|
14707
|
+
import { existsSync as existsSync12, readdirSync, readFileSync as readFileSync7, statSync as statSync5 } from "fs";
|
|
14708
|
+
import { join as join15, relative as relative4 } from "path";
|
|
14709
|
+
import { homedir as homedir11 } from "os";
|
|
14710
14710
|
function shouldSkip(p) {
|
|
14711
14711
|
return SKIP.some((s) => p.includes(s));
|
|
14712
14712
|
}
|
|
14713
14713
|
async function syncFromDir(dir, opts = {}) {
|
|
14714
14714
|
const store = opts.store ?? resolveConfigStore();
|
|
14715
14715
|
const absDir = expandPath(dir);
|
|
14716
|
-
if (!
|
|
14716
|
+
if (!existsSync12(absDir))
|
|
14717
14717
|
return { added: 0, updated: 0, unchanged: 0, skipped: [`Not found: ${absDir}`] };
|
|
14718
|
-
const files = opts.recursive !== false ? walkDir(absDir) : readdirSync(absDir).map((f) =>
|
|
14718
|
+
const files = opts.recursive !== false ? walkDir(absDir) : readdirSync(absDir).map((f) => join15(absDir, f)).filter((f) => statSync5(f).isFile());
|
|
14719
14719
|
const result = { added: 0, updated: 0, unchanged: 0, skipped: [] };
|
|
14720
|
-
const home =
|
|
14720
|
+
const home = homedir11();
|
|
14721
14721
|
const allConfigs = await store.listConfigs();
|
|
14722
14722
|
for (const file of files) {
|
|
14723
14723
|
if (shouldSkip(file)) {
|
|
@@ -14752,7 +14752,7 @@ async function syncFromDir(dir, opts = {}) {
|
|
|
14752
14752
|
}
|
|
14753
14753
|
async function syncToDir(dir, opts = {}) {
|
|
14754
14754
|
const store = opts.store ?? resolveConfigStore();
|
|
14755
|
-
const home =
|
|
14755
|
+
const home = homedir11();
|
|
14756
14756
|
const absDir = expandPath(dir);
|
|
14757
14757
|
const normalized = dir.startsWith("~/") ? dir : absDir.replace(home, "~");
|
|
14758
14758
|
const configs = (await store.listConfigs()).filter((c) => c.target_path && (c.target_path.startsWith(normalized) || c.target_path.startsWith(absDir)));
|
|
@@ -14776,7 +14776,7 @@ async function syncToDir(dir, opts = {}) {
|
|
|
14776
14776
|
}
|
|
14777
14777
|
function walkDir(dir, files = []) {
|
|
14778
14778
|
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
14779
|
-
const full =
|
|
14779
|
+
const full = join15(dir, entry.name);
|
|
14780
14780
|
if (shouldSkip(full))
|
|
14781
14781
|
continue;
|
|
14782
14782
|
if (entry.isDirectory())
|
|
@@ -14811,8 +14811,8 @@ __export(exports_sync, {
|
|
|
14811
14811
|
KNOWN_CONFIGS: () => KNOWN_CONFIGS,
|
|
14812
14812
|
CLAUDE_PROMPT_OUTPUTS: () => CLAUDE_PROMPT_OUTPUTS
|
|
14813
14813
|
});
|
|
14814
|
-
import { existsSync as
|
|
14815
|
-
import { basename as basename6, extname as extname3, join as
|
|
14814
|
+
import { existsSync as existsSync13, readdirSync as readdirSync2, readFileSync as readFileSync8 } from "fs";
|
|
14815
|
+
import { basename as basename6, extname as extname3, join as join16 } from "path";
|
|
14816
14816
|
function claudeRuleOutputs(fileName) {
|
|
14817
14817
|
const stem = basename6(fileName, extname3(fileName));
|
|
14818
14818
|
return [
|
|
@@ -14851,7 +14851,7 @@ function isGeneratedOutputTarget2(config, owners) {
|
|
|
14851
14851
|
return !!ownerIds && !ownerIds.has(config.id);
|
|
14852
14852
|
}
|
|
14853
14853
|
function hasClaudePromptSource() {
|
|
14854
|
-
return
|
|
14854
|
+
return existsSync13(expandPath("~/.claude/CLAUDE.md"));
|
|
14855
14855
|
}
|
|
14856
14856
|
function hasClaudeRuleSourceForCursorTarget(targetPath) {
|
|
14857
14857
|
const absoluteTargetPath = expandPath(targetPath);
|
|
@@ -14859,7 +14859,7 @@ function hasClaudeRuleSourceForCursorTarget(targetPath) {
|
|
|
14859
14859
|
if (!absoluteTargetPath.startsWith(`${absolutePrefix}/`) || !absoluteTargetPath.endsWith(".mdc"))
|
|
14860
14860
|
return false;
|
|
14861
14861
|
const stem = basename6(absoluteTargetPath, ".mdc");
|
|
14862
|
-
return
|
|
14862
|
+
return existsSync13(expandPath(`~/.claude/rules/${stem}.md`)) || existsSync13(expandPath(`~/.claude/rules/${stem}.mdc`));
|
|
14863
14863
|
}
|
|
14864
14864
|
function isKnownGeneratedTargetPath(targetPath) {
|
|
14865
14865
|
const normalizedTargetPath = normalizeTargetPath(targetPath);
|
|
@@ -14876,8 +14876,8 @@ async function syncProject(opts) {
|
|
|
14876
14876
|
const allConfigs = await store.listConfigs();
|
|
14877
14877
|
const machine = detectMachineContext();
|
|
14878
14878
|
for (const pf of PROJECT_CONFIG_FILES) {
|
|
14879
|
-
const abs =
|
|
14880
|
-
if (!
|
|
14879
|
+
const abs = join16(absDir, pf.file);
|
|
14880
|
+
if (!existsSync13(abs))
|
|
14881
14881
|
continue;
|
|
14882
14882
|
try {
|
|
14883
14883
|
const rawContent = readFileSync8(abs, "utf-8");
|
|
@@ -14909,19 +14909,19 @@ async function syncProject(opts) {
|
|
|
14909
14909
|
}
|
|
14910
14910
|
}
|
|
14911
14911
|
for (const ruleDir of [
|
|
14912
|
-
{ dir:
|
|
14913
|
-
{ dir:
|
|
14914
|
-
{ dir:
|
|
14915
|
-
{ dir:
|
|
14916
|
-
{ dir:
|
|
14917
|
-
{ dir:
|
|
14918
|
-
{ dir:
|
|
14912
|
+
{ dir: join16(absDir, ".claude", "rules"), agent: "claude", namePrefix: "rules" },
|
|
14913
|
+
{ dir: join16(absDir, ".agents", "rules"), agent: "antigravity", namePrefix: "antigravity-rules" },
|
|
14914
|
+
{ dir: join16(absDir, ".cursor", "rules"), agent: "cursor", namePrefix: "cursor-rules" },
|
|
14915
|
+
{ dir: join16(absDir, ".github", "instructions"), agent: "copilot", namePrefix: "copilot-instructions" },
|
|
14916
|
+
{ dir: join16(absDir, ".devin", "rules"), agent: "devin", namePrefix: "devin-rules" },
|
|
14917
|
+
{ dir: join16(absDir, ".windsurf", "rules"), agent: "windsurf-legacy", namePrefix: "windsurf-rules" },
|
|
14918
|
+
{ dir: join16(absDir, ".clinerules"), agent: "cline", namePrefix: "cline-rules" }
|
|
14919
14919
|
]) {
|
|
14920
|
-
if (!
|
|
14920
|
+
if (!existsSync13(ruleDir.dir))
|
|
14921
14921
|
continue;
|
|
14922
14922
|
const mdFiles = readdirSync2(ruleDir.dir).filter((f) => f.endsWith(".md") || f.endsWith(".mdc"));
|
|
14923
14923
|
for (const f of mdFiles) {
|
|
14924
|
-
const abs =
|
|
14924
|
+
const abs = join16(ruleDir.dir, f);
|
|
14925
14925
|
const raw = readFileSync8(abs, "utf-8");
|
|
14926
14926
|
const redacted = redactContent(raw, "markdown");
|
|
14927
14927
|
const machineAware = templateizeMachineContent(redacted.content, machine);
|
|
@@ -14961,14 +14961,14 @@ async function syncKnown(opts = {}) {
|
|
|
14961
14961
|
for (const known of targets) {
|
|
14962
14962
|
if (known.rulesDir) {
|
|
14963
14963
|
const absDir = expandPath(known.rulesDir);
|
|
14964
|
-
if (!
|
|
14964
|
+
if (!existsSync13(absDir)) {
|
|
14965
14965
|
result.skipped.push(known.rulesDir);
|
|
14966
14966
|
continue;
|
|
14967
14967
|
}
|
|
14968
14968
|
const extensions = known.rulesExtensions ?? [".md", ".mdc"];
|
|
14969
14969
|
const ruleFiles = readdirSync2(absDir).filter((f) => extensions.some((ext) => f.endsWith(ext)));
|
|
14970
14970
|
for (const f of ruleFiles) {
|
|
14971
|
-
const abs2 =
|
|
14971
|
+
const abs2 = join16(absDir, f);
|
|
14972
14972
|
const targetPath = abs2.replace(home, "~");
|
|
14973
14973
|
if (existingOutputOwners.has(normalizeTargetPath(targetPath)) || isKnownGeneratedTargetPath(targetPath)) {
|
|
14974
14974
|
result.skipped.push(`${targetPath} (generated output)`);
|
|
@@ -15002,7 +15002,7 @@ async function syncKnown(opts = {}) {
|
|
|
15002
15002
|
continue;
|
|
15003
15003
|
}
|
|
15004
15004
|
const abs = expandPath(known.path);
|
|
15005
|
-
if (!
|
|
15005
|
+
if (!existsSync13(abs)) {
|
|
15006
15006
|
result.skipped.push(known.path);
|
|
15007
15007
|
continue;
|
|
15008
15008
|
}
|
|
@@ -15108,7 +15108,7 @@ function storedPlaceholderIsLiteralOnDisk(storedLine, diskLine) {
|
|
|
15108
15108
|
}
|
|
15109
15109
|
function buildDiff(expectedContent, targetPath, storedFormat, showSecrets) {
|
|
15110
15110
|
const path = expandPath(targetPath);
|
|
15111
|
-
if (!
|
|
15111
|
+
if (!existsSync13(path))
|
|
15112
15112
|
return `(file not found on disk: ${path})`;
|
|
15113
15113
|
const diskContent = readFileSync8(path, "utf-8");
|
|
15114
15114
|
if (diskContent === expectedContent)
|
|
@@ -15343,16 +15343,16 @@ __export(exports_package_manager_guard, {
|
|
|
15343
15343
|
scanPackageManagerSecrets: () => scanPackageManagerSecrets
|
|
15344
15344
|
});
|
|
15345
15345
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
15346
|
-
import { existsSync as
|
|
15347
|
-
import { homedir as
|
|
15348
|
-
import { basename as basename7, dirname as dirname10, isAbsolute as isAbsolute5, join as
|
|
15346
|
+
import { existsSync as existsSync22, lstatSync as lstatSync7, readdirSync as readdirSync5, readFileSync as readFileSync16 } from "fs";
|
|
15347
|
+
import { homedir as homedir14 } from "os";
|
|
15348
|
+
import { basename as basename7, dirname as dirname10, isAbsolute as isAbsolute5, join as join24, relative as relative7, resolve as resolve14 } from "path";
|
|
15349
15349
|
function scanPackageManagerSecrets(options = {}) {
|
|
15350
|
-
const cwd = options.cwd ?
|
|
15351
|
-
const roots = (options.roots && options.roots.length > 0 ? options.roots : [cwd]).map((root) =>
|
|
15350
|
+
const cwd = options.cwd ? resolve14(options.cwd) : process.cwd();
|
|
15351
|
+
const roots = (options.roots && options.roots.length > 0 ? options.roots : [cwd]).map((root) => resolve14(cwd, root));
|
|
15352
15352
|
const findings = [];
|
|
15353
15353
|
let scannedFiles = 0;
|
|
15354
15354
|
for (const root of roots) {
|
|
15355
|
-
if (!
|
|
15355
|
+
if (!existsSync22(root))
|
|
15356
15356
|
continue;
|
|
15357
15357
|
const stat = lstatSync7(root);
|
|
15358
15358
|
if (stat.isFile()) {
|
|
@@ -15379,10 +15379,10 @@ function scanPackageManagerSecrets(options = {}) {
|
|
|
15379
15379
|
}
|
|
15380
15380
|
}
|
|
15381
15381
|
if (options.includeHome) {
|
|
15382
|
-
const home =
|
|
15382
|
+
const home = homedir14();
|
|
15383
15383
|
for (const name of HOME_FILES) {
|
|
15384
|
-
const file =
|
|
15385
|
-
if (!
|
|
15384
|
+
const file = join24(home, name);
|
|
15385
|
+
if (!existsSync22(file))
|
|
15386
15386
|
continue;
|
|
15387
15387
|
const text = readTextFile(file);
|
|
15388
15388
|
if (text === null)
|
|
@@ -15406,12 +15406,12 @@ function collectRepoFiles(root) {
|
|
|
15406
15406
|
if (entry.isDirectory()) {
|
|
15407
15407
|
if (SKIP_DIRS.has(entry.name))
|
|
15408
15408
|
continue;
|
|
15409
|
-
visit(
|
|
15409
|
+
visit(join24(dir, entry.name));
|
|
15410
15410
|
continue;
|
|
15411
15411
|
}
|
|
15412
15412
|
if (!entry.isFile())
|
|
15413
15413
|
continue;
|
|
15414
|
-
const file =
|
|
15414
|
+
const file = join24(dir, entry.name);
|
|
15415
15415
|
if (shouldScanRepoFile(file))
|
|
15416
15416
|
out.push(file);
|
|
15417
15417
|
}
|
|
@@ -15679,7 +15679,7 @@ function stripInlineComment(value) {
|
|
|
15679
15679
|
return value.replace(/\s[#;].*$/, "").trim();
|
|
15680
15680
|
}
|
|
15681
15681
|
function displayPath(file, root) {
|
|
15682
|
-
const home =
|
|
15682
|
+
const home = homedir14();
|
|
15683
15683
|
if (root === home && (file === home || file.startsWith(home + "/")))
|
|
15684
15684
|
return "~/" + toPosix(relative7(home, file));
|
|
15685
15685
|
if (isAbsolute5(root) && file.startsWith(root + "/"))
|
|
@@ -15733,7 +15733,11 @@ var init_package_manager_guard = __esm(() => {
|
|
|
15733
15733
|
// ../events/dist/commander.js
|
|
15734
15734
|
import { chmod, mkdir, readFile, rename, writeFile } from "fs/promises";
|
|
15735
15735
|
import { Buffer as Buffer2 } from "buffer";
|
|
15736
|
+
import { existsSync as existsSync2 } from "fs";
|
|
15737
|
+
import { join as join3 } from "path";
|
|
15736
15738
|
import { existsSync } from "fs";
|
|
15739
|
+
import { homedir as homedir2 } from "os";
|
|
15740
|
+
import { join as join2, resolve } from "path";
|
|
15737
15741
|
import { homedir } from "os";
|
|
15738
15742
|
import { join } from "path";
|
|
15739
15743
|
import { createHmac, timingSafeEqual } from "crypto";
|
|
@@ -15839,13 +15843,106 @@ function channelMatchesEvent(channel, event) {
|
|
|
15839
15843
|
return true;
|
|
15840
15844
|
return channel.filters.some((filter) => eventMatchesFilter(event, filter));
|
|
15841
15845
|
}
|
|
15846
|
+
var KIND_ENV = {
|
|
15847
|
+
config: "HASNA_CONFIG_HOME",
|
|
15848
|
+
data: "HASNA_DATA_HOME",
|
|
15849
|
+
state: "HASNA_STATE_HOME",
|
|
15850
|
+
cache: "HASNA_CACHE_HOME"
|
|
15851
|
+
};
|
|
15852
|
+
var APP_SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
15853
|
+
function assertApp(app) {
|
|
15854
|
+
if (typeof app !== "string" || app.length === 0) {
|
|
15855
|
+
throw new TypeError("paths: app must be a non-empty string");
|
|
15856
|
+
}
|
|
15857
|
+
if (!APP_SLUG_RE.test(app)) {
|
|
15858
|
+
throw new TypeError(`paths: invalid app slug "${app}" \u2014 expected lowercase kebab-case ([a-z0-9]+(-[a-z0-9]+)*)`);
|
|
15859
|
+
}
|
|
15860
|
+
}
|
|
15861
|
+
function envOf(options) {
|
|
15862
|
+
return options.env ?? process.env;
|
|
15863
|
+
}
|
|
15864
|
+
function envValue(options, kind) {
|
|
15865
|
+
const value = envOf(options)[KIND_ENV[kind]];
|
|
15866
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
15867
|
+
}
|
|
15868
|
+
function isMacOS(platform) {
|
|
15869
|
+
return platform === "darwin";
|
|
15870
|
+
}
|
|
15871
|
+
function baseDir(kind, options) {
|
|
15872
|
+
const override = envValue(options, kind);
|
|
15873
|
+
if (override)
|
|
15874
|
+
return override;
|
|
15875
|
+
const home = options.home ?? homedir();
|
|
15876
|
+
const platform = options.platform ?? process.platform;
|
|
15877
|
+
if (isMacOS(platform)) {
|
|
15878
|
+
switch (kind) {
|
|
15879
|
+
case "config":
|
|
15880
|
+
case "data":
|
|
15881
|
+
return join(home, "Library", "Application Support", "Hasna");
|
|
15882
|
+
case "cache":
|
|
15883
|
+
return join(home, "Library", "Caches", "Hasna");
|
|
15884
|
+
case "state":
|
|
15885
|
+
return join(home, "Library", "Logs", "Hasna");
|
|
15886
|
+
}
|
|
15887
|
+
}
|
|
15888
|
+
switch (kind) {
|
|
15889
|
+
case "config":
|
|
15890
|
+
return join(home, ".config", "hasna");
|
|
15891
|
+
case "data":
|
|
15892
|
+
return join(home, ".local", "share", "hasna");
|
|
15893
|
+
case "state":
|
|
15894
|
+
return join(home, ".local", "state", "hasna");
|
|
15895
|
+
case "cache":
|
|
15896
|
+
return join(home, ".cache", "hasna");
|
|
15897
|
+
}
|
|
15898
|
+
}
|
|
15899
|
+
function resolvePath(kind, options) {
|
|
15900
|
+
assertApp(options.app);
|
|
15901
|
+
const appSegment = options.internal === true ? join("internal", options.app) : options.app;
|
|
15902
|
+
return join(baseDir(kind, options), appSegment);
|
|
15903
|
+
}
|
|
15904
|
+
function dataDir(options) {
|
|
15905
|
+
return resolvePath("data", options);
|
|
15906
|
+
}
|
|
15842
15907
|
var HASNA_EVENTS_DIR_ENV = "HASNA_EVENTS_DIR";
|
|
15843
15908
|
var HASNA_EVENTS_HOME_ENV = "HASNA_EVENTS_HOME";
|
|
15909
|
+
var EVENTS_STORE_SENTINEL_FILE = "events.json";
|
|
15910
|
+
function effectiveHome() {
|
|
15911
|
+
return process.env["HOME"] || process.env["USERPROFILE"] || homedir2();
|
|
15912
|
+
}
|
|
15913
|
+
function legacyHomeDir() {
|
|
15914
|
+
return join2(effectiveHome(), ".hasna", "events");
|
|
15915
|
+
}
|
|
15916
|
+
function resolverHome() {
|
|
15917
|
+
return dataDir({ app: "events", home: effectiveHome() || undefined });
|
|
15918
|
+
}
|
|
15919
|
+
function adoptResolverHome(resolved, env = process.env) {
|
|
15920
|
+
const dataOverride = env.HASNA_DATA_HOME;
|
|
15921
|
+
if (typeof dataOverride === "string" && dataOverride.trim().length > 0)
|
|
15922
|
+
return true;
|
|
15923
|
+
return existsSync(join2(resolved, EVENTS_STORE_SENTINEL_FILE));
|
|
15924
|
+
}
|
|
15925
|
+
function exactEventsHome() {
|
|
15926
|
+
const dir = process.env[HASNA_EVENTS_DIR_ENV];
|
|
15927
|
+
if (dir && dir.trim())
|
|
15928
|
+
return dir.trim();
|
|
15929
|
+
const home = process.env[HASNA_EVENTS_HOME_ENV];
|
|
15930
|
+
if (home && home.trim())
|
|
15931
|
+
return home.trim();
|
|
15932
|
+
return;
|
|
15933
|
+
}
|
|
15934
|
+
function getEventsHome() {
|
|
15935
|
+
const exact = exactEventsHome();
|
|
15936
|
+
if (exact)
|
|
15937
|
+
return resolve(exact);
|
|
15938
|
+
const resolved = resolverHome();
|
|
15939
|
+
return adoptResolverHome(resolved) ? resolve(resolved) : resolve(legacyHomeDir());
|
|
15940
|
+
}
|
|
15844
15941
|
var LOCAL_JSON_EVENT_CURSOR_PREFIX = "local-json-v1:";
|
|
15845
15942
|
var DEFAULT_EVENT_PAGE_LIMIT = 100;
|
|
15846
15943
|
var MAX_EVENT_PAGE_LIMIT = 1000;
|
|
15847
15944
|
function getEventsDataDir(override) {
|
|
15848
|
-
return override ||
|
|
15945
|
+
return override || getEventsHome();
|
|
15849
15946
|
}
|
|
15850
15947
|
function getActiveEventsDirEnv() {
|
|
15851
15948
|
if (process.env[HASNA_EVENTS_DIR_ENV])
|
|
@@ -15861,12 +15958,12 @@ class JsonEventsStore {
|
|
|
15861
15958
|
channelsPath;
|
|
15862
15959
|
eventsPath;
|
|
15863
15960
|
deliveriesPath;
|
|
15864
|
-
constructor(
|
|
15865
|
-
this.dataDir =
|
|
15866
|
-
this.runtime = localJsonRuntime(
|
|
15867
|
-
this.channelsPath =
|
|
15868
|
-
this.eventsPath =
|
|
15869
|
-
this.deliveriesPath =
|
|
15961
|
+
constructor(dataDir2 = getEventsDataDir()) {
|
|
15962
|
+
this.dataDir = dataDir2;
|
|
15963
|
+
this.runtime = localJsonRuntime(dataDir2);
|
|
15964
|
+
this.channelsPath = join3(dataDir2, "channels.json");
|
|
15965
|
+
this.eventsPath = join3(dataDir2, "events.json");
|
|
15966
|
+
this.deliveriesPath = join3(dataDir2, "deliveries.json");
|
|
15870
15967
|
}
|
|
15871
15968
|
async init() {
|
|
15872
15969
|
await mkdir(this.dataDir, { recursive: true, mode: 448 });
|
|
@@ -15983,7 +16080,7 @@ class JsonEventsStore {
|
|
|
15983
16080
|
};
|
|
15984
16081
|
}
|
|
15985
16082
|
async ensureArrayFile(path) {
|
|
15986
|
-
if (!
|
|
16083
|
+
if (!existsSync2(path)) {
|
|
15987
16084
|
await writeFile(path, `[]
|
|
15988
16085
|
`, { encoding: "utf-8", mode: 384 });
|
|
15989
16086
|
}
|
|
@@ -16013,7 +16110,7 @@ class JsonEventsStore {
|
|
|
16013
16110
|
});
|
|
16014
16111
|
}
|
|
16015
16112
|
}
|
|
16016
|
-
function localJsonRuntime(
|
|
16113
|
+
function localJsonRuntime(dataDir2 = getEventsDataDir()) {
|
|
16017
16114
|
return {
|
|
16018
16115
|
mode: "local-files",
|
|
16019
16116
|
name: "json-events-store",
|
|
@@ -16026,7 +16123,7 @@ function localJsonRuntime(dataDir = getEventsDataDir()) {
|
|
|
16026
16123
|
durable: true,
|
|
16027
16124
|
idempotency: "best-effort-local",
|
|
16028
16125
|
replayCursors: true,
|
|
16029
|
-
description: `Local JSON files in ${
|
|
16126
|
+
description: `Local JSON files in ${dataDir2}; no SQLite, Postgres, S3, or AWS runtime is configured by this store.`
|
|
16030
16127
|
};
|
|
16031
16128
|
}
|
|
16032
16129
|
function encodeLocalJsonEventCursor(offset, options = {}) {
|
|
@@ -16090,8 +16187,8 @@ function assertCursorFilter(name, cursorValue, optionValue) {
|
|
|
16090
16187
|
function findEventByIdentity(events, identity) {
|
|
16091
16188
|
return events.find((event) => identity.id !== undefined && event.id === identity.id || identity.dedupeKey !== undefined && event.dedupeKey === identity.dedupeKey);
|
|
16092
16189
|
}
|
|
16093
|
-
async function getEventsStatus(
|
|
16094
|
-
const store = new JsonEventsStore(
|
|
16190
|
+
async function getEventsStatus(dataDir2) {
|
|
16191
|
+
const store = new JsonEventsStore(dataDir2);
|
|
16095
16192
|
await store.init();
|
|
16096
16193
|
const [channels, events, deliveries] = await Promise.all([
|
|
16097
16194
|
store.listChannels(),
|
|
@@ -16133,9 +16230,9 @@ async function getEventsStatus(dataDir) {
|
|
|
16133
16230
|
}
|
|
16134
16231
|
};
|
|
16135
16232
|
}
|
|
16136
|
-
function statusFile(
|
|
16137
|
-
const path =
|
|
16138
|
-
return { path, exists:
|
|
16233
|
+
function statusFile(dataDir2, fileName, records) {
|
|
16234
|
+
const path = join3(dataDir2, fileName);
|
|
16235
|
+
return { path, exists: existsSync2(path), records };
|
|
16139
16236
|
}
|
|
16140
16237
|
var DEFAULT_SIGNATURE_TOLERANCE_MS = 5 * 60 * 1000;
|
|
16141
16238
|
function buildSignatureBase(timestamp, body) {
|
|
@@ -16474,7 +16571,7 @@ async function pinnedNativeRequest(target, addresses, method, headers, body, sig
|
|
|
16474
16571
|
callback(null, entries);
|
|
16475
16572
|
}
|
|
16476
16573
|
};
|
|
16477
|
-
return new Promise((
|
|
16574
|
+
return new Promise((resolve2, reject) => {
|
|
16478
16575
|
const request = isHttps ? nodeHttpsRequest(requestOptions, onResponse) : nodeHttpRequest(requestOptions, onResponse);
|
|
16479
16576
|
const onAbort = () => {
|
|
16480
16577
|
const error = new Error("The operation was aborted.");
|
|
@@ -16501,7 +16598,7 @@ async function pinnedNativeRequest(target, addresses, method, headers, body, sig
|
|
|
16501
16598
|
else if (Array.isArray(value))
|
|
16502
16599
|
headersRecord[name] = value.join(", ");
|
|
16503
16600
|
}
|
|
16504
|
-
|
|
16601
|
+
resolve2(new Response(Buffer.concat(chunks), { status: response.statusCode ?? 200, headers: headersRecord }));
|
|
16505
16602
|
});
|
|
16506
16603
|
}
|
|
16507
16604
|
});
|
|
@@ -16598,7 +16695,7 @@ async function dispatchCommand(event, channel) {
|
|
|
16598
16695
|
HASNA_EVENT_SCHEMA_VERSION: event.schemaVersion,
|
|
16599
16696
|
HASNA_EVENT_JSON: eventJson
|
|
16600
16697
|
};
|
|
16601
|
-
return new Promise((
|
|
16698
|
+
return new Promise((resolve2) => {
|
|
16602
16699
|
const child = spawn(channel.command.command, channel.command.args ?? [], {
|
|
16603
16700
|
cwd: channel.command.cwd,
|
|
16604
16701
|
env,
|
|
@@ -16616,7 +16713,7 @@ async function dispatchCommand(event, channel) {
|
|
|
16616
16713
|
});
|
|
16617
16714
|
child.on("error", (error) => {
|
|
16618
16715
|
clearTimeout(timeout);
|
|
16619
|
-
|
|
16716
|
+
resolve2({
|
|
16620
16717
|
attempt: 1,
|
|
16621
16718
|
status: "failed",
|
|
16622
16719
|
startedAt,
|
|
@@ -16629,7 +16726,7 @@ async function dispatchCommand(event, channel) {
|
|
|
16629
16726
|
child.on("close", (code, signal) => {
|
|
16630
16727
|
clearTimeout(timeout);
|
|
16631
16728
|
const success = code === 0;
|
|
16632
|
-
|
|
16729
|
+
resolve2({
|
|
16633
16730
|
attempt: 1,
|
|
16634
16731
|
status: success ? "success" : "failed",
|
|
16635
16732
|
startedAt,
|
|
@@ -17282,9 +17379,9 @@ var {
|
|
|
17282
17379
|
// src/cli/index.tsx
|
|
17283
17380
|
init_apply();
|
|
17284
17381
|
import chalk from "chalk";
|
|
17285
|
-
import { existsSync as
|
|
17286
|
-
import { homedir as
|
|
17287
|
-
import { basename as basename8, join as
|
|
17382
|
+
import { existsSync as existsSync23, lstatSync as lstatSync8, readFileSync as readFileSync17, readSync, writeSync } from "fs";
|
|
17383
|
+
import { homedir as homedir15 } from "os";
|
|
17384
|
+
import { basename as basename8, join as join25, resolve as resolve15 } from "path";
|
|
17288
17385
|
|
|
17289
17386
|
// src/lib/config-target-identity.ts
|
|
17290
17387
|
init_apply();
|
|
@@ -17330,15 +17427,15 @@ init_redact();
|
|
|
17330
17427
|
|
|
17331
17428
|
// src/lib/export.ts
|
|
17332
17429
|
init_config_store();
|
|
17333
|
-
import { existsSync as
|
|
17334
|
-
import { join as
|
|
17430
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync4, rmSync as rmSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
17431
|
+
import { join as join17, resolve as resolve10 } from "path";
|
|
17335
17432
|
import { tmpdir } from "os";
|
|
17336
17433
|
async function exportConfigs(outputPath, opts = {}) {
|
|
17337
17434
|
const store = opts.store ?? resolveConfigStore();
|
|
17338
17435
|
const configs = await store.listConfigs(opts.filter);
|
|
17339
|
-
const absOutput =
|
|
17340
|
-
const tmpDir =
|
|
17341
|
-
const contentsDir =
|
|
17436
|
+
const absOutput = resolve10(outputPath);
|
|
17437
|
+
const tmpDir = join17(tmpdir(), `configs-export-${Date.now()}`);
|
|
17438
|
+
const contentsDir = join17(tmpDir, "contents");
|
|
17342
17439
|
try {
|
|
17343
17440
|
mkdirSync4(contentsDir, { recursive: true });
|
|
17344
17441
|
const manifest = {
|
|
@@ -17346,10 +17443,10 @@ async function exportConfigs(outputPath, opts = {}) {
|
|
|
17346
17443
|
exported_at: new Date().toISOString(),
|
|
17347
17444
|
configs: configs.map(({ content: _content, ...meta }) => meta)
|
|
17348
17445
|
};
|
|
17349
|
-
writeFileSync3(
|
|
17446
|
+
writeFileSync3(join17(tmpDir, "manifest.json"), JSON.stringify(manifest, null, 2), "utf-8");
|
|
17350
17447
|
for (const config of configs) {
|
|
17351
17448
|
const fileName = `${config.slug}.${config.format === "text" ? "txt" : config.format}`;
|
|
17352
|
-
writeFileSync3(
|
|
17449
|
+
writeFileSync3(join17(contentsDir, fileName), config.content, "utf-8");
|
|
17353
17450
|
}
|
|
17354
17451
|
const proc = Bun.spawn(["tar", "czf", absOutput, "-C", tmpDir, "."], {
|
|
17355
17452
|
stdout: "pipe",
|
|
@@ -17362,7 +17459,7 @@ async function exportConfigs(outputPath, opts = {}) {
|
|
|
17362
17459
|
}
|
|
17363
17460
|
return { path: absOutput, count: configs.length };
|
|
17364
17461
|
} finally {
|
|
17365
|
-
if (
|
|
17462
|
+
if (existsSync14(tmpDir)) {
|
|
17366
17463
|
rmSync3(tmpDir, { recursive: true, force: true });
|
|
17367
17464
|
}
|
|
17368
17465
|
}
|
|
@@ -17370,14 +17467,14 @@ async function exportConfigs(outputPath, opts = {}) {
|
|
|
17370
17467
|
|
|
17371
17468
|
// src/lib/import.ts
|
|
17372
17469
|
init_config_store();
|
|
17373
|
-
import { existsSync as
|
|
17374
|
-
import { join as
|
|
17470
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync5, readFileSync as readFileSync9, rmSync as rmSync4 } from "fs";
|
|
17471
|
+
import { join as join18, resolve as resolve11 } from "path";
|
|
17375
17472
|
import { tmpdir as tmpdir2 } from "os";
|
|
17376
17473
|
async function importConfigs(bundlePath, opts = {}) {
|
|
17377
17474
|
const store = opts.store ?? resolveConfigStore();
|
|
17378
17475
|
const conflict = opts.conflict ?? "skip";
|
|
17379
|
-
const absPath =
|
|
17380
|
-
const tmpDir =
|
|
17476
|
+
const absPath = resolve11(bundlePath);
|
|
17477
|
+
const tmpDir = join18(tmpdir2(), `configs-import-${Date.now()}`);
|
|
17381
17478
|
const result = { created: 0, updated: 0, skipped: 0, errors: [] };
|
|
17382
17479
|
try {
|
|
17383
17480
|
mkdirSync5(tmpDir, { recursive: true });
|
|
@@ -17390,15 +17487,15 @@ async function importConfigs(bundlePath, opts = {}) {
|
|
|
17390
17487
|
const stderr = await new Response(proc.stderr).text();
|
|
17391
17488
|
throw new Error(`tar extraction failed: ${stderr}`);
|
|
17392
17489
|
}
|
|
17393
|
-
const manifestPath =
|
|
17394
|
-
if (!
|
|
17490
|
+
const manifestPath = join18(tmpDir, "manifest.json");
|
|
17491
|
+
if (!existsSync15(manifestPath))
|
|
17395
17492
|
throw new Error("Invalid bundle: missing manifest.json");
|
|
17396
17493
|
const manifest = JSON.parse(readFileSync9(manifestPath, "utf-8"));
|
|
17397
17494
|
for (const meta of manifest.configs) {
|
|
17398
17495
|
try {
|
|
17399
17496
|
const ext = meta.format === "text" ? "txt" : meta.format;
|
|
17400
|
-
const contentFile =
|
|
17401
|
-
const content =
|
|
17497
|
+
const contentFile = join18(tmpDir, "contents", `${meta.slug}.${ext}`);
|
|
17498
|
+
const content = existsSync15(contentFile) ? readFileSync9(contentFile, "utf-8") : "";
|
|
17402
17499
|
let existing = null;
|
|
17403
17500
|
try {
|
|
17404
17501
|
existing = await store.getConfig(meta.slug);
|
|
@@ -17432,7 +17529,7 @@ async function importConfigs(bundlePath, opts = {}) {
|
|
|
17432
17529
|
}
|
|
17433
17530
|
return result;
|
|
17434
17531
|
} finally {
|
|
17435
|
-
if (
|
|
17532
|
+
if (existsSync15(tmpDir)) {
|
|
17436
17533
|
rmSync4(tmpDir, { recursive: true, force: true });
|
|
17437
17534
|
}
|
|
17438
17535
|
}
|
|
@@ -17449,14 +17546,14 @@ init_cursor_authority();
|
|
|
17449
17546
|
init_session_authority();
|
|
17450
17547
|
import { createHash as createHash8, randomUUID as randomUUID7 } from "crypto";
|
|
17451
17548
|
import {
|
|
17452
|
-
existsSync as
|
|
17549
|
+
existsSync as existsSync16,
|
|
17453
17550
|
lstatSync as lstatSync4,
|
|
17454
17551
|
mkdirSync as mkdirSync6,
|
|
17455
17552
|
readFileSync as readFileSync10,
|
|
17456
17553
|
readdirSync as readdirSync3,
|
|
17457
17554
|
statSync as statSync6
|
|
17458
17555
|
} from "fs";
|
|
17459
|
-
import { dirname as dirname6, isAbsolute as isAbsolute4, join as
|
|
17556
|
+
import { dirname as dirname6, isAbsolute as isAbsolute4, join as join19, parse as parse4, relative as relative5, resolve as resolve12 } from "path";
|
|
17460
17557
|
|
|
17461
17558
|
class SessionApplyError extends Error {
|
|
17462
17559
|
constructor(message) {
|
|
@@ -17588,13 +17685,13 @@ function assertClaudeAuthorityStillClear(plan, targetHome, ownedClaudeAuthoritie
|
|
|
17588
17685
|
throw new SessionApplyError(`Claude authority changed after planning; refusing to apply: ${summary}`);
|
|
17589
17686
|
}
|
|
17590
17687
|
function ensureSessionTargetHome(targetHome) {
|
|
17591
|
-
if (!
|
|
17688
|
+
if (!existsSync16(targetHome))
|
|
17592
17689
|
mkdirSync6(targetHome, { recursive: true, mode: 448 });
|
|
17593
17690
|
assertSafeTargetHome(targetHome);
|
|
17594
17691
|
}
|
|
17595
17692
|
function checkSessionRenderDrift(targetHome, manifestPath) {
|
|
17596
17693
|
const safeTargetHome = assertSafeTargetHome(targetHome);
|
|
17597
|
-
const resolvedManifestPath = manifestPath ? resolveManifestRelativePath(relative5(safeTargetHome,
|
|
17694
|
+
const resolvedManifestPath = manifestPath ? resolveManifestRelativePath(relative5(safeTargetHome, resolve12(manifestPath)), safeTargetHome) : resolve12(safeTargetHome, ".hasna", "session-render-manifest.json");
|
|
17598
17695
|
const checkedAt = new Date().toISOString();
|
|
17599
17696
|
const previousManifest = readPreviousManifest(resolvedManifestPath);
|
|
17600
17697
|
if (!previousManifest) {
|
|
@@ -17611,7 +17708,7 @@ function checkSessionRenderDrift(targetHome, manifestPath) {
|
|
|
17611
17708
|
const drifted = [];
|
|
17612
17709
|
for (const file of previousManifest.files) {
|
|
17613
17710
|
const target = resolveManifestRelativePath(file.relativePath, safeTargetHome);
|
|
17614
|
-
if (!
|
|
17711
|
+
if (!existsSync16(target)) {
|
|
17615
17712
|
missing.push({
|
|
17616
17713
|
path: target,
|
|
17617
17714
|
relativePath: file.relativePath,
|
|
@@ -17644,7 +17741,7 @@ function checkSessionRenderDrift(targetHome, manifestPath) {
|
|
|
17644
17741
|
function restoreSessionRenderSnapshot(snapshotPath, options = {}) {
|
|
17645
17742
|
const snapshot = readSessionRenderSnapshot(snapshotPath);
|
|
17646
17743
|
const targetHome = assertSafeTargetHome(snapshot.targetHome);
|
|
17647
|
-
const resolvedSnapshotPath =
|
|
17744
|
+
const resolvedSnapshotPath = resolve12(snapshotPath);
|
|
17648
17745
|
const snapshotRelativePath = relative5(targetHome, resolvedSnapshotPath);
|
|
17649
17746
|
if (snapshotRelativePath === "" || snapshotRelativePath === ".." || snapshotRelativePath.startsWith("../") || isAbsolute4(snapshotRelativePath)) {
|
|
17650
17747
|
throw new SessionApplyError("Session snapshot must be stored inside its target home.");
|
|
@@ -17762,8 +17859,8 @@ function requiredRestoreHash(file) {
|
|
|
17762
17859
|
return file.previousSha256;
|
|
17763
17860
|
}
|
|
17764
17861
|
function readSessionRenderSnapshot(snapshotPath) {
|
|
17765
|
-
const resolved =
|
|
17766
|
-
if (!
|
|
17862
|
+
const resolved = resolve12(snapshotPath);
|
|
17863
|
+
if (!existsSync16(resolved))
|
|
17767
17864
|
throw new SessionApplyError(`Session snapshot not found: ${snapshotPath}`);
|
|
17768
17865
|
const stat = lstatSync4(resolved);
|
|
17769
17866
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
@@ -17843,7 +17940,7 @@ function readSessionRenderSnapshot(snapshotPath) {
|
|
|
17843
17940
|
}
|
|
17844
17941
|
function reconstructPreRollbackLegacyV1Snapshot(snapshot, previousFiles, previousManifestFiles, targetHome, snapshotPath) {
|
|
17845
17942
|
assertNoNewerSessionSnapshot(snapshotPath, snapshot.createdAt, targetHome);
|
|
17846
|
-
const manifestPath =
|
|
17943
|
+
const manifestPath = resolve12(snapshot.manifestPath);
|
|
17847
17944
|
const manifestRelativePath = relative5(targetHome, manifestPath).replaceAll("\\", "/");
|
|
17848
17945
|
resolveSnapshotFilePath(manifestRelativePath, snapshot.manifestPath, targetHome);
|
|
17849
17946
|
const manifestSha256 = currentSessionFileHash(manifestPath, targetHome);
|
|
@@ -17860,7 +17957,7 @@ function reconstructPreRollbackLegacyV1Snapshot(snapshot, previousFiles, previou
|
|
|
17860
17957
|
throw new SessionApplyError(`Pre-rollback legacy v1 applied manifest is invalid: ${snapshotPath}`);
|
|
17861
17958
|
}
|
|
17862
17959
|
const appliedManifest = parsedManifest;
|
|
17863
|
-
if (appliedManifest.schema !== SESSION_RENDER_SCHEMA || appliedManifest.tool !== snapshot.tool || appliedManifest.profile !== snapshot.profile || typeof appliedManifest.targetHome !== "string" ||
|
|
17960
|
+
if (appliedManifest.schema !== SESSION_RENDER_SCHEMA || appliedManifest.tool !== snapshot.tool || appliedManifest.profile !== snapshot.profile || typeof appliedManifest.targetHome !== "string" || resolve12(appliedManifest.targetHome) !== targetHome || appliedManifest.targetKind !== "session-home" && appliedManifest.targetKind !== "project-root" || !Array.isArray(appliedManifest.files)) {
|
|
17864
17961
|
throw new SessionApplyError(`Pre-rollback legacy v1 applied manifest does not match its snapshot: ${snapshotPath}`);
|
|
17865
17962
|
}
|
|
17866
17963
|
const afterFiles = [];
|
|
@@ -17945,8 +18042,8 @@ function assertNoNewerSessionSnapshot(snapshotPath, createdAt, targetHome) {
|
|
|
17945
18042
|
throw new SessionApplyError(`Pre-rollback legacy v1 snapshot has an invalid creation time: ${snapshotPath}`);
|
|
17946
18043
|
}
|
|
17947
18044
|
for (const entry of readdirSync3(dirname6(snapshotPath))) {
|
|
17948
|
-
const candidatePath =
|
|
17949
|
-
if (candidatePath ===
|
|
18045
|
+
const candidatePath = resolve12(dirname6(snapshotPath), entry);
|
|
18046
|
+
if (candidatePath === resolve12(snapshotPath) || !entry.endsWith(".json"))
|
|
17950
18047
|
continue;
|
|
17951
18048
|
const candidateStat = lstatSync4(candidatePath);
|
|
17952
18049
|
if (candidateStat.isSymbolicLink() || !candidateStat.isFile() || candidateStat.size > 32 * 1024 * 1024)
|
|
@@ -17954,7 +18051,7 @@ function assertNoNewerSessionSnapshot(snapshotPath, createdAt, targetHome) {
|
|
|
17954
18051
|
try {
|
|
17955
18052
|
const candidate = JSON.parse(readFileSync10(candidatePath, "utf8"));
|
|
17956
18053
|
const candidateCreatedAtMs = typeof candidate.createdAt === "string" ? Date.parse(candidate.createdAt) : Number.NaN;
|
|
17957
|
-
if ((candidate.schema === "hasna.configs.session-render-snapshot/v1" || candidate.schema === "hasna.configs.session-render-snapshot/v2") && typeof candidate.targetHome === "string" &&
|
|
18054
|
+
if ((candidate.schema === "hasna.configs.session-render-snapshot/v1" || candidate.schema === "hasna.configs.session-render-snapshot/v2") && typeof candidate.targetHome === "string" && resolve12(candidate.targetHome) === targetHome && Number.isFinite(candidateCreatedAtMs) && candidateCreatedAtMs >= createdAtMs) {
|
|
17958
18055
|
throw new SessionApplyError(`Cannot restore pre-rollback legacy v1 snapshot after a newer session snapshot exists: ${candidatePath}`);
|
|
17959
18056
|
}
|
|
17960
18057
|
} catch (error) {
|
|
@@ -18023,14 +18120,14 @@ function inferLegacySnapshotAction(file, previousFiles, previousManifestFiles, p
|
|
|
18023
18120
|
}
|
|
18024
18121
|
function resolveSnapshotFilePath(relativePath, recordedPath, targetHome) {
|
|
18025
18122
|
const path = resolveManifestRelativePath(relativePath, targetHome);
|
|
18026
|
-
if (
|
|
18123
|
+
if (resolve12(recordedPath) !== path) {
|
|
18027
18124
|
throw new SessionApplyError(`Session snapshot file path mismatch for ${relativePath}`);
|
|
18028
18125
|
}
|
|
18029
18126
|
return path;
|
|
18030
18127
|
}
|
|
18031
18128
|
function planFileResult(plan, file, targetHome, previousHashes, previousManifest, options) {
|
|
18032
18129
|
const target = resolvePlannedFilePath(plan, file, targetHome);
|
|
18033
|
-
const previousContent =
|
|
18130
|
+
const previousContent = existsSync16(target) ? readFileSync10(target, "utf-8") : null;
|
|
18034
18131
|
const previousSha256 = previousContent === null ? null : sha2568(previousContent);
|
|
18035
18132
|
const previouslyManaged = isPreviouslyManaged(file, previousSha256, previousHashes, previousManifest);
|
|
18036
18133
|
const changed = previousContent !== file.content;
|
|
@@ -18129,7 +18226,7 @@ function planStaleFileResults(plan, targetHome, previousManifest, currentRelativ
|
|
|
18129
18226
|
}
|
|
18130
18227
|
function planStaleFileResult(file, targetHome, options) {
|
|
18131
18228
|
const target = resolveManifestRelativePath(file.relativePath, targetHome);
|
|
18132
|
-
if (!
|
|
18229
|
+
if (!existsSync16(target))
|
|
18133
18230
|
return null;
|
|
18134
18231
|
const previousContent = readFileSync10(target, "utf-8");
|
|
18135
18232
|
const previousSha256 = sha2568(previousContent);
|
|
@@ -18176,19 +18273,19 @@ function isPreviouslyManaged(file, previousSha256, previousHashes, previousManif
|
|
|
18176
18273
|
return previousHashes.get(file.relativePath) === previousSha256;
|
|
18177
18274
|
}
|
|
18178
18275
|
function resolvePlannedFilePath(plan, file, targetHome) {
|
|
18179
|
-
const target =
|
|
18276
|
+
const target = resolve12(targetHome, ...file.relativePath.split("/"));
|
|
18180
18277
|
const rel = relative5(targetHome, target);
|
|
18181
18278
|
if (rel === "" || rel === ".." || rel.startsWith("../") || isAbsolute4(rel)) {
|
|
18182
18279
|
throw new SessionApplyError(`Session file escapes target home: ${file.relativePath}`);
|
|
18183
18280
|
}
|
|
18184
|
-
if (
|
|
18281
|
+
if (resolve12(file.path) !== target) {
|
|
18185
18282
|
throw new SessionApplyError(`Session file path mismatch for ${file.relativePath}: ${file.path}`);
|
|
18186
18283
|
}
|
|
18187
18284
|
assertNoSymlinkSegments2(targetHome, target);
|
|
18188
18285
|
return target;
|
|
18189
18286
|
}
|
|
18190
18287
|
function resolveManifestRelativePath(relativePath, targetHome) {
|
|
18191
|
-
const target =
|
|
18288
|
+
const target = resolve12(targetHome, ...relativePath.split(/[\\/]+/));
|
|
18192
18289
|
const rel = relative5(targetHome, target);
|
|
18193
18290
|
if (rel === "" || rel === ".." || rel.startsWith("../") || isAbsolute4(rel)) {
|
|
18194
18291
|
throw new SessionApplyError(`Session manifest file escapes target home: ${relativePath}`);
|
|
@@ -18197,7 +18294,7 @@ function resolveManifestRelativePath(relativePath, targetHome) {
|
|
|
18197
18294
|
return target;
|
|
18198
18295
|
}
|
|
18199
18296
|
function readPreviousManifest(path) {
|
|
18200
|
-
if (!
|
|
18297
|
+
if (!existsSync16(path))
|
|
18201
18298
|
return null;
|
|
18202
18299
|
try {
|
|
18203
18300
|
const parsed = JSON.parse(readFileSync10(path, "utf-8"));
|
|
@@ -18239,7 +18336,7 @@ function assertExpectedSessionFileHash(path, targetHome, expectedHash) {
|
|
|
18239
18336
|
}
|
|
18240
18337
|
function currentSessionFileHash(path, targetHome) {
|
|
18241
18338
|
assertNoSymlinkSegments2(targetHome, path);
|
|
18242
|
-
if (!
|
|
18339
|
+
if (!existsSync16(path))
|
|
18243
18340
|
return null;
|
|
18244
18341
|
const stat = lstatSync4(path);
|
|
18245
18342
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
@@ -18254,7 +18351,7 @@ function requiredPreviousHash(result) {
|
|
|
18254
18351
|
return result.previousSha256;
|
|
18255
18352
|
}
|
|
18256
18353
|
function writeSessionSnapshot(plan, targetHome, manifestPath, results, previousManifest, coordination, allowPortableFallback, forcePortableFileOps) {
|
|
18257
|
-
const existingFiles = results.filter((result) => result.action === "update" || result.action === "delete").filter((result) =>
|
|
18354
|
+
const existingFiles = results.filter((result) => result.action === "update" || result.action === "delete").filter((result) => existsSync16(result.path)).map((result) => {
|
|
18258
18355
|
const content = readFileSync10(result.path, "utf-8");
|
|
18259
18356
|
return {
|
|
18260
18357
|
path: result.path,
|
|
@@ -18273,7 +18370,7 @@ function writeSessionSnapshot(plan, targetHome, manifestPath, results, previousM
|
|
|
18273
18370
|
};
|
|
18274
18371
|
}
|
|
18275
18372
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
18276
|
-
const snapshotPath =
|
|
18373
|
+
const snapshotPath = resolve12(targetHome, ".hasna", "session-render-snapshots", `${timestamp}-${randomUUID7()}.json`);
|
|
18277
18374
|
const afterFiles = results.map((result) => {
|
|
18278
18375
|
if (result.action === "conflict") {
|
|
18279
18376
|
throw new SessionApplyError(`Cannot snapshot unresolved conflict: ${result.relativePath}`);
|
|
@@ -18321,12 +18418,12 @@ function writeSessionSnapshot(plan, targetHome, manifestPath, results, previousM
|
|
|
18321
18418
|
function assertSafeTargetHome(targetHome) {
|
|
18322
18419
|
if (!isAbsolute4(targetHome))
|
|
18323
18420
|
throw new SessionApplyError(`Session target home must be absolute: ${targetHome}`);
|
|
18324
|
-
const normalized =
|
|
18421
|
+
const normalized = resolve12(targetHome);
|
|
18325
18422
|
if (normalized === parse4(normalized).root) {
|
|
18326
18423
|
throw new SessionApplyError(`Session target home cannot be the filesystem root: ${targetHome}`);
|
|
18327
18424
|
}
|
|
18328
18425
|
assertNoSymlinkAncestors2(normalized);
|
|
18329
|
-
if (
|
|
18426
|
+
if (existsSync16(normalized) && lstatSync4(normalized).isSymbolicLink()) {
|
|
18330
18427
|
throw new SessionApplyError(`Session target home cannot be a symlink: ${normalized}`);
|
|
18331
18428
|
}
|
|
18332
18429
|
return normalized;
|
|
@@ -18336,20 +18433,20 @@ function assertNoSymlinkSegments2(root, target) {
|
|
|
18336
18433
|
const rel = relative5(root, target);
|
|
18337
18434
|
let current = root;
|
|
18338
18435
|
for (const segment of rel.split(/[\\/]+/).filter(Boolean)) {
|
|
18339
|
-
current =
|
|
18340
|
-
if (
|
|
18436
|
+
current = join19(current, segment);
|
|
18437
|
+
if (existsSync16(current) && lstatSync4(current).isSymbolicLink()) {
|
|
18341
18438
|
throw new SessionApplyError(`Session apply path uses a symlink: ${current}`);
|
|
18342
18439
|
}
|
|
18343
18440
|
}
|
|
18344
18441
|
}
|
|
18345
18442
|
function assertNoSymlinkAncestors2(path) {
|
|
18346
|
-
const normalized =
|
|
18443
|
+
const normalized = resolve12(path);
|
|
18347
18444
|
const parsed = parse4(normalized);
|
|
18348
18445
|
let current = parsed.root;
|
|
18349
18446
|
const rel = relative5(parsed.root, normalized);
|
|
18350
18447
|
for (const segment of rel.split(/[\\/]+/).filter(Boolean)) {
|
|
18351
|
-
current =
|
|
18352
|
-
if (!
|
|
18448
|
+
current = join19(current, segment);
|
|
18449
|
+
if (!existsSync16(current))
|
|
18353
18450
|
return;
|
|
18354
18451
|
if (lstatSync4(current).isSymbolicLink()) {
|
|
18355
18452
|
throw new SessionApplyError(`Session apply path uses a symlink ancestor: ${current}`);
|
|
@@ -18400,9 +18497,9 @@ function formatGlobalSourceCoverageWarnings(result) {
|
|
|
18400
18497
|
// src/lib/station-profile.ts
|
|
18401
18498
|
init_raw_store_root();
|
|
18402
18499
|
import { spawnSync } from "child_process";
|
|
18403
|
-
import { existsSync as
|
|
18404
|
-
import { arch as osArch, homedir as
|
|
18405
|
-
import { dirname as dirname7, join as
|
|
18500
|
+
import { existsSync as existsSync17, lstatSync as lstatSync5, mkdirSync as mkdirSync7, readFileSync as readFileSync11, readdirSync as readdirSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
18501
|
+
import { arch as osArch, homedir as homedir12, hostname as osHostname, platform as osPlatform, userInfo as osUserInfo } from "os";
|
|
18502
|
+
import { dirname as dirname7, join as join20 } from "path";
|
|
18406
18503
|
var STATION_PROFILE_CACHE_FILENAME = "station-profile.md";
|
|
18407
18504
|
var STATION_PROFILE_SOURCE_ID = "station-profile";
|
|
18408
18505
|
var STATION_PROFILE_LAYER = "machine";
|
|
@@ -18413,20 +18510,20 @@ var STATION_PROFILE_PRIMARY_SCOPE = "@hasna";
|
|
|
18413
18510
|
var MACHINES_MANIFEST_PATH_ENV = "HASNA_MACHINES_MANIFEST_PATH";
|
|
18414
18511
|
var BUN_INSTALL_ENV = "BUN_INSTALL";
|
|
18415
18512
|
function homeDir3(env = process.env) {
|
|
18416
|
-
return env["HOME"] || env["USERPROFILE"] ||
|
|
18513
|
+
return env["HOME"] || env["USERPROFILE"] || homedir12();
|
|
18417
18514
|
}
|
|
18418
18515
|
function getStationProfileCachePath(env = process.env) {
|
|
18419
|
-
return
|
|
18516
|
+
return join20(getRawStoreRoot(env), STATION_PROFILE_CACHE_FILENAME);
|
|
18420
18517
|
}
|
|
18421
18518
|
function getMachinesManifestPath(env = process.env) {
|
|
18422
|
-
return env[MACHINES_MANIFEST_PATH_ENV] ||
|
|
18519
|
+
return env[MACHINES_MANIFEST_PATH_ENV] || join20(homeDir3(env), ".hasna", "machines", "machines.json");
|
|
18423
18520
|
}
|
|
18424
18521
|
function getBunGlobalModulesDir(env = process.env) {
|
|
18425
|
-
return
|
|
18522
|
+
return join20(env[BUN_INSTALL_ENV] || join20(homeDir3(env), ".bun"), "install", "global", "node_modules");
|
|
18426
18523
|
}
|
|
18427
18524
|
function readMachinesManifest(path) {
|
|
18428
18525
|
try {
|
|
18429
|
-
if (!
|
|
18526
|
+
if (!existsSync17(path))
|
|
18430
18527
|
return null;
|
|
18431
18528
|
const parsed = JSON.parse(readFileSync11(path, "utf8"));
|
|
18432
18529
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
@@ -18484,7 +18581,7 @@ function resolveStationProfileMachine(env = process.env, options = {}) {
|
|
|
18484
18581
|
const record = findLocalManifestMachine(readMachinesManifest(getMachinesManifestPath(env)), hostname2);
|
|
18485
18582
|
const home = homeDir3(env);
|
|
18486
18583
|
const platform = stringField(record, "platform") ?? osPlatform();
|
|
18487
|
-
const workspacePath = stringField(record, "workspacePath") ??
|
|
18584
|
+
const workspacePath = stringField(record, "workspacePath") ?? join20(home, platform === "darwin" ? "Workspace" : "workspace");
|
|
18488
18585
|
const machine = {
|
|
18489
18586
|
id: stringField(record, "id") ?? hostname2,
|
|
18490
18587
|
hostname: stringField(record, "hostname") ?? hostname2,
|
|
@@ -18501,9 +18598,9 @@ function resolveStationProfileMachine(env = process.env, options = {}) {
|
|
|
18501
18598
|
return machine;
|
|
18502
18599
|
}
|
|
18503
18600
|
function scopedPackageNames(modulesDir, scope) {
|
|
18504
|
-
const scopeDir =
|
|
18601
|
+
const scopeDir = join20(modulesDir, scope);
|
|
18505
18602
|
try {
|
|
18506
|
-
if (!
|
|
18603
|
+
if (!existsSync17(scopeDir))
|
|
18507
18604
|
return null;
|
|
18508
18605
|
return readdirNames(scopeDir).sort();
|
|
18509
18606
|
} catch {
|
|
@@ -18513,7 +18610,7 @@ function scopedPackageNames(modulesDir, scope) {
|
|
|
18513
18610
|
function readdirNames(dir) {
|
|
18514
18611
|
return readdirSync4(dir).filter((name) => {
|
|
18515
18612
|
try {
|
|
18516
|
-
return lstatSync5(
|
|
18613
|
+
return lstatSync5(join20(dir, name)).isDirectory();
|
|
18517
18614
|
} catch {
|
|
18518
18615
|
return false;
|
|
18519
18616
|
}
|
|
@@ -18523,7 +18620,7 @@ function resolveStationProfilePackages(env = process.env) {
|
|
|
18523
18620
|
const modulesDir = getBunGlobalModulesDir(env);
|
|
18524
18621
|
let scopeDirs;
|
|
18525
18622
|
try {
|
|
18526
|
-
if (!
|
|
18623
|
+
if (!existsSync17(modulesDir))
|
|
18527
18624
|
return null;
|
|
18528
18625
|
scopeDirs = readdirNames(modulesDir).filter((name) => name.startsWith("@") && name.toLowerCase().includes("hasna"));
|
|
18529
18626
|
} catch {
|
|
@@ -18598,7 +18695,7 @@ function refreshStationProfile(options = {}) {
|
|
|
18598
18695
|
const path = getStationProfileCachePath(env);
|
|
18599
18696
|
const generatedAt = new Date().toISOString();
|
|
18600
18697
|
if (!options.dryRun) {
|
|
18601
|
-
const existing =
|
|
18698
|
+
const existing = existsSync17(path) ? readFileSync11(path, "utf8") : null;
|
|
18602
18699
|
if (existing !== content) {
|
|
18603
18700
|
mkdirSync7(dirname7(path), { recursive: true });
|
|
18604
18701
|
writeFileSync4(path, content, "utf8");
|
|
@@ -18617,7 +18714,7 @@ function refreshStationProfile(options = {}) {
|
|
|
18617
18714
|
function readStationProfile(env = process.env) {
|
|
18618
18715
|
const path = getStationProfileCachePath(env);
|
|
18619
18716
|
try {
|
|
18620
|
-
if (!
|
|
18717
|
+
if (!existsSync17(path))
|
|
18621
18718
|
return null;
|
|
18622
18719
|
return readFileSync11(path, "utf8");
|
|
18623
18720
|
} catch {
|
|
@@ -18956,7 +19053,7 @@ init_codewith_shared_todos_storage_standard();
|
|
|
18956
19053
|
import { createHash as createHash9 } from "crypto";
|
|
18957
19054
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
18958
19055
|
import {
|
|
18959
|
-
existsSync as
|
|
19056
|
+
existsSync as existsSync18,
|
|
18960
19057
|
lstatSync as lstatSync6,
|
|
18961
19058
|
mkdirSync as mkdirSync8,
|
|
18962
19059
|
readFileSync as readFileSync12,
|
|
@@ -18964,8 +19061,8 @@ import {
|
|
|
18964
19061
|
rmSync as rmSync5,
|
|
18965
19062
|
writeFileSync as writeFileSync5
|
|
18966
19063
|
} from "fs";
|
|
18967
|
-
import { homedir as
|
|
18968
|
-
import { dirname as dirname8, join as
|
|
19064
|
+
import { homedir as homedir13 } from "os";
|
|
19065
|
+
import { dirname as dirname8, join as join21, parse as parse5, relative as relative6, resolve as resolve13 } from "path";
|
|
18969
19066
|
var INBOX_CONVERSATIONS_MINIMUM_VERSION = "0.5.28";
|
|
18970
19067
|
var INBOX_SKILL_MARKERS = [
|
|
18971
19068
|
[".claude", "skills", "inbox", "SKILL.md"],
|
|
@@ -18986,13 +19083,13 @@ function lstatOrNull(path) {
|
|
|
18986
19083
|
}
|
|
18987
19084
|
}
|
|
18988
19085
|
function findSymlinkedAncestor(path) {
|
|
18989
|
-
const normalized =
|
|
19086
|
+
const normalized = resolve13(path);
|
|
18990
19087
|
const parsed = parse5(normalized);
|
|
18991
19088
|
let current = parsed.root;
|
|
18992
19089
|
const rel = relative6(parsed.root, normalized);
|
|
18993
19090
|
for (const segment of rel.split(/[\\/]+/).filter(Boolean)) {
|
|
18994
|
-
current =
|
|
18995
|
-
if (!
|
|
19091
|
+
current = join21(current, segment);
|
|
19092
|
+
if (!existsSync18(current))
|
|
18996
19093
|
return null;
|
|
18997
19094
|
if (lstatSync6(current).isSymbolicLink())
|
|
18998
19095
|
return current;
|
|
@@ -19009,11 +19106,11 @@ function packagedInboxSkillPath(explicitPath) {
|
|
|
19009
19106
|
if (explicitPath)
|
|
19010
19107
|
return explicitPath;
|
|
19011
19108
|
const candidates = [
|
|
19012
|
-
|
|
19013
|
-
|
|
19014
|
-
|
|
19109
|
+
join21(import.meta.dir, "..", "..", "assets", "skills", "inbox", "SKILL.md"),
|
|
19110
|
+
join21(import.meta.dir, "..", "assets", "skills", "inbox", "SKILL.md"),
|
|
19111
|
+
join21(process.cwd(), "assets", "skills", "inbox", "SKILL.md")
|
|
19015
19112
|
];
|
|
19016
|
-
const found = candidates.find((candidate) =>
|
|
19113
|
+
const found = candidates.find((candidate) => existsSync18(candidate));
|
|
19017
19114
|
if (!found) {
|
|
19018
19115
|
throw new Error(`packaged inbox skill contract is missing (checked ${candidates.length} package-relative locations)`);
|
|
19019
19116
|
}
|
|
@@ -19063,7 +19160,7 @@ function compareVersions(left, right) {
|
|
|
19063
19160
|
return 0;
|
|
19064
19161
|
}
|
|
19065
19162
|
function inspectSkillMarkers(homeDir4) {
|
|
19066
|
-
return INBOX_SKILL_MARKERS.map((parts) =>
|
|
19163
|
+
return INBOX_SKILL_MARKERS.map((parts) => join21(homeDir4, ...parts)).map((path) => {
|
|
19067
19164
|
const stat = lstatOrNull(path);
|
|
19068
19165
|
if (!stat)
|
|
19069
19166
|
return null;
|
|
@@ -19079,7 +19176,7 @@ function inspectSkillMarkers(homeDir4) {
|
|
|
19079
19176
|
}).filter((snapshot) => snapshot !== null);
|
|
19080
19177
|
}
|
|
19081
19178
|
function inspectInbox(options) {
|
|
19082
|
-
const homeDir4 = options.homeDir ??
|
|
19179
|
+
const homeDir4 = options.homeDir ?? homedir13();
|
|
19083
19180
|
const runtimeCommand = options.conversationsCommand ?? "conversations";
|
|
19084
19181
|
const snapshots = inspectSkillMarkers(homeDir4);
|
|
19085
19182
|
const skillPresent = snapshots.length > 0;
|
|
@@ -19356,11 +19453,11 @@ init_project_context();
|
|
|
19356
19453
|
init_config_store();
|
|
19357
19454
|
init_apply();
|
|
19358
19455
|
init_config_agents();
|
|
19359
|
-
import { existsSync as
|
|
19456
|
+
import { existsSync as existsSync20, readFileSync as readFileSync14 } from "fs";
|
|
19360
19457
|
|
|
19361
19458
|
// src/lib/package-version.ts
|
|
19362
|
-
import { existsSync as
|
|
19363
|
-
import { dirname as dirname9, join as
|
|
19459
|
+
import { existsSync as existsSync19, readFileSync as readFileSync13 } from "fs";
|
|
19460
|
+
import { dirname as dirname9, join as join22 } from "path";
|
|
19364
19461
|
import { fileURLToPath } from "url";
|
|
19365
19462
|
var cached = null;
|
|
19366
19463
|
function getPackageVersion() {
|
|
@@ -19369,8 +19466,8 @@ function getPackageVersion() {
|
|
|
19369
19466
|
try {
|
|
19370
19467
|
let dir = dirname9(fileURLToPath(import.meta.url));
|
|
19371
19468
|
for (let i = 0;i < 8; i++) {
|
|
19372
|
-
const pkgPath =
|
|
19373
|
-
if (
|
|
19469
|
+
const pkgPath = join22(dir, "package.json");
|
|
19470
|
+
if (existsSync19(pkgPath)) {
|
|
19374
19471
|
const pkg = JSON.parse(readFileSync13(pkgPath, "utf8"));
|
|
19375
19472
|
if (pkg.name === "@hasna/instructions" && pkg.version) {
|
|
19376
19473
|
cached = pkg.version;
|
|
@@ -19434,7 +19531,7 @@ async function getConfigsStatus(store = resolveConfigStore(), options = {}) {
|
|
|
19434
19531
|
continue;
|
|
19435
19532
|
knownTargets += 1;
|
|
19436
19533
|
const targetPath = expandPath(config.target_path);
|
|
19437
|
-
if (!
|
|
19534
|
+
if (!existsSync20(targetPath)) {
|
|
19438
19535
|
missingTargets += 1;
|
|
19439
19536
|
continue;
|
|
19440
19537
|
}
|
|
@@ -19534,8 +19631,8 @@ init_config_store();
|
|
|
19534
19631
|
|
|
19535
19632
|
// src/lib/provider-context.ts
|
|
19536
19633
|
import { createHash as createHash10 } from "crypto";
|
|
19537
|
-
import { existsSync as
|
|
19538
|
-
import { join as
|
|
19634
|
+
import { existsSync as existsSync21, mkdirSync as mkdirSync9, readFileSync as readFileSync15, writeFileSync as writeFileSync6 } from "fs";
|
|
19635
|
+
import { join as join23 } from "path";
|
|
19539
19636
|
var PROVIDER_CONTEXT_DIR = ".hasna/provider-context";
|
|
19540
19637
|
var PROVIDER_CONTEXT_MANIFEST = "manifest.json";
|
|
19541
19638
|
var PROVIDER_CONTEXT_SCHEMA = "hasna.instructions.provider-context/v1";
|
|
@@ -19680,17 +19777,17 @@ function resolveAndRenderProviderContext(opts) {
|
|
|
19680
19777
|
const recordedEndpoint = originAccepted ? `${opts.origin.host}${opts.origin.pathPrefix || ""}` : null;
|
|
19681
19778
|
const reason = entry === null && opts.rawEndpoint ? originAccepted ? `endpoint "${recordedEndpoint}" is not in the provider-context registry; using the invariant fragment` : "endpoint rejected (embedded credentials or unparseable); using the invariant fragment" : null;
|
|
19682
19779
|
const content = renderProviderFragment(entry);
|
|
19683
|
-
const dir =
|
|
19684
|
-
if (!
|
|
19780
|
+
const dir = join23(opts.homeDir, PROVIDER_CONTEXT_DIR);
|
|
19781
|
+
if (!existsSync21(dir))
|
|
19685
19782
|
mkdirSync9(dir, { recursive: true });
|
|
19686
19783
|
const filename = `${entry ? entry.key : "invariant"}.md`;
|
|
19687
|
-
const fragmentPath2 =
|
|
19784
|
+
const fragmentPath2 = join23(dir, filename);
|
|
19688
19785
|
const fragmentSha256 = sha25610(content);
|
|
19689
19786
|
writeFileSync6(fragmentPath2, content, "utf8");
|
|
19690
|
-
const manifestPath =
|
|
19787
|
+
const manifestPath = join23(dir, PROVIDER_CONTEXT_MANIFEST);
|
|
19691
19788
|
let manifest = { schema: PROVIDER_CONTEXT_SCHEMA, fragments: {} };
|
|
19692
19789
|
try {
|
|
19693
|
-
if (
|
|
19790
|
+
if (existsSync21(manifestPath)) {
|
|
19694
19791
|
const parsed = JSON.parse(readFileSync15(manifestPath, "utf8"));
|
|
19695
19792
|
if (parsed && typeof parsed === "object")
|
|
19696
19793
|
manifest = parsed;
|
|
@@ -19834,7 +19931,7 @@ function parseSessionSource(value, order) {
|
|
|
19834
19931
|
if (!path)
|
|
19835
19932
|
throw new Error(`Invalid --source "${value}" (expected path or id=path)`);
|
|
19836
19933
|
const absPath = resolveSessionPath(path);
|
|
19837
|
-
if (!
|
|
19934
|
+
if (!existsSync23(absPath))
|
|
19838
19935
|
throw new Error(`Instruction source file not found: ${absPath}`);
|
|
19839
19936
|
const content = readSessionInstructionSourceFile(absPath);
|
|
19840
19937
|
const source = sourceFromFilePath(absPath, content, order);
|
|
@@ -19915,7 +20012,7 @@ async function collectSessionSources(opts, tool, store) {
|
|
|
19915
20012
|
}
|
|
19916
20013
|
for (const value of opts.identityExport ?? []) {
|
|
19917
20014
|
const path = resolveSessionPath(value);
|
|
19918
|
-
if (!
|
|
20015
|
+
if (!existsSync23(path))
|
|
19919
20016
|
throw new Error(`Identity instruction export not found: ${path}`);
|
|
19920
20017
|
const parsed = JSON.parse(readFileSync17(path, "utf-8"));
|
|
19921
20018
|
sources.push(...sourcesFromIdentityExport(parsed, { path, tool, orderOffset: sources.length }));
|
|
@@ -20049,7 +20146,7 @@ function readProjectContextBundleOption(value, allowMissing = false) {
|
|
|
20049
20146
|
if (value === "-")
|
|
20050
20147
|
return { json: readBoundedProjectContextStdin() };
|
|
20051
20148
|
const path = resolveSessionPath(value);
|
|
20052
|
-
if (!
|
|
20149
|
+
if (!existsSync23(path)) {
|
|
20053
20150
|
if (allowMissing)
|
|
20054
20151
|
return {};
|
|
20055
20152
|
throw new ProjectContextError("PROJECT_CONTEXT_INPUT_MISSING", `bundle file not found: ${path}`);
|
|
@@ -20220,8 +20317,8 @@ program.command("tag <id>").description("Add or remove tags on a stored config (
|
|
|
20220
20317
|
console.log(chalk.green("\u2713") + ` Tags on ${chalk.bold(updated.name)} ${chalk.dim(`(${updated.slug})`)}: ${nextTags.join(", ") || chalk.dim("(none)")}`);
|
|
20221
20318
|
});
|
|
20222
20319
|
program.command("add <path>").description("Ingest a file into the config DB").option("-n, --name <name>", "config name (defaults to filename)").option("-c, --category <cat>", "category override").option("-a, --agent <agent>", "agent override").option("-k, --kind <kind>", "kind: file|reference", "file").option("--template", "mark as template (has {{VAR}} placeholders)").option("--update", "if a config already owns this path, update that row in place instead of refusing").action(async (filePath, opts) => {
|
|
20223
|
-
const abs =
|
|
20224
|
-
if (!
|
|
20320
|
+
const abs = resolve15(filePath);
|
|
20321
|
+
if (!existsSync23(abs)) {
|
|
20225
20322
|
console.error(chalk.red(`File not found: ${abs}`));
|
|
20226
20323
|
process.exit(1);
|
|
20227
20324
|
}
|
|
@@ -20229,7 +20326,7 @@ program.command("add <path>").description("Ingest a file into the config DB").op
|
|
|
20229
20326
|
const storedFmt = detectFormat(abs);
|
|
20230
20327
|
const fmt = redactFormatForTarget(abs, storedFmt);
|
|
20231
20328
|
const { content, redacted, isTemplate: isTemplate2 } = redactContent(rawContent, fmt);
|
|
20232
|
-
const targetPath = abs.startsWith(
|
|
20329
|
+
const targetPath = abs.startsWith(homedir15()) ? abs.replace(homedir15(), "~") : abs;
|
|
20233
20330
|
const name = opts.name || filePath.split("/").pop();
|
|
20234
20331
|
const store = resolveConfigStore();
|
|
20235
20332
|
const allConfigs = await store.listConfigs();
|
|
@@ -20404,7 +20501,7 @@ program.command("sync").description("Sync known AI coding configs from disk into
|
|
|
20404
20501
|
for (const entry of entries) {
|
|
20405
20502
|
if (!entry.isDirectory())
|
|
20406
20503
|
continue;
|
|
20407
|
-
const projDir =
|
|
20504
|
+
const projDir = join25(absDir, entry.name);
|
|
20408
20505
|
const hasAgentConfig = [
|
|
20409
20506
|
"CLAUDE.md",
|
|
20410
20507
|
".mcp.json",
|
|
@@ -20417,7 +20514,7 @@ program.command("sync").description("Sync known AI coding configs from disk into
|
|
|
20417
20514
|
".aicopilot",
|
|
20418
20515
|
".cursor",
|
|
20419
20516
|
".agents"
|
|
20420
|
-
].some((marker) =>
|
|
20517
|
+
].some((marker) => existsSync23(join25(projDir, marker)));
|
|
20421
20518
|
if (!hasAgentConfig)
|
|
20422
20519
|
continue;
|
|
20423
20520
|
const result2 = await syncProject({ projectDir: projDir, dryRun: opts.dryRun, store });
|
|
@@ -20468,7 +20565,7 @@ program.command("import <file>").description("Import configs from a tar.gz bundl
|
|
|
20468
20565
|
});
|
|
20469
20566
|
program.command("whoami").description("Show setup summary").action(async () => {
|
|
20470
20567
|
const store = resolveConfigStore();
|
|
20471
|
-
const dbPath = isApiTransport() ? `${process.env["HASNA_INSTRUCTIONS_API_URL"]}/v1` : process.env["HASNA_INSTRUCTIONS_DB_PATH"] ||
|
|
20568
|
+
const dbPath = isApiTransport() ? `${process.env["HASNA_INSTRUCTIONS_API_URL"]}/v1` : process.env["HASNA_INSTRUCTIONS_DB_PATH"] || join25(getRawStoreRoot(), "instructions.db");
|
|
20472
20569
|
const stats = await store.getConfigStats();
|
|
20473
20570
|
console.log(chalk.bold("@hasna/instructions") + chalk.dim(" v" + pkg.version));
|
|
20474
20571
|
console.log(chalk.cyan(isApiTransport() ? "API:" : "DB:") + " " + dbPath);
|
|
@@ -21347,7 +21444,7 @@ mcpCmd.command("install").alias("add").description("Install configs MCP server i
|
|
|
21347
21444
|
} else if (target === "codex") {
|
|
21348
21445
|
const { appendFileSync, existsSync: ex } = await import("fs");
|
|
21349
21446
|
const { join: j } = await import("path");
|
|
21350
|
-
const configPath = j(
|
|
21447
|
+
const configPath = j(homedir15(), ".codex", "config.toml");
|
|
21351
21448
|
const block = `
|
|
21352
21449
|
[mcp_servers.configs]
|
|
21353
21450
|
command = "${mcpBinary}"
|
|
@@ -21365,7 +21462,7 @@ args = []
|
|
|
21365
21462
|
} else if (target === "antigravity") {
|
|
21366
21463
|
const { mkdirSync: md, readFileSync: rf, writeFileSync: wf, existsSync: ex } = await import("fs");
|
|
21367
21464
|
const { dirname: dn, join: j } = await import("path");
|
|
21368
|
-
const configPath = j(
|
|
21465
|
+
const configPath = j(homedir15(), ".gemini", "config", "mcp_config.json");
|
|
21369
21466
|
let settings = {};
|
|
21370
21467
|
if (ex(configPath)) {
|
|
21371
21468
|
try {
|
|
@@ -21449,7 +21546,7 @@ DB stats:`));
|
|
|
21449
21546
|
if (count > 0)
|
|
21450
21547
|
console.log(` ${key.padEnd(18)} ${count}`);
|
|
21451
21548
|
}
|
|
21452
|
-
const location = isApiTransport() ? `${process.env["HASNA_INSTRUCTIONS_API_URL"]}/v1` : process.env["HASNA_INSTRUCTIONS_DB_PATH"] ||
|
|
21549
|
+
const location = isApiTransport() ? `${process.env["HASNA_INSTRUCTIONS_API_URL"]}/v1` : process.env["HASNA_INSTRUCTIONS_DB_PATH"] || join25(getRawStoreRoot(), "instructions.db");
|
|
21453
21550
|
console.log(chalk.dim(`
|
|
21454
21551
|
${isApiTransport() ? "API" : "DB"}: ${location}`));
|
|
21455
21552
|
});
|
|
@@ -21510,10 +21607,10 @@ managedSkillsCmd.command("apply").option("--dry-run", "preview without writing")
|
|
|
21510
21607
|
});
|
|
21511
21608
|
program.command("backup").description("Export configs to a timestamped backup file").action(async () => {
|
|
21512
21609
|
const { mkdirSync: mk } = await import("fs");
|
|
21513
|
-
const backupDir =
|
|
21610
|
+
const backupDir = join25(getRawStoreRoot(), "backups");
|
|
21514
21611
|
mk(backupDir, { recursive: true });
|
|
21515
21612
|
const ts = new Date().toISOString().replace(/[:.]/g, "-").replace("T", "-").slice(0, 19);
|
|
21516
|
-
const outPath =
|
|
21613
|
+
const outPath = join25(backupDir, `configs-${ts}.tar.gz`);
|
|
21517
21614
|
const result = await exportConfigs(outPath, { store: resolveConfigStore() });
|
|
21518
21615
|
const { statSync: st } = await import("fs");
|
|
21519
21616
|
const size = st(outPath).size;
|
|
@@ -21541,9 +21638,9 @@ program.command("doctor").description("Validate configs: syntax, permissions, mi
|
|
|
21541
21638
|
console.log(chalk.cyan("Known files on disk:"));
|
|
21542
21639
|
for (const k of KNOWN_CONFIGS) {
|
|
21543
21640
|
if (k.rulesDir) {
|
|
21544
|
-
|
|
21641
|
+
existsSync23(expandPath(k.rulesDir)) ? pass(`${k.rulesDir}/ exists`) : k.optional ? skip(`${k.rulesDir}/ (optional)`) : fail2(`${k.rulesDir}/ not found`);
|
|
21545
21642
|
} else {
|
|
21546
|
-
|
|
21643
|
+
existsSync23(expandPath(k.path)) ? pass(k.path) : k.optional ? skip(`${k.path} (optional)`) : fail2(`${k.path} not found`);
|
|
21547
21644
|
}
|
|
21548
21645
|
}
|
|
21549
21646
|
const allConfigs = await store.listConfigs();
|
|
@@ -21697,16 +21794,16 @@ program.command("watch").description("Watch known config files for changes and a
|
|
|
21697
21794
|
for (const k of KNOWN_CONFIGS) {
|
|
21698
21795
|
if (k.rulesDir) {
|
|
21699
21796
|
const absDir = expandPath2(k.rulesDir);
|
|
21700
|
-
if (!
|
|
21797
|
+
if (!existsSync23(absDir))
|
|
21701
21798
|
continue;
|
|
21702
21799
|
const { readdirSync: readdirSync6 } = await import("fs");
|
|
21703
21800
|
for (const f of readdirSync6(absDir).filter((f2) => f2.endsWith(".md"))) {
|
|
21704
|
-
const abs =
|
|
21801
|
+
const abs = join25(absDir, f);
|
|
21705
21802
|
mtimes.set(abs, st(abs).mtimeMs);
|
|
21706
21803
|
}
|
|
21707
21804
|
} else {
|
|
21708
21805
|
const abs = expandPath2(k.path);
|
|
21709
|
-
if (
|
|
21806
|
+
if (existsSync23(abs))
|
|
21710
21807
|
mtimes.set(abs, st(abs).mtimeMs);
|
|
21711
21808
|
}
|
|
21712
21809
|
}
|
|
@@ -21714,7 +21811,7 @@ program.command("watch").description("Watch known config files for changes and a
|
|
|
21714
21811
|
const tick = async () => {
|
|
21715
21812
|
let changed = 0;
|
|
21716
21813
|
for (const [abs, oldMtime] of mtimes) {
|
|
21717
|
-
if (!
|
|
21814
|
+
if (!existsSync23(abs))
|
|
21718
21815
|
continue;
|
|
21719
21816
|
const newMtime = st(abs).mtimeMs;
|
|
21720
21817
|
if (newMtime !== oldMtime) {
|
|
@@ -21726,10 +21823,10 @@ program.command("watch").description("Watch known config files for changes and a
|
|
|
21726
21823
|
for (const k of KNOWN_CONFIGS) {
|
|
21727
21824
|
if (k.rulesDir) {
|
|
21728
21825
|
const absDir = expandPath2(k.rulesDir);
|
|
21729
|
-
if (!
|
|
21826
|
+
if (!existsSync23(absDir))
|
|
21730
21827
|
continue;
|
|
21731
21828
|
for (const f of rd(absDir).filter((f2) => f2.endsWith(".md"))) {
|
|
21732
|
-
const abs =
|
|
21829
|
+
const abs = join25(absDir, f);
|
|
21733
21830
|
if (!mtimes.has(abs)) {
|
|
21734
21831
|
mtimes.set(abs, st(abs).mtimeMs);
|
|
21735
21832
|
changed++;
|
|
@@ -21737,7 +21834,7 @@ program.command("watch").description("Watch known config files for changes and a
|
|
|
21737
21834
|
}
|
|
21738
21835
|
} else {
|
|
21739
21836
|
const abs = expandPath2(k.path);
|
|
21740
|
-
if (
|
|
21837
|
+
if (existsSync23(abs) && !mtimes.has(abs)) {
|
|
21741
21838
|
mtimes.set(abs, st(abs).mtimeMs);
|
|
21742
21839
|
changed++;
|
|
21743
21840
|
}
|
|
@@ -21765,7 +21862,7 @@ program.command("report").description("Summary of stored configs, drift, and eco
|
|
|
21765
21862
|
if (!c.target_path)
|
|
21766
21863
|
continue;
|
|
21767
21864
|
const abs = expandPath(c.target_path);
|
|
21768
|
-
if (!
|
|
21865
|
+
if (!existsSync23(abs)) {
|
|
21769
21866
|
missing++;
|
|
21770
21867
|
continue;
|
|
21771
21868
|
}
|
|
@@ -21836,7 +21933,7 @@ program.command("clean").description("Remove configs from DB whose target files
|
|
|
21836
21933
|
if (!c.target_path)
|
|
21837
21934
|
continue;
|
|
21838
21935
|
const abs = expandPath(c.target_path);
|
|
21839
|
-
if (!
|
|
21936
|
+
if (!existsSync23(abs)) {
|
|
21840
21937
|
if (printed < maxPrinted) {
|
|
21841
21938
|
if (opts.dryRun) {
|
|
21842
21939
|
console.log(chalk.yellow(" would remove:") + ` ${c.slug} ${chalk.dim(`(${truncateMiddle(c.target_path, 88)})`)}`);
|
|
@@ -21982,7 +22079,7 @@ providerContextCmd.command("resolve").description("Resolve the endpoint to a pro
|
|
|
21982
22079
|
try {
|
|
21983
22080
|
const rawEndpoint = opts.endpoint ?? process.env["ANTHROPIC_BASE_URL"] ?? "";
|
|
21984
22081
|
const rawModel = opts.model ?? process.env["ANTHROPIC_MODEL"] ?? "";
|
|
21985
|
-
const homeDir4 = opts.home ??
|
|
22082
|
+
const homeDir4 = opts.home ?? homedir15();
|
|
21986
22083
|
const origin = normalizeEndpointOrigin(rawEndpoint);
|
|
21987
22084
|
const resolution = resolveAndRenderProviderContext({
|
|
21988
22085
|
origin,
|