@hasna/instructions 0.4.36 → 0.4.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -8
- package/assets/skills/inbox/SKILL.md +86 -0
- package/dashboard/README.md +34 -70
- package/dist/cli/index.js +1839 -721
- package/dist/cli/raw-store-root.test.d.ts +2 -0
- package/dist/cli/raw-store-root.test.d.ts.map +1 -0
- package/dist/data/config-store.d.ts +4 -4
- package/dist/data/config-store.d.ts.map +1 -1
- package/dist/db/configs.d.ts.map +1 -1
- package/dist/db/database.d.ts.map +1 -1
- package/dist/generated/storage-kit/backend.d.ts +20 -0
- package/dist/generated/storage-kit/backend.d.ts.map +1 -0
- package/dist/generated/storage-kit/index.d.ts +2 -2
- package/dist/generated/storage-kit/index.d.ts.map +1 -1
- package/dist/generated/storage-kit/migrations.d.ts.map +1 -1
- package/dist/generated/storage-kit/own.d.ts +11 -0
- package/dist/generated/storage-kit/own.d.ts.map +1 -0
- package/dist/generated/storage-kit/pool.d.ts +7 -6
- package/dist/generated/storage-kit/pool.d.ts.map +1 -1
- package/dist/generated/storage-kit/tls.d.ts +30 -3
- package/dist/generated/storage-kit/tls.d.ts.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1237 -704
- package/dist/lib/managed-skill-runtimes.d.ts +80 -0
- package/dist/lib/managed-skill-runtimes.d.ts.map +1 -0
- package/dist/lib/managed-skill-runtimes.test.d.ts +2 -0
- package/dist/lib/managed-skill-runtimes.test.d.ts.map +1 -0
- package/dist/lib/raw-store-root.d.ts +17 -0
- package/dist/lib/raw-store-root.d.ts.map +1 -0
- package/dist/lib/retired-storage-mode.d.ts +8 -0
- package/dist/lib/retired-storage-mode.d.ts.map +1 -0
- package/dist/lib/session-apply.d.ts.map +1 -1
- package/dist/lib/session-authority.d.ts +27 -0
- package/dist/lib/session-authority.d.ts.map +1 -0
- package/dist/lib/session-authority.test.d.ts +2 -0
- package/dist/lib/session-authority.test.d.ts.map +1 -0
- package/dist/lib/session-render.d.ts +5 -3
- package/dist/lib/session-render.d.ts.map +1 -1
- package/dist/mcp/index.js +303 -246
- package/dist/server/cloud.d.ts +2 -2
- package/dist/server/cloud.d.ts.map +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +875 -496
- package/dist/status.d.ts +11 -1
- package/dist/status.d.ts.map +1 -1
- package/dist/storage/cloud-store.d.ts.map +1 -1
- package/dist/storage/cloud-store.test.d.ts +2 -0
- package/dist/storage/cloud-store.test.d.ts.map +1 -0
- package/package.json +10 -7
- package/dist/generated/storage-kit/mode.d.ts +0 -48
- package/dist/generated/storage-kit/mode.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -104,16 +104,46 @@ import { randomUUID as randomUUID3 } from "crypto";
|
|
|
104
104
|
// src/db/database.ts
|
|
105
105
|
import { Database } from "bun:sqlite";
|
|
106
106
|
import { existsSync, mkdirSync, rmSync } from "fs";
|
|
107
|
-
import { join } from "path";
|
|
107
|
+
import { join as join2 } from "path";
|
|
108
108
|
import { randomUUID } from "crypto";
|
|
109
|
+
|
|
110
|
+
// src/lib/retired-storage-mode.ts
|
|
111
|
+
var LEGACY_STORAGE_MODE_KEYS = [
|
|
112
|
+
"HASNA_INSTRUCTIONS_STORAGE_MODE",
|
|
113
|
+
"HASNA_INSTRUCTIONS_MODE",
|
|
114
|
+
"INSTRUCTIONS_STORAGE_MODE",
|
|
115
|
+
"INSTRUCTIONS_MODE"
|
|
116
|
+
];
|
|
117
|
+
function firstDefinedEnvKey(env, keys) {
|
|
118
|
+
for (const key of keys) {
|
|
119
|
+
if (Object.hasOwn(env, key) && env[key] !== undefined)
|
|
120
|
+
return key;
|
|
121
|
+
}
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
function assertNoLegacyStorageMode(env = process.env) {
|
|
125
|
+
const legacyKey = firstDefinedEnvKey(env, LEGACY_STORAGE_MODE_KEYS);
|
|
126
|
+
if (!legacyKey)
|
|
127
|
+
return;
|
|
128
|
+
throw new Error(`${legacyKey} was removed. Deployment modes no longer exist: delete the storage-mode variable. ` + `The client uses the local SQLite store, or the HTTP API selected by ` + `HASNA_INSTRUCTIONS_API_URL + HASNA_INSTRUCTIONS_API_KEY. ` + `On the server, set HASNA_INSTRUCTIONS_DATABASE_URL to select the postgresql backend, ` + `or leave it unset for sqlite.`);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// src/lib/raw-store-root.ts
|
|
132
|
+
import { homedir } from "os";
|
|
133
|
+
import { join, resolve } from "path";
|
|
134
|
+
var RAW_STORE_ROOT_ENV = "HASNA_CONFIGS_HOME";
|
|
135
|
+
function getRawStoreRoot() {
|
|
136
|
+
return resolve(process.env[RAW_STORE_ROOT_ENV] || join(process.env["HOME"] || homedir(), ".hasna", "instructions"));
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// src/db/database.ts
|
|
109
140
|
function getDbPath() {
|
|
110
141
|
if (process.env["HASNA_INSTRUCTIONS_DB_PATH"]) {
|
|
111
142
|
return process.env["HASNA_INSTRUCTIONS_DB_PATH"];
|
|
112
143
|
}
|
|
113
|
-
const
|
|
114
|
-
const dir = join(home, ".hasna", "instructions");
|
|
144
|
+
const dir = getRawStoreRoot();
|
|
115
145
|
mkdirSync(dir, { recursive: true });
|
|
116
|
-
return
|
|
146
|
+
return join2(dir, "instructions.db");
|
|
117
147
|
}
|
|
118
148
|
function uuid() {
|
|
119
149
|
return randomUUID();
|
|
@@ -210,8 +240,9 @@ var _db = null;
|
|
|
210
240
|
function getDatabase(path) {
|
|
211
241
|
if (_db)
|
|
212
242
|
return _db;
|
|
243
|
+
assertNoLegacyStorageMode();
|
|
213
244
|
if (!path && process.env["HASNA_INSTRUCTIONS_API_URL"] && process.env["HASNA_INSTRUCTIONS_API_KEY"]) {
|
|
214
|
-
throw new Error("instructions is
|
|
245
|
+
throw new Error("instructions is using the HTTP API transport (HASNA_INSTRUCTIONS_API_URL set): this command is not wired to the API yet. " + "Unset HASNA_INSTRUCTIONS_API_URL / HASNA_INSTRUCTIONS_API_KEY to use it against the local store.");
|
|
215
246
|
}
|
|
216
247
|
const dbPath = path || getDbPath();
|
|
217
248
|
const db = new Database(dbPath);
|
|
@@ -291,6 +322,34 @@ function insertFeedback(input, db) {
|
|
|
291
322
|
d.run("INSERT INTO feedback (message, email, category, version) VALUES (?, ?, ?, ?)", [input.message, input.email ?? null, input.category ?? "general", input.version ?? null]);
|
|
292
323
|
}
|
|
293
324
|
|
|
325
|
+
// src/db/snapshots.ts
|
|
326
|
+
function createSnapshot(configId, content, version, db) {
|
|
327
|
+
const d = db || getDatabase();
|
|
328
|
+
const id = uuid();
|
|
329
|
+
const ts = now();
|
|
330
|
+
d.run("INSERT INTO config_snapshots (id, config_id, content, version, created_at) VALUES (?, ?, ?, ?, ?)", [id, configId, content, version, ts]);
|
|
331
|
+
return { id, config_id: configId, content, version, created_at: ts };
|
|
332
|
+
}
|
|
333
|
+
function listSnapshots(configId, db) {
|
|
334
|
+
const d = db || getDatabase();
|
|
335
|
+
return d.query("SELECT * FROM config_snapshots WHERE config_id = ? ORDER BY version DESC").all(configId);
|
|
336
|
+
}
|
|
337
|
+
function getSnapshot(id, db) {
|
|
338
|
+
const d = db || getDatabase();
|
|
339
|
+
return d.query("SELECT * FROM config_snapshots WHERE id = ?").get(id);
|
|
340
|
+
}
|
|
341
|
+
function getSnapshotByVersion(configId, version, db) {
|
|
342
|
+
const d = db || getDatabase();
|
|
343
|
+
return d.query("SELECT * FROM config_snapshots WHERE config_id = ? AND version = ?").get(configId, version);
|
|
344
|
+
}
|
|
345
|
+
function pruneSnapshots(configId, keep = 10, db) {
|
|
346
|
+
const d = db || getDatabase();
|
|
347
|
+
const result = d.run(`DELETE FROM config_snapshots WHERE config_id = ? AND id NOT IN (
|
|
348
|
+
SELECT id FROM config_snapshots WHERE config_id = ? ORDER BY version DESC LIMIT ?
|
|
349
|
+
)`, [configId, configId, keep]);
|
|
350
|
+
return result.changes;
|
|
351
|
+
}
|
|
352
|
+
|
|
294
353
|
// src/db/configs.ts
|
|
295
354
|
function rowToConfig(row) {
|
|
296
355
|
let outputs = [];
|
|
@@ -329,25 +388,28 @@ function createConfig(input, db) {
|
|
|
329
388
|
const slug = uniqueSlug(input.name, d);
|
|
330
389
|
const tags = JSON.stringify(input.tags || []);
|
|
331
390
|
const outputs = JSON.stringify(input.outputs || []);
|
|
332
|
-
d.
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
391
|
+
return d.transaction(() => {
|
|
392
|
+
d.run(`INSERT INTO configs (id, name, slug, kind, category, agent, target_path, outputs, format, content, description, tags, is_template, version, created_at, updated_at, synced_at)
|
|
393
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, NULL)`, [
|
|
394
|
+
id,
|
|
395
|
+
input.name,
|
|
396
|
+
slug,
|
|
397
|
+
input.kind ?? "file",
|
|
398
|
+
input.category,
|
|
399
|
+
input.agent ?? "global",
|
|
400
|
+
input.target_path ?? null,
|
|
401
|
+
outputs,
|
|
402
|
+
input.format ?? "text",
|
|
403
|
+
input.content,
|
|
404
|
+
input.description ?? null,
|
|
405
|
+
tags,
|
|
406
|
+
input.is_template ? 1 : 0,
|
|
407
|
+
ts,
|
|
408
|
+
ts
|
|
409
|
+
]);
|
|
410
|
+
createSnapshot(id, input.content, 1, d);
|
|
411
|
+
return getConfig(id, d);
|
|
412
|
+
})();
|
|
351
413
|
}
|
|
352
414
|
function getConfig(idOrSlug, db) {
|
|
353
415
|
const d = db || getDatabase();
|
|
@@ -452,9 +514,13 @@ function updateConfig(idOrSlug, input, db) {
|
|
|
452
514
|
updates.push("synced_at = ?");
|
|
453
515
|
params.push(input.synced_at);
|
|
454
516
|
}
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
517
|
+
return d.transaction(() => {
|
|
518
|
+
params.push(existing.id);
|
|
519
|
+
d.run(`UPDATE configs SET ${updates.join(", ")} WHERE id = ?`, params);
|
|
520
|
+
const updated = getConfigById(existing.id, d);
|
|
521
|
+
createSnapshot(updated.id, updated.content, updated.version, d);
|
|
522
|
+
return updated;
|
|
523
|
+
})();
|
|
458
524
|
}
|
|
459
525
|
function deleteConfig(idOrSlug, db) {
|
|
460
526
|
const d = db || getDatabase();
|
|
@@ -473,9 +539,9 @@ function getConfigStats(db) {
|
|
|
473
539
|
}
|
|
474
540
|
|
|
475
541
|
// src/lib/machine.ts
|
|
476
|
-
import { arch as currentArch, homedir, hostname as currentHostname, type as currentOsType } from "os";
|
|
542
|
+
import { arch as currentArch, homedir as homedir2, hostname as currentHostname, type as currentOsType } from "os";
|
|
477
543
|
import { existsSync as existsSync2 } from "fs";
|
|
478
|
-
import { join as
|
|
544
|
+
import { join as join3 } from "path";
|
|
479
545
|
|
|
480
546
|
// src/lib/template.ts
|
|
481
547
|
var VAR_PATTERN = /\{\{([A-Z0-9_]+)(?::([^}]*))?\}\}/g;
|
|
@@ -548,11 +614,11 @@ function normalizeOsFamily(os) {
|
|
|
548
614
|
return value || "unknown";
|
|
549
615
|
}
|
|
550
616
|
function detectMachineContext(overrides = {}) {
|
|
551
|
-
const homeDir = overrides.home_dir ?? process.env["CONFIGS_HOME"] ?? process.env["HOME"] ??
|
|
617
|
+
const homeDir = overrides.home_dir ?? process.env["CONFIGS_HOME"] ?? process.env["HOME"] ?? homedir2();
|
|
552
618
|
const os = overrides.os ?? currentOsType();
|
|
553
619
|
const osFamily = normalizeOsFamily(os);
|
|
554
|
-
const bunBinDir = overrides.bun_bin_dir ??
|
|
555
|
-
const defaultBunPath = osFamily === "macos" && existsSync2(BREW_BUN_PATH) ? BREW_BUN_PATH :
|
|
620
|
+
const bunBinDir = overrides.bun_bin_dir ?? join3(homeDir, ".bun", "bin");
|
|
621
|
+
const defaultBunPath = osFamily === "macos" && existsSync2(BREW_BUN_PATH) ? BREW_BUN_PATH : join3(bunBinDir, "bun");
|
|
556
622
|
return {
|
|
557
623
|
id: "current-machine",
|
|
558
624
|
hostname: overrides.hostname ?? currentHostname(),
|
|
@@ -562,10 +628,10 @@ function detectMachineContext(overrides = {}) {
|
|
|
562
628
|
created_at: "",
|
|
563
629
|
os_family: osFamily,
|
|
564
630
|
home_dir: homeDir,
|
|
565
|
-
workspace_root: overrides.workspace_root ??
|
|
631
|
+
workspace_root: overrides.workspace_root ?? join3(homeDir, osFamily === "macos" ? "Workspace" : "workspace"),
|
|
566
632
|
bun_bin_dir: bunBinDir,
|
|
567
633
|
bun_path: overrides.bun_path ?? defaultBunPath,
|
|
568
|
-
path_prefix: overrides.path_prefix ?? (osFamily === "macos" ? `${
|
|
634
|
+
path_prefix: overrides.path_prefix ?? (osFamily === "macos" ? `${join3("/opt", "homebrew", "bin")}:${bunBinDir}` : bunBinDir)
|
|
569
635
|
};
|
|
570
636
|
}
|
|
571
637
|
function machineContextToVariables(machine) {
|
|
@@ -679,13 +745,13 @@ function boundedReadPage(items, total, options = {}) {
|
|
|
679
745
|
}
|
|
680
746
|
|
|
681
747
|
// src/lib/instruction-graph.ts
|
|
682
|
-
import { createHash as
|
|
748
|
+
import { createHash as createHash7 } from "crypto";
|
|
683
749
|
|
|
684
750
|
// src/lib/session-render.ts
|
|
685
|
-
import { createHash as
|
|
686
|
-
import { existsSync as existsSync4, readFileSync as
|
|
687
|
-
import { homedir as
|
|
688
|
-
import { basename as basename3, dirname as dirname2, extname as extname2, isAbsolute as isAbsolute3, join as
|
|
751
|
+
import { createHash as createHash6 } from "crypto";
|
|
752
|
+
import { existsSync as existsSync4, readFileSync as readFileSync4, realpathSync, statSync as statSync3 } from "fs";
|
|
753
|
+
import { homedir as homedir4 } from "os";
|
|
754
|
+
import { basename as basename3, dirname as dirname2, extname as extname2, isAbsolute as isAbsolute3, join as join7, parse as parse2, posix as posix2, relative as relative2, resolve as resolve6 } from "path";
|
|
689
755
|
|
|
690
756
|
// src/lib/global-agent-rules-standard.ts
|
|
691
757
|
import { createHash } from "crypto";
|
|
@@ -989,213 +1055,213 @@ import {
|
|
|
989
1055
|
statSync,
|
|
990
1056
|
writeFileSync
|
|
991
1057
|
} from "fs";
|
|
992
|
-
import { basename, dirname, isAbsolute, join as
|
|
1058
|
+
import { basename, dirname, isAbsolute, join as join4, parse, relative, resolve as resolve2 } from "path";
|
|
993
1059
|
|
|
994
|
-
// node_modules/zod/v3/external.js
|
|
1060
|
+
// ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/external.js
|
|
995
1061
|
var exports_external = {};
|
|
996
1062
|
__export(exports_external, {
|
|
997
|
-
|
|
998
|
-
util: () => util,
|
|
999
|
-
unknown: () => unknownType,
|
|
1000
|
-
union: () => unionType,
|
|
1001
|
-
undefined: () => undefinedType,
|
|
1002
|
-
tuple: () => tupleType,
|
|
1003
|
-
transformer: () => effectsType,
|
|
1004
|
-
symbol: () => symbolType,
|
|
1005
|
-
string: () => stringType,
|
|
1006
|
-
strictObject: () => strictObjectType,
|
|
1007
|
-
setErrorMap: () => setErrorMap,
|
|
1008
|
-
set: () => setType,
|
|
1009
|
-
record: () => recordType,
|
|
1010
|
-
quotelessJson: () => quotelessJson,
|
|
1011
|
-
promise: () => promiseType,
|
|
1012
|
-
preprocess: () => preprocessType,
|
|
1013
|
-
pipeline: () => pipelineType,
|
|
1014
|
-
ostring: () => ostring,
|
|
1015
|
-
optional: () => optionalType,
|
|
1016
|
-
onumber: () => onumber,
|
|
1017
|
-
oboolean: () => oboolean,
|
|
1018
|
-
objectUtil: () => objectUtil,
|
|
1019
|
-
object: () => objectType,
|
|
1020
|
-
number: () => numberType,
|
|
1021
|
-
nullable: () => nullableType,
|
|
1022
|
-
null: () => nullType,
|
|
1023
|
-
never: () => neverType,
|
|
1024
|
-
nativeEnum: () => nativeEnumType,
|
|
1025
|
-
nan: () => nanType,
|
|
1026
|
-
map: () => mapType,
|
|
1027
|
-
makeIssue: () => makeIssue,
|
|
1028
|
-
literal: () => literalType,
|
|
1029
|
-
lazy: () => lazyType,
|
|
1030
|
-
late: () => late,
|
|
1031
|
-
isValid: () => isValid,
|
|
1032
|
-
isDirty: () => isDirty,
|
|
1033
|
-
isAsync: () => isAsync,
|
|
1034
|
-
isAborted: () => isAborted,
|
|
1035
|
-
intersection: () => intersectionType,
|
|
1036
|
-
instanceof: () => instanceOfType,
|
|
1037
|
-
getParsedType: () => getParsedType,
|
|
1038
|
-
getErrorMap: () => getErrorMap,
|
|
1039
|
-
function: () => functionType,
|
|
1040
|
-
enum: () => enumType,
|
|
1041
|
-
effect: () => effectsType,
|
|
1042
|
-
discriminatedUnion: () => discriminatedUnionType,
|
|
1043
|
-
defaultErrorMap: () => en_default,
|
|
1044
|
-
datetimeRegex: () => datetimeRegex,
|
|
1045
|
-
date: () => dateType,
|
|
1046
|
-
custom: () => custom,
|
|
1047
|
-
coerce: () => coerce,
|
|
1048
|
-
boolean: () => booleanType,
|
|
1049
|
-
bigint: () => bigIntType,
|
|
1050
|
-
array: () => arrayType,
|
|
1051
|
-
any: () => anyType,
|
|
1052
|
-
addIssueToContext: () => addIssueToContext,
|
|
1053
|
-
ZodVoid: () => ZodVoid,
|
|
1054
|
-
ZodUnknown: () => ZodUnknown,
|
|
1055
|
-
ZodUnion: () => ZodUnion,
|
|
1056
|
-
ZodUndefined: () => ZodUndefined,
|
|
1057
|
-
ZodType: () => ZodType,
|
|
1058
|
-
ZodTuple: () => ZodTuple,
|
|
1059
|
-
ZodTransformer: () => ZodEffects,
|
|
1060
|
-
ZodSymbol: () => ZodSymbol,
|
|
1061
|
-
ZodString: () => ZodString,
|
|
1062
|
-
ZodSet: () => ZodSet,
|
|
1063
|
-
ZodSchema: () => ZodType,
|
|
1064
|
-
ZodRecord: () => ZodRecord,
|
|
1065
|
-
ZodReadonly: () => ZodReadonly,
|
|
1066
|
-
ZodPromise: () => ZodPromise,
|
|
1067
|
-
ZodPipeline: () => ZodPipeline,
|
|
1068
|
-
ZodParsedType: () => ZodParsedType,
|
|
1069
|
-
ZodOptional: () => ZodOptional,
|
|
1070
|
-
ZodObject: () => ZodObject,
|
|
1071
|
-
ZodNumber: () => ZodNumber,
|
|
1072
|
-
ZodNullable: () => ZodNullable,
|
|
1073
|
-
ZodNull: () => ZodNull,
|
|
1074
|
-
ZodNever: () => ZodNever,
|
|
1075
|
-
ZodNativeEnum: () => ZodNativeEnum,
|
|
1076
|
-
ZodNaN: () => ZodNaN,
|
|
1077
|
-
ZodMap: () => ZodMap,
|
|
1078
|
-
ZodLiteral: () => ZodLiteral,
|
|
1079
|
-
ZodLazy: () => ZodLazy,
|
|
1080
|
-
ZodIssueCode: () => ZodIssueCode,
|
|
1081
|
-
ZodIntersection: () => ZodIntersection,
|
|
1082
|
-
ZodFunction: () => ZodFunction,
|
|
1083
|
-
ZodFirstPartyTypeKind: () => ZodFirstPartyTypeKind,
|
|
1084
|
-
ZodError: () => ZodError,
|
|
1085
|
-
ZodEnum: () => ZodEnum,
|
|
1086
|
-
ZodEffects: () => ZodEffects,
|
|
1087
|
-
ZodDiscriminatedUnion: () => ZodDiscriminatedUnion,
|
|
1088
|
-
ZodDefault: () => ZodDefault,
|
|
1089
|
-
ZodDate: () => ZodDate,
|
|
1090
|
-
ZodCatch: () => ZodCatch,
|
|
1091
|
-
ZodBranded: () => ZodBranded,
|
|
1092
|
-
ZodBoolean: () => ZodBoolean,
|
|
1093
|
-
ZodBigInt: () => ZodBigInt,
|
|
1094
|
-
ZodArray: () => ZodArray,
|
|
1095
|
-
ZodAny: () => ZodAny,
|
|
1096
|
-
Schema: () => ZodType,
|
|
1097
|
-
ParseStatus: () => ParseStatus,
|
|
1098
|
-
OK: () => OK,
|
|
1099
|
-
NEVER: () => NEVER,
|
|
1100
|
-
INVALID: () => INVALID,
|
|
1101
|
-
EMPTY_PATH: () => EMPTY_PATH,
|
|
1063
|
+
BRAND: () => BRAND,
|
|
1102
1064
|
DIRTY: () => DIRTY,
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
(
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1065
|
+
EMPTY_PATH: () => EMPTY_PATH,
|
|
1066
|
+
INVALID: () => INVALID,
|
|
1067
|
+
NEVER: () => NEVER,
|
|
1068
|
+
OK: () => OK,
|
|
1069
|
+
ParseStatus: () => ParseStatus,
|
|
1070
|
+
Schema: () => ZodType,
|
|
1071
|
+
ZodAny: () => ZodAny,
|
|
1072
|
+
ZodArray: () => ZodArray,
|
|
1073
|
+
ZodBigInt: () => ZodBigInt,
|
|
1074
|
+
ZodBoolean: () => ZodBoolean,
|
|
1075
|
+
ZodBranded: () => ZodBranded,
|
|
1076
|
+
ZodCatch: () => ZodCatch,
|
|
1077
|
+
ZodDate: () => ZodDate,
|
|
1078
|
+
ZodDefault: () => ZodDefault,
|
|
1079
|
+
ZodDiscriminatedUnion: () => ZodDiscriminatedUnion,
|
|
1080
|
+
ZodEffects: () => ZodEffects,
|
|
1081
|
+
ZodEnum: () => ZodEnum,
|
|
1082
|
+
ZodError: () => ZodError,
|
|
1083
|
+
ZodFirstPartyTypeKind: () => ZodFirstPartyTypeKind,
|
|
1084
|
+
ZodFunction: () => ZodFunction,
|
|
1085
|
+
ZodIntersection: () => ZodIntersection,
|
|
1086
|
+
ZodIssueCode: () => ZodIssueCode,
|
|
1087
|
+
ZodLazy: () => ZodLazy,
|
|
1088
|
+
ZodLiteral: () => ZodLiteral,
|
|
1089
|
+
ZodMap: () => ZodMap,
|
|
1090
|
+
ZodNaN: () => ZodNaN,
|
|
1091
|
+
ZodNativeEnum: () => ZodNativeEnum,
|
|
1092
|
+
ZodNever: () => ZodNever,
|
|
1093
|
+
ZodNull: () => ZodNull,
|
|
1094
|
+
ZodNullable: () => ZodNullable,
|
|
1095
|
+
ZodNumber: () => ZodNumber,
|
|
1096
|
+
ZodObject: () => ZodObject,
|
|
1097
|
+
ZodOptional: () => ZodOptional,
|
|
1098
|
+
ZodParsedType: () => ZodParsedType,
|
|
1099
|
+
ZodPipeline: () => ZodPipeline,
|
|
1100
|
+
ZodPromise: () => ZodPromise,
|
|
1101
|
+
ZodReadonly: () => ZodReadonly,
|
|
1102
|
+
ZodRecord: () => ZodRecord,
|
|
1103
|
+
ZodSchema: () => ZodType,
|
|
1104
|
+
ZodSet: () => ZodSet,
|
|
1105
|
+
ZodString: () => ZodString,
|
|
1106
|
+
ZodSymbol: () => ZodSymbol,
|
|
1107
|
+
ZodTransformer: () => ZodEffects,
|
|
1108
|
+
ZodTuple: () => ZodTuple,
|
|
1109
|
+
ZodType: () => ZodType,
|
|
1110
|
+
ZodUndefined: () => ZodUndefined,
|
|
1111
|
+
ZodUnion: () => ZodUnion,
|
|
1112
|
+
ZodUnknown: () => ZodUnknown,
|
|
1113
|
+
ZodVoid: () => ZodVoid,
|
|
1114
|
+
addIssueToContext: () => addIssueToContext,
|
|
1115
|
+
any: () => anyType,
|
|
1116
|
+
array: () => arrayType,
|
|
1117
|
+
bigint: () => bigIntType,
|
|
1118
|
+
boolean: () => booleanType,
|
|
1119
|
+
coerce: () => coerce,
|
|
1120
|
+
custom: () => custom,
|
|
1121
|
+
date: () => dateType,
|
|
1122
|
+
datetimeRegex: () => datetimeRegex,
|
|
1123
|
+
defaultErrorMap: () => en_default,
|
|
1124
|
+
discriminatedUnion: () => discriminatedUnionType,
|
|
1125
|
+
effect: () => effectsType,
|
|
1126
|
+
enum: () => enumType,
|
|
1127
|
+
function: () => functionType,
|
|
1128
|
+
getErrorMap: () => getErrorMap,
|
|
1129
|
+
getParsedType: () => getParsedType,
|
|
1130
|
+
instanceof: () => instanceOfType,
|
|
1131
|
+
intersection: () => intersectionType,
|
|
1132
|
+
isAborted: () => isAborted,
|
|
1133
|
+
isAsync: () => isAsync,
|
|
1134
|
+
isDirty: () => isDirty,
|
|
1135
|
+
isValid: () => isValid,
|
|
1136
|
+
late: () => late,
|
|
1137
|
+
lazy: () => lazyType,
|
|
1138
|
+
literal: () => literalType,
|
|
1139
|
+
makeIssue: () => makeIssue,
|
|
1140
|
+
map: () => mapType,
|
|
1141
|
+
nan: () => nanType,
|
|
1142
|
+
nativeEnum: () => nativeEnumType,
|
|
1143
|
+
never: () => neverType,
|
|
1144
|
+
null: () => nullType,
|
|
1145
|
+
nullable: () => nullableType,
|
|
1146
|
+
number: () => numberType,
|
|
1147
|
+
object: () => objectType,
|
|
1148
|
+
objectUtil: () => objectUtil,
|
|
1149
|
+
oboolean: () => oboolean,
|
|
1150
|
+
onumber: () => onumber,
|
|
1151
|
+
optional: () => optionalType,
|
|
1152
|
+
ostring: () => ostring,
|
|
1153
|
+
pipeline: () => pipelineType,
|
|
1154
|
+
preprocess: () => preprocessType,
|
|
1155
|
+
promise: () => promiseType,
|
|
1156
|
+
quotelessJson: () => quotelessJson,
|
|
1157
|
+
record: () => recordType,
|
|
1158
|
+
set: () => setType,
|
|
1159
|
+
setErrorMap: () => setErrorMap,
|
|
1160
|
+
strictObject: () => strictObjectType,
|
|
1161
|
+
string: () => stringType,
|
|
1162
|
+
symbol: () => symbolType,
|
|
1163
|
+
transformer: () => effectsType,
|
|
1164
|
+
tuple: () => tupleType,
|
|
1165
|
+
undefined: () => undefinedType,
|
|
1166
|
+
union: () => unionType,
|
|
1167
|
+
unknown: () => unknownType,
|
|
1168
|
+
util: () => util,
|
|
1169
|
+
void: () => voidType
|
|
1170
|
+
});
|
|
1171
|
+
|
|
1172
|
+
// ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/helpers/util.js
|
|
1173
|
+
var util;
|
|
1174
|
+
(function(util2) {
|
|
1175
|
+
util2.assertEqual = (_) => {};
|
|
1176
|
+
function assertIs(_arg) {}
|
|
1177
|
+
util2.assertIs = assertIs;
|
|
1178
|
+
function assertNever(_x) {
|
|
1179
|
+
throw new Error;
|
|
1180
|
+
}
|
|
1181
|
+
util2.assertNever = assertNever;
|
|
1182
|
+
util2.arrayToEnum = (items) => {
|
|
1183
|
+
const obj = {};
|
|
1184
|
+
for (const item of items) {
|
|
1185
|
+
obj[item] = item;
|
|
1186
|
+
}
|
|
1187
|
+
return obj;
|
|
1188
|
+
};
|
|
1189
|
+
util2.getValidEnumValues = (obj) => {
|
|
1190
|
+
const validKeys = util2.objectKeys(obj).filter((k) => typeof obj[obj[k]] !== "number");
|
|
1191
|
+
const filtered = {};
|
|
1192
|
+
for (const k of validKeys) {
|
|
1193
|
+
filtered[k] = obj[k];
|
|
1194
|
+
}
|
|
1195
|
+
return util2.objectValues(filtered);
|
|
1196
|
+
};
|
|
1197
|
+
util2.objectValues = (obj) => {
|
|
1198
|
+
return util2.objectKeys(obj).map(function(e) {
|
|
1199
|
+
return obj[e];
|
|
1200
|
+
});
|
|
1201
|
+
};
|
|
1202
|
+
util2.objectKeys = typeof Object.keys === "function" ? (obj) => Object.keys(obj) : (object) => {
|
|
1203
|
+
const keys = [];
|
|
1204
|
+
for (const key in object) {
|
|
1205
|
+
if (Object.prototype.hasOwnProperty.call(object, key)) {
|
|
1206
|
+
keys.push(key);
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
return keys;
|
|
1210
|
+
};
|
|
1211
|
+
util2.find = (arr, checker) => {
|
|
1212
|
+
for (const item of arr) {
|
|
1213
|
+
if (checker(item))
|
|
1214
|
+
return item;
|
|
1215
|
+
}
|
|
1216
|
+
return;
|
|
1217
|
+
};
|
|
1218
|
+
util2.isInteger = typeof Number.isInteger === "function" ? (val) => Number.isInteger(val) : (val) => typeof val === "number" && Number.isFinite(val) && Math.floor(val) === val;
|
|
1219
|
+
function joinValues(array, separator = " | ") {
|
|
1220
|
+
return array.map((val) => typeof val === "string" ? `'${val}'` : val).join(separator);
|
|
1221
|
+
}
|
|
1222
|
+
util2.joinValues = joinValues;
|
|
1223
|
+
util2.jsonStringifyReplacer = (_, value) => {
|
|
1224
|
+
if (typeof value === "bigint") {
|
|
1225
|
+
return value.toString();
|
|
1226
|
+
}
|
|
1227
|
+
return value;
|
|
1228
|
+
};
|
|
1229
|
+
})(util || (util = {}));
|
|
1230
|
+
var objectUtil;
|
|
1231
|
+
(function(objectUtil2) {
|
|
1232
|
+
objectUtil2.mergeShapes = (first, second) => {
|
|
1233
|
+
return {
|
|
1234
|
+
...first,
|
|
1235
|
+
...second
|
|
1236
|
+
};
|
|
1237
|
+
};
|
|
1238
|
+
})(objectUtil || (objectUtil = {}));
|
|
1239
|
+
var ZodParsedType = util.arrayToEnum([
|
|
1240
|
+
"string",
|
|
1241
|
+
"nan",
|
|
1242
|
+
"number",
|
|
1243
|
+
"integer",
|
|
1244
|
+
"float",
|
|
1245
|
+
"boolean",
|
|
1246
|
+
"date",
|
|
1247
|
+
"bigint",
|
|
1248
|
+
"symbol",
|
|
1249
|
+
"function",
|
|
1250
|
+
"undefined",
|
|
1251
|
+
"null",
|
|
1252
|
+
"array",
|
|
1253
|
+
"object",
|
|
1254
|
+
"unknown",
|
|
1255
|
+
"promise",
|
|
1256
|
+
"void",
|
|
1257
|
+
"never",
|
|
1258
|
+
"map",
|
|
1259
|
+
"set"
|
|
1260
|
+
]);
|
|
1261
|
+
var getParsedType = (data) => {
|
|
1262
|
+
const t = typeof data;
|
|
1263
|
+
switch (t) {
|
|
1264
|
+
case "undefined":
|
|
1199
1265
|
return ZodParsedType.undefined;
|
|
1200
1266
|
case "string":
|
|
1201
1267
|
return ZodParsedType.string;
|
|
@@ -1234,7 +1300,7 @@ var getParsedType = (data) => {
|
|
|
1234
1300
|
}
|
|
1235
1301
|
};
|
|
1236
1302
|
|
|
1237
|
-
// node_modules/zod/v3/ZodError.js
|
|
1303
|
+
// ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/ZodError.js
|
|
1238
1304
|
var ZodIssueCode = util.arrayToEnum([
|
|
1239
1305
|
"invalid_type",
|
|
1240
1306
|
"invalid_literal",
|
|
@@ -1353,7 +1419,7 @@ ZodError.create = (issues) => {
|
|
|
1353
1419
|
return error;
|
|
1354
1420
|
};
|
|
1355
1421
|
|
|
1356
|
-
// node_modules/zod/v3/locales/en.js
|
|
1422
|
+
// ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/locales/en.js
|
|
1357
1423
|
var errorMap = (issue, _ctx) => {
|
|
1358
1424
|
let message;
|
|
1359
1425
|
switch (issue.code) {
|
|
@@ -1456,7 +1522,7 @@ var errorMap = (issue, _ctx) => {
|
|
|
1456
1522
|
};
|
|
1457
1523
|
var en_default = errorMap;
|
|
1458
1524
|
|
|
1459
|
-
// node_modules/zod/v3/errors.js
|
|
1525
|
+
// ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/errors.js
|
|
1460
1526
|
var overrideErrorMap = en_default;
|
|
1461
1527
|
function setErrorMap(map) {
|
|
1462
1528
|
overrideErrorMap = map;
|
|
@@ -1464,7 +1530,7 @@ function setErrorMap(map) {
|
|
|
1464
1530
|
function getErrorMap() {
|
|
1465
1531
|
return overrideErrorMap;
|
|
1466
1532
|
}
|
|
1467
|
-
// node_modules/zod/v3/helpers/parseUtil.js
|
|
1533
|
+
// ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
|
|
1468
1534
|
var makeIssue = (params) => {
|
|
1469
1535
|
const { data, path, errorMaps, issueData } = params;
|
|
1470
1536
|
const fullPath = [...path, ...issueData.path || []];
|
|
@@ -1570,14 +1636,14 @@ var isAborted = (x) => x.status === "aborted";
|
|
|
1570
1636
|
var isDirty = (x) => x.status === "dirty";
|
|
1571
1637
|
var isValid = (x) => x.status === "valid";
|
|
1572
1638
|
var isAsync = (x) => typeof Promise !== "undefined" && x instanceof Promise;
|
|
1573
|
-
// node_modules/zod/v3/helpers/errorUtil.js
|
|
1639
|
+
// ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/helpers/errorUtil.js
|
|
1574
1640
|
var errorUtil;
|
|
1575
1641
|
(function(errorUtil2) {
|
|
1576
1642
|
errorUtil2.errToObj = (message) => typeof message === "string" ? { message } : message || {};
|
|
1577
1643
|
errorUtil2.toString = (message) => typeof message === "string" ? message : message?.message;
|
|
1578
1644
|
})(errorUtil || (errorUtil = {}));
|
|
1579
1645
|
|
|
1580
|
-
// node_modules/zod/v3/types.js
|
|
1646
|
+
// ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/types.js
|
|
1581
1647
|
class ParseInputLazyPath {
|
|
1582
1648
|
constructor(parent, value, path, key) {
|
|
1583
1649
|
this._cachedPath = [];
|
|
@@ -4969,7 +5035,7 @@ var SECRET_KEY_PATTERN = /^(.*_?API_?KEY|.*_?TOKEN|.*_?SECRET|.*_?PASSWORD|.*_?P
|
|
|
4969
5035
|
var VALUE_PATTERNS = [
|
|
4970
5036
|
{ re: /npm_[A-Za-z0-9]{36,}/, reason: "npm token" },
|
|
4971
5037
|
{ re: /gh[pousr]_[A-Za-z0-9_]{36,}/, reason: "GitHub token" },
|
|
4972
|
-
{ re: /sk-ant-[A-Za-z0-9\-_]{40,}/, reason: "Anthropic API key" },
|
|
5038
|
+
{ re: /sk[-]ant-[A-Za-z0-9\-_]{40,}/, reason: "Anthropic API key" },
|
|
4973
5039
|
{ re: /sk-[A-Za-z0-9]{48,}/, reason: "OpenAI API key" },
|
|
4974
5040
|
{ re: /xoxb-[0-9]+-[A-Za-z0-9\-]+/, reason: "Slack bot token" },
|
|
4975
5041
|
{ re: /AIza[0-9A-Za-z\-_]{35}/, reason: "Google API key" },
|
|
@@ -5576,7 +5642,7 @@ function composeProjectContextSessionRender(input) {
|
|
|
5576
5642
|
if (currentMarkers.block.id !== cache.project_id || currentMarkers.block.revision !== cache.revision || currentMarkers.block.hash !== cache.hash) {
|
|
5577
5643
|
throw new ProjectContextError("MANAGED_BLOCK_CONFLICT", "project-context provider markers differ from the durable cache");
|
|
5578
5644
|
}
|
|
5579
|
-
const plannedIndexes = input.files.filter((file) => file.role === "index" &&
|
|
5645
|
+
const plannedIndexes = input.files.filter((file) => file.role === "index" && resolve2(file.path) === paths.target);
|
|
5580
5646
|
if (plannedIndexes.length !== 1) {
|
|
5581
5647
|
throw new ProjectContextError("PROJECT_CONTEXT_MANIFEST_INVALID", "session renderer does not own the selected project-context provider target");
|
|
5582
5648
|
}
|
|
@@ -5634,7 +5700,7 @@ function withProjectContextSessionGuard(guard, action, options = {}) {
|
|
|
5634
5700
|
verify();
|
|
5635
5701
|
return action(null);
|
|
5636
5702
|
}
|
|
5637
|
-
const lockPath =
|
|
5703
|
+
const lockPath = resolve2(validated.workspace_root, ...PROJECT_CONTEXT_LOCK_PATH.split("/"));
|
|
5638
5704
|
const lock = acquireWorkspaceLock(validated.workspace_root, lockPath);
|
|
5639
5705
|
try {
|
|
5640
5706
|
verify();
|
|
@@ -5660,7 +5726,7 @@ function validateProjectContextSessionGuard(guard) {
|
|
|
5660
5726
|
if (!isRecord(observed) || typeof observed.path !== "string") {
|
|
5661
5727
|
throw new ProjectContextError("PROJECT_CONTEXT_SESSION_STALE", "session project-context guard contains malformed hash metadata");
|
|
5662
5728
|
}
|
|
5663
|
-
const path =
|
|
5729
|
+
const path = resolve2(observed.path);
|
|
5664
5730
|
if (!allowedPaths.has(path) || observedPaths.has(path)) {
|
|
5665
5731
|
throw new ProjectContextError("PROJECT_CONTEXT_SESSION_STALE", "session project-context guard contains an unexpected or duplicate path");
|
|
5666
5732
|
}
|
|
@@ -5682,7 +5748,7 @@ function validateProjectContextSessionGuard(guard) {
|
|
|
5682
5748
|
function applyProjectContext(options) {
|
|
5683
5749
|
const workspaceRoot = assertSafeWorkspaceRoot(options.workspace_root);
|
|
5684
5750
|
const now2 = options.now ?? new Date;
|
|
5685
|
-
const lockPath =
|
|
5751
|
+
const lockPath = resolve2(workspaceRoot, ...PROJECT_CONTEXT_LOCK_PATH.split("/"));
|
|
5686
5752
|
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);
|
|
5687
5753
|
try {
|
|
5688
5754
|
const resolved = resolveBundleForApply(options, workspaceRoot, now2);
|
|
@@ -5829,7 +5895,7 @@ function resolveBundleForApply(options, workspaceRoot, now2) {
|
|
|
5829
5895
|
if (!options.expected_project_id) {
|
|
5830
5896
|
throw new ProjectContextError("PROJECT_CONTEXT_CACHE_ID_REQUIRED", "expected_project_id is required for stale-cache fallback");
|
|
5831
5897
|
}
|
|
5832
|
-
const cachePath =
|
|
5898
|
+
const cachePath = resolve2(workspaceRoot, ...PROJECT_CONTEXT_CACHE_PATH.split("/"));
|
|
5833
5899
|
const cache = readProjectContextCache(cachePath, workspaceRoot);
|
|
5834
5900
|
if (!cache)
|
|
5835
5901
|
throw new ProjectContextError("PROJECT_CONTEXT_CACHE_MISSING", "no last-known-good project context cache exists");
|
|
@@ -6185,7 +6251,7 @@ function buildManifest(plan, now2) {
|
|
|
6185
6251
|
function buildSessionCompatibilityManifest(plan, now2) {
|
|
6186
6252
|
const paths = runtimePaths(plan.workspace_root, plan.runtime);
|
|
6187
6253
|
const tool = manifestTool(plan.runtime);
|
|
6188
|
-
const targetHome = plan.runtime === "codewith" ?
|
|
6254
|
+
const targetHome = plan.runtime === "codewith" ? resolve2(plan.workspace_root, ".codewith") : plan.workspace_root;
|
|
6189
6255
|
const targetRelativePath = sessionTargetRelativePath(plan.runtime);
|
|
6190
6256
|
const existing = existsSync3(paths.sessionManifest) ? readSessionManifestRecord(paths.sessionManifest, plan.workspace_root) : {
|
|
6191
6257
|
schema: SESSION_RENDER_SCHEMA,
|
|
@@ -6207,7 +6273,7 @@ function buildSessionCompatibilityManifest(plan, now2) {
|
|
|
6207
6273
|
throw new ProjectContextError("PROJECT_CONTEXT_MANIFEST_INVALID", "provider session manifest is malformed or incompatible");
|
|
6208
6274
|
}
|
|
6209
6275
|
const existingTargetHome = safeLegacyMetadataString(existing["targetHome"], null);
|
|
6210
|
-
if (existingTargetHome !== null &&
|
|
6276
|
+
if (existingTargetHome !== null && resolve2(existingTargetHome) !== targetHome) {
|
|
6211
6277
|
throw new ProjectContextError("PROJECT_CONTEXT_MANIFEST_INVALID", "provider session manifest targets a different workspace");
|
|
6212
6278
|
}
|
|
6213
6279
|
const sources = sanitizeLegacySources(existing["sources"]).filter((source) => source["id"] !== "project-context-bundle");
|
|
@@ -6493,9 +6559,9 @@ function writeMetadataSnapshot(plan, now2) {
|
|
|
6493
6559
|
const previous = readProjectContextManifest(plan.manifest_path, plan.workspace_root);
|
|
6494
6560
|
if (!previous || previous.projectContext.revision === plan.bundle.revision && previous.projectContext.hash === plan.bundle.hash)
|
|
6495
6561
|
return null;
|
|
6496
|
-
const snapshotDir =
|
|
6562
|
+
const snapshotDir = resolve2(plan.workspace_root, ...PROJECT_CONTEXT_SNAPSHOT_DIR.split("/"));
|
|
6497
6563
|
ensureSafeDirectory(snapshotDir, plan.workspace_root, 448);
|
|
6498
|
-
const snapshotPath =
|
|
6564
|
+
const snapshotPath = resolve2(snapshotDir, `${safeFilename(previous.projectContext.revision)}-${previous.projectContext.hash.slice(-12)}.json`);
|
|
6499
6565
|
const snapshot = {
|
|
6500
6566
|
schema: "hasna.configs.session-render-snapshot/v1",
|
|
6501
6567
|
kind: "project-context-metadata",
|
|
@@ -6511,8 +6577,8 @@ function writeMetadataSnapshot(plan, now2) {
|
|
|
6511
6577
|
return snapshotPath;
|
|
6512
6578
|
}
|
|
6513
6579
|
function metadataSnapshotMatchesManifest(plan, manifest) {
|
|
6514
|
-
const snapshotDir =
|
|
6515
|
-
const snapshotPath =
|
|
6580
|
+
const snapshotDir = resolve2(plan.workspace_root, ...PROJECT_CONTEXT_SNAPSHOT_DIR.split("/"));
|
|
6581
|
+
const snapshotPath = resolve2(snapshotDir, `${safeFilename(manifest.projectContext.revision)}-${manifest.projectContext.hash.slice(-12)}.json`);
|
|
6516
6582
|
if (!existsSync3(snapshotPath))
|
|
6517
6583
|
return false;
|
|
6518
6584
|
const record = readJsonRecord(snapshotPath, plan.workspace_root);
|
|
@@ -6561,10 +6627,10 @@ function writeProjectContextRollbackSnapshot(plan, now2, outputs) {
|
|
|
6561
6627
|
sha256: nextHash
|
|
6562
6628
|
};
|
|
6563
6629
|
});
|
|
6564
|
-
const snapshotDir =
|
|
6630
|
+
const snapshotDir = resolve2(plan.workspace_root, ...SESSION_RENDER_SNAPSHOT_RELATIVE_DIR.split("/"));
|
|
6565
6631
|
ensureSafeDirectory(snapshotDir, plan.workspace_root, 448);
|
|
6566
6632
|
const timestamp = now2.toISOString().replace(/[:.]/g, "-");
|
|
6567
|
-
const snapshotPath =
|
|
6633
|
+
const snapshotPath = resolve2(snapshotDir, `${timestamp}-${randomUUID2()}.json`);
|
|
6568
6634
|
const snapshot = {
|
|
6569
6635
|
schema: "hasna.configs.session-render-snapshot/v2",
|
|
6570
6636
|
createdAt: now2.toISOString(),
|
|
@@ -6629,7 +6695,7 @@ function readSessionManifestRecord(path, workspaceRoot) {
|
|
|
6629
6695
|
}
|
|
6630
6696
|
}
|
|
6631
6697
|
function atomicWriteFile(path, content, workspaceRoot, defaultMode, expectedHash, afterExchange, atomicExchangeUnavailable = false, beforeInstall, portableCreateOnly = false, maxObservedBytes, allowPortableReplacement = false) {
|
|
6632
|
-
const dir =
|
|
6698
|
+
const dir = resolve2(path, "..");
|
|
6633
6699
|
ensureSafeDirectory(dir, workspaceRoot, 448);
|
|
6634
6700
|
assertNoSymlinkSegments(workspaceRoot, path);
|
|
6635
6701
|
const anchoredOps = portableCreateOnly ? null : resolveAnchoredFsOps();
|
|
@@ -6646,7 +6712,7 @@ function atomicWriteFile(path, content, workspaceRoot, defaultMode, expectedHash
|
|
|
6646
6712
|
const previous = anchoredFileObservation(directory, targetName);
|
|
6647
6713
|
const previousMode = previous?.mode ?? defaultMode;
|
|
6648
6714
|
const tempName = `.project-context-${randomUUID2()}.tmp`;
|
|
6649
|
-
const tempPath =
|
|
6715
|
+
const tempPath = join4(dir, tempName);
|
|
6650
6716
|
let fd = null;
|
|
6651
6717
|
let preserveTemp = false;
|
|
6652
6718
|
let directoryChanged = false;
|
|
@@ -6777,7 +6843,7 @@ function atomicWritePortable(path, content, workspaceRoot, defaultMode, expected
|
|
|
6777
6843
|
}
|
|
6778
6844
|
const dir = dirname(path);
|
|
6779
6845
|
const directoryIdentity = captureManagedDirectoryIdentity(dir, workspaceRoot);
|
|
6780
|
-
const tempPath =
|
|
6846
|
+
const tempPath = join4(dir, `.project-context-${randomUUID2()}.tmp`);
|
|
6781
6847
|
let fd = null;
|
|
6782
6848
|
let tempIdentity = null;
|
|
6783
6849
|
try {
|
|
@@ -6834,7 +6900,7 @@ function atomicWritePortableReplacement(path, content, workspaceRoot, expectedHa
|
|
|
6834
6900
|
}
|
|
6835
6901
|
const dir = dirname(path);
|
|
6836
6902
|
const directoryIdentity = captureManagedDirectoryIdentity(dir, workspaceRoot);
|
|
6837
|
-
const tempPath =
|
|
6903
|
+
const tempPath = join4(dir, `.project-context-${randomUUID2()}.tmp`);
|
|
6838
6904
|
const desiredHash = sha2562(content);
|
|
6839
6905
|
let fd = null;
|
|
6840
6906
|
let tempIdentity = null;
|
|
@@ -6903,11 +6969,11 @@ function portableFileHash(path, workspaceRoot, maxObservedBytes) {
|
|
|
6903
6969
|
return createHash2("sha256").update(readFileSync(path)).digest("hex");
|
|
6904
6970
|
}
|
|
6905
6971
|
function writeProjectContextCoordinatedFile(input) {
|
|
6906
|
-
atomicWriteFile(
|
|
6972
|
+
atomicWriteFile(resolve2(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);
|
|
6907
6973
|
}
|
|
6908
6974
|
function removeProjectContextCoordinatedFile(input) {
|
|
6909
6975
|
const workspaceRoot = assertSafeWorkspaceRoot(input.workspace_root);
|
|
6910
|
-
const path =
|
|
6976
|
+
const path = resolve2(input.path);
|
|
6911
6977
|
assertNoSymlinkSegments(workspaceRoot, path);
|
|
6912
6978
|
const dir = dirname(path);
|
|
6913
6979
|
const anchoredOps = input.force_portable_file_ops ? null : resolveAnchoredFsOps();
|
|
@@ -6933,7 +6999,7 @@ function removeProjectContextCoordinatedFile(input) {
|
|
|
6933
6999
|
throw new ProjectContextHashRace(`managed path changed during deletion: ${relativePosix(workspaceRoot, path)}`);
|
|
6934
7000
|
}
|
|
6935
7001
|
displaced = true;
|
|
6936
|
-
input.test_hooks?.after_displace?.(
|
|
7002
|
+
input.test_hooks?.after_displace?.(join4(dir, displacedName));
|
|
6937
7003
|
const moved = anchoredFileObservation(directory, displacedName);
|
|
6938
7004
|
if (!moved || moved.dev !== observed.dev || moved.ino !== observed.ino || moved.hash !== input.expected_hash || anchoredFileObservation(directory, targetName) !== null) {
|
|
6939
7005
|
throw new ProjectContextHashRace(`managed path changed during deletion validation: ${relativePosix(workspaceRoot, path)}`);
|
|
@@ -6979,7 +7045,7 @@ function removePortableCoordinatedFile(path, workspaceRoot, expectedHash, maxObs
|
|
|
6979
7045
|
}
|
|
6980
7046
|
const dir = dirname(path);
|
|
6981
7047
|
const directoryIdentity = captureManagedDirectoryIdentity(dir, workspaceRoot);
|
|
6982
|
-
const displacedPath =
|
|
7048
|
+
const displacedPath = join4(dir, `.project-context-delete-${randomUUID2()}.tmp`);
|
|
6983
7049
|
let displaced = false;
|
|
6984
7050
|
try {
|
|
6985
7051
|
assertManagedDirectoryStable(dir, workspaceRoot, directoryIdentity);
|
|
@@ -7051,7 +7117,7 @@ function anchoredOpenExclusive(directory, name, mode) {
|
|
|
7051
7117
|
const requestedMode = mode & 4095;
|
|
7052
7118
|
let fd;
|
|
7053
7119
|
try {
|
|
7054
|
-
fd = openSync(
|
|
7120
|
+
fd = openSync(join4(directory.path, name), constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW, requestedMode);
|
|
7055
7121
|
} catch {
|
|
7056
7122
|
throw new ProjectContextHashRace(`could not create prepared managed file in ${relativePosix(directory.workspaceRoot, directory.path)}`);
|
|
7057
7123
|
}
|
|
@@ -7094,7 +7160,7 @@ function anchoredFileObservation(directory, name) {
|
|
|
7094
7160
|
const stat = fstatSync(fd);
|
|
7095
7161
|
if (!stat.isFile())
|
|
7096
7162
|
throw new ProjectContextHashRace("managed output is not a regular file");
|
|
7097
|
-
const relativePath = relativePosix(directory.workspaceRoot,
|
|
7163
|
+
const relativePath = relativePosix(directory.workspaceRoot, join4(directory.path, name));
|
|
7098
7164
|
const maxBytes = directory.maxObservedBytes === undefined ? managedObservationMaxBytes(relativePath) : directory.maxObservedBytes;
|
|
7099
7165
|
if (maxBytes !== null && stat.size > maxBytes) {
|
|
7100
7166
|
throw new ProjectContextHashRace(`managed output exceeds the safe read limit: ${relativePath}`);
|
|
@@ -7120,7 +7186,7 @@ function anchoredPreparedObservation(directory, name, path, stage) {
|
|
|
7120
7186
|
return observed;
|
|
7121
7187
|
}
|
|
7122
7188
|
function captureManagedDirectoryIdentity(path, workspaceRoot) {
|
|
7123
|
-
assertNoSymlinkSegments(workspaceRoot,
|
|
7189
|
+
assertNoSymlinkSegments(workspaceRoot, join4(path, ".project-context-directory-guard"));
|
|
7124
7190
|
let stat;
|
|
7125
7191
|
try {
|
|
7126
7192
|
stat = lstatSync(path);
|
|
@@ -7133,7 +7199,7 @@ function captureManagedDirectoryIdentity(path, workspaceRoot) {
|
|
|
7133
7199
|
return { dev: stat.dev, ino: stat.ino };
|
|
7134
7200
|
}
|
|
7135
7201
|
function assertManagedDirectoryStable(path, workspaceRoot, expected) {
|
|
7136
|
-
assertNoSymlinkSegments(workspaceRoot,
|
|
7202
|
+
assertNoSymlinkSegments(workspaceRoot, join4(path, ".project-context-directory-guard"));
|
|
7137
7203
|
let current;
|
|
7138
7204
|
try {
|
|
7139
7205
|
current = lstatSync(path);
|
|
@@ -7268,10 +7334,10 @@ function resolveAnchoredFsOps() {
|
|
|
7268
7334
|
return null;
|
|
7269
7335
|
}
|
|
7270
7336
|
function acquireWorkspaceLock(workspaceRoot, lockPath, afterOpen, beforeStaleRemove, processStartIdentityLookup = processStartIdentity) {
|
|
7271
|
-
const lockDirectory =
|
|
7337
|
+
const lockDirectory = resolve2(lockPath, "..");
|
|
7272
7338
|
ensureSafeDirectory(lockDirectory, workspaceRoot, 448);
|
|
7273
7339
|
assertNoSymlinkSegments(workspaceRoot, lockPath);
|
|
7274
|
-
const tempPath =
|
|
7340
|
+
const tempPath = join4(lockDirectory, `.project-context-lock-${randomUUID2()}.tmp`);
|
|
7275
7341
|
let fd = null;
|
|
7276
7342
|
let openedIdentity = null;
|
|
7277
7343
|
let openedContentHash = null;
|
|
@@ -7343,7 +7409,7 @@ function removeOwnedLockByInode(lockPath, identity, expectedHash) {
|
|
|
7343
7409
|
if (expectedHash !== undefined && sha2562(readFileSync(lockPath, "utf8")) !== expectedHash)
|
|
7344
7410
|
return;
|
|
7345
7411
|
rmSync2(lockPath);
|
|
7346
|
-
fsyncDirectory(
|
|
7412
|
+
fsyncDirectory(resolve2(lockPath, ".."));
|
|
7347
7413
|
} catch {}
|
|
7348
7414
|
}
|
|
7349
7415
|
function observeStaleWorkspaceLock(lockPath, workspaceRoot, processStartIdentityLookup = processStartIdentity) {
|
|
@@ -7422,7 +7488,7 @@ function tryTakeoverStaleWorkspaceLock(candidatePath, lockPath, workspaceRoot, c
|
|
|
7422
7488
|
throw new ProjectContextError("PROJECT_CONTEXT_LOCK_LOST", "workspace lock changed during stale-lock takeover and could not be restored safely");
|
|
7423
7489
|
}
|
|
7424
7490
|
rmSync2(candidatePath);
|
|
7425
|
-
fsyncDirectory(
|
|
7491
|
+
fsyncDirectory(resolve2(lockPath, ".."));
|
|
7426
7492
|
exchanged = false;
|
|
7427
7493
|
return true;
|
|
7428
7494
|
} catch (error) {
|
|
@@ -7501,8 +7567,8 @@ function releaseWorkspaceLock(lockPath, lock, workspaceRoot) {
|
|
|
7501
7567
|
}
|
|
7502
7568
|
return;
|
|
7503
7569
|
}
|
|
7504
|
-
const lockDirectory =
|
|
7505
|
-
const releasePath =
|
|
7570
|
+
const lockDirectory = resolve2(lockPath, "..");
|
|
7571
|
+
const releasePath = join4(lockDirectory, `.project-context-release-${randomUUID2()}.tmp`);
|
|
7506
7572
|
let releaseFd = null;
|
|
7507
7573
|
let releaseIdentity = null;
|
|
7508
7574
|
let releaseHash = null;
|
|
@@ -7582,7 +7648,7 @@ function ensureSafeDirectory(path, workspaceRoot, mode) {
|
|
|
7582
7648
|
const segments = rel.split(/[\\/]+/).filter(Boolean);
|
|
7583
7649
|
let current = workspaceRoot;
|
|
7584
7650
|
for (const segment of segments) {
|
|
7585
|
-
current =
|
|
7651
|
+
current = join4(current, segment);
|
|
7586
7652
|
if (existsSync3(current)) {
|
|
7587
7653
|
if (lstatSync(current).isSymbolicLink())
|
|
7588
7654
|
throw new ProjectContextError("PROJECT_CONTEXT_SYMLINK_REJECTED", `managed path uses a symlink: ${current}`);
|
|
@@ -7590,7 +7656,7 @@ function ensureSafeDirectory(path, workspaceRoot, mode) {
|
|
|
7590
7656
|
throw new ProjectContextError("PROJECT_CONTEXT_PATH_INVALID", `managed path is not a directory: ${current}`);
|
|
7591
7657
|
} else {
|
|
7592
7658
|
mkdirSync2(current, { mode });
|
|
7593
|
-
fsyncDirectory(
|
|
7659
|
+
fsyncDirectory(resolve2(current, ".."));
|
|
7594
7660
|
}
|
|
7595
7661
|
}
|
|
7596
7662
|
}
|
|
@@ -7646,11 +7712,11 @@ function scanGeneratedContent(content) {
|
|
|
7646
7712
|
function runtimePaths(workspaceRoot, runtime) {
|
|
7647
7713
|
const relativeTarget = runtime === "claude" ? "CLAUDE.md" : runtime === "codewith" ? ".codewith/CODEWITH.md" : "AGENTS.md";
|
|
7648
7714
|
return {
|
|
7649
|
-
target:
|
|
7650
|
-
fragment:
|
|
7651
|
-
manifest:
|
|
7652
|
-
cache:
|
|
7653
|
-
sessionManifest: runtime === "codewith" ?
|
|
7715
|
+
target: resolve2(workspaceRoot, ...relativeTarget.split("/")),
|
|
7716
|
+
fragment: resolve2(workspaceRoot, ...PROJECT_CONTEXT_FRAGMENT_PATH.split("/")),
|
|
7717
|
+
manifest: resolve2(workspaceRoot, ...PROJECT_CONTEXT_MANIFEST_PATH.split("/")),
|
|
7718
|
+
cache: resolve2(workspaceRoot, ...PROJECT_CONTEXT_CACHE_PATH.split("/")),
|
|
7719
|
+
sessionManifest: runtime === "codewith" ? resolve2(workspaceRoot, ".codewith", ".hasna", "session-render-manifest.json") : resolve2(workspaceRoot, ".hasna", "session-render-manifest.json")
|
|
7654
7720
|
};
|
|
7655
7721
|
}
|
|
7656
7722
|
function projectContextSessionGuardPaths(paths, runtime) {
|
|
@@ -7660,7 +7726,7 @@ function projectContextSessionGuardPaths(paths, runtime) {
|
|
|
7660
7726
|
paths.fragment,
|
|
7661
7727
|
paths.target,
|
|
7662
7728
|
paths.sessionManifest,
|
|
7663
|
-
...runtime === "codewith" ? [
|
|
7729
|
+
...runtime === "codewith" ? [resolve2(paths.target, "..", "CODEWITH.override.md")] : []
|
|
7664
7730
|
];
|
|
7665
7731
|
}
|
|
7666
7732
|
function sessionTargetRelativePath(runtime) {
|
|
@@ -7680,12 +7746,12 @@ function projectContextRuntimeForSessionTool(tool) {
|
|
|
7680
7746
|
return null;
|
|
7681
7747
|
}
|
|
7682
7748
|
function projectContextWorkspaceForSession(input, runtime) {
|
|
7683
|
-
const targetHome =
|
|
7749
|
+
const targetHome = resolve2(input.target_home);
|
|
7684
7750
|
if (runtime === "codewith") {
|
|
7685
7751
|
const workspaceRoot = basename(targetHome) === ".codewith" ? dirname(targetHome) : null;
|
|
7686
7752
|
if (!workspaceRoot)
|
|
7687
7753
|
return null;
|
|
7688
|
-
if (input.project_root &&
|
|
7754
|
+
if (input.project_root && resolve2(input.project_root) !== workspaceRoot) {
|
|
7689
7755
|
throw new ProjectContextError("PROJECT_CONTEXT_PATH_INVALID", "Codewith project_root must be the parent workspace of target_home");
|
|
7690
7756
|
}
|
|
7691
7757
|
if (!existsSync3(workspaceRoot) || !lstatSync(workspaceRoot).isDirectory())
|
|
@@ -7699,7 +7765,7 @@ function projectContextWorkspaceForSession(input, runtime) {
|
|
|
7699
7765
|
function assertCodewithTargetIsConsumed(workspaceRoot, runtime) {
|
|
7700
7766
|
if (runtime !== "codewith")
|
|
7701
7767
|
return;
|
|
7702
|
-
const override =
|
|
7768
|
+
const override = resolve2(workspaceRoot, ".codewith", "CODEWITH.override.md");
|
|
7703
7769
|
if (!existsSync3(override))
|
|
7704
7770
|
return;
|
|
7705
7771
|
assertNoSymlinkSegments(workspaceRoot, override);
|
|
@@ -7710,7 +7776,7 @@ function assertCodewithTargetIsConsumed(workspaceRoot, runtime) {
|
|
|
7710
7776
|
function assertSafeWorkspaceRoot(path) {
|
|
7711
7777
|
if (!isAbsolute(path))
|
|
7712
7778
|
throw new ProjectContextError("PROJECT_CONTEXT_PATH_INVALID", "workspace root must be absolute");
|
|
7713
|
-
const normalized =
|
|
7779
|
+
const normalized = resolve2(path);
|
|
7714
7780
|
if (normalized === parse(normalized).root)
|
|
7715
7781
|
throw new ProjectContextError("PROJECT_CONTEXT_PATH_INVALID", "workspace root cannot be the filesystem root");
|
|
7716
7782
|
if (!existsSync3(normalized) || !lstatSync(normalized).isDirectory())
|
|
@@ -7727,17 +7793,17 @@ function assertNoSymlinkSegments(root, target) {
|
|
|
7727
7793
|
}
|
|
7728
7794
|
let current = root;
|
|
7729
7795
|
for (const segment of rel.split(/[\\/]+/).filter(Boolean)) {
|
|
7730
|
-
current =
|
|
7796
|
+
current = join4(current, segment);
|
|
7731
7797
|
if (existsSync3(current) && lstatSync(current).isSymbolicLink()) {
|
|
7732
7798
|
throw new ProjectContextError("PROJECT_CONTEXT_SYMLINK_REJECTED", `managed path uses a symlink: ${current}`);
|
|
7733
7799
|
}
|
|
7734
7800
|
}
|
|
7735
7801
|
}
|
|
7736
7802
|
function assertNoSymlinkAncestors(path) {
|
|
7737
|
-
const normalized =
|
|
7803
|
+
const normalized = resolve2(path);
|
|
7738
7804
|
let current = parse(normalized).root;
|
|
7739
7805
|
for (const segment of relative(current, normalized).split(/[\\/]+/).filter(Boolean)) {
|
|
7740
|
-
current =
|
|
7806
|
+
current = join4(current, segment);
|
|
7741
7807
|
if (!existsSync3(current))
|
|
7742
7808
|
return;
|
|
7743
7809
|
if (lstatSync(current).isSymbolicLink())
|
|
@@ -7773,10 +7839,10 @@ function fragmentMatchesBundle(path, bundle, workspaceRoot) {
|
|
|
7773
7839
|
}
|
|
7774
7840
|
function durableSourcePath(path, workspaceRoot) {
|
|
7775
7841
|
if (!path || path.startsWith("/dev/fd/"))
|
|
7776
|
-
return
|
|
7777
|
-
const normalized = isAbsolute(path) ?
|
|
7842
|
+
return resolve2(workspaceRoot, ...PROJECT_CONTEXT_CACHE_PATH.split("/"));
|
|
7843
|
+
const normalized = isAbsolute(path) ? resolve2(path) : resolve2(workspaceRoot, path);
|
|
7778
7844
|
if (normalized.startsWith("/dev/fd/"))
|
|
7779
|
-
return
|
|
7845
|
+
return resolve2(workspaceRoot, ...PROJECT_CONTEXT_CACHE_PATH.split("/"));
|
|
7780
7846
|
return normalized;
|
|
7781
7847
|
}
|
|
7782
7848
|
function compareRevisions(incoming, previous) {
|
|
@@ -8074,7 +8140,7 @@ function applyTransform(source, output, context = {}) {
|
|
|
8074
8140
|
|
|
8075
8141
|
// src/lib/asset-plan.ts
|
|
8076
8142
|
import { createHash as createHash3 } from "crypto";
|
|
8077
|
-
import { isAbsolute as isAbsolute2, posix, resolve as
|
|
8143
|
+
import { isAbsolute as isAbsolute2, posix, resolve as resolve3 } from "path";
|
|
8078
8144
|
|
|
8079
8145
|
// src/lib/provider-version.ts
|
|
8080
8146
|
function providerVersionSatisfies(version, range) {
|
|
@@ -8384,8 +8450,8 @@ function resolveAssetDestination(item, roots) {
|
|
|
8384
8450
|
if (!isAbsolute2(root))
|
|
8385
8451
|
throw new Error(`Asset ${item.assetKey} destination root must be absolute.`);
|
|
8386
8452
|
const relativePath = safeRelativePath(item.destination.relativePath);
|
|
8387
|
-
const target =
|
|
8388
|
-
const normalizedRoot =
|
|
8453
|
+
const target = resolve3(root, ...relativePath.split("/"));
|
|
8454
|
+
const normalizedRoot = resolve3(root);
|
|
8389
8455
|
if (target === normalizedRoot)
|
|
8390
8456
|
throw new Error(`Asset ${item.assetKey} destination cannot replace its root.`);
|
|
8391
8457
|
if (!target.startsWith(`${normalizedRoot}/`))
|
|
@@ -8507,8 +8573,8 @@ function deepFreeze(value) {
|
|
|
8507
8573
|
// src/lib/cursor-authority.ts
|
|
8508
8574
|
import { createHash as createHash4 } from "crypto";
|
|
8509
8575
|
import { lstatSync as lstatSync2, readFileSync as readFileSync2 } from "fs";
|
|
8510
|
-
import { homedir as
|
|
8511
|
-
import { join as
|
|
8576
|
+
import { homedir as homedir3 } from "os";
|
|
8577
|
+
import { join as join5, resolve as resolve4 } from "path";
|
|
8512
8578
|
var CURSOR_GLOBAL_AUTHORITY_RELATIVE_PATH = ".cursor/rules/hasna-global.mdc";
|
|
8513
8579
|
var CURSOR_GLOBAL_AUTHORITY_MAX_BYTES = 256 * 1024;
|
|
8514
8580
|
var CURSOR_GLOBAL_AUTHORITY_MANAGED_MARKER = "Managed by @hasna/configs cursor global authority";
|
|
@@ -8518,7 +8584,7 @@ function sha2564(content) {
|
|
|
8518
8584
|
return createHash4("sha256").update(content).digest("hex");
|
|
8519
8585
|
}
|
|
8520
8586
|
function homeDir() {
|
|
8521
|
-
return process.env["HOME"] ||
|
|
8587
|
+
return process.env["HOME"] || homedir3();
|
|
8522
8588
|
}
|
|
8523
8589
|
function markerPayload(content, markerLine, markerIndex) {
|
|
8524
8590
|
const index = markerIndex ?? content.indexOf(markerLine);
|
|
@@ -8534,12 +8600,12 @@ function baseObservation(path) {
|
|
|
8534
8600
|
};
|
|
8535
8601
|
}
|
|
8536
8602
|
function observeCursorGlobalAuthority(options = {}) {
|
|
8537
|
-
const authorityPath =
|
|
8603
|
+
const authorityPath = resolve4(join5(options.home ?? homeDir(), CURSOR_GLOBAL_AUTHORITY_RELATIVE_PATH));
|
|
8538
8604
|
const readFile = options.readFile ?? ((path) => readFileSync2(path, "utf8"));
|
|
8539
8605
|
return observeCursorGlobalAuthorityPath(authorityPath, readFile);
|
|
8540
8606
|
}
|
|
8541
8607
|
function observeCursorGlobalAuthorityAtPath(authorityPath) {
|
|
8542
|
-
return observeCursorGlobalAuthorityPath(
|
|
8608
|
+
return observeCursorGlobalAuthorityPath(resolve4(authorityPath), (path) => readFileSync2(path, "utf8"));
|
|
8543
8609
|
}
|
|
8544
8610
|
function observeCursorGlobalAuthorityPath(authorityPath, readFile) {
|
|
8545
8611
|
const base = baseObservation(authorityPath);
|
|
@@ -8684,7 +8750,7 @@ function observeCursorGlobalAuthorityPath(authorityPath, readFile) {
|
|
|
8684
8750
|
};
|
|
8685
8751
|
}
|
|
8686
8752
|
function isCursorGlobalAuthorityPath(path) {
|
|
8687
|
-
return
|
|
8753
|
+
return resolve4(path) === resolve4(join5(homeDir(), CURSOR_GLOBAL_AUTHORITY_RELATIVE_PATH));
|
|
8688
8754
|
}
|
|
8689
8755
|
function stampCursorGlobalAuthorityMarker(content) {
|
|
8690
8756
|
if (CURSOR_GLOBAL_AUTHORITY_MARKER_PATTERN.test(content))
|
|
@@ -8721,8 +8787,82 @@ function detectCursorAuthorityConflicts(observation = observeCursorGlobalAuthori
|
|
|
8721
8787
|
}];
|
|
8722
8788
|
}
|
|
8723
8789
|
|
|
8790
|
+
// src/lib/session-authority.ts
|
|
8791
|
+
import { createHash as createHash5 } from "crypto";
|
|
8792
|
+
import { lstatSync as lstatSync3, readFileSync as readFileSync3, statSync as statSync2 } from "fs";
|
|
8793
|
+
import { join as join6, resolve as resolve5 } from "path";
|
|
8794
|
+
var CLAUDE_LEGACY_AUTHORITY_RELATIVE_PATH = "AGENTS.md";
|
|
8795
|
+
var CLAUDE_LEGACY_AUTHORITY_MAX_BYTES = 256 * 1024;
|
|
8796
|
+
var CLAUDE_LEGACY_MARKERS = [
|
|
8797
|
+
{ id: "claude-agent-rules-heading", pattern: /^# Agent Rules \(Claude\)/m },
|
|
8798
|
+
{ id: "no-worktrees-heading", pattern: /^## No Worktrees/m },
|
|
8799
|
+
{ id: "no-worktrees-directive", pattern: /\bNever use git worktrees\b/m }
|
|
8800
|
+
];
|
|
8801
|
+
function sha2565(content) {
|
|
8802
|
+
return createHash5("sha256").update(content).digest("hex");
|
|
8803
|
+
}
|
|
8804
|
+
function detectClaudeAuthorityConflicts(targetHome) {
|
|
8805
|
+
const authorityPath = resolve5(join6(targetHome, CLAUDE_LEGACY_AUTHORITY_RELATIVE_PATH));
|
|
8806
|
+
let stat;
|
|
8807
|
+
try {
|
|
8808
|
+
stat = lstatSync3(authorityPath);
|
|
8809
|
+
} catch {
|
|
8810
|
+
return [];
|
|
8811
|
+
}
|
|
8812
|
+
const provenanceBase = {
|
|
8813
|
+
tool: "claude",
|
|
8814
|
+
relativePath: CLAUDE_LEGACY_AUTHORITY_RELATIVE_PATH,
|
|
8815
|
+
path: authorityPath
|
|
8816
|
+
};
|
|
8817
|
+
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
8818
|
+
return [{
|
|
8819
|
+
...provenanceBase,
|
|
8820
|
+
kind: "invalid-unmanaged-authority",
|
|
8821
|
+
sha256: null,
|
|
8822
|
+
markers: [],
|
|
8823
|
+
provenance: {
|
|
8824
|
+
source: "filesystem",
|
|
8825
|
+
authority: "unmanaged",
|
|
8826
|
+
observedPath: authorityPath,
|
|
8827
|
+
detection: "non-regular-file"
|
|
8828
|
+
},
|
|
8829
|
+
reason: "Claude target contains unmanaged AGENTS.md that is not a regular file; authority cannot be verified safely."
|
|
8830
|
+
}];
|
|
8831
|
+
}
|
|
8832
|
+
if (statSync2(authorityPath).size > CLAUDE_LEGACY_AUTHORITY_MAX_BYTES) {
|
|
8833
|
+
return [{
|
|
8834
|
+
...provenanceBase,
|
|
8835
|
+
kind: "invalid-unmanaged-authority",
|
|
8836
|
+
sha256: null,
|
|
8837
|
+
markers: [],
|
|
8838
|
+
provenance: {
|
|
8839
|
+
source: "filesystem",
|
|
8840
|
+
authority: "unmanaged",
|
|
8841
|
+
observedPath: authorityPath,
|
|
8842
|
+
detection: "oversized-file"
|
|
8843
|
+
},
|
|
8844
|
+
reason: `Claude target contains unmanaged AGENTS.md larger than ${CLAUDE_LEGACY_AUTHORITY_MAX_BYTES} bytes; authority cannot be classified safely.`
|
|
8845
|
+
}];
|
|
8846
|
+
}
|
|
8847
|
+
const content = readFileSync3(authorityPath, "utf8");
|
|
8848
|
+
const markers = CLAUDE_LEGACY_MARKERS.filter((marker) => marker.pattern.test(content)).map((marker) => marker.id);
|
|
8849
|
+
const knownLegacy = markers.includes("no-worktrees-heading") && markers.includes("no-worktrees-directive");
|
|
8850
|
+
return [{
|
|
8851
|
+
...provenanceBase,
|
|
8852
|
+
kind: knownLegacy ? "known-legacy-no-worktree" : "unknown-unmanaged-authority",
|
|
8853
|
+
sha256: sha2565(content),
|
|
8854
|
+
markers,
|
|
8855
|
+
provenance: {
|
|
8856
|
+
source: "filesystem",
|
|
8857
|
+
authority: "unmanaged",
|
|
8858
|
+
observedPath: authorityPath,
|
|
8859
|
+
detection: knownLegacy ? "known-legacy-markers" : "unknown-content"
|
|
8860
|
+
},
|
|
8861
|
+
reason: knownLegacy ? "Claude target contains unmanaged legacy AGENTS.md with no-worktree directives; migrate or remove it through an owned authority path before applying." : "Claude target contains unmanaged AGENTS.md with unknown authority content; refusing to guess whether it conflicts with the managed Claude render."
|
|
8862
|
+
}];
|
|
8863
|
+
}
|
|
8864
|
+
|
|
8724
8865
|
// src/lib/session-render.ts
|
|
8725
|
-
var RAW_STORE_ROOT_ENV = "HASNA_CONFIGS_HOME";
|
|
8726
8866
|
var ANTIGRAVITY_RULE_FILE_CHAR_LIMIT = 12000;
|
|
8727
8867
|
var SESSION_RENDERER_OWNER_ID = "instructions-session-renderer";
|
|
8728
8868
|
var SESSION_RENDER_TOOLS = [
|
|
@@ -8934,11 +9074,11 @@ function ensureTrailingNewline3(content) {
|
|
|
8934
9074
|
`) ? content : `${content}
|
|
8935
9075
|
`;
|
|
8936
9076
|
}
|
|
8937
|
-
function
|
|
8938
|
-
return
|
|
9077
|
+
function sha2566(content) {
|
|
9078
|
+
return createHash6("sha256").update(content).digest("hex");
|
|
8939
9079
|
}
|
|
8940
9080
|
function fingerprint(value) {
|
|
8941
|
-
return
|
|
9081
|
+
return sha2566(JSON.stringify(value));
|
|
8942
9082
|
}
|
|
8943
9083
|
function canonicalFingerprintValue(value) {
|
|
8944
9084
|
if (Array.isArray(value))
|
|
@@ -8956,7 +9096,7 @@ function ruleAttestation(rule) {
|
|
|
8956
9096
|
};
|
|
8957
9097
|
const applied = metadata["payloadFloorApplied"];
|
|
8958
9098
|
return {
|
|
8959
|
-
contentSha256:
|
|
9099
|
+
contentSha256: sha2566(rule.content ?? ""),
|
|
8960
9100
|
payloadFloorApplied: typeof applied === "boolean" ? applied : null,
|
|
8961
9101
|
flooredFromRulesVersion: read("flooredFromRulesVersion"),
|
|
8962
9102
|
flooredFromPayloadSha256: read("flooredFromPayloadSha256"),
|
|
@@ -9002,16 +9142,14 @@ function slug(value) {
|
|
|
9002
9142
|
function yamlQuote2(value) {
|
|
9003
9143
|
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`;
|
|
9004
9144
|
}
|
|
9005
|
-
function getRawStoreRoot() {
|
|
9006
|
-
return resolve4(process.env[RAW_STORE_ROOT_ENV] || join5(process.env["HOME"] || homedir3(), ".hasna", "configs"));
|
|
9007
|
-
}
|
|
9008
9145
|
function defaultTargetHome(tool, profile, sessionId) {
|
|
9009
|
-
|
|
9146
|
+
const home = process.env["HOME"] || homedir4();
|
|
9147
|
+
return join7(home, ".hasna", "accounts", "profiles", tool, slug(profile));
|
|
9010
9148
|
}
|
|
9011
9149
|
function joinTarget(targetHome, relativePath) {
|
|
9012
9150
|
const safeTargetHome = assertSafeTargetRoot(targetHome);
|
|
9013
9151
|
const safeRelativePath2 = assertSafeRelativePath(relativePath);
|
|
9014
|
-
return
|
|
9152
|
+
return join7(safeTargetHome, ...safeRelativePath2.split("/"));
|
|
9015
9153
|
}
|
|
9016
9154
|
function makeFile(targetHome, relativePath, role, content, sourceIds) {
|
|
9017
9155
|
const safeTargetHome = assertSafeTargetRoot(targetHome);
|
|
@@ -9022,7 +9160,7 @@ function makeFile(targetHome, relativePath, role, content, sourceIds) {
|
|
|
9022
9160
|
relativePath: safeRelativePath2,
|
|
9023
9161
|
role,
|
|
9024
9162
|
content: normalizedContent,
|
|
9025
|
-
sha256:
|
|
9163
|
+
sha256: sha2566(normalizedContent),
|
|
9026
9164
|
sourceIds
|
|
9027
9165
|
};
|
|
9028
9166
|
}
|
|
@@ -9056,7 +9194,7 @@ function applyAgentOperatingRulesFloor(source, content) {
|
|
|
9056
9194
|
const floored = {
|
|
9057
9195
|
payloadFloorApplied: true,
|
|
9058
9196
|
flooredFromRulesVersion: parseAgentOperatingRulesVersion(content),
|
|
9059
|
-
flooredFromPayloadSha256:
|
|
9197
|
+
flooredFromPayloadSha256: sha2566(content)
|
|
9060
9198
|
};
|
|
9061
9199
|
return {
|
|
9062
9200
|
content: payload.content,
|
|
@@ -9078,7 +9216,7 @@ function applyAgentOperatingRulesFloorToRule(source, rule, content) {
|
|
|
9078
9216
|
const floored = {
|
|
9079
9217
|
payloadFloorApplied: true,
|
|
9080
9218
|
flooredFromRulesVersion: parseAgentOperatingRulesVersion(content),
|
|
9081
|
-
flooredFromPayloadSha256:
|
|
9219
|
+
flooredFromPayloadSha256: sha2566(content)
|
|
9082
9220
|
};
|
|
9083
9221
|
return {
|
|
9084
9222
|
content: payload.content,
|
|
@@ -9097,7 +9235,7 @@ function skippedSource(source, reason) {
|
|
|
9097
9235
|
order: source.resolvedOrder,
|
|
9098
9236
|
path: source.path ?? null,
|
|
9099
9237
|
hash: source.hash ?? null,
|
|
9100
|
-
renderedPayloadSha256:
|
|
9238
|
+
renderedPayloadSha256: sha2566(source.content),
|
|
9101
9239
|
nonOverridable: source.nonOverridable === true,
|
|
9102
9240
|
provenance: source.provenance ?? null
|
|
9103
9241
|
}
|
|
@@ -9139,7 +9277,7 @@ function compareSessionInstructionSources(a, b) {
|
|
|
9139
9277
|
return SESSION_LAYER_RANK[a.resolvedLayer] - SESSION_LAYER_RANK[b.resolvedLayer] || a.resolvedOrder - b.resolvedOrder || a.id.localeCompare(b.id);
|
|
9140
9278
|
}
|
|
9141
9279
|
function semanticPolicyIntegrity(body) {
|
|
9142
|
-
return
|
|
9280
|
+
return sha2566(body) === AGENT_OPERATING_RULES_PAYLOAD_SHA256 ? "pinned-digest" : "unverified-self-declared";
|
|
9143
9281
|
}
|
|
9144
9282
|
function semanticPolicyDeclaration(source) {
|
|
9145
9283
|
const normalize = (value) => value.replace(/\r\n/g, `
|
|
@@ -9364,7 +9502,7 @@ function composeSources(sources, tool) {
|
|
|
9364
9502
|
targetSourceId: target.id,
|
|
9365
9503
|
targetNormalizedSourceId: target.normalizedId,
|
|
9366
9504
|
targetHash: target.hash ?? null,
|
|
9367
|
-
targetRenderedPayloadSha256:
|
|
9505
|
+
targetRenderedPayloadSha256: sha2566(target.content),
|
|
9368
9506
|
targetNonOverridable: protectedReplacement,
|
|
9369
9507
|
authority: protectedReplacement ? "canonical-identity-export/codewith-provider/v1" : "overridable-source/v1"
|
|
9370
9508
|
}
|
|
@@ -9546,7 +9684,7 @@ function buildOpenCodeFiles(targetHome, adapter, profile, sources, providerConfi
|
|
|
9546
9684
|
...sources.flatMap((source) => source.resolvedRules.map((rule) => rule.id))
|
|
9547
9685
|
]);
|
|
9548
9686
|
const existingConfigPath = joinTarget(targetHome, adapter.configFile);
|
|
9549
|
-
const selectedConfig = existsSync4(existingConfigPath) ? readOpenCodeConfig(
|
|
9687
|
+
const selectedConfig = existsSync4(existingConfigPath) ? readOpenCodeConfig(readFileSync4(existingConfigPath, "utf8"), existingConfigPath) : providerConfig ? readOpenCodeConfig(providerConfig.content, providerConfig.sourceId) : {};
|
|
9550
9688
|
const preservedInstructions = normalizeOpenCodeInstructions(selectedConfig["instructions"]).filter((path) => !pathIsManagedOpenCodeInstruction(path, adapter.managedDir));
|
|
9551
9689
|
const config = {
|
|
9552
9690
|
...selectedConfig,
|
|
@@ -9695,7 +9833,7 @@ function buildAssetFiles(input, targetHome, blocked) {
|
|
|
9695
9833
|
relativePath: assertSafeRelativePath(relativePath),
|
|
9696
9834
|
role: "asset",
|
|
9697
9835
|
content,
|
|
9698
|
-
sha256:
|
|
9836
|
+
sha256: sha2566(content),
|
|
9699
9837
|
sourceIds: [item.sourceConfigId, item.assetId]
|
|
9700
9838
|
};
|
|
9701
9839
|
});
|
|
@@ -9735,7 +9873,7 @@ function adapterFor(input) {
|
|
|
9735
9873
|
return gatedNativeImports ? CODEWITH_NATIVE_ADAPTER : CODEWITH_FLATTENED_ADAPTER;
|
|
9736
9874
|
}
|
|
9737
9875
|
function getHomeDir() {
|
|
9738
|
-
return process.env["CONFIGS_HOME"] || process.env["HOME"] ||
|
|
9876
|
+
return process.env["CONFIGS_HOME"] || process.env["HOME"] || homedir4();
|
|
9739
9877
|
}
|
|
9740
9878
|
function cleanSessionPathInput(path) {
|
|
9741
9879
|
const trimmed = path.trim();
|
|
@@ -9750,16 +9888,16 @@ function resolveSessionPath(path) {
|
|
|
9750
9888
|
throw new Error("Session render path cannot be empty.");
|
|
9751
9889
|
const home = getHomeDir();
|
|
9752
9890
|
if (cleaned === "~")
|
|
9753
|
-
return
|
|
9891
|
+
return resolve6(home);
|
|
9754
9892
|
if (cleaned.startsWith("~/"))
|
|
9755
|
-
return
|
|
9893
|
+
return resolve6(home, cleaned.slice(2));
|
|
9756
9894
|
if (cleaned === "{{HOME}}" || cleaned === "${HOME}")
|
|
9757
|
-
return
|
|
9895
|
+
return resolve6(home);
|
|
9758
9896
|
if (cleaned.startsWith("{{HOME}}/"))
|
|
9759
|
-
return
|
|
9897
|
+
return resolve6(home, cleaned.slice("{{HOME}}/".length));
|
|
9760
9898
|
if (cleaned.startsWith("${HOME}/"))
|
|
9761
|
-
return
|
|
9762
|
-
return
|
|
9899
|
+
return resolve6(home, cleaned.slice("${HOME}/".length));
|
|
9900
|
+
return resolve6(cleaned);
|
|
9763
9901
|
}
|
|
9764
9902
|
function assertSafeRelativePath(relativePath) {
|
|
9765
9903
|
if (!relativePath.trim())
|
|
@@ -9775,7 +9913,7 @@ function assertSafeRelativePath(relativePath) {
|
|
|
9775
9913
|
function assertSafeTargetRoot(targetHome) {
|
|
9776
9914
|
if (!isAbsolute3(targetHome))
|
|
9777
9915
|
throw new Error(`Session render target must be an absolute path: ${targetHome}`);
|
|
9778
|
-
const normalized =
|
|
9916
|
+
const normalized = resolve6(targetHome);
|
|
9779
9917
|
if (normalized === parse2(normalized).root) {
|
|
9780
9918
|
throw new Error(`Session render target cannot be the filesystem root: ${targetHome}`);
|
|
9781
9919
|
}
|
|
@@ -9873,7 +10011,7 @@ function planSessionRender(input) {
|
|
|
9873
10011
|
blockers: targetBlockers
|
|
9874
10012
|
} = resolveRenderTarget(input);
|
|
9875
10013
|
const authorityObservations = input.tool === "cursor" && targetKind !== "blocked" ? [observeCursorGlobalAuthority({ home: input.cursorAuthorityHome })] : [];
|
|
9876
|
-
const authorityConflicts = input.tool === "cursor" && targetKind !== "blocked" ? detectCursorAuthorityConflicts(authorityObservations[0]) : [];
|
|
10014
|
+
const authorityConflicts = input.tool === "cursor" && targetKind !== "blocked" ? detectCursorAuthorityConflicts(authorityObservations[0]) : input.tool === "claude" && targetKind !== "blocked" ? detectClaudeAuthorityConflicts(targetHome) : [];
|
|
9877
10015
|
const blockers = [
|
|
9878
10016
|
...targetBlockers,
|
|
9879
10017
|
...authorityConflicts.map((conflict) => `${conflict.relativePath}: ${conflict.reason}`)
|
|
@@ -9971,7 +10109,7 @@ function planSessionRender(input) {
|
|
|
9971
10109
|
hash: rule.hash ?? null,
|
|
9972
10110
|
...ruleAttestation(rule)
|
|
9973
10111
|
})),
|
|
9974
|
-
renderedPayloadSha256:
|
|
10112
|
+
renderedPayloadSha256: sha2566(source.content),
|
|
9975
10113
|
provenance: source.provenance ?? null,
|
|
9976
10114
|
metadata: source.metadata ?? null
|
|
9977
10115
|
})),
|
|
@@ -10009,8 +10147,8 @@ function planSessionRender(input) {
|
|
|
10009
10147
|
...input.providerConfig ? {
|
|
10010
10148
|
providerConfig: {
|
|
10011
10149
|
sourceId: input.providerConfig.sourceId,
|
|
10012
|
-
selectedPayloadSha256:
|
|
10013
|
-
renderedPayloadSha256: files.find((file) => file.relativePath === adapter.configFile)?.sha256 ??
|
|
10150
|
+
selectedPayloadSha256: sha2566(input.providerConfig.content),
|
|
10151
|
+
renderedPayloadSha256: files.find((file) => file.relativePath === adapter.configFile)?.sha256 ?? sha2566(input.providerConfig.content),
|
|
10014
10152
|
selected: !existsSync4(joinTarget(targetHome, adapter.configFile))
|
|
10015
10153
|
}
|
|
10016
10154
|
} : {},
|
|
@@ -10118,7 +10256,7 @@ function selectProfileConfigsForSessionRender(configs, tool) {
|
|
|
10118
10256
|
const selectedSources = [];
|
|
10119
10257
|
const equivalentSources = new Map;
|
|
10120
10258
|
for (const candidate of sources) {
|
|
10121
|
-
const key =
|
|
10259
|
+
const key = sha2566(candidate.source.content);
|
|
10122
10260
|
const existing = equivalentSources.get(key);
|
|
10123
10261
|
if (!existing) {
|
|
10124
10262
|
equivalentSources.set(key, {
|
|
@@ -10397,7 +10535,7 @@ function readIdentitySourcePath(sourcePath, baseDir, sourceId) {
|
|
|
10397
10535
|
}
|
|
10398
10536
|
return;
|
|
10399
10537
|
}
|
|
10400
|
-
const stat =
|
|
10538
|
+
const stat = statSync3(resolvedPath);
|
|
10401
10539
|
if (!stat.isFile()) {
|
|
10402
10540
|
throw new Error(`Identity instruction source path is not a file for ${sourceId}: ${sourcePath.path}`);
|
|
10403
10541
|
}
|
|
@@ -10406,7 +10544,7 @@ function readIdentitySourcePath(sourcePath, baseDir, sourceId) {
|
|
|
10406
10544
|
if (!pathIsInside(realPath, realBase)) {
|
|
10407
10545
|
throw new Error(`Identity instruction source path escapes export directory for ${sourceId}: ${sourcePath.path}`);
|
|
10408
10546
|
}
|
|
10409
|
-
return
|
|
10547
|
+
return readFileSync4(realPath, "utf-8");
|
|
10410
10548
|
}
|
|
10411
10549
|
function resolveIdentitySourcePath(path, baseDir, sourceId) {
|
|
10412
10550
|
const cleaned = cleanSessionPathInput(path);
|
|
@@ -10414,8 +10552,8 @@ function resolveIdentitySourcePath(path, baseDir, sourceId) {
|
|
|
10414
10552
|
throw new Error(`Identity instruction source path cannot be empty for ${sourceId}.`);
|
|
10415
10553
|
if (cleaned.includes("\\"))
|
|
10416
10554
|
throw new Error(`Identity instruction source path must use POSIX separators for ${sourceId}: ${path}`);
|
|
10417
|
-
const resolvedPath = isAbsolute3(cleaned) ?
|
|
10418
|
-
if (!pathIsInside(resolvedPath,
|
|
10555
|
+
const resolvedPath = isAbsolute3(cleaned) ? resolve6(cleaned) : resolve6(baseDir, cleaned);
|
|
10556
|
+
if (!pathIsInside(resolvedPath, resolve6(baseDir))) {
|
|
10419
10557
|
throw new Error(`Identity instruction source path escapes export directory for ${sourceId}: ${path}`);
|
|
10420
10558
|
}
|
|
10421
10559
|
return resolvedPath;
|
|
@@ -10811,7 +10949,7 @@ function compileInstructionGraph(input) {
|
|
|
10811
10949
|
effective_activation: effective.get(configId),
|
|
10812
10950
|
fallback: row.binding.fallback,
|
|
10813
10951
|
required: row.binding.required,
|
|
10814
|
-
content_sha256:
|
|
10952
|
+
content_sha256: sha2567(config.content),
|
|
10815
10953
|
dependencies: dependencies.get(configId) ?? []
|
|
10816
10954
|
};
|
|
10817
10955
|
});
|
|
@@ -10848,7 +10986,7 @@ function compileInstructionGraph(input) {
|
|
|
10848
10986
|
diagnostics
|
|
10849
10987
|
};
|
|
10850
10988
|
return {
|
|
10851
|
-
plan: deepFreeze2({ ...planWithoutHash, source_hash:
|
|
10989
|
+
plan: deepFreeze2({ ...planWithoutHash, source_hash: sha2567(stableJson2(planWithoutHash)) }),
|
|
10852
10990
|
sources,
|
|
10853
10991
|
capability: capability2
|
|
10854
10992
|
};
|
|
@@ -11031,8 +11169,8 @@ class InstructionGraphValidationError extends Error {
|
|
|
11031
11169
|
this.name = "InstructionGraphValidationError";
|
|
11032
11170
|
}
|
|
11033
11171
|
}
|
|
11034
|
-
function
|
|
11035
|
-
return
|
|
11172
|
+
function sha2567(value) {
|
|
11173
|
+
return createHash7("sha256").update(value).digest("hex");
|
|
11036
11174
|
}
|
|
11037
11175
|
function stableJson2(value) {
|
|
11038
11176
|
const canonical = (entry) => Array.isArray(entry) ? entry.map(canonical) : entry && typeof entry === "object" ? Object.fromEntries(Object.entries(entry).sort(([a], [b]) => a.localeCompare(b)).map(([key, child]) => [key, canonical(child)])) : entry;
|
|
@@ -11251,34 +11389,6 @@ function resolveProfileForMachineRead(machine = detectMachineContext(), options
|
|
|
11251
11389
|
};
|
|
11252
11390
|
}
|
|
11253
11391
|
|
|
11254
|
-
// src/db/snapshots.ts
|
|
11255
|
-
function createSnapshot(configId, content, version, db) {
|
|
11256
|
-
const d = db || getDatabase();
|
|
11257
|
-
const id = uuid();
|
|
11258
|
-
const ts = now();
|
|
11259
|
-
d.run("INSERT INTO config_snapshots (id, config_id, content, version, created_at) VALUES (?, ?, ?, ?, ?)", [id, configId, content, version, ts]);
|
|
11260
|
-
return { id, config_id: configId, content, version, created_at: ts };
|
|
11261
|
-
}
|
|
11262
|
-
function listSnapshots(configId, db) {
|
|
11263
|
-
const d = db || getDatabase();
|
|
11264
|
-
return d.query("SELECT * FROM config_snapshots WHERE config_id = ? ORDER BY version DESC").all(configId);
|
|
11265
|
-
}
|
|
11266
|
-
function getSnapshot(id, db) {
|
|
11267
|
-
const d = db || getDatabase();
|
|
11268
|
-
return d.query("SELECT * FROM config_snapshots WHERE id = ?").get(id);
|
|
11269
|
-
}
|
|
11270
|
-
function getSnapshotByVersion(configId, version, db) {
|
|
11271
|
-
const d = db || getDatabase();
|
|
11272
|
-
return d.query("SELECT * FROM config_snapshots WHERE config_id = ? AND version = ?").get(configId, version);
|
|
11273
|
-
}
|
|
11274
|
-
function pruneSnapshots(configId, keep = 10, db) {
|
|
11275
|
-
const d = db || getDatabase();
|
|
11276
|
-
const result = d.run(`DELETE FROM config_snapshots WHERE config_id = ? AND id NOT IN (
|
|
11277
|
-
SELECT id FROM config_snapshots WHERE config_id = ? ORDER BY version DESC LIMIT ?
|
|
11278
|
-
)`, [configId, configId, keep]);
|
|
11279
|
-
return result.changes;
|
|
11280
|
-
}
|
|
11281
|
-
|
|
11282
11392
|
// src/db/machines.ts
|
|
11283
11393
|
import { arch, hostname, type } from "os";
|
|
11284
11394
|
function currentHostname2() {
|
|
@@ -11358,16 +11468,17 @@ function parseBoundedOrLegacyPage(value, legacyItems, options, label) {
|
|
|
11358
11468
|
var API_URL_ENV = "HASNA_INSTRUCTIONS_API_URL";
|
|
11359
11469
|
var API_KEY_ENV = "HASNA_INSTRUCTIONS_API_KEY";
|
|
11360
11470
|
function resolveCloudConfig(env = process.env) {
|
|
11471
|
+
assertNoLegacyStorageMode(env);
|
|
11361
11472
|
const apiUrl = env[API_URL_ENV]?.trim();
|
|
11362
11473
|
const apiKey = env[API_KEY_ENV]?.trim();
|
|
11363
11474
|
if (!apiUrl && !apiKey)
|
|
11364
11475
|
return null;
|
|
11365
11476
|
if (!apiUrl || !apiKey) {
|
|
11366
|
-
throw new Error(`API mode requires BOTH ${API_URL_ENV} and ${API_KEY_ENV}; only ` + `${apiUrl ? API_URL_ENV : API_KEY_ENV} is set. Set both to use the
|
|
11477
|
+
throw new Error(`API mode requires BOTH ${API_URL_ENV} and ${API_KEY_ENV}; only ` + `${apiUrl ? API_URL_ENV : API_KEY_ENV} is set. Set both to use the HTTP API, ` + `or unset both to use the local store.`);
|
|
11367
11478
|
}
|
|
11368
11479
|
return { apiUrl, apiKey };
|
|
11369
11480
|
}
|
|
11370
|
-
function
|
|
11481
|
+
function isApiTransport(env = process.env) {
|
|
11371
11482
|
return resolveCloudConfig(env) !== null;
|
|
11372
11483
|
}
|
|
11373
11484
|
|
|
@@ -11844,16 +11955,16 @@ function resolveConfigStore(env = process.env) {
|
|
|
11844
11955
|
return cloud ? new CloudConfigStore(cloud) : new LocalConfigStore;
|
|
11845
11956
|
}
|
|
11846
11957
|
// src/status.ts
|
|
11847
|
-
import { existsSync as
|
|
11958
|
+
import { existsSync as existsSync9, readFileSync as readFileSync9 } from "fs";
|
|
11848
11959
|
|
|
11849
11960
|
// src/lib/apply.ts
|
|
11850
|
-
import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as
|
|
11851
|
-
import { basename as basename4, dirname as dirname4, join as
|
|
11852
|
-
import { homedir as
|
|
11961
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync6, realpathSync as realpathSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
11962
|
+
import { basename as basename4, dirname as dirname4, join as join9, resolve as resolve7 } from "path";
|
|
11963
|
+
import { homedir as homedir5 } from "os";
|
|
11853
11964
|
|
|
11854
11965
|
// src/lib/session-render-ownership.ts
|
|
11855
|
-
import { existsSync as existsSync5, readFileSync as
|
|
11856
|
-
import { dirname as dirname3, join as
|
|
11966
|
+
import { existsSync as existsSync5, readFileSync as readFileSync5, statSync as statSync4 } from "fs";
|
|
11967
|
+
import { dirname as dirname3, join as join8, parse as parse3, relative as relative3, sep } from "path";
|
|
11857
11968
|
var MANIFEST_ANCESTOR_LIMIT = 24;
|
|
11858
11969
|
var MANAGED_PATH_SEGMENTS = SESSION_RENDER_EXCLUSIVE_MANAGED_PATHS.map((managedPath) => managedPath.split("/").filter(Boolean));
|
|
11859
11970
|
var manifestCache = new Map;
|
|
@@ -11877,7 +11988,7 @@ function readManifestRelativePaths(manifestPath) {
|
|
|
11877
11988
|
try {
|
|
11878
11989
|
if (!existsSync5(manifestPath))
|
|
11879
11990
|
return null;
|
|
11880
|
-
stats =
|
|
11991
|
+
stats = statSync4(manifestPath);
|
|
11881
11992
|
} catch {
|
|
11882
11993
|
return null;
|
|
11883
11994
|
}
|
|
@@ -11887,7 +11998,7 @@ function readManifestRelativePaths(manifestPath) {
|
|
|
11887
11998
|
}
|
|
11888
11999
|
let manifest;
|
|
11889
12000
|
try {
|
|
11890
|
-
manifest = JSON.parse(
|
|
12001
|
+
manifest = JSON.parse(readFileSync5(manifestPath, "utf-8"));
|
|
11891
12002
|
} catch {
|
|
11892
12003
|
return null;
|
|
11893
12004
|
}
|
|
@@ -11904,7 +12015,7 @@ function sessionRenderManifestClaimsPath(absolutePath2) {
|
|
|
11904
12015
|
const root = parse3(absolutePath2).root;
|
|
11905
12016
|
let home = dirname3(absolutePath2);
|
|
11906
12017
|
for (let depth = 0;depth < MANIFEST_ANCESTOR_LIMIT; depth += 1) {
|
|
11907
|
-
const manifestPath =
|
|
12018
|
+
const manifestPath = join8(home, ...SESSION_RENDER_MANIFEST_RELATIVE_PATH.split("/"));
|
|
11908
12019
|
const relativePaths = readManifestRelativePaths(manifestPath);
|
|
11909
12020
|
if (relativePaths) {
|
|
11910
12021
|
const claimed = relative3(home, absolutePath2).split(sep).join("/");
|
|
@@ -11924,13 +12035,13 @@ function sessionRenderOwnsPath(absolutePath2) {
|
|
|
11924
12035
|
|
|
11925
12036
|
// src/lib/apply.ts
|
|
11926
12037
|
function getConfigHome() {
|
|
11927
|
-
return process.env["CONFIGS_HOME"] || process.env["HOME"] ||
|
|
12038
|
+
return process.env["CONFIGS_HOME"] || process.env["HOME"] || homedir5();
|
|
11928
12039
|
}
|
|
11929
12040
|
function expandPath(p) {
|
|
11930
12041
|
if (p.startsWith("~/")) {
|
|
11931
|
-
return
|
|
12042
|
+
return resolve7(getConfigHome(), p.slice(2));
|
|
11932
12043
|
}
|
|
11933
|
-
return
|
|
12044
|
+
return resolve7(p);
|
|
11934
12045
|
}
|
|
11935
12046
|
function normalizeTargetPath(p) {
|
|
11936
12047
|
const expanded = expandPath(p);
|
|
@@ -11942,7 +12053,7 @@ function normalizeTargetPath(p) {
|
|
|
11942
12053
|
while (true) {
|
|
11943
12054
|
if (existsSync6(current)) {
|
|
11944
12055
|
try {
|
|
11945
|
-
return
|
|
12056
|
+
return resolve7(realpathSync2(current), ...missingSegments);
|
|
11946
12057
|
} catch {
|
|
11947
12058
|
return expanded;
|
|
11948
12059
|
}
|
|
@@ -11971,7 +12082,7 @@ async function writeConfigResult(config, targetPath, content, opts, meta = {}) {
|
|
|
11971
12082
|
}
|
|
11972
12083
|
const path = expandPath(renderedTargetPath);
|
|
11973
12084
|
const renderedForTarget = isCursorGlobalAuthorityPath(path) ? stampCursorGlobalAuthorityMarker(renderedContent) : renderedContent;
|
|
11974
|
-
const previousContent = existsSync6(path) ?
|
|
12085
|
+
const previousContent = existsSync6(path) ? readFileSync6(path, "utf-8") : null;
|
|
11975
12086
|
const changed = previousContent !== renderedForTarget;
|
|
11976
12087
|
if (!opts.dryRun) {
|
|
11977
12088
|
const dir = dirname4(path);
|
|
@@ -12011,7 +12122,7 @@ function wouldDestroyACredential(targetPath, renderedContent, format) {
|
|
|
12011
12122
|
const path = expandPath(targetPath);
|
|
12012
12123
|
if (!existsSync6(path))
|
|
12013
12124
|
return [];
|
|
12014
|
-
current =
|
|
12125
|
+
current = readFileSync6(path, "utf-8");
|
|
12015
12126
|
} catch {
|
|
12016
12127
|
return secretTokens;
|
|
12017
12128
|
}
|
|
@@ -12335,14 +12446,14 @@ function sessionRendererOwnsCanonicalTarget(normalized, opts) {
|
|
|
12335
12446
|
getConfigHome(),
|
|
12336
12447
|
opts.vars?.["HOME_DIR"]
|
|
12337
12448
|
].filter((home) => typeof home === "string" && home.length > 0));
|
|
12338
|
-
if ([...homes].some((home) => SESSION_RENDER_OWNED_CONFIG_TARGETS.some((relativePath) => normalized === normalizeTargetPath(
|
|
12449
|
+
if ([...homes].some((home) => SESSION_RENDER_OWNED_CONFIG_TARGETS.some((relativePath) => normalized === normalizeTargetPath(join9(home, ...relativePath.split("/"))))))
|
|
12339
12450
|
return true;
|
|
12340
12451
|
return sessionRenderOwnsPath(normalized);
|
|
12341
12452
|
}
|
|
12342
12453
|
|
|
12343
12454
|
// src/lib/package-version.ts
|
|
12344
|
-
import { existsSync as existsSync7, readFileSync as
|
|
12345
|
-
import { dirname as dirname5, join as
|
|
12455
|
+
import { existsSync as existsSync7, readFileSync as readFileSync7 } from "fs";
|
|
12456
|
+
import { dirname as dirname5, join as join10 } from "path";
|
|
12346
12457
|
import { fileURLToPath } from "url";
|
|
12347
12458
|
var cached = null;
|
|
12348
12459
|
function getPackageVersion() {
|
|
@@ -12351,9 +12462,9 @@ function getPackageVersion() {
|
|
|
12351
12462
|
try {
|
|
12352
12463
|
let dir = dirname5(fileURLToPath(import.meta.url));
|
|
12353
12464
|
for (let i = 0;i < 8; i++) {
|
|
12354
|
-
const pkgPath =
|
|
12465
|
+
const pkgPath = join10(dir, "package.json");
|
|
12355
12466
|
if (existsSync7(pkgPath)) {
|
|
12356
|
-
const pkg = JSON.parse(
|
|
12467
|
+
const pkg = JSON.parse(readFileSync7(pkgPath, "utf8"));
|
|
12357
12468
|
if (pkg.name === "@hasna/instructions" && pkg.version) {
|
|
12358
12469
|
cached = pkg.version;
|
|
12359
12470
|
return cached;
|
|
@@ -12369,6 +12480,403 @@ function getPackageVersion() {
|
|
|
12369
12480
|
return cached;
|
|
12370
12481
|
}
|
|
12371
12482
|
|
|
12483
|
+
// src/lib/managed-skill-runtimes.ts
|
|
12484
|
+
import { createHash as createHash8 } from "crypto";
|
|
12485
|
+
import { spawnSync } from "child_process";
|
|
12486
|
+
import {
|
|
12487
|
+
existsSync as existsSync8,
|
|
12488
|
+
lstatSync as lstatSync4,
|
|
12489
|
+
mkdirSync as mkdirSync4,
|
|
12490
|
+
readFileSync as readFileSync8,
|
|
12491
|
+
renameSync as renameSync2,
|
|
12492
|
+
rmSync as rmSync3,
|
|
12493
|
+
writeFileSync as writeFileSync3
|
|
12494
|
+
} from "fs";
|
|
12495
|
+
import { homedir as homedir6 } from "os";
|
|
12496
|
+
import { dirname as dirname6, join as join11, parse as parse4, relative as relative4, resolve as resolve8 } from "path";
|
|
12497
|
+
var INBOX_CONVERSATIONS_MINIMUM_VERSION = "0.5.28";
|
|
12498
|
+
var INBOX_SKILL_MARKERS = [
|
|
12499
|
+
[".claude", "skills", "inbox", "SKILL.md"],
|
|
12500
|
+
[".codex", "skills", "inbox", "SKILL.md"],
|
|
12501
|
+
[".codewith", "skills", "inbox", "SKILL.md"],
|
|
12502
|
+
[".config", "opencode", "skills", "inbox", "SKILL.md"],
|
|
12503
|
+
[".cursor", "skills", "inbox", "SKILL.md"]
|
|
12504
|
+
];
|
|
12505
|
+
var REQUIRED_WATCH_FLAGS = ["--from <agent>", "--all", "--full-content"];
|
|
12506
|
+
function sha2568(content) {
|
|
12507
|
+
return createHash8("sha256").update(content).digest("hex");
|
|
12508
|
+
}
|
|
12509
|
+
function lstatOrNull(path) {
|
|
12510
|
+
try {
|
|
12511
|
+
return lstatSync4(path);
|
|
12512
|
+
} catch {
|
|
12513
|
+
return null;
|
|
12514
|
+
}
|
|
12515
|
+
}
|
|
12516
|
+
function findSymlinkedAncestor(path) {
|
|
12517
|
+
const normalized = resolve8(path);
|
|
12518
|
+
const parsed = parse4(normalized);
|
|
12519
|
+
let current = parsed.root;
|
|
12520
|
+
const rel = relative4(parsed.root, normalized);
|
|
12521
|
+
for (const segment of rel.split(/[\\/]+/).filter(Boolean)) {
|
|
12522
|
+
current = join11(current, segment);
|
|
12523
|
+
if (!existsSync8(current))
|
|
12524
|
+
return null;
|
|
12525
|
+
if (lstatSync4(current).isSymbolicLink())
|
|
12526
|
+
return current;
|
|
12527
|
+
}
|
|
12528
|
+
return null;
|
|
12529
|
+
}
|
|
12530
|
+
function assertNoSymlinkAncestors2(path) {
|
|
12531
|
+
const found = findSymlinkedAncestor(path);
|
|
12532
|
+
if (found !== null) {
|
|
12533
|
+
throw new Error(`managed skill path uses a symlink ancestor: ${found}`);
|
|
12534
|
+
}
|
|
12535
|
+
}
|
|
12536
|
+
function packagedInboxSkillPath(explicitPath) {
|
|
12537
|
+
if (explicitPath)
|
|
12538
|
+
return explicitPath;
|
|
12539
|
+
const candidates = [
|
|
12540
|
+
join11(import.meta.dir, "..", "..", "assets", "skills", "inbox", "SKILL.md"),
|
|
12541
|
+
join11(import.meta.dir, "..", "assets", "skills", "inbox", "SKILL.md"),
|
|
12542
|
+
join11(process.cwd(), "assets", "skills", "inbox", "SKILL.md")
|
|
12543
|
+
];
|
|
12544
|
+
const found = candidates.find((candidate) => existsSync8(candidate));
|
|
12545
|
+
if (!found) {
|
|
12546
|
+
throw new Error(`packaged inbox skill contract is missing (checked ${candidates.length} package-relative locations)`);
|
|
12547
|
+
}
|
|
12548
|
+
return found;
|
|
12549
|
+
}
|
|
12550
|
+
function readCanonicalSkill(explicitPath) {
|
|
12551
|
+
const assetPath = packagedInboxSkillPath(explicitPath);
|
|
12552
|
+
const stat = lstatOrNull(assetPath);
|
|
12553
|
+
if (!stat?.isFile()) {
|
|
12554
|
+
throw new Error("packaged inbox skill contract is not a regular file");
|
|
12555
|
+
}
|
|
12556
|
+
const content = readFileSync8(assetPath, "utf8");
|
|
12557
|
+
if (!content.includes("conversations watch --from <agent> --all")) {
|
|
12558
|
+
throw new Error("packaged inbox skill contract does not declare the canonical conversations watcher");
|
|
12559
|
+
}
|
|
12560
|
+
if (!content.includes("There is no separate")) {
|
|
12561
|
+
throw new Error("packaged inbox skill contract does not retire the legacy executable");
|
|
12562
|
+
}
|
|
12563
|
+
return { content, sha256: sha2568(content) };
|
|
12564
|
+
}
|
|
12565
|
+
function runProbe(command, args) {
|
|
12566
|
+
const result = spawnSync(command, args, {
|
|
12567
|
+
encoding: "utf8",
|
|
12568
|
+
timeout: 5000,
|
|
12569
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
12570
|
+
});
|
|
12571
|
+
if (result.error || result.status !== 0) {
|
|
12572
|
+
return { ok: false, output: "" };
|
|
12573
|
+
}
|
|
12574
|
+
return {
|
|
12575
|
+
ok: true,
|
|
12576
|
+
output: `${result.stdout ?? ""}
|
|
12577
|
+
${result.stderr ?? ""}`.trim()
|
|
12578
|
+
};
|
|
12579
|
+
}
|
|
12580
|
+
function parseVersion(output) {
|
|
12581
|
+
return output.match(/\b(\d+\.\d+\.\d+)\b/)?.[1] ?? null;
|
|
12582
|
+
}
|
|
12583
|
+
function compareVersions(left, right) {
|
|
12584
|
+
const a = left.split(".").map(Number);
|
|
12585
|
+
const b = right.split(".").map(Number);
|
|
12586
|
+
for (let i = 0;i < Math.max(a.length, b.length); i++) {
|
|
12587
|
+
const delta = (a[i] ?? 0) - (b[i] ?? 0);
|
|
12588
|
+
if (delta !== 0)
|
|
12589
|
+
return delta;
|
|
12590
|
+
}
|
|
12591
|
+
return 0;
|
|
12592
|
+
}
|
|
12593
|
+
function inspectSkillMarkers(homeDir2) {
|
|
12594
|
+
return INBOX_SKILL_MARKERS.map((parts) => join11(homeDir2, ...parts)).map((path) => {
|
|
12595
|
+
const stat = lstatOrNull(path);
|
|
12596
|
+
if (!stat)
|
|
12597
|
+
return null;
|
|
12598
|
+
if (!stat.isFile()) {
|
|
12599
|
+
return { path, content: null, mode: null, regular: false };
|
|
12600
|
+
}
|
|
12601
|
+
return {
|
|
12602
|
+
path,
|
|
12603
|
+
content: readFileSync8(path, "utf8"),
|
|
12604
|
+
mode: stat.mode & 511,
|
|
12605
|
+
regular: true
|
|
12606
|
+
};
|
|
12607
|
+
}).filter((snapshot) => snapshot !== null);
|
|
12608
|
+
}
|
|
12609
|
+
function inspectInbox(options) {
|
|
12610
|
+
const homeDir2 = options.homeDir ?? homedir6();
|
|
12611
|
+
const runtimeCommand = options.conversationsCommand ?? "conversations";
|
|
12612
|
+
const snapshots = inspectSkillMarkers(homeDir2);
|
|
12613
|
+
const skillPresent = snapshots.length > 0;
|
|
12614
|
+
let canonicalContent = null;
|
|
12615
|
+
let canonicalSha256 = null;
|
|
12616
|
+
let assetError = null;
|
|
12617
|
+
try {
|
|
12618
|
+
const canonical = readCanonicalSkill(options.assetPath);
|
|
12619
|
+
canonicalContent = canonical.content;
|
|
12620
|
+
canonicalSha256 = canonical.sha256;
|
|
12621
|
+
} catch (error) {
|
|
12622
|
+
assetError = error instanceof Error ? error.message : String(error);
|
|
12623
|
+
}
|
|
12624
|
+
const versionProbe = skillPresent ? runProbe(runtimeCommand, ["--version"]) : { ok: false, output: "" };
|
|
12625
|
+
const helpProbe = versionProbe.ok ? runProbe(runtimeCommand, ["watch", "--help"]) : { ok: false, output: "" };
|
|
12626
|
+
const runtimeVersion = versionProbe.ok ? parseVersion(versionProbe.output) : null;
|
|
12627
|
+
const supportsFrom = helpProbe.ok && helpProbe.output.includes(REQUIRED_WATCH_FLAGS[0]);
|
|
12628
|
+
const supportsAll = helpProbe.ok && helpProbe.output.includes(REQUIRED_WATCH_FLAGS[1]);
|
|
12629
|
+
const supportsFullContent = helpProbe.ok && helpProbe.output.includes(REQUIRED_WATCH_FLAGS[2]);
|
|
12630
|
+
const packageReady = versionProbe.ok && runtimeVersion !== null && compareVersions(runtimeVersion, INBOX_CONVERSATIONS_MINIMUM_VERSION) >= 0 && helpProbe.ok && supportsFrom && supportsAll && supportsFullContent;
|
|
12631
|
+
const heartbeatProbe = skillPresent && packageReady && options.agent ? runProbe(runtimeCommand, ["agents", "heartbeat", "--from", options.agent, "--json"]) : null;
|
|
12632
|
+
const hostedHeartbeat = heartbeatProbe === null ? "unverified" : heartbeatProbe.ok ? "passed" : "failed";
|
|
12633
|
+
const deliveryVerified = hostedHeartbeat === "passed" && options.deliveryVerified === true;
|
|
12634
|
+
const staleMarkers = canonicalContent === null ? snapshots.map((snapshot) => snapshot.path) : snapshots.filter((snapshot) => !snapshot.regular || snapshot.content !== canonicalContent).map((snapshot) => snapshot.path);
|
|
12635
|
+
let reason = "skill not installed";
|
|
12636
|
+
if (skillPresent) {
|
|
12637
|
+
const nonRegular = snapshots.some((snapshot) => !snapshot.regular);
|
|
12638
|
+
const symlinkAncestor = snapshots.map((snapshot) => snapshot.path).map((path) => findSymlinkedAncestor(dirname6(path))).find((found) => found !== null);
|
|
12639
|
+
if (nonRegular)
|
|
12640
|
+
reason = "managed skill target is not a regular file";
|
|
12641
|
+
else if (symlinkAncestor)
|
|
12642
|
+
reason = `managed skill path uses a symlink ancestor: ${symlinkAncestor}`;
|
|
12643
|
+
else if (assetError)
|
|
12644
|
+
reason = assetError;
|
|
12645
|
+
else if (!versionProbe.ok)
|
|
12646
|
+
reason = "conversations command unavailable";
|
|
12647
|
+
else if (!runtimeVersion)
|
|
12648
|
+
reason = "conversations version is unreadable";
|
|
12649
|
+
else if (compareVersions(runtimeVersion, INBOX_CONVERSATIONS_MINIMUM_VERSION) < 0) {
|
|
12650
|
+
reason = `conversations ${runtimeVersion} is older than ${INBOX_CONVERSATIONS_MINIMUM_VERSION}`;
|
|
12651
|
+
} else if (!helpProbe.ok)
|
|
12652
|
+
reason = "conversations watch help is unavailable";
|
|
12653
|
+
else if (!supportsFrom || !supportsAll || !supportsFullContent) {
|
|
12654
|
+
const missing = [
|
|
12655
|
+
!supportsFrom ? "--from" : null,
|
|
12656
|
+
!supportsAll ? "--all" : null,
|
|
12657
|
+
!supportsFullContent ? "--full-content" : null
|
|
12658
|
+
].filter((flag) => flag !== null);
|
|
12659
|
+
reason = `conversations watch is missing required flags: ${missing.join(", ")}`;
|
|
12660
|
+
} else if (staleMarkers.length > 0)
|
|
12661
|
+
reason = "skill contract stale";
|
|
12662
|
+
else if (hostedHeartbeat === "failed")
|
|
12663
|
+
reason = "hosted heartbeat failed; manual fallback required";
|
|
12664
|
+
else if (hostedHeartbeat === "unverified")
|
|
12665
|
+
reason = "hosted heartbeat unverified; manual fallback required";
|
|
12666
|
+
else if (!deliveryVerified)
|
|
12667
|
+
reason = "hosted heartbeat passed; channel and DM delivery verification required";
|
|
12668
|
+
else
|
|
12669
|
+
reason = "ready";
|
|
12670
|
+
}
|
|
12671
|
+
return {
|
|
12672
|
+
status: {
|
|
12673
|
+
skill: "inbox",
|
|
12674
|
+
runtime: "conversations watch",
|
|
12675
|
+
minimum_version: INBOX_CONVERSATIONS_MINIMUM_VERSION,
|
|
12676
|
+
skill_present: skillPresent,
|
|
12677
|
+
skill_markers: snapshots.map((snapshot) => snapshot.path),
|
|
12678
|
+
skill_contracts_current: snapshots.length - staleMarkers.length,
|
|
12679
|
+
stale_skill_markers: staleMarkers,
|
|
12680
|
+
expected_skill_sha256: canonicalSha256,
|
|
12681
|
+
runtime_command: runtimeCommand,
|
|
12682
|
+
runtime_present: versionProbe.ok,
|
|
12683
|
+
runtime_version: runtimeVersion,
|
|
12684
|
+
watch_supports_from: supportsFrom,
|
|
12685
|
+
watch_supports_all: supportsAll,
|
|
12686
|
+
watch_supports_full_content: supportsFullContent,
|
|
12687
|
+
hosted_heartbeat: hostedHeartbeat,
|
|
12688
|
+
delivery_verified: deliveryVerified,
|
|
12689
|
+
manual_fallback_ready: skillPresent && staleMarkers.length === 0 && packageReady,
|
|
12690
|
+
healthy: !skillPresent || reason === "ready",
|
|
12691
|
+
reason
|
|
12692
|
+
},
|
|
12693
|
+
canonicalContent,
|
|
12694
|
+
snapshots
|
|
12695
|
+
};
|
|
12696
|
+
}
|
|
12697
|
+
function inspectManagedSkillRuntimes(options = {}) {
|
|
12698
|
+
const runtime = inspectInbox(options).status;
|
|
12699
|
+
const installed = runtime.skill_present ? [runtime] : [];
|
|
12700
|
+
return {
|
|
12701
|
+
runtimes: [runtime],
|
|
12702
|
+
skills_present: installed.length,
|
|
12703
|
+
healthy: installed.filter((item) => item.healthy).length,
|
|
12704
|
+
missing: installed.filter((item) => !item.healthy).length
|
|
12705
|
+
};
|
|
12706
|
+
}
|
|
12707
|
+
function runtimeReadyForWrite(status) {
|
|
12708
|
+
return status.runtime_present && status.runtime_version !== null && compareVersions(status.runtime_version, INBOX_CONVERSATIONS_MINIMUM_VERSION) >= 0 && status.watch_supports_from && status.watch_supports_all && status.watch_supports_full_content;
|
|
12709
|
+
}
|
|
12710
|
+
function projectUpdatedStatus(status, contractCount) {
|
|
12711
|
+
const healthy = status.hosted_heartbeat === "passed" && status.delivery_verified;
|
|
12712
|
+
return {
|
|
12713
|
+
...status,
|
|
12714
|
+
skill_contracts_current: contractCount,
|
|
12715
|
+
stale_skill_markers: [],
|
|
12716
|
+
manual_fallback_ready: true,
|
|
12717
|
+
healthy,
|
|
12718
|
+
reason: healthy ? "ready" : status.hosted_heartbeat === "failed" ? "hosted heartbeat failed; manual fallback required" : status.hosted_heartbeat === "unverified" ? "hosted heartbeat unverified; manual fallback required" : "hosted heartbeat passed; channel and DM delivery verification required"
|
|
12719
|
+
};
|
|
12720
|
+
}
|
|
12721
|
+
function cleanup(path) {
|
|
12722
|
+
rmSync3(path, { force: true });
|
|
12723
|
+
}
|
|
12724
|
+
function writeAtomic(path, content, mode) {
|
|
12725
|
+
assertNoSymlinkAncestors2(dirname6(path));
|
|
12726
|
+
const tempPath = `${path}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
12727
|
+
try {
|
|
12728
|
+
mkdirSync4(dirname6(path), { recursive: true, mode: 493 });
|
|
12729
|
+
writeFileSync3(tempPath, content, { mode, flag: "wx" });
|
|
12730
|
+
renameSync2(tempPath, path);
|
|
12731
|
+
} finally {
|
|
12732
|
+
cleanup(tempPath);
|
|
12733
|
+
}
|
|
12734
|
+
}
|
|
12735
|
+
var DEFAULT_SKILL_WRITE_FILE_OPERATIONS = {
|
|
12736
|
+
lstat: lstatOrNull,
|
|
12737
|
+
read: (path) => readFileSync8(path, "utf8"),
|
|
12738
|
+
write: writeAtomic
|
|
12739
|
+
};
|
|
12740
|
+
function writeSkillContractsTransactional(snapshots, canonicalContent, fileOperations = DEFAULT_SKILL_WRITE_FILE_OPERATIONS) {
|
|
12741
|
+
const written = [];
|
|
12742
|
+
try {
|
|
12743
|
+
for (const snapshot of snapshots) {
|
|
12744
|
+
const currentStat = fileOperations.lstat(snapshot.path);
|
|
12745
|
+
if (!currentStat?.isFile() || fileOperations.read(snapshot.path) !== snapshot.content) {
|
|
12746
|
+
throw new Error("managed skill changed after inspection; refusing a stale write");
|
|
12747
|
+
}
|
|
12748
|
+
fileOperations.write(snapshot.path, canonicalContent, snapshot.mode);
|
|
12749
|
+
written.push(snapshot);
|
|
12750
|
+
}
|
|
12751
|
+
return { ok: true, error: null, rollback_conflicts: [] };
|
|
12752
|
+
} catch (error) {
|
|
12753
|
+
const rollbackConflicts = [];
|
|
12754
|
+
for (const snapshot of written.reverse()) {
|
|
12755
|
+
const currentStat = fileOperations.lstat(snapshot.path);
|
|
12756
|
+
if (!currentStat?.isFile()) {
|
|
12757
|
+
rollbackConflicts.push(`${snapshot.path}: no longer a regular file`);
|
|
12758
|
+
continue;
|
|
12759
|
+
}
|
|
12760
|
+
let currentContent;
|
|
12761
|
+
try {
|
|
12762
|
+
currentContent = fileOperations.read(snapshot.path);
|
|
12763
|
+
} catch {
|
|
12764
|
+
rollbackConflicts.push(`${snapshot.path}: could not read the current file`);
|
|
12765
|
+
continue;
|
|
12766
|
+
}
|
|
12767
|
+
if (currentContent !== canonicalContent) {
|
|
12768
|
+
rollbackConflicts.push(`${snapshot.path}: changed after this reconciliation wrote it`);
|
|
12769
|
+
continue;
|
|
12770
|
+
}
|
|
12771
|
+
try {
|
|
12772
|
+
fileOperations.write(snapshot.path, snapshot.content, snapshot.mode);
|
|
12773
|
+
} catch {
|
|
12774
|
+
rollbackConflicts.push(`${snapshot.path}: still owned but could not be restored`);
|
|
12775
|
+
}
|
|
12776
|
+
}
|
|
12777
|
+
return {
|
|
12778
|
+
ok: false,
|
|
12779
|
+
error: error instanceof Error ? error.message : String(error),
|
|
12780
|
+
rollback_conflicts: rollbackConflicts
|
|
12781
|
+
};
|
|
12782
|
+
}
|
|
12783
|
+
}
|
|
12784
|
+
async function reconcileManagedSkillRuntimes(options = {}) {
|
|
12785
|
+
const dryRun = options.dryRun ?? false;
|
|
12786
|
+
const before = inspectInbox(options);
|
|
12787
|
+
const status = before.status;
|
|
12788
|
+
if (!status.skill_present) {
|
|
12789
|
+
return {
|
|
12790
|
+
runtimes: [{ ...status, action: "skipped", dry_run: dryRun, skill_contracts_changed: 0 }],
|
|
12791
|
+
changed: 0,
|
|
12792
|
+
failed: 0,
|
|
12793
|
+
dry_run: dryRun
|
|
12794
|
+
};
|
|
12795
|
+
}
|
|
12796
|
+
if (before.snapshots.some((snapshot) => !snapshot.regular)) {
|
|
12797
|
+
return {
|
|
12798
|
+
runtimes: [{ ...status, action: "failed", dry_run: dryRun, skill_contracts_changed: 0 }],
|
|
12799
|
+
changed: 0,
|
|
12800
|
+
failed: 1,
|
|
12801
|
+
dry_run: dryRun
|
|
12802
|
+
};
|
|
12803
|
+
}
|
|
12804
|
+
const symlinkedAncestor = before.snapshots.map((snapshot) => snapshot.path).map((path) => findSymlinkedAncestor(dirname6(path))).find((found) => found !== null);
|
|
12805
|
+
if (symlinkedAncestor) {
|
|
12806
|
+
return {
|
|
12807
|
+
runtimes: [{ ...status, action: "failed", dry_run: dryRun, skill_contracts_changed: 0 }],
|
|
12808
|
+
changed: 0,
|
|
12809
|
+
failed: 1,
|
|
12810
|
+
dry_run: dryRun
|
|
12811
|
+
};
|
|
12812
|
+
}
|
|
12813
|
+
if (!before.canonicalContent || !runtimeReadyForWrite(status)) {
|
|
12814
|
+
return {
|
|
12815
|
+
runtimes: [{ ...status, action: "failed", dry_run: dryRun, skill_contracts_changed: 0 }],
|
|
12816
|
+
changed: 0,
|
|
12817
|
+
failed: 1,
|
|
12818
|
+
dry_run: dryRun
|
|
12819
|
+
};
|
|
12820
|
+
}
|
|
12821
|
+
const staleSnapshots = before.snapshots.filter((snapshot) => snapshot.content !== before.canonicalContent);
|
|
12822
|
+
if (staleSnapshots.length === 0) {
|
|
12823
|
+
return {
|
|
12824
|
+
runtimes: [{ ...status, action: "unchanged", dry_run: dryRun, skill_contracts_changed: 0 }],
|
|
12825
|
+
changed: 0,
|
|
12826
|
+
failed: 0,
|
|
12827
|
+
dry_run: dryRun
|
|
12828
|
+
};
|
|
12829
|
+
}
|
|
12830
|
+
if (dryRun) {
|
|
12831
|
+
const projected = projectUpdatedStatus(status, before.snapshots.length);
|
|
12832
|
+
return {
|
|
12833
|
+
runtimes: [{
|
|
12834
|
+
...projected,
|
|
12835
|
+
action: "update",
|
|
12836
|
+
dry_run: true,
|
|
12837
|
+
skill_contracts_changed: staleSnapshots.length
|
|
12838
|
+
}],
|
|
12839
|
+
changed: 1,
|
|
12840
|
+
failed: 0,
|
|
12841
|
+
dry_run: true
|
|
12842
|
+
};
|
|
12843
|
+
}
|
|
12844
|
+
const transaction = writeSkillContractsTransactional(staleSnapshots.map((snapshot) => ({
|
|
12845
|
+
path: snapshot.path,
|
|
12846
|
+
content: snapshot.content,
|
|
12847
|
+
mode: snapshot.mode ?? 420
|
|
12848
|
+
})), before.canonicalContent);
|
|
12849
|
+
if (!transaction.ok) {
|
|
12850
|
+
const rollbackConflictReason = transaction.rollback_conflicts.length > 0 ? `; rollback conflicts: ${transaction.rollback_conflicts.join("; ")}` : "";
|
|
12851
|
+
const reason = `${transaction.error ?? "managed skill reconciliation failed"}${rollbackConflictReason}`;
|
|
12852
|
+
return {
|
|
12853
|
+
runtimes: [{
|
|
12854
|
+
...status,
|
|
12855
|
+
action: "failed",
|
|
12856
|
+
dry_run: false,
|
|
12857
|
+
skill_contracts_changed: 0,
|
|
12858
|
+
reason
|
|
12859
|
+
}],
|
|
12860
|
+
changed: 0,
|
|
12861
|
+
failed: 1,
|
|
12862
|
+
dry_run: false
|
|
12863
|
+
};
|
|
12864
|
+
}
|
|
12865
|
+
const after = inspectInbox(options).status;
|
|
12866
|
+
const accepted = after.healthy || after.manual_fallback_ready;
|
|
12867
|
+
return {
|
|
12868
|
+
runtimes: [{
|
|
12869
|
+
...after,
|
|
12870
|
+
action: accepted ? "update" : "failed",
|
|
12871
|
+
dry_run: false,
|
|
12872
|
+
skill_contracts_changed: accepted ? staleSnapshots.length : 0
|
|
12873
|
+
}],
|
|
12874
|
+
changed: accepted ? 1 : 0,
|
|
12875
|
+
failed: accepted ? 0 : 1,
|
|
12876
|
+
dry_run: false
|
|
12877
|
+
};
|
|
12878
|
+
}
|
|
12879
|
+
|
|
12372
12880
|
// src/status.ts
|
|
12373
12881
|
var PACKAGE_NAME = "@hasna/instructions";
|
|
12374
12882
|
var PACKAGE_VERSION = getPackageVersion();
|
|
@@ -12391,7 +12899,7 @@ function countBy(items, getValue) {
|
|
|
12391
12899
|
}
|
|
12392
12900
|
return counts;
|
|
12393
12901
|
}
|
|
12394
|
-
async function getConfigsStatus(store = resolveConfigStore()) {
|
|
12902
|
+
async function getConfigsStatus(store = resolveConfigStore(), options = {}) {
|
|
12395
12903
|
let databaseReachable = true;
|
|
12396
12904
|
let configs = [];
|
|
12397
12905
|
let categoryStats = { total: 0 };
|
|
@@ -12415,11 +12923,11 @@ async function getConfigsStatus(store = resolveConfigStore()) {
|
|
|
12415
12923
|
continue;
|
|
12416
12924
|
knownTargets += 1;
|
|
12417
12925
|
const targetPath = expandPath(config.target_path);
|
|
12418
|
-
if (!
|
|
12926
|
+
if (!existsSync9(targetPath)) {
|
|
12419
12927
|
missingTargets += 1;
|
|
12420
12928
|
continue;
|
|
12421
12929
|
}
|
|
12422
|
-
const disk =
|
|
12930
|
+
const disk = readFileSync9(targetPath, "utf-8");
|
|
12423
12931
|
const { content: redactedDisk } = redactContent(disk, config.format);
|
|
12424
12932
|
if (redactedDisk !== config.content) {
|
|
12425
12933
|
driftedTargets += 1;
|
|
@@ -12445,7 +12953,11 @@ async function getConfigsStatus(store = resolveConfigStore()) {
|
|
|
12445
12953
|
}
|
|
12446
12954
|
}
|
|
12447
12955
|
const byCategory = Object.fromEntries(Object.entries(categoryStats).filter(([key]) => key !== "total"));
|
|
12448
|
-
const
|
|
12956
|
+
const managedSkillRuntimes = inspectManagedSkillRuntimes({
|
|
12957
|
+
homeDir: options.homeDir,
|
|
12958
|
+
conversationsCommand: options.conversationsCommand
|
|
12959
|
+
});
|
|
12960
|
+
const status = databaseReachable && driftedTargets === 0 && missingTargets === 0 && unredactedSecretFindings === 0 && retiredAgentRows === 0 && managedSkillRuntimes.missing === 0 ? "ok" : "warn";
|
|
12449
12961
|
return {
|
|
12450
12962
|
service: "configs",
|
|
12451
12963
|
schemaVersion: "1.0",
|
|
@@ -12475,7 +12987,12 @@ async function getConfigsStatus(store = resolveConfigStore()) {
|
|
|
12475
12987
|
profileLinks,
|
|
12476
12988
|
machines,
|
|
12477
12989
|
snapshots,
|
|
12478
|
-
knownTargets
|
|
12990
|
+
knownTargets,
|
|
12991
|
+
managedSkillRuntimes: {
|
|
12992
|
+
skillsPresent: managedSkillRuntimes.skills_present,
|
|
12993
|
+
healthy: managedSkillRuntimes.healthy,
|
|
12994
|
+
missing: managedSkillRuntimes.missing
|
|
12995
|
+
}
|
|
12479
12996
|
},
|
|
12480
12997
|
health: {
|
|
12481
12998
|
status,
|
|
@@ -12484,10 +13001,12 @@ async function getConfigsStatus(store = resolveConfigStore()) {
|
|
|
12484
13001
|
missingTargets,
|
|
12485
13002
|
unredactedSecretFindings,
|
|
12486
13003
|
retiredAgentRows,
|
|
13004
|
+
missingManagedSkillRuntimes: managedSkillRuntimes.missing,
|
|
12487
13005
|
hasDrift: driftedTargets > 0,
|
|
12488
13006
|
hasMissingTargets: missingTargets > 0,
|
|
12489
13007
|
hasUnredactedSecrets: unredactedSecretFindings > 0,
|
|
12490
|
-
hasRetiredAgentRows: retiredAgentRows > 0
|
|
13008
|
+
hasRetiredAgentRows: retiredAgentRows > 0,
|
|
13009
|
+
hasMissingManagedSkillRuntimes: managedSkillRuntimes.missing > 0
|
|
12491
13010
|
},
|
|
12492
13011
|
safety: {
|
|
12493
13012
|
includesConfigValues: false,
|
|
@@ -12572,16 +13091,16 @@ var PG_MIGRATIONS = [
|
|
|
12572
13091
|
`CREATE INDEX IF NOT EXISTS profile_assets_source_config_idx ON profile_assets (source_config_id)`
|
|
12573
13092
|
];
|
|
12574
13093
|
// src/lib/session-apply.ts
|
|
12575
|
-
import { createHash as
|
|
13094
|
+
import { createHash as createHash9, randomUUID as randomUUID4 } from "crypto";
|
|
12576
13095
|
import {
|
|
12577
|
-
existsSync as
|
|
12578
|
-
lstatSync as
|
|
12579
|
-
mkdirSync as
|
|
12580
|
-
readFileSync as
|
|
13096
|
+
existsSync as existsSync10,
|
|
13097
|
+
lstatSync as lstatSync5,
|
|
13098
|
+
mkdirSync as mkdirSync5,
|
|
13099
|
+
readFileSync as readFileSync10,
|
|
12581
13100
|
readdirSync,
|
|
12582
|
-
statSync as
|
|
13101
|
+
statSync as statSync5
|
|
12583
13102
|
} from "fs";
|
|
12584
|
-
import { dirname as
|
|
13103
|
+
import { dirname as dirname7, isAbsolute as isAbsolute4, join as join12, parse as parse5, relative as relative5, resolve as resolve9 } from "path";
|
|
12585
13104
|
class SessionApplyError extends Error {
|
|
12586
13105
|
constructor(message) {
|
|
12587
13106
|
super(message);
|
|
@@ -12601,6 +13120,7 @@ function applySessionRenderUnlocked(plan, options, coordination) {
|
|
|
12601
13120
|
}
|
|
12602
13121
|
assertCursorAuthorityUnchanged(plan);
|
|
12603
13122
|
const targetHome = assertSafeTargetHome(plan.targetHome);
|
|
13123
|
+
assertClaudeAuthorityStillClear(plan, targetHome);
|
|
12604
13124
|
const payloadFiles = [...plan.files, ...plan.assetFiles ?? []];
|
|
12605
13125
|
const files = [...payloadFiles, plan.manifestFile];
|
|
12606
13126
|
const manifestPath = resolvePlannedFilePath(plan, plan.manifestFile, targetHome);
|
|
@@ -12701,14 +13221,23 @@ function assertCursorAuthorityUnchanged(plan) {
|
|
|
12701
13221
|
throw new SessionApplyError("Cursor fixed global authority changed after planning; refusing to apply a stale render plan.");
|
|
12702
13222
|
}
|
|
12703
13223
|
}
|
|
13224
|
+
function assertClaudeAuthorityStillClear(plan, targetHome) {
|
|
13225
|
+
if (plan.tool !== "claude" || plan.targetKind === "blocked")
|
|
13226
|
+
return;
|
|
13227
|
+
const conflicts = detectClaudeAuthorityConflicts(targetHome);
|
|
13228
|
+
if (conflicts.length === 0)
|
|
13229
|
+
return;
|
|
13230
|
+
const summary = conflicts.map((conflict) => `${conflict.relativePath}: ${conflict.reason}`).join("; ");
|
|
13231
|
+
throw new SessionApplyError(`Claude authority changed after planning; refusing to apply: ${summary}`);
|
|
13232
|
+
}
|
|
12704
13233
|
function ensureSessionTargetHome(targetHome) {
|
|
12705
|
-
if (!
|
|
12706
|
-
|
|
13234
|
+
if (!existsSync10(targetHome))
|
|
13235
|
+
mkdirSync5(targetHome, { recursive: true, mode: 448 });
|
|
12707
13236
|
assertSafeTargetHome(targetHome);
|
|
12708
13237
|
}
|
|
12709
13238
|
function checkSessionRenderDrift(targetHome, manifestPath) {
|
|
12710
13239
|
const safeTargetHome = assertSafeTargetHome(targetHome);
|
|
12711
|
-
const resolvedManifestPath = manifestPath ? resolveManifestRelativePath(
|
|
13240
|
+
const resolvedManifestPath = manifestPath ? resolveManifestRelativePath(relative5(safeTargetHome, resolve9(manifestPath)), safeTargetHome) : resolve9(safeTargetHome, ".hasna", "session-render-manifest.json");
|
|
12712
13241
|
const checkedAt = new Date().toISOString();
|
|
12713
13242
|
const previousManifest = readPreviousManifest(resolvedManifestPath);
|
|
12714
13243
|
if (!previousManifest) {
|
|
@@ -12725,7 +13254,7 @@ function checkSessionRenderDrift(targetHome, manifestPath) {
|
|
|
12725
13254
|
const drifted = [];
|
|
12726
13255
|
for (const file of previousManifest.files) {
|
|
12727
13256
|
const target = resolveManifestRelativePath(file.relativePath, safeTargetHome);
|
|
12728
|
-
if (!
|
|
13257
|
+
if (!existsSync10(target)) {
|
|
12729
13258
|
missing.push({
|
|
12730
13259
|
path: target,
|
|
12731
13260
|
relativePath: file.relativePath,
|
|
@@ -12735,7 +13264,7 @@ function checkSessionRenderDrift(targetHome, manifestPath) {
|
|
|
12735
13264
|
});
|
|
12736
13265
|
continue;
|
|
12737
13266
|
}
|
|
12738
|
-
const actualSha256 =
|
|
13267
|
+
const actualSha256 = sha2569(readFileSync10(target, "utf-8"));
|
|
12739
13268
|
if (actualSha256 !== file.sha256) {
|
|
12740
13269
|
drifted.push({
|
|
12741
13270
|
path: target,
|
|
@@ -12758,8 +13287,8 @@ function checkSessionRenderDrift(targetHome, manifestPath) {
|
|
|
12758
13287
|
function restoreSessionRenderSnapshot(snapshotPath, options = {}) {
|
|
12759
13288
|
const snapshot = readSessionRenderSnapshot(snapshotPath);
|
|
12760
13289
|
const targetHome = assertSafeTargetHome(snapshot.targetHome);
|
|
12761
|
-
const resolvedSnapshotPath =
|
|
12762
|
-
const snapshotRelativePath =
|
|
13290
|
+
const resolvedSnapshotPath = resolve9(snapshotPath);
|
|
13291
|
+
const snapshotRelativePath = relative5(targetHome, resolvedSnapshotPath);
|
|
12763
13292
|
if (snapshotRelativePath === "" || snapshotRelativePath === ".." || snapshotRelativePath.startsWith("../") || isAbsolute4(snapshotRelativePath)) {
|
|
12764
13293
|
throw new SessionApplyError("Session snapshot must be stored inside its target home.");
|
|
12765
13294
|
}
|
|
@@ -12876,19 +13405,19 @@ function requiredRestoreHash(file) {
|
|
|
12876
13405
|
return file.previousSha256;
|
|
12877
13406
|
}
|
|
12878
13407
|
function readSessionRenderSnapshot(snapshotPath) {
|
|
12879
|
-
const resolved =
|
|
12880
|
-
if (!
|
|
13408
|
+
const resolved = resolve9(snapshotPath);
|
|
13409
|
+
if (!existsSync10(resolved))
|
|
12881
13410
|
throw new SessionApplyError(`Session snapshot not found: ${snapshotPath}`);
|
|
12882
|
-
const stat =
|
|
13411
|
+
const stat = lstatSync5(resolved);
|
|
12883
13412
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
12884
13413
|
throw new SessionApplyError(`Session snapshot is not a regular file: ${snapshotPath}`);
|
|
12885
13414
|
}
|
|
12886
|
-
if (
|
|
13415
|
+
if (statSync5(resolved).size > 32 * 1024 * 1024) {
|
|
12887
13416
|
throw new SessionApplyError(`Session snapshot exceeds the 32 MiB restore limit: ${snapshotPath}`);
|
|
12888
13417
|
}
|
|
12889
13418
|
let parsed;
|
|
12890
13419
|
try {
|
|
12891
|
-
parsed = JSON.parse(
|
|
13420
|
+
parsed = JSON.parse(readFileSync10(resolved, "utf8"));
|
|
12892
13421
|
} catch {
|
|
12893
13422
|
throw new SessionApplyError(`Session snapshot is not valid JSON: ${snapshotPath}`);
|
|
12894
13423
|
}
|
|
@@ -12910,7 +13439,7 @@ function readSessionRenderSnapshot(snapshotPath) {
|
|
|
12910
13439
|
const previousManifest = snapshot.previousManifest;
|
|
12911
13440
|
const previousFiles = new Map;
|
|
12912
13441
|
for (const file of snapshot.files) {
|
|
12913
|
-
if (!file || typeof file.relativePath !== "string" || typeof file.path !== "string" || typeof file.sha256 !== "string" || typeof file.content !== "string" ||
|
|
13442
|
+
if (!file || typeof file.relativePath !== "string" || typeof file.path !== "string" || typeof file.sha256 !== "string" || typeof file.content !== "string" || sha2569(file.content) !== file.sha256) {
|
|
12914
13443
|
throw new SessionApplyError(`Session snapshot previous file metadata is invalid: ${snapshotPath}`);
|
|
12915
13444
|
}
|
|
12916
13445
|
resolveSnapshotFilePath(file.relativePath, file.path, targetHome);
|
|
@@ -12957,8 +13486,8 @@ function readSessionRenderSnapshot(snapshotPath) {
|
|
|
12957
13486
|
}
|
|
12958
13487
|
function reconstructPreRollbackLegacyV1Snapshot(snapshot, previousFiles, previousManifestFiles, targetHome, snapshotPath) {
|
|
12959
13488
|
assertNoNewerSessionSnapshot(snapshotPath, snapshot.createdAt, targetHome);
|
|
12960
|
-
const manifestPath =
|
|
12961
|
-
const manifestRelativePath =
|
|
13489
|
+
const manifestPath = resolve9(snapshot.manifestPath);
|
|
13490
|
+
const manifestRelativePath = relative5(targetHome, manifestPath).replaceAll("\\", "/");
|
|
12962
13491
|
resolveSnapshotFilePath(manifestRelativePath, snapshot.manifestPath, targetHome);
|
|
12963
13492
|
const manifestSha256 = currentSessionFileHash(manifestPath, targetHome);
|
|
12964
13493
|
if (manifestSha256 === null) {
|
|
@@ -12966,7 +13495,7 @@ function reconstructPreRollbackLegacyV1Snapshot(snapshot, previousFiles, previou
|
|
|
12966
13495
|
}
|
|
12967
13496
|
let parsedManifest;
|
|
12968
13497
|
try {
|
|
12969
|
-
parsedManifest = JSON.parse(
|
|
13498
|
+
parsedManifest = JSON.parse(readFileSync10(manifestPath, "utf8"));
|
|
12970
13499
|
} catch {
|
|
12971
13500
|
throw new SessionApplyError(`Pre-rollback legacy v1 applied manifest is not valid JSON: ${snapshotPath}`);
|
|
12972
13501
|
}
|
|
@@ -12974,7 +13503,7 @@ function reconstructPreRollbackLegacyV1Snapshot(snapshot, previousFiles, previou
|
|
|
12974
13503
|
throw new SessionApplyError(`Pre-rollback legacy v1 applied manifest is invalid: ${snapshotPath}`);
|
|
12975
13504
|
}
|
|
12976
13505
|
const appliedManifest = parsedManifest;
|
|
12977
|
-
if (appliedManifest.schema !== SESSION_RENDER_SCHEMA || appliedManifest.tool !== snapshot.tool || appliedManifest.profile !== snapshot.profile || typeof appliedManifest.targetHome !== "string" ||
|
|
13506
|
+
if (appliedManifest.schema !== SESSION_RENDER_SCHEMA || appliedManifest.tool !== snapshot.tool || appliedManifest.profile !== snapshot.profile || typeof appliedManifest.targetHome !== "string" || resolve9(appliedManifest.targetHome) !== targetHome || appliedManifest.targetKind !== "session-home" && appliedManifest.targetKind !== "project-root" || !Array.isArray(appliedManifest.files)) {
|
|
12978
13507
|
throw new SessionApplyError(`Pre-rollback legacy v1 applied manifest does not match its snapshot: ${snapshotPath}`);
|
|
12979
13508
|
}
|
|
12980
13509
|
const afterFiles = [];
|
|
@@ -13058,17 +13587,17 @@ function assertNoNewerSessionSnapshot(snapshotPath, createdAt, targetHome) {
|
|
|
13058
13587
|
if (!Number.isFinite(createdAtMs)) {
|
|
13059
13588
|
throw new SessionApplyError(`Pre-rollback legacy v1 snapshot has an invalid creation time: ${snapshotPath}`);
|
|
13060
13589
|
}
|
|
13061
|
-
for (const entry of readdirSync(
|
|
13062
|
-
const candidatePath =
|
|
13063
|
-
if (candidatePath ===
|
|
13590
|
+
for (const entry of readdirSync(dirname7(snapshotPath))) {
|
|
13591
|
+
const candidatePath = resolve9(dirname7(snapshotPath), entry);
|
|
13592
|
+
if (candidatePath === resolve9(snapshotPath) || !entry.endsWith(".json"))
|
|
13064
13593
|
continue;
|
|
13065
|
-
const candidateStat =
|
|
13594
|
+
const candidateStat = lstatSync5(candidatePath);
|
|
13066
13595
|
if (candidateStat.isSymbolicLink() || !candidateStat.isFile() || candidateStat.size > 32 * 1024 * 1024)
|
|
13067
13596
|
continue;
|
|
13068
13597
|
try {
|
|
13069
|
-
const candidate = JSON.parse(
|
|
13598
|
+
const candidate = JSON.parse(readFileSync10(candidatePath, "utf8"));
|
|
13070
13599
|
const candidateCreatedAtMs = typeof candidate.createdAt === "string" ? Date.parse(candidate.createdAt) : Number.NaN;
|
|
13071
|
-
if ((candidate.schema === "hasna.configs.session-render-snapshot/v1" || candidate.schema === "hasna.configs.session-render-snapshot/v2") && typeof candidate.targetHome === "string" &&
|
|
13600
|
+
if ((candidate.schema === "hasna.configs.session-render-snapshot/v1" || candidate.schema === "hasna.configs.session-render-snapshot/v2") && typeof candidate.targetHome === "string" && resolve9(candidate.targetHome) === targetHome && Number.isFinite(candidateCreatedAtMs) && candidateCreatedAtMs >= createdAtMs) {
|
|
13072
13601
|
throw new SessionApplyError(`Cannot restore pre-rollback legacy v1 snapshot after a newer session snapshot exists: ${candidatePath}`);
|
|
13073
13602
|
}
|
|
13074
13603
|
} catch (error) {
|
|
@@ -13126,7 +13655,7 @@ function inferLegacySnapshotAction(file, previousFiles, previousManifestFiles, p
|
|
|
13126
13655
|
return "create";
|
|
13127
13656
|
}
|
|
13128
13657
|
if (file.role === "manifest" && previousManifest) {
|
|
13129
|
-
const previousManifestSha256 =
|
|
13658
|
+
const previousManifestSha256 = sha2569(`${JSON.stringify(previousManifest, null, 2)}
|
|
13130
13659
|
`);
|
|
13131
13660
|
if (previousManifestSha256 !== file.sha256) {
|
|
13132
13661
|
throw new SessionApplyError(`Cannot infer legacy v1 manifest action without a before-image: ${file.relativePath}`);
|
|
@@ -13137,15 +13666,15 @@ function inferLegacySnapshotAction(file, previousFiles, previousManifestFiles, p
|
|
|
13137
13666
|
}
|
|
13138
13667
|
function resolveSnapshotFilePath(relativePath, recordedPath, targetHome) {
|
|
13139
13668
|
const path = resolveManifestRelativePath(relativePath, targetHome);
|
|
13140
|
-
if (
|
|
13669
|
+
if (resolve9(recordedPath) !== path) {
|
|
13141
13670
|
throw new SessionApplyError(`Session snapshot file path mismatch for ${relativePath}`);
|
|
13142
13671
|
}
|
|
13143
13672
|
return path;
|
|
13144
13673
|
}
|
|
13145
13674
|
function planFileResult(plan, file, targetHome, previousHashes, previousManifest, options) {
|
|
13146
13675
|
const target = resolvePlannedFilePath(plan, file, targetHome);
|
|
13147
|
-
const previousContent =
|
|
13148
|
-
const previousSha256 = previousContent === null ? null :
|
|
13676
|
+
const previousContent = existsSync10(target) ? readFileSync10(target, "utf-8") : null;
|
|
13677
|
+
const previousSha256 = previousContent === null ? null : sha2569(previousContent);
|
|
13149
13678
|
const previouslyManaged = isPreviouslyManaged(file, previousSha256, previousHashes, previousManifest);
|
|
13150
13679
|
const changed = previousContent !== file.content;
|
|
13151
13680
|
if (previousContent !== null && !options.force && !previouslyManaged) {
|
|
@@ -13240,10 +13769,10 @@ function planStaleFileResults(plan, targetHome, previousManifest, currentRelativ
|
|
|
13240
13769
|
}
|
|
13241
13770
|
function planStaleFileResult(file, targetHome, options) {
|
|
13242
13771
|
const target = resolveManifestRelativePath(file.relativePath, targetHome);
|
|
13243
|
-
if (!
|
|
13772
|
+
if (!existsSync10(target))
|
|
13244
13773
|
return null;
|
|
13245
|
-
const previousContent =
|
|
13246
|
-
const previousSha256 =
|
|
13774
|
+
const previousContent = readFileSync10(target, "utf-8");
|
|
13775
|
+
const previousSha256 = sha2569(previousContent);
|
|
13247
13776
|
if (!options.force && previousSha256 !== file.sha256) {
|
|
13248
13777
|
return {
|
|
13249
13778
|
path: target,
|
|
@@ -13287,20 +13816,20 @@ function isPreviouslyManaged(file, previousSha256, previousHashes, previousManif
|
|
|
13287
13816
|
return previousHashes.get(file.relativePath) === previousSha256;
|
|
13288
13817
|
}
|
|
13289
13818
|
function resolvePlannedFilePath(plan, file, targetHome) {
|
|
13290
|
-
const target =
|
|
13291
|
-
const rel =
|
|
13819
|
+
const target = resolve9(targetHome, ...file.relativePath.split("/"));
|
|
13820
|
+
const rel = relative5(targetHome, target);
|
|
13292
13821
|
if (rel === "" || rel === ".." || rel.startsWith("../") || isAbsolute4(rel)) {
|
|
13293
13822
|
throw new SessionApplyError(`Session file escapes target home: ${file.relativePath}`);
|
|
13294
13823
|
}
|
|
13295
|
-
if (
|
|
13824
|
+
if (resolve9(file.path) !== target) {
|
|
13296
13825
|
throw new SessionApplyError(`Session file path mismatch for ${file.relativePath}: ${file.path}`);
|
|
13297
13826
|
}
|
|
13298
13827
|
assertNoSymlinkSegments2(targetHome, target);
|
|
13299
13828
|
return target;
|
|
13300
13829
|
}
|
|
13301
13830
|
function resolveManifestRelativePath(relativePath, targetHome) {
|
|
13302
|
-
const target =
|
|
13303
|
-
const rel =
|
|
13831
|
+
const target = resolve9(targetHome, ...relativePath.split(/[\\/]+/));
|
|
13832
|
+
const rel = relative5(targetHome, target);
|
|
13304
13833
|
if (rel === "" || rel === ".." || rel.startsWith("../") || isAbsolute4(rel)) {
|
|
13305
13834
|
throw new SessionApplyError(`Session manifest file escapes target home: ${relativePath}`);
|
|
13306
13835
|
}
|
|
@@ -13308,10 +13837,10 @@ function resolveManifestRelativePath(relativePath, targetHome) {
|
|
|
13308
13837
|
return target;
|
|
13309
13838
|
}
|
|
13310
13839
|
function readPreviousManifest(path) {
|
|
13311
|
-
if (!
|
|
13840
|
+
if (!existsSync10(path))
|
|
13312
13841
|
return null;
|
|
13313
13842
|
try {
|
|
13314
|
-
const parsed = JSON.parse(
|
|
13843
|
+
const parsed = JSON.parse(readFileSync10(path, "utf-8"));
|
|
13315
13844
|
if (parsed.schema !== SESSION_RENDER_SCHEMA)
|
|
13316
13845
|
return null;
|
|
13317
13846
|
if (!Array.isArray(parsed.files))
|
|
@@ -13345,18 +13874,18 @@ function applyPlannedFile(plan, file, targetHome, resultsByPath, coordination, a
|
|
|
13345
13874
|
function assertExpectedSessionFileHash(path, targetHome, expectedHash) {
|
|
13346
13875
|
const actualHash = currentSessionFileHash(path, targetHome);
|
|
13347
13876
|
if (actualHash !== expectedHash) {
|
|
13348
|
-
throw new SessionApplyError(`Session apply path changed after planning: ${
|
|
13877
|
+
throw new SessionApplyError(`Session apply path changed after planning: ${relative5(targetHome, path)}`);
|
|
13349
13878
|
}
|
|
13350
13879
|
}
|
|
13351
13880
|
function currentSessionFileHash(path, targetHome) {
|
|
13352
13881
|
assertNoSymlinkSegments2(targetHome, path);
|
|
13353
|
-
if (!
|
|
13882
|
+
if (!existsSync10(path))
|
|
13354
13883
|
return null;
|
|
13355
|
-
const stat =
|
|
13884
|
+
const stat = lstatSync5(path);
|
|
13356
13885
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
13357
13886
|
throw new SessionApplyError(`Session apply path is not a regular file: ${path}`);
|
|
13358
13887
|
}
|
|
13359
|
-
return
|
|
13888
|
+
return sha2569(readFileSync10(path, "utf-8"));
|
|
13360
13889
|
}
|
|
13361
13890
|
function requiredPreviousHash(result) {
|
|
13362
13891
|
if (result.previousSha256 === null) {
|
|
@@ -13365,13 +13894,13 @@ function requiredPreviousHash(result) {
|
|
|
13365
13894
|
return result.previousSha256;
|
|
13366
13895
|
}
|
|
13367
13896
|
function writeSessionSnapshot(plan, targetHome, manifestPath, results, previousManifest, coordination, allowPortableFallback, forcePortableFileOps) {
|
|
13368
|
-
const existingFiles = results.filter((result) => result.action === "update" || result.action === "delete").filter((result) =>
|
|
13369
|
-
const content =
|
|
13897
|
+
const existingFiles = results.filter((result) => result.action === "update" || result.action === "delete").filter((result) => existsSync10(result.path)).map((result) => {
|
|
13898
|
+
const content = readFileSync10(result.path, "utf-8");
|
|
13370
13899
|
return {
|
|
13371
13900
|
path: result.path,
|
|
13372
13901
|
relativePath: result.relativePath,
|
|
13373
13902
|
role: result.role,
|
|
13374
|
-
sha256:
|
|
13903
|
+
sha256: sha2569(content),
|
|
13375
13904
|
content
|
|
13376
13905
|
};
|
|
13377
13906
|
});
|
|
@@ -13384,7 +13913,7 @@ function writeSessionSnapshot(plan, targetHome, manifestPath, results, previousM
|
|
|
13384
13913
|
};
|
|
13385
13914
|
}
|
|
13386
13915
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
13387
|
-
const snapshotPath =
|
|
13916
|
+
const snapshotPath = resolve9(targetHome, ".hasna", "session-render-snapshots", `${timestamp}-${randomUUID4()}.json`);
|
|
13388
13917
|
const afterFiles = results.map((result) => {
|
|
13389
13918
|
if (result.action === "conflict") {
|
|
13390
13919
|
throw new SessionApplyError(`Cannot snapshot unresolved conflict: ${result.relativePath}`);
|
|
@@ -13432,43 +13961,43 @@ function writeSessionSnapshot(plan, targetHome, manifestPath, results, previousM
|
|
|
13432
13961
|
function assertSafeTargetHome(targetHome) {
|
|
13433
13962
|
if (!isAbsolute4(targetHome))
|
|
13434
13963
|
throw new SessionApplyError(`Session target home must be absolute: ${targetHome}`);
|
|
13435
|
-
const normalized =
|
|
13436
|
-
if (normalized ===
|
|
13964
|
+
const normalized = resolve9(targetHome);
|
|
13965
|
+
if (normalized === parse5(normalized).root) {
|
|
13437
13966
|
throw new SessionApplyError(`Session target home cannot be the filesystem root: ${targetHome}`);
|
|
13438
13967
|
}
|
|
13439
|
-
|
|
13440
|
-
if (
|
|
13968
|
+
assertNoSymlinkAncestors3(normalized);
|
|
13969
|
+
if (existsSync10(normalized) && lstatSync5(normalized).isSymbolicLink()) {
|
|
13441
13970
|
throw new SessionApplyError(`Session target home cannot be a symlink: ${normalized}`);
|
|
13442
13971
|
}
|
|
13443
13972
|
return normalized;
|
|
13444
13973
|
}
|
|
13445
13974
|
function assertNoSymlinkSegments2(root, target) {
|
|
13446
|
-
|
|
13447
|
-
const rel =
|
|
13975
|
+
assertNoSymlinkAncestors3(root);
|
|
13976
|
+
const rel = relative5(root, target);
|
|
13448
13977
|
let current = root;
|
|
13449
13978
|
for (const segment of rel.split(/[\\/]+/).filter(Boolean)) {
|
|
13450
|
-
current =
|
|
13451
|
-
if (
|
|
13979
|
+
current = join12(current, segment);
|
|
13980
|
+
if (existsSync10(current) && lstatSync5(current).isSymbolicLink()) {
|
|
13452
13981
|
throw new SessionApplyError(`Session apply path uses a symlink: ${current}`);
|
|
13453
13982
|
}
|
|
13454
13983
|
}
|
|
13455
13984
|
}
|
|
13456
|
-
function
|
|
13457
|
-
const normalized =
|
|
13458
|
-
const parsed =
|
|
13985
|
+
function assertNoSymlinkAncestors3(path) {
|
|
13986
|
+
const normalized = resolve9(path);
|
|
13987
|
+
const parsed = parse5(normalized);
|
|
13459
13988
|
let current = parsed.root;
|
|
13460
|
-
const rel =
|
|
13989
|
+
const rel = relative5(parsed.root, normalized);
|
|
13461
13990
|
for (const segment of rel.split(/[\\/]+/).filter(Boolean)) {
|
|
13462
|
-
current =
|
|
13463
|
-
if (!
|
|
13991
|
+
current = join12(current, segment);
|
|
13992
|
+
if (!existsSync10(current))
|
|
13464
13993
|
return;
|
|
13465
|
-
if (
|
|
13994
|
+
if (lstatSync5(current).isSymbolicLink()) {
|
|
13466
13995
|
throw new SessionApplyError(`Session apply path uses a symlink ancestor: ${current}`);
|
|
13467
13996
|
}
|
|
13468
13997
|
}
|
|
13469
13998
|
}
|
|
13470
|
-
function
|
|
13471
|
-
return
|
|
13999
|
+
function sha2569(content) {
|
|
14000
|
+
return createHash9("sha256").update(content).digest("hex");
|
|
13472
14001
|
}
|
|
13473
14002
|
// src/lib/project-dashboard-standard.ts
|
|
13474
14003
|
var PROJECT_DASHBOARD_STANDARD_SLUG = "agent-managed-project-dashboard-standard";
|
|
@@ -13771,13 +14300,13 @@ async function ensureDangerousOperationGuardStandardConfig(store = resolveConfig
|
|
|
13771
14300
|
}
|
|
13772
14301
|
}
|
|
13773
14302
|
// src/lib/sync.ts
|
|
13774
|
-
import { existsSync as
|
|
13775
|
-
import { basename as basename5, extname as extname3, join as
|
|
14303
|
+
import { existsSync as existsSync12, readdirSync as readdirSync3, readFileSync as readFileSync12 } from "fs";
|
|
14304
|
+
import { basename as basename5, extname as extname3, join as join14 } from "path";
|
|
13776
14305
|
|
|
13777
14306
|
// src/lib/sync-dir.ts
|
|
13778
|
-
import { existsSync as
|
|
13779
|
-
import { join as
|
|
13780
|
-
import { homedir as
|
|
14307
|
+
import { existsSync as existsSync11, readdirSync as readdirSync2, readFileSync as readFileSync11, statSync as statSync6 } from "fs";
|
|
14308
|
+
import { join as join13, relative as relative6 } from "path";
|
|
14309
|
+
import { homedir as homedir7 } from "os";
|
|
13781
14310
|
var SKIP = [".db", ".db-shm", ".db-wal", ".log", ".lock", ".DS_Store", "node_modules", ".git"];
|
|
13782
14311
|
function shouldSkip(p) {
|
|
13783
14312
|
return SKIP.some((s) => p.includes(s));
|
|
@@ -13785,11 +14314,11 @@ function shouldSkip(p) {
|
|
|
13785
14314
|
async function syncFromDir(dir, opts = {}) {
|
|
13786
14315
|
const store = opts.store ?? resolveConfigStore();
|
|
13787
14316
|
const absDir = expandPath(dir);
|
|
13788
|
-
if (!
|
|
14317
|
+
if (!existsSync11(absDir))
|
|
13789
14318
|
return { added: 0, updated: 0, unchanged: 0, skipped: [`Not found: ${absDir}`] };
|
|
13790
|
-
const files = opts.recursive !== false ? walkDir(absDir) : readdirSync2(absDir).map((f) =>
|
|
14319
|
+
const files = opts.recursive !== false ? walkDir(absDir) : readdirSync2(absDir).map((f) => join13(absDir, f)).filter((f) => statSync6(f).isFile());
|
|
13791
14320
|
const result = { added: 0, updated: 0, unchanged: 0, skipped: [] };
|
|
13792
|
-
const home =
|
|
14321
|
+
const home = homedir7();
|
|
13793
14322
|
const allConfigs = await store.listConfigs();
|
|
13794
14323
|
for (const file of files) {
|
|
13795
14324
|
if (shouldSkip(file)) {
|
|
@@ -13797,7 +14326,7 @@ async function syncFromDir(dir, opts = {}) {
|
|
|
13797
14326
|
continue;
|
|
13798
14327
|
}
|
|
13799
14328
|
try {
|
|
13800
|
-
const content =
|
|
14329
|
+
const content = readFileSync11(file, "utf-8");
|
|
13801
14330
|
if (content.length > 500000) {
|
|
13802
14331
|
result.skipped.push(file + " (too large)");
|
|
13803
14332
|
continue;
|
|
@@ -13806,7 +14335,7 @@ async function syncFromDir(dir, opts = {}) {
|
|
|
13806
14335
|
const existing = allConfigs.find((c) => c.target_path === targetPath);
|
|
13807
14336
|
if (!existing) {
|
|
13808
14337
|
if (!opts.dryRun)
|
|
13809
|
-
await store.createConfig({ name:
|
|
14338
|
+
await store.createConfig({ name: relative6(absDir, file), category: detectCategory(file), agent: detectAgent(file), target_path: targetPath, format: detectFormat(file), content });
|
|
13810
14339
|
result.added++;
|
|
13811
14340
|
} else if (existing.content !== content) {
|
|
13812
14341
|
if (!opts.dryRun)
|
|
@@ -13823,7 +14352,7 @@ async function syncFromDir(dir, opts = {}) {
|
|
|
13823
14352
|
}
|
|
13824
14353
|
async function syncToDir(dir, opts = {}) {
|
|
13825
14354
|
const store = opts.store ?? resolveConfigStore();
|
|
13826
|
-
const home =
|
|
14355
|
+
const home = homedir7();
|
|
13827
14356
|
const absDir = expandPath(dir);
|
|
13828
14357
|
const normalized = dir.startsWith("~/") ? dir : absDir.replace(home, "~");
|
|
13829
14358
|
const configs = (await store.listConfigs()).filter((c) => c.target_path && (c.target_path.startsWith(normalized) || c.target_path.startsWith(absDir)));
|
|
@@ -13847,7 +14376,7 @@ async function syncToDir(dir, opts = {}) {
|
|
|
13847
14376
|
}
|
|
13848
14377
|
function walkDir(dir, files = []) {
|
|
13849
14378
|
for (const entry of readdirSync2(dir, { withFileTypes: true })) {
|
|
13850
|
-
const full =
|
|
14379
|
+
const full = join13(dir, entry.name);
|
|
13851
14380
|
if (shouldSkip(full))
|
|
13852
14381
|
continue;
|
|
13853
14382
|
if (entry.isDirectory())
|
|
@@ -13908,7 +14437,7 @@ function isGeneratedOutputTarget2(config, owners) {
|
|
|
13908
14437
|
return !!ownerIds && !ownerIds.has(config.id);
|
|
13909
14438
|
}
|
|
13910
14439
|
function hasClaudePromptSource() {
|
|
13911
|
-
return
|
|
14440
|
+
return existsSync12(expandPath("~/.claude/CLAUDE.md"));
|
|
13912
14441
|
}
|
|
13913
14442
|
function hasClaudeRuleSourceForCursorTarget(targetPath) {
|
|
13914
14443
|
const absoluteTargetPath = expandPath(targetPath);
|
|
@@ -13916,7 +14445,7 @@ function hasClaudeRuleSourceForCursorTarget(targetPath) {
|
|
|
13916
14445
|
if (!absoluteTargetPath.startsWith(`${absolutePrefix}/`) || !absoluteTargetPath.endsWith(".mdc"))
|
|
13917
14446
|
return false;
|
|
13918
14447
|
const stem = basename5(absoluteTargetPath, ".mdc");
|
|
13919
|
-
return
|
|
14448
|
+
return existsSync12(expandPath(`~/.claude/rules/${stem}.md`)) || existsSync12(expandPath(`~/.claude/rules/${stem}.mdc`));
|
|
13920
14449
|
}
|
|
13921
14450
|
function isKnownGeneratedTargetPath(targetPath) {
|
|
13922
14451
|
const normalizedTargetPath = normalizeTargetPath(targetPath);
|
|
@@ -13981,11 +14510,11 @@ async function syncProject(opts) {
|
|
|
13981
14510
|
const allConfigs = await store.listConfigs();
|
|
13982
14511
|
const machine = detectMachineContext();
|
|
13983
14512
|
for (const pf of PROJECT_CONFIG_FILES) {
|
|
13984
|
-
const abs =
|
|
13985
|
-
if (!
|
|
14513
|
+
const abs = join14(absDir, pf.file);
|
|
14514
|
+
if (!existsSync12(abs))
|
|
13986
14515
|
continue;
|
|
13987
14516
|
try {
|
|
13988
|
-
const rawContent =
|
|
14517
|
+
const rawContent = readFileSync12(abs, "utf-8");
|
|
13989
14518
|
if (rawContent.length > 500000) {
|
|
13990
14519
|
result.skipped.push(pf.file);
|
|
13991
14520
|
continue;
|
|
@@ -14014,20 +14543,20 @@ async function syncProject(opts) {
|
|
|
14014
14543
|
}
|
|
14015
14544
|
}
|
|
14016
14545
|
for (const ruleDir of [
|
|
14017
|
-
{ dir:
|
|
14018
|
-
{ dir:
|
|
14019
|
-
{ dir:
|
|
14020
|
-
{ dir:
|
|
14021
|
-
{ dir:
|
|
14022
|
-
{ dir:
|
|
14023
|
-
{ dir:
|
|
14546
|
+
{ dir: join14(absDir, ".claude", "rules"), agent: "claude", namePrefix: "rules" },
|
|
14547
|
+
{ dir: join14(absDir, ".agents", "rules"), agent: "antigravity", namePrefix: "antigravity-rules" },
|
|
14548
|
+
{ dir: join14(absDir, ".cursor", "rules"), agent: "cursor", namePrefix: "cursor-rules" },
|
|
14549
|
+
{ dir: join14(absDir, ".github", "instructions"), agent: "copilot", namePrefix: "copilot-instructions" },
|
|
14550
|
+
{ dir: join14(absDir, ".devin", "rules"), agent: "devin", namePrefix: "devin-rules" },
|
|
14551
|
+
{ dir: join14(absDir, ".windsurf", "rules"), agent: "windsurf-legacy", namePrefix: "windsurf-rules" },
|
|
14552
|
+
{ dir: join14(absDir, ".clinerules"), agent: "cline", namePrefix: "cline-rules" }
|
|
14024
14553
|
]) {
|
|
14025
|
-
if (!
|
|
14554
|
+
if (!existsSync12(ruleDir.dir))
|
|
14026
14555
|
continue;
|
|
14027
14556
|
const mdFiles = readdirSync3(ruleDir.dir).filter((f) => f.endsWith(".md") || f.endsWith(".mdc"));
|
|
14028
14557
|
for (const f of mdFiles) {
|
|
14029
|
-
const abs =
|
|
14030
|
-
const raw =
|
|
14558
|
+
const abs = join14(ruleDir.dir, f);
|
|
14559
|
+
const raw = readFileSync12(abs, "utf-8");
|
|
14031
14560
|
const redacted = redactContent(raw, "markdown");
|
|
14032
14561
|
const machineAware = templateizeMachineContent(redacted.content, machine);
|
|
14033
14562
|
const content = machineAware.content;
|
|
@@ -14066,20 +14595,20 @@ async function syncKnown(opts = {}) {
|
|
|
14066
14595
|
for (const known of targets) {
|
|
14067
14596
|
if (known.rulesDir) {
|
|
14068
14597
|
const absDir = expandPath(known.rulesDir);
|
|
14069
|
-
if (!
|
|
14598
|
+
if (!existsSync12(absDir)) {
|
|
14070
14599
|
result.skipped.push(known.rulesDir);
|
|
14071
14600
|
continue;
|
|
14072
14601
|
}
|
|
14073
14602
|
const extensions = known.rulesExtensions ?? [".md", ".mdc"];
|
|
14074
14603
|
const ruleFiles = readdirSync3(absDir).filter((f) => extensions.some((ext) => f.endsWith(ext)));
|
|
14075
14604
|
for (const f of ruleFiles) {
|
|
14076
|
-
const abs2 =
|
|
14605
|
+
const abs2 = join14(absDir, f);
|
|
14077
14606
|
const targetPath = abs2.replace(home, "~");
|
|
14078
14607
|
if (existingOutputOwners.has(normalizeTargetPath(targetPath)) || isKnownGeneratedTargetPath(targetPath)) {
|
|
14079
14608
|
result.skipped.push(`${targetPath} (generated output)`);
|
|
14080
14609
|
continue;
|
|
14081
14610
|
}
|
|
14082
|
-
const raw =
|
|
14611
|
+
const raw = readFileSync12(abs2, "utf-8");
|
|
14083
14612
|
const redacted = redactContent(raw, "markdown");
|
|
14084
14613
|
const machineAware = templateizeMachineContent(redacted.content, machine);
|
|
14085
14614
|
const content = machineAware.content;
|
|
@@ -14107,12 +14636,12 @@ async function syncKnown(opts = {}) {
|
|
|
14107
14636
|
continue;
|
|
14108
14637
|
}
|
|
14109
14638
|
const abs = expandPath(known.path);
|
|
14110
|
-
if (!
|
|
14639
|
+
if (!existsSync12(abs)) {
|
|
14111
14640
|
result.skipped.push(known.path);
|
|
14112
14641
|
continue;
|
|
14113
14642
|
}
|
|
14114
14643
|
try {
|
|
14115
|
-
const rawContent = normalizeKnownConfigSource(known,
|
|
14644
|
+
const rawContent = normalizeKnownConfigSource(known, readFileSync12(abs, "utf-8"));
|
|
14116
14645
|
if (rawContent.length > 500000) {
|
|
14117
14646
|
result.skipped.push(known.path + " (too large)");
|
|
14118
14647
|
continue;
|
|
@@ -14215,9 +14744,9 @@ function storedPlaceholderIsLiteralOnDisk(storedLine, diskLine) {
|
|
|
14215
14744
|
}
|
|
14216
14745
|
function buildDiff(expectedContent, targetPath, storedFormat, showSecrets) {
|
|
14217
14746
|
const path = expandPath(targetPath);
|
|
14218
|
-
if (!
|
|
14747
|
+
if (!existsSync12(path))
|
|
14219
14748
|
return `(file not found on disk: ${path})`;
|
|
14220
|
-
const diskContent =
|
|
14749
|
+
const diskContent = readFileSync12(path, "utf-8");
|
|
14221
14750
|
if (diskContent === expectedContent)
|
|
14222
14751
|
return "(no diff \u2014 identical)";
|
|
14223
14752
|
const format = redactFormatForTarget(targetPath, storedFormat);
|
|
@@ -14375,26 +14904,26 @@ function detectFormat(filePath) {
|
|
|
14375
14904
|
return "text";
|
|
14376
14905
|
}
|
|
14377
14906
|
// src/lib/export.ts
|
|
14378
|
-
import { existsSync as
|
|
14379
|
-
import { join as
|
|
14907
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync6, rmSync as rmSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
14908
|
+
import { join as join15, resolve as resolve10 } from "path";
|
|
14380
14909
|
import { tmpdir } from "os";
|
|
14381
14910
|
async function exportConfigs(outputPath, opts = {}) {
|
|
14382
14911
|
const store = opts.store ?? resolveConfigStore();
|
|
14383
14912
|
const configs = await store.listConfigs(opts.filter);
|
|
14384
|
-
const absOutput =
|
|
14385
|
-
const tmpDir =
|
|
14386
|
-
const contentsDir =
|
|
14913
|
+
const absOutput = resolve10(outputPath);
|
|
14914
|
+
const tmpDir = join15(tmpdir(), `configs-export-${Date.now()}`);
|
|
14915
|
+
const contentsDir = join15(tmpDir, "contents");
|
|
14387
14916
|
try {
|
|
14388
|
-
|
|
14917
|
+
mkdirSync6(contentsDir, { recursive: true });
|
|
14389
14918
|
const manifest = {
|
|
14390
14919
|
version: "1.0.0",
|
|
14391
14920
|
exported_at: new Date().toISOString(),
|
|
14392
14921
|
configs: configs.map(({ content: _content, ...meta }) => meta)
|
|
14393
14922
|
};
|
|
14394
|
-
|
|
14923
|
+
writeFileSync4(join15(tmpDir, "manifest.json"), JSON.stringify(manifest, null, 2), "utf-8");
|
|
14395
14924
|
for (const config of configs) {
|
|
14396
14925
|
const fileName = `${config.slug}.${config.format === "text" ? "txt" : config.format}`;
|
|
14397
|
-
|
|
14926
|
+
writeFileSync4(join15(contentsDir, fileName), config.content, "utf-8");
|
|
14398
14927
|
}
|
|
14399
14928
|
const proc = Bun.spawn(["tar", "czf", absOutput, "-C", tmpDir, "."], {
|
|
14400
14929
|
stdout: "pipe",
|
|
@@ -14407,23 +14936,23 @@ async function exportConfigs(outputPath, opts = {}) {
|
|
|
14407
14936
|
}
|
|
14408
14937
|
return { path: absOutput, count: configs.length };
|
|
14409
14938
|
} finally {
|
|
14410
|
-
if (
|
|
14411
|
-
|
|
14939
|
+
if (existsSync13(tmpDir)) {
|
|
14940
|
+
rmSync4(tmpDir, { recursive: true, force: true });
|
|
14412
14941
|
}
|
|
14413
14942
|
}
|
|
14414
14943
|
}
|
|
14415
14944
|
// src/lib/import.ts
|
|
14416
|
-
import { existsSync as
|
|
14417
|
-
import { join as
|
|
14945
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync7, readFileSync as readFileSync13, rmSync as rmSync5 } from "fs";
|
|
14946
|
+
import { join as join16, resolve as resolve11 } from "path";
|
|
14418
14947
|
import { tmpdir as tmpdir2 } from "os";
|
|
14419
14948
|
async function importConfigs(bundlePath, opts = {}) {
|
|
14420
14949
|
const store = opts.store ?? resolveConfigStore();
|
|
14421
14950
|
const conflict = opts.conflict ?? "skip";
|
|
14422
|
-
const absPath =
|
|
14423
|
-
const tmpDir =
|
|
14951
|
+
const absPath = resolve11(bundlePath);
|
|
14952
|
+
const tmpDir = join16(tmpdir2(), `configs-import-${Date.now()}`);
|
|
14424
14953
|
const result = { created: 0, updated: 0, skipped: 0, errors: [] };
|
|
14425
14954
|
try {
|
|
14426
|
-
|
|
14955
|
+
mkdirSync7(tmpDir, { recursive: true });
|
|
14427
14956
|
const proc = Bun.spawn(["tar", "xzf", absPath, "-C", tmpDir], {
|
|
14428
14957
|
stdout: "pipe",
|
|
14429
14958
|
stderr: "pipe"
|
|
@@ -14433,15 +14962,15 @@ async function importConfigs(bundlePath, opts = {}) {
|
|
|
14433
14962
|
const stderr = await new Response(proc.stderr).text();
|
|
14434
14963
|
throw new Error(`tar extraction failed: ${stderr}`);
|
|
14435
14964
|
}
|
|
14436
|
-
const manifestPath =
|
|
14437
|
-
if (!
|
|
14965
|
+
const manifestPath = join16(tmpDir, "manifest.json");
|
|
14966
|
+
if (!existsSync14(manifestPath))
|
|
14438
14967
|
throw new Error("Invalid bundle: missing manifest.json");
|
|
14439
|
-
const manifest = JSON.parse(
|
|
14968
|
+
const manifest = JSON.parse(readFileSync13(manifestPath, "utf-8"));
|
|
14440
14969
|
for (const meta of manifest.configs) {
|
|
14441
14970
|
try {
|
|
14442
14971
|
const ext = meta.format === "text" ? "txt" : meta.format;
|
|
14443
|
-
const contentFile =
|
|
14444
|
-
const content =
|
|
14972
|
+
const contentFile = join16(tmpDir, "contents", `${meta.slug}.${ext}`);
|
|
14973
|
+
const content = existsSync14(contentFile) ? readFileSync13(contentFile, "utf-8") : "";
|
|
14445
14974
|
let existing = null;
|
|
14446
14975
|
try {
|
|
14447
14976
|
existing = await store.getConfig(meta.slug);
|
|
@@ -14475,16 +15004,16 @@ async function importConfigs(bundlePath, opts = {}) {
|
|
|
14475
15004
|
}
|
|
14476
15005
|
return result;
|
|
14477
15006
|
} finally {
|
|
14478
|
-
if (
|
|
14479
|
-
|
|
15007
|
+
if (existsSync14(tmpDir)) {
|
|
15008
|
+
rmSync5(tmpDir, { recursive: true, force: true });
|
|
14480
15009
|
}
|
|
14481
15010
|
}
|
|
14482
15011
|
}
|
|
14483
15012
|
// src/lib/package-manager-guard.ts
|
|
14484
15013
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
14485
|
-
import { existsSync as
|
|
14486
|
-
import { homedir as
|
|
14487
|
-
import { basename as basename6, dirname as
|
|
15014
|
+
import { existsSync as existsSync15, lstatSync as lstatSync6, readdirSync as readdirSync4, readFileSync as readFileSync14 } from "fs";
|
|
15015
|
+
import { homedir as homedir8 } from "os";
|
|
15016
|
+
import { basename as basename6, dirname as dirname8, isAbsolute as isAbsolute5, join as join17, relative as relative7, resolve as resolve12 } from "path";
|
|
14488
15017
|
var SKIP_DIRS = new Set([
|
|
14489
15018
|
".git",
|
|
14490
15019
|
"node_modules",
|
|
@@ -14515,20 +15044,20 @@ var HOME_FILES = [
|
|
|
14515
15044
|
var TOKEN_VALUE_PATTERNS = [
|
|
14516
15045
|
{ re: /npm_[A-Za-z0-9]{36,}/, rule: "literal-npm-token", detail: "literal npm token-like value" },
|
|
14517
15046
|
{ re: /gh[pousr]_[A-Za-z0-9_]{36,}/, rule: "literal-github-token", detail: "literal GitHub token-like value" },
|
|
14518
|
-
{ re: /sk-ant-[A-Za-z0-9\-_]{40,}/, rule: "literal-anthropic-key", detail: "literal Anthropic key-like value" },
|
|
15047
|
+
{ re: /sk[-]ant-[A-Za-z0-9\-_]{40,}/, rule: "literal-anthropic-key", detail: "literal Anthropic key-like value" },
|
|
14519
15048
|
{ re: /sk-[A-Za-z0-9]{48,}/, rule: "literal-openai-key", detail: "literal OpenAI key-like value" },
|
|
14520
15049
|
{ re: /AKIA[0-9A-Z]{16}/, rule: "literal-aws-access-key", detail: "literal AWS access-key-like value" },
|
|
14521
15050
|
{ re: /xoxb-[0-9]+-[A-Za-z0-9-]+/, rule: "literal-slack-token", detail: "literal Slack token-like value" }
|
|
14522
15051
|
];
|
|
14523
15052
|
function scanPackageManagerSecrets(options = {}) {
|
|
14524
|
-
const cwd = options.cwd ?
|
|
14525
|
-
const roots = (options.roots && options.roots.length > 0 ? options.roots : [cwd]).map((root) =>
|
|
15053
|
+
const cwd = options.cwd ? resolve12(options.cwd) : process.cwd();
|
|
15054
|
+
const roots = (options.roots && options.roots.length > 0 ? options.roots : [cwd]).map((root) => resolve12(cwd, root));
|
|
14526
15055
|
const findings = [];
|
|
14527
15056
|
let scannedFiles = 0;
|
|
14528
15057
|
for (const root of roots) {
|
|
14529
|
-
if (!
|
|
15058
|
+
if (!existsSync15(root))
|
|
14530
15059
|
continue;
|
|
14531
|
-
const stat =
|
|
15060
|
+
const stat = lstatSync6(root);
|
|
14532
15061
|
if (stat.isFile()) {
|
|
14533
15062
|
if (!shouldScanRepoFile(root))
|
|
14534
15063
|
continue;
|
|
@@ -14536,14 +15065,14 @@ function scanPackageManagerSecrets(options = {}) {
|
|
|
14536
15065
|
if (text === null)
|
|
14537
15066
|
continue;
|
|
14538
15067
|
scannedFiles++;
|
|
14539
|
-
findings.push(...scanFile(root, text, classifyRepoFile(root), isTrackedFile(root),
|
|
15068
|
+
findings.push(...scanFile(root, text, classifyRepoFile(root), isTrackedFile(root), dirname8(root)));
|
|
14540
15069
|
continue;
|
|
14541
15070
|
}
|
|
14542
15071
|
if (!stat.isDirectory())
|
|
14543
15072
|
continue;
|
|
14544
15073
|
const tracked = trackedFiles(root);
|
|
14545
15074
|
for (const file of collectRepoFiles(root)) {
|
|
14546
|
-
const rel = toPosix(
|
|
15075
|
+
const rel = toPosix(relative7(root, file));
|
|
14547
15076
|
const isTracked = tracked.has(rel);
|
|
14548
15077
|
const text = readTextFile(file);
|
|
14549
15078
|
if (text === null)
|
|
@@ -14553,10 +15082,10 @@ function scanPackageManagerSecrets(options = {}) {
|
|
|
14553
15082
|
}
|
|
14554
15083
|
}
|
|
14555
15084
|
if (options.includeHome) {
|
|
14556
|
-
const home =
|
|
15085
|
+
const home = homedir8();
|
|
14557
15086
|
for (const name of HOME_FILES) {
|
|
14558
|
-
const file =
|
|
14559
|
-
if (!
|
|
15087
|
+
const file = join17(home, name);
|
|
15088
|
+
if (!existsSync15(file))
|
|
14560
15089
|
continue;
|
|
14561
15090
|
const text = readTextFile(file);
|
|
14562
15091
|
if (text === null)
|
|
@@ -14580,12 +15109,12 @@ function collectRepoFiles(root) {
|
|
|
14580
15109
|
if (entry.isDirectory()) {
|
|
14581
15110
|
if (SKIP_DIRS.has(entry.name))
|
|
14582
15111
|
continue;
|
|
14583
|
-
visit(
|
|
15112
|
+
visit(join17(dir, entry.name));
|
|
14584
15113
|
continue;
|
|
14585
15114
|
}
|
|
14586
15115
|
if (!entry.isFile())
|
|
14587
15116
|
continue;
|
|
14588
|
-
const file =
|
|
15117
|
+
const file = join17(dir, entry.name);
|
|
14589
15118
|
if (shouldScanRepoFile(file))
|
|
14590
15119
|
out.push(file);
|
|
14591
15120
|
}
|
|
@@ -14620,10 +15149,10 @@ function isNpmrcName(name) {
|
|
|
14620
15149
|
}
|
|
14621
15150
|
function readTextFile(file) {
|
|
14622
15151
|
try {
|
|
14623
|
-
const stat =
|
|
15152
|
+
const stat = lstatSync6(file);
|
|
14624
15153
|
if (!stat.isFile() || stat.size > 5000000)
|
|
14625
15154
|
return null;
|
|
14626
|
-
const buf =
|
|
15155
|
+
const buf = readFileSync14(file);
|
|
14627
15156
|
if (buf.includes(0))
|
|
14628
15157
|
return null;
|
|
14629
15158
|
return buf.toString("utf-8");
|
|
@@ -14823,11 +15352,11 @@ function trackedFiles(root) {
|
|
|
14823
15352
|
}
|
|
14824
15353
|
function isTrackedFile(file) {
|
|
14825
15354
|
try {
|
|
14826
|
-
const repoRoot = execFileSync2("git", ["-C",
|
|
15355
|
+
const repoRoot = execFileSync2("git", ["-C", dirname8(file), "rev-parse", "--show-toplevel"], {
|
|
14827
15356
|
encoding: "utf-8",
|
|
14828
15357
|
stdio: ["ignore", "pipe", "ignore"]
|
|
14829
15358
|
}).trim();
|
|
14830
|
-
const rel = toPosix(
|
|
15359
|
+
const rel = toPosix(relative7(repoRoot, file));
|
|
14831
15360
|
execFileSync2("git", ["-C", repoRoot, "ls-files", "--error-unmatch", "--", rel], {
|
|
14832
15361
|
stdio: ["ignore", "ignore", "ignore"]
|
|
14833
15362
|
});
|
|
@@ -14853,172 +15382,176 @@ function stripInlineComment(value) {
|
|
|
14853
15382
|
return value.replace(/\s[#;].*$/, "").trim();
|
|
14854
15383
|
}
|
|
14855
15384
|
function displayPath(file, root) {
|
|
14856
|
-
const home =
|
|
15385
|
+
const home = homedir8();
|
|
14857
15386
|
if (root === home && (file === home || file.startsWith(home + "/")))
|
|
14858
|
-
return "~/" + toPosix(
|
|
15387
|
+
return "~/" + toPosix(relative7(home, file));
|
|
14859
15388
|
if (isAbsolute5(root) && file.startsWith(root + "/"))
|
|
14860
|
-
return toPosix(
|
|
15389
|
+
return toPosix(relative7(root, file));
|
|
14861
15390
|
if (file === home || file.startsWith(home + "/"))
|
|
14862
|
-
return "~/" + toPosix(
|
|
15391
|
+
return "~/" + toPosix(relative7(home, file));
|
|
14863
15392
|
return file;
|
|
14864
15393
|
}
|
|
14865
15394
|
function toPosix(path) {
|
|
14866
15395
|
return path.split("\\").join("/");
|
|
14867
15396
|
}
|
|
14868
15397
|
export {
|
|
14869
|
-
|
|
14870
|
-
transformSkillContent,
|
|
14871
|
-
templateizeMachineContent,
|
|
14872
|
-
syncToDisk,
|
|
14873
|
-
syncToDir,
|
|
14874
|
-
syncProject,
|
|
14875
|
-
syncKnown,
|
|
14876
|
-
syncFromDir,
|
|
14877
|
-
stripClaudeOnlySections,
|
|
14878
|
-
sourcesFromIdentityExport,
|
|
14879
|
-
sourceFromFilePath,
|
|
14880
|
-
sourceFromConfig,
|
|
14881
|
-
slugify,
|
|
14882
|
-
selectProviderCapability,
|
|
14883
|
-
selectProfileConfigsForSessionRender,
|
|
14884
|
-
selectAssetCapability,
|
|
14885
|
-
scanSecrets,
|
|
14886
|
-
scanPackageManagerSecrets,
|
|
14887
|
-
restoreSessionRenderSnapshot,
|
|
14888
|
-
resolveSessionTargetOwnership,
|
|
14889
|
-
resolveSessionPath,
|
|
14890
|
-
resolveProfileVariables,
|
|
14891
|
-
resolveConfigStore,
|
|
14892
|
-
resolveCloudConfig,
|
|
14893
|
-
resolveAssetDestination,
|
|
14894
|
-
resolveAgentOperatingRulesPayload,
|
|
14895
|
-
renderTemplatePreview,
|
|
14896
|
-
renderTemplate,
|
|
14897
|
-
renderMachineAwareContentPreview,
|
|
14898
|
-
renderMachineAwareContent,
|
|
14899
|
-
redactContent,
|
|
14900
|
-
providerVersionSatisfies,
|
|
14901
|
-
previewConfigs,
|
|
14902
|
-
planSessionRender,
|
|
14903
|
-
planProjectContext,
|
|
14904
|
-
planProfileSessionRender,
|
|
14905
|
-
parseTemplateVars,
|
|
14906
|
-
parseProjectContextBundle,
|
|
14907
|
-
parseAgentOperatingRulesVersion,
|
|
14908
|
-
now,
|
|
14909
|
-
normalizeProfileConfigBinding,
|
|
14910
|
-
normalizeProfileAssetBinding,
|
|
14911
|
-
normalizeOsFamily,
|
|
14912
|
-
normalizeBoundedReadOptions,
|
|
14913
|
-
machineContextToVariables,
|
|
14914
|
-
legacyProfileConfigBinding,
|
|
14915
|
-
isTemplate,
|
|
14916
|
-
isCloudMode,
|
|
14917
|
-
importConfigs,
|
|
14918
|
-
hasSecrets,
|
|
14919
|
-
getConfigsStatus,
|
|
14920
|
-
extractTemplateVars,
|
|
14921
|
-
exportConfigs,
|
|
14922
|
-
expandPath,
|
|
14923
|
-
ensureProjectDashboardStandardConfig,
|
|
14924
|
-
ensurePlatformProfiles,
|
|
14925
|
-
ensureGlobalAgentRulesStandardConfig,
|
|
14926
|
-
ensureDangerousOperationGuardStandardConfig,
|
|
14927
|
-
ensureCodewithSharedTodosStorageStandardConfig,
|
|
14928
|
-
diffConfig,
|
|
14929
|
-
detectMachineContext,
|
|
14930
|
-
detectFormat,
|
|
14931
|
-
detectCategory,
|
|
14932
|
-
detectAgent,
|
|
14933
|
-
currentOs,
|
|
14934
|
-
currentHostname2 as currentHostname,
|
|
14935
|
-
currentArch2 as currentArch,
|
|
14936
|
-
configAssetLocator,
|
|
14937
|
-
configAssetDigest,
|
|
14938
|
-
computeProjectContextSourceHash,
|
|
14939
|
-
compileInstructionGraph,
|
|
14940
|
-
compileAssetPlan,
|
|
14941
|
-
compareAgentOperatingRulesVersions,
|
|
14942
|
-
cleanSessionPathInput,
|
|
14943
|
-
checkSessionRenderDrift,
|
|
14944
|
-
buildOpenCodeAgentsMd,
|
|
14945
|
-
buildCursorMdc,
|
|
14946
|
-
buildCodexAgentsMd,
|
|
14947
|
-
boundedReadPage,
|
|
14948
|
-
assetBundleFromConfig,
|
|
14949
|
-
applyTransform,
|
|
14950
|
-
applySessionRender,
|
|
14951
|
-
applyProjectContext,
|
|
14952
|
-
applyConfigsWithReport,
|
|
14953
|
-
applyConfigs,
|
|
14954
|
-
applyConfig,
|
|
14955
|
-
TemplateRenderError,
|
|
14956
|
-
SessionApplyError,
|
|
14957
|
-
SESSION_TOOL_ADAPTERS,
|
|
14958
|
-
SESSION_RENDER_TOOLS,
|
|
14959
|
-
SESSION_RENDER_SCHEMA,
|
|
14960
|
-
SESSION_RENDER_MANAGED_MARKER,
|
|
14961
|
-
SESSION_LAYER_RANK,
|
|
14962
|
-
SESSION_INSTRUCTION_LAYERS,
|
|
14963
|
-
RAW_STORE_ROOT_ENV,
|
|
14964
|
-
ProjectContextError,
|
|
14965
|
-
ProfileNotFoundError,
|
|
14966
|
-
PROVIDER_CAPABILITY_SCHEMA,
|
|
14967
|
-
PROVIDER_CAPABILITY_DESCRIPTORS,
|
|
14968
|
-
PROVIDER_CAPABILITIES,
|
|
14969
|
-
PROJECT_DASHBOARD_STANDARD_SLUG,
|
|
14970
|
-
PROJECT_DASHBOARD_STANDARD_CONTENT,
|
|
14971
|
-
PROJECT_DASHBOARD_PROFILE_VARIABLES,
|
|
14972
|
-
PROJECT_CONTEXT_SCHEMA,
|
|
14973
|
-
PROJECT_CONTEXT_MAX_RENDERED_BYTES,
|
|
14974
|
-
PROJECT_CONTEXT_MAX_INPUT_BYTES,
|
|
14975
|
-
PROJECT_CONTEXT_MAX_COMMANDS,
|
|
14976
|
-
PROJECT_CONTEXT_MANIFEST_PATH,
|
|
14977
|
-
PROJECT_CONTEXT_MANAGED_COMMENT,
|
|
14978
|
-
PROJECT_CONTEXT_LOCK_PATH,
|
|
14979
|
-
PROJECT_CONTEXT_FRAGMENT_PATH,
|
|
14980
|
-
PROJECT_CONTEXT_CACHE_PATH,
|
|
14981
|
-
PROJECT_CONFIG_FILES,
|
|
14982
|
-
PROFILE_CONFIG_BINDING_SCHEMA,
|
|
14983
|
-
PROFILE_ASSET_BINDING_SCHEMA,
|
|
14984
|
-
PLATFORM_PROFILE_PRESETS,
|
|
14985
|
-
PG_MIGRATIONS,
|
|
14986
|
-
LocalConfigStore,
|
|
14987
|
-
LEGACY_CONFIGS_PACKAGE,
|
|
14988
|
-
LEGACY_CONFIGS_EXECUTABLE,
|
|
14989
|
-
LEGACY_CONFIGS_COMPAT_VERSION,
|
|
14990
|
-
KNOWN_CONFIGS,
|
|
14991
|
-
InstructionGraphValidationError,
|
|
14992
|
-
INSTRUCTION_GRAPH_PLAN_SCHEMA,
|
|
14993
|
-
INSTRUCTION_FALLBACKS,
|
|
14994
|
-
INSTRUCTION_ACTIVATION_MODES,
|
|
14995
|
-
GLOBAL_AGENT_RULES_STANDARD_SLUG,
|
|
14996
|
-
GLOBAL_AGENT_RULES_STANDARD_CONTENT,
|
|
14997
|
-
DANGEROUS_OPERATION_GUARD_STANDARD_SLUG,
|
|
14998
|
-
DANGEROUS_OPERATION_GUARD_STANDARD_CONTENT,
|
|
14999
|
-
ConfigNotFoundError,
|
|
15000
|
-
ConfigApplyError,
|
|
15001
|
-
CloudHttpError,
|
|
15002
|
-
CloudConfigStore,
|
|
15003
|
-
CONFIG_TRANSFORMS,
|
|
15004
|
-
CONFIG_KINDS,
|
|
15005
|
-
CONFIG_FORMATS,
|
|
15006
|
-
CONFIG_CATEGORIES,
|
|
15007
|
-
CONFIG_AGENTS,
|
|
15008
|
-
CODEWITH_SHARED_TODOS_STORAGE_STANDARD_SLUG,
|
|
15009
|
-
CODEWITH_SHARED_TODOS_STORAGE_STANDARD_CONTENT,
|
|
15010
|
-
CODEWITH_SHARED_TODOS_STORAGE_POLICY_REFERENCE,
|
|
15011
|
-
CODEWITH_NATIVE_IMPORTS_ENV,
|
|
15012
|
-
AssetPlanValidationError,
|
|
15013
|
-
ASSET_UNINSTALL_POLICIES,
|
|
15014
|
-
ASSET_SCOPES,
|
|
15015
|
-
ASSET_ROLLBACK_POLICIES,
|
|
15016
|
-
ASSET_PLAN_SCHEMA,
|
|
15017
|
-
ASSET_KINDS,
|
|
15018
|
-
ASSET_DESTINATION_STRATEGIES,
|
|
15019
|
-
ASSET_CAPABILITY_SCHEMA,
|
|
15020
|
-
ASSET_CAPABILITY_DESCRIPTORS,
|
|
15021
|
-
ASSET_BUNDLE_SCHEMA,
|
|
15398
|
+
AGENT_OPERATING_RULES_SEMANTIC_POLICY_KEY,
|
|
15022
15399
|
AGENT_OPERATING_RULES_SENTINEL_PATTERN,
|
|
15023
|
-
|
|
15400
|
+
ASSET_BUNDLE_SCHEMA,
|
|
15401
|
+
ASSET_CAPABILITY_DESCRIPTORS,
|
|
15402
|
+
ASSET_CAPABILITY_SCHEMA,
|
|
15403
|
+
ASSET_DESTINATION_STRATEGIES,
|
|
15404
|
+
ASSET_KINDS,
|
|
15405
|
+
ASSET_PLAN_SCHEMA,
|
|
15406
|
+
ASSET_ROLLBACK_POLICIES,
|
|
15407
|
+
ASSET_SCOPES,
|
|
15408
|
+
ASSET_UNINSTALL_POLICIES,
|
|
15409
|
+
AssetPlanValidationError,
|
|
15410
|
+
CODEWITH_NATIVE_IMPORTS_ENV,
|
|
15411
|
+
CODEWITH_SHARED_TODOS_STORAGE_POLICY_REFERENCE,
|
|
15412
|
+
CODEWITH_SHARED_TODOS_STORAGE_STANDARD_CONTENT,
|
|
15413
|
+
CODEWITH_SHARED_TODOS_STORAGE_STANDARD_SLUG,
|
|
15414
|
+
CONFIG_AGENTS,
|
|
15415
|
+
CONFIG_CATEGORIES,
|
|
15416
|
+
CONFIG_FORMATS,
|
|
15417
|
+
CONFIG_KINDS,
|
|
15418
|
+
CONFIG_TRANSFORMS,
|
|
15419
|
+
CloudConfigStore,
|
|
15420
|
+
CloudHttpError,
|
|
15421
|
+
ConfigApplyError,
|
|
15422
|
+
ConfigNotFoundError,
|
|
15423
|
+
DANGEROUS_OPERATION_GUARD_STANDARD_CONTENT,
|
|
15424
|
+
DANGEROUS_OPERATION_GUARD_STANDARD_SLUG,
|
|
15425
|
+
GLOBAL_AGENT_RULES_STANDARD_CONTENT,
|
|
15426
|
+
GLOBAL_AGENT_RULES_STANDARD_SLUG,
|
|
15427
|
+
INBOX_CONVERSATIONS_MINIMUM_VERSION,
|
|
15428
|
+
INSTRUCTION_ACTIVATION_MODES,
|
|
15429
|
+
INSTRUCTION_FALLBACKS,
|
|
15430
|
+
INSTRUCTION_GRAPH_PLAN_SCHEMA,
|
|
15431
|
+
InstructionGraphValidationError,
|
|
15432
|
+
KNOWN_CONFIGS,
|
|
15433
|
+
LEGACY_CONFIGS_COMPAT_VERSION,
|
|
15434
|
+
LEGACY_CONFIGS_EXECUTABLE,
|
|
15435
|
+
LEGACY_CONFIGS_PACKAGE,
|
|
15436
|
+
LocalConfigStore,
|
|
15437
|
+
PG_MIGRATIONS,
|
|
15438
|
+
PLATFORM_PROFILE_PRESETS,
|
|
15439
|
+
PROFILE_ASSET_BINDING_SCHEMA,
|
|
15440
|
+
PROFILE_CONFIG_BINDING_SCHEMA,
|
|
15441
|
+
PROJECT_CONFIG_FILES,
|
|
15442
|
+
PROJECT_CONTEXT_CACHE_PATH,
|
|
15443
|
+
PROJECT_CONTEXT_FRAGMENT_PATH,
|
|
15444
|
+
PROJECT_CONTEXT_LOCK_PATH,
|
|
15445
|
+
PROJECT_CONTEXT_MANAGED_COMMENT,
|
|
15446
|
+
PROJECT_CONTEXT_MANIFEST_PATH,
|
|
15447
|
+
PROJECT_CONTEXT_MAX_COMMANDS,
|
|
15448
|
+
PROJECT_CONTEXT_MAX_INPUT_BYTES,
|
|
15449
|
+
PROJECT_CONTEXT_MAX_RENDERED_BYTES,
|
|
15450
|
+
PROJECT_CONTEXT_SCHEMA,
|
|
15451
|
+
PROJECT_DASHBOARD_PROFILE_VARIABLES,
|
|
15452
|
+
PROJECT_DASHBOARD_STANDARD_CONTENT,
|
|
15453
|
+
PROJECT_DASHBOARD_STANDARD_SLUG,
|
|
15454
|
+
PROVIDER_CAPABILITIES,
|
|
15455
|
+
PROVIDER_CAPABILITY_DESCRIPTORS,
|
|
15456
|
+
PROVIDER_CAPABILITY_SCHEMA,
|
|
15457
|
+
ProfileNotFoundError,
|
|
15458
|
+
ProjectContextError,
|
|
15459
|
+
RAW_STORE_ROOT_ENV,
|
|
15460
|
+
SESSION_INSTRUCTION_LAYERS,
|
|
15461
|
+
SESSION_LAYER_RANK,
|
|
15462
|
+
SESSION_RENDER_MANAGED_MARKER,
|
|
15463
|
+
SESSION_RENDER_SCHEMA,
|
|
15464
|
+
SESSION_RENDER_TOOLS,
|
|
15465
|
+
SESSION_TOOL_ADAPTERS,
|
|
15466
|
+
SessionApplyError,
|
|
15467
|
+
TemplateRenderError,
|
|
15468
|
+
applyConfig,
|
|
15469
|
+
applyConfigs,
|
|
15470
|
+
applyConfigsWithReport,
|
|
15471
|
+
applyProjectContext,
|
|
15472
|
+
applySessionRender,
|
|
15473
|
+
applyTransform,
|
|
15474
|
+
assetBundleFromConfig,
|
|
15475
|
+
boundedReadPage,
|
|
15476
|
+
buildCodexAgentsMd,
|
|
15477
|
+
buildCursorMdc,
|
|
15478
|
+
buildOpenCodeAgentsMd,
|
|
15479
|
+
checkSessionRenderDrift,
|
|
15480
|
+
cleanSessionPathInput,
|
|
15481
|
+
compareAgentOperatingRulesVersions,
|
|
15482
|
+
compileAssetPlan,
|
|
15483
|
+
compileInstructionGraph,
|
|
15484
|
+
computeProjectContextSourceHash,
|
|
15485
|
+
configAssetDigest,
|
|
15486
|
+
configAssetLocator,
|
|
15487
|
+
currentArch2 as currentArch,
|
|
15488
|
+
currentHostname2 as currentHostname,
|
|
15489
|
+
currentOs,
|
|
15490
|
+
detectAgent,
|
|
15491
|
+
detectCategory,
|
|
15492
|
+
detectFormat,
|
|
15493
|
+
detectMachineContext,
|
|
15494
|
+
diffConfig,
|
|
15495
|
+
ensureCodewithSharedTodosStorageStandardConfig,
|
|
15496
|
+
ensureDangerousOperationGuardStandardConfig,
|
|
15497
|
+
ensureGlobalAgentRulesStandardConfig,
|
|
15498
|
+
ensurePlatformProfiles,
|
|
15499
|
+
ensureProjectDashboardStandardConfig,
|
|
15500
|
+
expandPath,
|
|
15501
|
+
exportConfigs,
|
|
15502
|
+
extractTemplateVars,
|
|
15503
|
+
getConfigsStatus,
|
|
15504
|
+
getRawStoreRoot,
|
|
15505
|
+
hasSecrets,
|
|
15506
|
+
importConfigs,
|
|
15507
|
+
inspectManagedSkillRuntimes,
|
|
15508
|
+
isApiTransport,
|
|
15509
|
+
isTemplate,
|
|
15510
|
+
legacyProfileConfigBinding,
|
|
15511
|
+
machineContextToVariables,
|
|
15512
|
+
normalizeBoundedReadOptions,
|
|
15513
|
+
normalizeOsFamily,
|
|
15514
|
+
normalizeProfileAssetBinding,
|
|
15515
|
+
normalizeProfileConfigBinding,
|
|
15516
|
+
now,
|
|
15517
|
+
parseAgentOperatingRulesVersion,
|
|
15518
|
+
parseProjectContextBundle,
|
|
15519
|
+
parseTemplateVars,
|
|
15520
|
+
planProfileSessionRender,
|
|
15521
|
+
planProjectContext,
|
|
15522
|
+
planSessionRender,
|
|
15523
|
+
previewConfigs,
|
|
15524
|
+
providerVersionSatisfies,
|
|
15525
|
+
reconcileManagedSkillRuntimes,
|
|
15526
|
+
redactContent,
|
|
15527
|
+
renderMachineAwareContent,
|
|
15528
|
+
renderMachineAwareContentPreview,
|
|
15529
|
+
renderTemplate,
|
|
15530
|
+
renderTemplatePreview,
|
|
15531
|
+
resolveAgentOperatingRulesPayload,
|
|
15532
|
+
resolveAssetDestination,
|
|
15533
|
+
resolveCloudConfig,
|
|
15534
|
+
resolveConfigStore,
|
|
15535
|
+
resolveProfileVariables,
|
|
15536
|
+
resolveSessionPath,
|
|
15537
|
+
resolveSessionTargetOwnership,
|
|
15538
|
+
restoreSessionRenderSnapshot,
|
|
15539
|
+
scanPackageManagerSecrets,
|
|
15540
|
+
scanSecrets,
|
|
15541
|
+
selectAssetCapability,
|
|
15542
|
+
selectProfileConfigsForSessionRender,
|
|
15543
|
+
selectProviderCapability,
|
|
15544
|
+
slugify,
|
|
15545
|
+
sourceFromConfig,
|
|
15546
|
+
sourceFromFilePath,
|
|
15547
|
+
sourcesFromIdentityExport,
|
|
15548
|
+
stripClaudeOnlySections,
|
|
15549
|
+
syncFromDir,
|
|
15550
|
+
syncKnown,
|
|
15551
|
+
syncProject,
|
|
15552
|
+
syncToDir,
|
|
15553
|
+
syncToDisk,
|
|
15554
|
+
templateizeMachineContent,
|
|
15555
|
+
transformSkillContent,
|
|
15556
|
+
uuid
|
|
15024
15557
|
};
|