@hasna/instructions 0.4.35 → 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 +4 -2
- package/assets/skills/inbox/SKILL.md +86 -0
- package/dashboard/README.md +34 -70
- package/dist/cli/index.js +1136 -526
- 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/db/configs.d.ts.map +1 -1
- package/dist/generated/storage-kit/index.d.ts +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1276 -754
- package/dist/lib/apply.d.ts.map +1 -1
- package/dist/lib/cursor-authority.d.ts +36 -3
- package/dist/lib/cursor-authority.d.ts.map +1 -1
- 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/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 +290 -233
- package/dist/server/index.js +425 -231
- 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 +9 -7
package/dist/index.js
CHANGED
|
@@ -104,7 +104,7 @@ 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
109
|
|
|
110
110
|
// src/lib/retired-storage-mode.ts
|
|
@@ -128,15 +128,22 @@ function assertNoLegacyStorageMode(env = process.env) {
|
|
|
128
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
129
|
}
|
|
130
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
|
+
|
|
131
139
|
// src/db/database.ts
|
|
132
140
|
function getDbPath() {
|
|
133
141
|
if (process.env["HASNA_INSTRUCTIONS_DB_PATH"]) {
|
|
134
142
|
return process.env["HASNA_INSTRUCTIONS_DB_PATH"];
|
|
135
143
|
}
|
|
136
|
-
const
|
|
137
|
-
const dir = join(home, ".hasna", "instructions");
|
|
144
|
+
const dir = getRawStoreRoot();
|
|
138
145
|
mkdirSync(dir, { recursive: true });
|
|
139
|
-
return
|
|
146
|
+
return join2(dir, "instructions.db");
|
|
140
147
|
}
|
|
141
148
|
function uuid() {
|
|
142
149
|
return randomUUID();
|
|
@@ -315,6 +322,34 @@ function insertFeedback(input, db) {
|
|
|
315
322
|
d.run("INSERT INTO feedback (message, email, category, version) VALUES (?, ?, ?, ?)", [input.message, input.email ?? null, input.category ?? "general", input.version ?? null]);
|
|
316
323
|
}
|
|
317
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
|
+
|
|
318
353
|
// src/db/configs.ts
|
|
319
354
|
function rowToConfig(row) {
|
|
320
355
|
let outputs = [];
|
|
@@ -353,25 +388,28 @@ function createConfig(input, db) {
|
|
|
353
388
|
const slug = uniqueSlug(input.name, d);
|
|
354
389
|
const tags = JSON.stringify(input.tags || []);
|
|
355
390
|
const outputs = JSON.stringify(input.outputs || []);
|
|
356
|
-
d.
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
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
|
+
})();
|
|
375
413
|
}
|
|
376
414
|
function getConfig(idOrSlug, db) {
|
|
377
415
|
const d = db || getDatabase();
|
|
@@ -476,9 +514,13 @@ function updateConfig(idOrSlug, input, db) {
|
|
|
476
514
|
updates.push("synced_at = ?");
|
|
477
515
|
params.push(input.synced_at);
|
|
478
516
|
}
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
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
|
+
})();
|
|
482
524
|
}
|
|
483
525
|
function deleteConfig(idOrSlug, db) {
|
|
484
526
|
const d = db || getDatabase();
|
|
@@ -497,9 +539,9 @@ function getConfigStats(db) {
|
|
|
497
539
|
}
|
|
498
540
|
|
|
499
541
|
// src/lib/machine.ts
|
|
500
|
-
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";
|
|
501
543
|
import { existsSync as existsSync2 } from "fs";
|
|
502
|
-
import { join as
|
|
544
|
+
import { join as join3 } from "path";
|
|
503
545
|
|
|
504
546
|
// src/lib/template.ts
|
|
505
547
|
var VAR_PATTERN = /\{\{([A-Z0-9_]+)(?::([^}]*))?\}\}/g;
|
|
@@ -572,11 +614,11 @@ function normalizeOsFamily(os) {
|
|
|
572
614
|
return value || "unknown";
|
|
573
615
|
}
|
|
574
616
|
function detectMachineContext(overrides = {}) {
|
|
575
|
-
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();
|
|
576
618
|
const os = overrides.os ?? currentOsType();
|
|
577
619
|
const osFamily = normalizeOsFamily(os);
|
|
578
|
-
const bunBinDir = overrides.bun_bin_dir ??
|
|
579
|
-
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");
|
|
580
622
|
return {
|
|
581
623
|
id: "current-machine",
|
|
582
624
|
hostname: overrides.hostname ?? currentHostname(),
|
|
@@ -586,10 +628,10 @@ function detectMachineContext(overrides = {}) {
|
|
|
586
628
|
created_at: "",
|
|
587
629
|
os_family: osFamily,
|
|
588
630
|
home_dir: homeDir,
|
|
589
|
-
workspace_root: overrides.workspace_root ??
|
|
631
|
+
workspace_root: overrides.workspace_root ?? join3(homeDir, osFamily === "macos" ? "Workspace" : "workspace"),
|
|
590
632
|
bun_bin_dir: bunBinDir,
|
|
591
633
|
bun_path: overrides.bun_path ?? defaultBunPath,
|
|
592
|
-
path_prefix: overrides.path_prefix ?? (osFamily === "macos" ? `${
|
|
634
|
+
path_prefix: overrides.path_prefix ?? (osFamily === "macos" ? `${join3("/opt", "homebrew", "bin")}:${bunBinDir}` : bunBinDir)
|
|
593
635
|
};
|
|
594
636
|
}
|
|
595
637
|
function machineContextToVariables(machine) {
|
|
@@ -703,13 +745,13 @@ function boundedReadPage(items, total, options = {}) {
|
|
|
703
745
|
}
|
|
704
746
|
|
|
705
747
|
// src/lib/instruction-graph.ts
|
|
706
|
-
import { createHash as
|
|
748
|
+
import { createHash as createHash7 } from "crypto";
|
|
707
749
|
|
|
708
750
|
// src/lib/session-render.ts
|
|
709
|
-
import { createHash as
|
|
710
|
-
import { existsSync as existsSync4, readFileSync as
|
|
711
|
-
import { homedir as
|
|
712
|
-
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";
|
|
713
755
|
|
|
714
756
|
// src/lib/global-agent-rules-standard.ts
|
|
715
757
|
import { createHash } from "crypto";
|
|
@@ -1013,221 +1055,221 @@ import {
|
|
|
1013
1055
|
statSync,
|
|
1014
1056
|
writeFileSync
|
|
1015
1057
|
} from "fs";
|
|
1016
|
-
import { basename, dirname, isAbsolute, join as
|
|
1058
|
+
import { basename, dirname, isAbsolute, join as join4, parse, relative, resolve as resolve2 } from "path";
|
|
1017
1059
|
|
|
1018
1060
|
// ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/external.js
|
|
1019
1061
|
var exports_external = {};
|
|
1020
1062
|
__export(exports_external, {
|
|
1021
|
-
|
|
1022
|
-
util: () => util,
|
|
1023
|
-
unknown: () => unknownType,
|
|
1024
|
-
union: () => unionType,
|
|
1025
|
-
undefined: () => undefinedType,
|
|
1026
|
-
tuple: () => tupleType,
|
|
1027
|
-
transformer: () => effectsType,
|
|
1028
|
-
symbol: () => symbolType,
|
|
1029
|
-
string: () => stringType,
|
|
1030
|
-
strictObject: () => strictObjectType,
|
|
1031
|
-
setErrorMap: () => setErrorMap,
|
|
1032
|
-
set: () => setType,
|
|
1033
|
-
record: () => recordType,
|
|
1034
|
-
quotelessJson: () => quotelessJson,
|
|
1035
|
-
promise: () => promiseType,
|
|
1036
|
-
preprocess: () => preprocessType,
|
|
1037
|
-
pipeline: () => pipelineType,
|
|
1038
|
-
ostring: () => ostring,
|
|
1039
|
-
optional: () => optionalType,
|
|
1040
|
-
onumber: () => onumber,
|
|
1041
|
-
oboolean: () => oboolean,
|
|
1042
|
-
objectUtil: () => objectUtil,
|
|
1043
|
-
object: () => objectType,
|
|
1044
|
-
number: () => numberType,
|
|
1045
|
-
nullable: () => nullableType,
|
|
1046
|
-
null: () => nullType,
|
|
1047
|
-
never: () => neverType,
|
|
1048
|
-
nativeEnum: () => nativeEnumType,
|
|
1049
|
-
nan: () => nanType,
|
|
1050
|
-
map: () => mapType,
|
|
1051
|
-
makeIssue: () => makeIssue,
|
|
1052
|
-
literal: () => literalType,
|
|
1053
|
-
lazy: () => lazyType,
|
|
1054
|
-
late: () => late,
|
|
1055
|
-
isValid: () => isValid,
|
|
1056
|
-
isDirty: () => isDirty,
|
|
1057
|
-
isAsync: () => isAsync,
|
|
1058
|
-
isAborted: () => isAborted,
|
|
1059
|
-
intersection: () => intersectionType,
|
|
1060
|
-
instanceof: () => instanceOfType,
|
|
1061
|
-
getParsedType: () => getParsedType,
|
|
1062
|
-
getErrorMap: () => getErrorMap,
|
|
1063
|
-
function: () => functionType,
|
|
1064
|
-
enum: () => enumType,
|
|
1065
|
-
effect: () => effectsType,
|
|
1066
|
-
discriminatedUnion: () => discriminatedUnionType,
|
|
1067
|
-
defaultErrorMap: () => en_default,
|
|
1068
|
-
datetimeRegex: () => datetimeRegex,
|
|
1069
|
-
date: () => dateType,
|
|
1070
|
-
custom: () => custom,
|
|
1071
|
-
coerce: () => coerce,
|
|
1072
|
-
boolean: () => booleanType,
|
|
1073
|
-
bigint: () => bigIntType,
|
|
1074
|
-
array: () => arrayType,
|
|
1075
|
-
any: () => anyType,
|
|
1076
|
-
addIssueToContext: () => addIssueToContext,
|
|
1077
|
-
ZodVoid: () => ZodVoid,
|
|
1078
|
-
ZodUnknown: () => ZodUnknown,
|
|
1079
|
-
ZodUnion: () => ZodUnion,
|
|
1080
|
-
ZodUndefined: () => ZodUndefined,
|
|
1081
|
-
ZodType: () => ZodType,
|
|
1082
|
-
ZodTuple: () => ZodTuple,
|
|
1083
|
-
ZodTransformer: () => ZodEffects,
|
|
1084
|
-
ZodSymbol: () => ZodSymbol,
|
|
1085
|
-
ZodString: () => ZodString,
|
|
1086
|
-
ZodSet: () => ZodSet,
|
|
1087
|
-
ZodSchema: () => ZodType,
|
|
1088
|
-
ZodRecord: () => ZodRecord,
|
|
1089
|
-
ZodReadonly: () => ZodReadonly,
|
|
1090
|
-
ZodPromise: () => ZodPromise,
|
|
1091
|
-
ZodPipeline: () => ZodPipeline,
|
|
1092
|
-
ZodParsedType: () => ZodParsedType,
|
|
1093
|
-
ZodOptional: () => ZodOptional,
|
|
1094
|
-
ZodObject: () => ZodObject,
|
|
1095
|
-
ZodNumber: () => ZodNumber,
|
|
1096
|
-
ZodNullable: () => ZodNullable,
|
|
1097
|
-
ZodNull: () => ZodNull,
|
|
1098
|
-
ZodNever: () => ZodNever,
|
|
1099
|
-
ZodNativeEnum: () => ZodNativeEnum,
|
|
1100
|
-
ZodNaN: () => ZodNaN,
|
|
1101
|
-
ZodMap: () => ZodMap,
|
|
1102
|
-
ZodLiteral: () => ZodLiteral,
|
|
1103
|
-
ZodLazy: () => ZodLazy,
|
|
1104
|
-
ZodIssueCode: () => ZodIssueCode,
|
|
1105
|
-
ZodIntersection: () => ZodIntersection,
|
|
1106
|
-
ZodFunction: () => ZodFunction,
|
|
1107
|
-
ZodFirstPartyTypeKind: () => ZodFirstPartyTypeKind,
|
|
1108
|
-
ZodError: () => ZodError,
|
|
1109
|
-
ZodEnum: () => ZodEnum,
|
|
1110
|
-
ZodEffects: () => ZodEffects,
|
|
1111
|
-
ZodDiscriminatedUnion: () => ZodDiscriminatedUnion,
|
|
1112
|
-
ZodDefault: () => ZodDefault,
|
|
1113
|
-
ZodDate: () => ZodDate,
|
|
1114
|
-
ZodCatch: () => ZodCatch,
|
|
1115
|
-
ZodBranded: () => ZodBranded,
|
|
1116
|
-
ZodBoolean: () => ZodBoolean,
|
|
1117
|
-
ZodBigInt: () => ZodBigInt,
|
|
1118
|
-
ZodArray: () => ZodArray,
|
|
1119
|
-
ZodAny: () => ZodAny,
|
|
1120
|
-
Schema: () => ZodType,
|
|
1121
|
-
ParseStatus: () => ParseStatus,
|
|
1122
|
-
OK: () => OK,
|
|
1123
|
-
NEVER: () => NEVER,
|
|
1124
|
-
INVALID: () => INVALID,
|
|
1125
|
-
EMPTY_PATH: () => EMPTY_PATH,
|
|
1063
|
+
BRAND: () => BRAND,
|
|
1126
1064
|
DIRTY: () => DIRTY,
|
|
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
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
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":
|
|
1265
|
+
return ZodParsedType.undefined;
|
|
1266
|
+
case "string":
|
|
1267
|
+
return ZodParsedType.string;
|
|
1268
|
+
case "number":
|
|
1269
|
+
return Number.isNaN(data) ? ZodParsedType.nan : ZodParsedType.number;
|
|
1270
|
+
case "boolean":
|
|
1271
|
+
return ZodParsedType.boolean;
|
|
1272
|
+
case "function":
|
|
1231
1273
|
return ZodParsedType.function;
|
|
1232
1274
|
case "bigint":
|
|
1233
1275
|
return ZodParsedType.bigint;
|
|
@@ -5600,7 +5642,7 @@ function composeProjectContextSessionRender(input) {
|
|
|
5600
5642
|
if (currentMarkers.block.id !== cache.project_id || currentMarkers.block.revision !== cache.revision || currentMarkers.block.hash !== cache.hash) {
|
|
5601
5643
|
throw new ProjectContextError("MANAGED_BLOCK_CONFLICT", "project-context provider markers differ from the durable cache");
|
|
5602
5644
|
}
|
|
5603
|
-
const plannedIndexes = input.files.filter((file) => file.role === "index" &&
|
|
5645
|
+
const plannedIndexes = input.files.filter((file) => file.role === "index" && resolve2(file.path) === paths.target);
|
|
5604
5646
|
if (plannedIndexes.length !== 1) {
|
|
5605
5647
|
throw new ProjectContextError("PROJECT_CONTEXT_MANIFEST_INVALID", "session renderer does not own the selected project-context provider target");
|
|
5606
5648
|
}
|
|
@@ -5658,7 +5700,7 @@ function withProjectContextSessionGuard(guard, action, options = {}) {
|
|
|
5658
5700
|
verify();
|
|
5659
5701
|
return action(null);
|
|
5660
5702
|
}
|
|
5661
|
-
const lockPath =
|
|
5703
|
+
const lockPath = resolve2(validated.workspace_root, ...PROJECT_CONTEXT_LOCK_PATH.split("/"));
|
|
5662
5704
|
const lock = acquireWorkspaceLock(validated.workspace_root, lockPath);
|
|
5663
5705
|
try {
|
|
5664
5706
|
verify();
|
|
@@ -5684,7 +5726,7 @@ function validateProjectContextSessionGuard(guard) {
|
|
|
5684
5726
|
if (!isRecord(observed) || typeof observed.path !== "string") {
|
|
5685
5727
|
throw new ProjectContextError("PROJECT_CONTEXT_SESSION_STALE", "session project-context guard contains malformed hash metadata");
|
|
5686
5728
|
}
|
|
5687
|
-
const path =
|
|
5729
|
+
const path = resolve2(observed.path);
|
|
5688
5730
|
if (!allowedPaths.has(path) || observedPaths.has(path)) {
|
|
5689
5731
|
throw new ProjectContextError("PROJECT_CONTEXT_SESSION_STALE", "session project-context guard contains an unexpected or duplicate path");
|
|
5690
5732
|
}
|
|
@@ -5706,7 +5748,7 @@ function validateProjectContextSessionGuard(guard) {
|
|
|
5706
5748
|
function applyProjectContext(options) {
|
|
5707
5749
|
const workspaceRoot = assertSafeWorkspaceRoot(options.workspace_root);
|
|
5708
5750
|
const now2 = options.now ?? new Date;
|
|
5709
|
-
const lockPath =
|
|
5751
|
+
const lockPath = resolve2(workspaceRoot, ...PROJECT_CONTEXT_LOCK_PATH.split("/"));
|
|
5710
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);
|
|
5711
5753
|
try {
|
|
5712
5754
|
const resolved = resolveBundleForApply(options, workspaceRoot, now2);
|
|
@@ -5853,7 +5895,7 @@ function resolveBundleForApply(options, workspaceRoot, now2) {
|
|
|
5853
5895
|
if (!options.expected_project_id) {
|
|
5854
5896
|
throw new ProjectContextError("PROJECT_CONTEXT_CACHE_ID_REQUIRED", "expected_project_id is required for stale-cache fallback");
|
|
5855
5897
|
}
|
|
5856
|
-
const cachePath =
|
|
5898
|
+
const cachePath = resolve2(workspaceRoot, ...PROJECT_CONTEXT_CACHE_PATH.split("/"));
|
|
5857
5899
|
const cache = readProjectContextCache(cachePath, workspaceRoot);
|
|
5858
5900
|
if (!cache)
|
|
5859
5901
|
throw new ProjectContextError("PROJECT_CONTEXT_CACHE_MISSING", "no last-known-good project context cache exists");
|
|
@@ -6209,7 +6251,7 @@ function buildManifest(plan, now2) {
|
|
|
6209
6251
|
function buildSessionCompatibilityManifest(plan, now2) {
|
|
6210
6252
|
const paths = runtimePaths(plan.workspace_root, plan.runtime);
|
|
6211
6253
|
const tool = manifestTool(plan.runtime);
|
|
6212
|
-
const targetHome = plan.runtime === "codewith" ?
|
|
6254
|
+
const targetHome = plan.runtime === "codewith" ? resolve2(plan.workspace_root, ".codewith") : plan.workspace_root;
|
|
6213
6255
|
const targetRelativePath = sessionTargetRelativePath(plan.runtime);
|
|
6214
6256
|
const existing = existsSync3(paths.sessionManifest) ? readSessionManifestRecord(paths.sessionManifest, plan.workspace_root) : {
|
|
6215
6257
|
schema: SESSION_RENDER_SCHEMA,
|
|
@@ -6231,7 +6273,7 @@ function buildSessionCompatibilityManifest(plan, now2) {
|
|
|
6231
6273
|
throw new ProjectContextError("PROJECT_CONTEXT_MANIFEST_INVALID", "provider session manifest is malformed or incompatible");
|
|
6232
6274
|
}
|
|
6233
6275
|
const existingTargetHome = safeLegacyMetadataString(existing["targetHome"], null);
|
|
6234
|
-
if (existingTargetHome !== null &&
|
|
6276
|
+
if (existingTargetHome !== null && resolve2(existingTargetHome) !== targetHome) {
|
|
6235
6277
|
throw new ProjectContextError("PROJECT_CONTEXT_MANIFEST_INVALID", "provider session manifest targets a different workspace");
|
|
6236
6278
|
}
|
|
6237
6279
|
const sources = sanitizeLegacySources(existing["sources"]).filter((source) => source["id"] !== "project-context-bundle");
|
|
@@ -6517,9 +6559,9 @@ function writeMetadataSnapshot(plan, now2) {
|
|
|
6517
6559
|
const previous = readProjectContextManifest(plan.manifest_path, plan.workspace_root);
|
|
6518
6560
|
if (!previous || previous.projectContext.revision === plan.bundle.revision && previous.projectContext.hash === plan.bundle.hash)
|
|
6519
6561
|
return null;
|
|
6520
|
-
const snapshotDir =
|
|
6562
|
+
const snapshotDir = resolve2(plan.workspace_root, ...PROJECT_CONTEXT_SNAPSHOT_DIR.split("/"));
|
|
6521
6563
|
ensureSafeDirectory(snapshotDir, plan.workspace_root, 448);
|
|
6522
|
-
const snapshotPath =
|
|
6564
|
+
const snapshotPath = resolve2(snapshotDir, `${safeFilename(previous.projectContext.revision)}-${previous.projectContext.hash.slice(-12)}.json`);
|
|
6523
6565
|
const snapshot = {
|
|
6524
6566
|
schema: "hasna.configs.session-render-snapshot/v1",
|
|
6525
6567
|
kind: "project-context-metadata",
|
|
@@ -6535,8 +6577,8 @@ function writeMetadataSnapshot(plan, now2) {
|
|
|
6535
6577
|
return snapshotPath;
|
|
6536
6578
|
}
|
|
6537
6579
|
function metadataSnapshotMatchesManifest(plan, manifest) {
|
|
6538
|
-
const snapshotDir =
|
|
6539
|
-
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`);
|
|
6540
6582
|
if (!existsSync3(snapshotPath))
|
|
6541
6583
|
return false;
|
|
6542
6584
|
const record = readJsonRecord(snapshotPath, plan.workspace_root);
|
|
@@ -6585,10 +6627,10 @@ function writeProjectContextRollbackSnapshot(plan, now2, outputs) {
|
|
|
6585
6627
|
sha256: nextHash
|
|
6586
6628
|
};
|
|
6587
6629
|
});
|
|
6588
|
-
const snapshotDir =
|
|
6630
|
+
const snapshotDir = resolve2(plan.workspace_root, ...SESSION_RENDER_SNAPSHOT_RELATIVE_DIR.split("/"));
|
|
6589
6631
|
ensureSafeDirectory(snapshotDir, plan.workspace_root, 448);
|
|
6590
6632
|
const timestamp = now2.toISOString().replace(/[:.]/g, "-");
|
|
6591
|
-
const snapshotPath =
|
|
6633
|
+
const snapshotPath = resolve2(snapshotDir, `${timestamp}-${randomUUID2()}.json`);
|
|
6592
6634
|
const snapshot = {
|
|
6593
6635
|
schema: "hasna.configs.session-render-snapshot/v2",
|
|
6594
6636
|
createdAt: now2.toISOString(),
|
|
@@ -6653,7 +6695,7 @@ function readSessionManifestRecord(path, workspaceRoot) {
|
|
|
6653
6695
|
}
|
|
6654
6696
|
}
|
|
6655
6697
|
function atomicWriteFile(path, content, workspaceRoot, defaultMode, expectedHash, afterExchange, atomicExchangeUnavailable = false, beforeInstall, portableCreateOnly = false, maxObservedBytes, allowPortableReplacement = false) {
|
|
6656
|
-
const dir =
|
|
6698
|
+
const dir = resolve2(path, "..");
|
|
6657
6699
|
ensureSafeDirectory(dir, workspaceRoot, 448);
|
|
6658
6700
|
assertNoSymlinkSegments(workspaceRoot, path);
|
|
6659
6701
|
const anchoredOps = portableCreateOnly ? null : resolveAnchoredFsOps();
|
|
@@ -6670,7 +6712,7 @@ function atomicWriteFile(path, content, workspaceRoot, defaultMode, expectedHash
|
|
|
6670
6712
|
const previous = anchoredFileObservation(directory, targetName);
|
|
6671
6713
|
const previousMode = previous?.mode ?? defaultMode;
|
|
6672
6714
|
const tempName = `.project-context-${randomUUID2()}.tmp`;
|
|
6673
|
-
const tempPath =
|
|
6715
|
+
const tempPath = join4(dir, tempName);
|
|
6674
6716
|
let fd = null;
|
|
6675
6717
|
let preserveTemp = false;
|
|
6676
6718
|
let directoryChanged = false;
|
|
@@ -6801,7 +6843,7 @@ function atomicWritePortable(path, content, workspaceRoot, defaultMode, expected
|
|
|
6801
6843
|
}
|
|
6802
6844
|
const dir = dirname(path);
|
|
6803
6845
|
const directoryIdentity = captureManagedDirectoryIdentity(dir, workspaceRoot);
|
|
6804
|
-
const tempPath =
|
|
6846
|
+
const tempPath = join4(dir, `.project-context-${randomUUID2()}.tmp`);
|
|
6805
6847
|
let fd = null;
|
|
6806
6848
|
let tempIdentity = null;
|
|
6807
6849
|
try {
|
|
@@ -6858,7 +6900,7 @@ function atomicWritePortableReplacement(path, content, workspaceRoot, expectedHa
|
|
|
6858
6900
|
}
|
|
6859
6901
|
const dir = dirname(path);
|
|
6860
6902
|
const directoryIdentity = captureManagedDirectoryIdentity(dir, workspaceRoot);
|
|
6861
|
-
const tempPath =
|
|
6903
|
+
const tempPath = join4(dir, `.project-context-${randomUUID2()}.tmp`);
|
|
6862
6904
|
const desiredHash = sha2562(content);
|
|
6863
6905
|
let fd = null;
|
|
6864
6906
|
let tempIdentity = null;
|
|
@@ -6927,11 +6969,11 @@ function portableFileHash(path, workspaceRoot, maxObservedBytes) {
|
|
|
6927
6969
|
return createHash2("sha256").update(readFileSync(path)).digest("hex");
|
|
6928
6970
|
}
|
|
6929
6971
|
function writeProjectContextCoordinatedFile(input) {
|
|
6930
|
-
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);
|
|
6931
6973
|
}
|
|
6932
6974
|
function removeProjectContextCoordinatedFile(input) {
|
|
6933
6975
|
const workspaceRoot = assertSafeWorkspaceRoot(input.workspace_root);
|
|
6934
|
-
const path =
|
|
6976
|
+
const path = resolve2(input.path);
|
|
6935
6977
|
assertNoSymlinkSegments(workspaceRoot, path);
|
|
6936
6978
|
const dir = dirname(path);
|
|
6937
6979
|
const anchoredOps = input.force_portable_file_ops ? null : resolveAnchoredFsOps();
|
|
@@ -6957,7 +6999,7 @@ function removeProjectContextCoordinatedFile(input) {
|
|
|
6957
6999
|
throw new ProjectContextHashRace(`managed path changed during deletion: ${relativePosix(workspaceRoot, path)}`);
|
|
6958
7000
|
}
|
|
6959
7001
|
displaced = true;
|
|
6960
|
-
input.test_hooks?.after_displace?.(
|
|
7002
|
+
input.test_hooks?.after_displace?.(join4(dir, displacedName));
|
|
6961
7003
|
const moved = anchoredFileObservation(directory, displacedName);
|
|
6962
7004
|
if (!moved || moved.dev !== observed.dev || moved.ino !== observed.ino || moved.hash !== input.expected_hash || anchoredFileObservation(directory, targetName) !== null) {
|
|
6963
7005
|
throw new ProjectContextHashRace(`managed path changed during deletion validation: ${relativePosix(workspaceRoot, path)}`);
|
|
@@ -7003,7 +7045,7 @@ function removePortableCoordinatedFile(path, workspaceRoot, expectedHash, maxObs
|
|
|
7003
7045
|
}
|
|
7004
7046
|
const dir = dirname(path);
|
|
7005
7047
|
const directoryIdentity = captureManagedDirectoryIdentity(dir, workspaceRoot);
|
|
7006
|
-
const displacedPath =
|
|
7048
|
+
const displacedPath = join4(dir, `.project-context-delete-${randomUUID2()}.tmp`);
|
|
7007
7049
|
let displaced = false;
|
|
7008
7050
|
try {
|
|
7009
7051
|
assertManagedDirectoryStable(dir, workspaceRoot, directoryIdentity);
|
|
@@ -7075,7 +7117,7 @@ function anchoredOpenExclusive(directory, name, mode) {
|
|
|
7075
7117
|
const requestedMode = mode & 4095;
|
|
7076
7118
|
let fd;
|
|
7077
7119
|
try {
|
|
7078
|
-
fd = openSync(
|
|
7120
|
+
fd = openSync(join4(directory.path, name), constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW, requestedMode);
|
|
7079
7121
|
} catch {
|
|
7080
7122
|
throw new ProjectContextHashRace(`could not create prepared managed file in ${relativePosix(directory.workspaceRoot, directory.path)}`);
|
|
7081
7123
|
}
|
|
@@ -7118,7 +7160,7 @@ function anchoredFileObservation(directory, name) {
|
|
|
7118
7160
|
const stat = fstatSync(fd);
|
|
7119
7161
|
if (!stat.isFile())
|
|
7120
7162
|
throw new ProjectContextHashRace("managed output is not a regular file");
|
|
7121
|
-
const relativePath = relativePosix(directory.workspaceRoot,
|
|
7163
|
+
const relativePath = relativePosix(directory.workspaceRoot, join4(directory.path, name));
|
|
7122
7164
|
const maxBytes = directory.maxObservedBytes === undefined ? managedObservationMaxBytes(relativePath) : directory.maxObservedBytes;
|
|
7123
7165
|
if (maxBytes !== null && stat.size > maxBytes) {
|
|
7124
7166
|
throw new ProjectContextHashRace(`managed output exceeds the safe read limit: ${relativePath}`);
|
|
@@ -7144,7 +7186,7 @@ function anchoredPreparedObservation(directory, name, path, stage) {
|
|
|
7144
7186
|
return observed;
|
|
7145
7187
|
}
|
|
7146
7188
|
function captureManagedDirectoryIdentity(path, workspaceRoot) {
|
|
7147
|
-
assertNoSymlinkSegments(workspaceRoot,
|
|
7189
|
+
assertNoSymlinkSegments(workspaceRoot, join4(path, ".project-context-directory-guard"));
|
|
7148
7190
|
let stat;
|
|
7149
7191
|
try {
|
|
7150
7192
|
stat = lstatSync(path);
|
|
@@ -7157,7 +7199,7 @@ function captureManagedDirectoryIdentity(path, workspaceRoot) {
|
|
|
7157
7199
|
return { dev: stat.dev, ino: stat.ino };
|
|
7158
7200
|
}
|
|
7159
7201
|
function assertManagedDirectoryStable(path, workspaceRoot, expected) {
|
|
7160
|
-
assertNoSymlinkSegments(workspaceRoot,
|
|
7202
|
+
assertNoSymlinkSegments(workspaceRoot, join4(path, ".project-context-directory-guard"));
|
|
7161
7203
|
let current;
|
|
7162
7204
|
try {
|
|
7163
7205
|
current = lstatSync(path);
|
|
@@ -7292,10 +7334,10 @@ function resolveAnchoredFsOps() {
|
|
|
7292
7334
|
return null;
|
|
7293
7335
|
}
|
|
7294
7336
|
function acquireWorkspaceLock(workspaceRoot, lockPath, afterOpen, beforeStaleRemove, processStartIdentityLookup = processStartIdentity) {
|
|
7295
|
-
const lockDirectory =
|
|
7337
|
+
const lockDirectory = resolve2(lockPath, "..");
|
|
7296
7338
|
ensureSafeDirectory(lockDirectory, workspaceRoot, 448);
|
|
7297
7339
|
assertNoSymlinkSegments(workspaceRoot, lockPath);
|
|
7298
|
-
const tempPath =
|
|
7340
|
+
const tempPath = join4(lockDirectory, `.project-context-lock-${randomUUID2()}.tmp`);
|
|
7299
7341
|
let fd = null;
|
|
7300
7342
|
let openedIdentity = null;
|
|
7301
7343
|
let openedContentHash = null;
|
|
@@ -7367,7 +7409,7 @@ function removeOwnedLockByInode(lockPath, identity, expectedHash) {
|
|
|
7367
7409
|
if (expectedHash !== undefined && sha2562(readFileSync(lockPath, "utf8")) !== expectedHash)
|
|
7368
7410
|
return;
|
|
7369
7411
|
rmSync2(lockPath);
|
|
7370
|
-
fsyncDirectory(
|
|
7412
|
+
fsyncDirectory(resolve2(lockPath, ".."));
|
|
7371
7413
|
} catch {}
|
|
7372
7414
|
}
|
|
7373
7415
|
function observeStaleWorkspaceLock(lockPath, workspaceRoot, processStartIdentityLookup = processStartIdentity) {
|
|
@@ -7446,7 +7488,7 @@ function tryTakeoverStaleWorkspaceLock(candidatePath, lockPath, workspaceRoot, c
|
|
|
7446
7488
|
throw new ProjectContextError("PROJECT_CONTEXT_LOCK_LOST", "workspace lock changed during stale-lock takeover and could not be restored safely");
|
|
7447
7489
|
}
|
|
7448
7490
|
rmSync2(candidatePath);
|
|
7449
|
-
fsyncDirectory(
|
|
7491
|
+
fsyncDirectory(resolve2(lockPath, ".."));
|
|
7450
7492
|
exchanged = false;
|
|
7451
7493
|
return true;
|
|
7452
7494
|
} catch (error) {
|
|
@@ -7525,8 +7567,8 @@ function releaseWorkspaceLock(lockPath, lock, workspaceRoot) {
|
|
|
7525
7567
|
}
|
|
7526
7568
|
return;
|
|
7527
7569
|
}
|
|
7528
|
-
const lockDirectory =
|
|
7529
|
-
const releasePath =
|
|
7570
|
+
const lockDirectory = resolve2(lockPath, "..");
|
|
7571
|
+
const releasePath = join4(lockDirectory, `.project-context-release-${randomUUID2()}.tmp`);
|
|
7530
7572
|
let releaseFd = null;
|
|
7531
7573
|
let releaseIdentity = null;
|
|
7532
7574
|
let releaseHash = null;
|
|
@@ -7606,7 +7648,7 @@ function ensureSafeDirectory(path, workspaceRoot, mode) {
|
|
|
7606
7648
|
const segments = rel.split(/[\\/]+/).filter(Boolean);
|
|
7607
7649
|
let current = workspaceRoot;
|
|
7608
7650
|
for (const segment of segments) {
|
|
7609
|
-
current =
|
|
7651
|
+
current = join4(current, segment);
|
|
7610
7652
|
if (existsSync3(current)) {
|
|
7611
7653
|
if (lstatSync(current).isSymbolicLink())
|
|
7612
7654
|
throw new ProjectContextError("PROJECT_CONTEXT_SYMLINK_REJECTED", `managed path uses a symlink: ${current}`);
|
|
@@ -7614,7 +7656,7 @@ function ensureSafeDirectory(path, workspaceRoot, mode) {
|
|
|
7614
7656
|
throw new ProjectContextError("PROJECT_CONTEXT_PATH_INVALID", `managed path is not a directory: ${current}`);
|
|
7615
7657
|
} else {
|
|
7616
7658
|
mkdirSync2(current, { mode });
|
|
7617
|
-
fsyncDirectory(
|
|
7659
|
+
fsyncDirectory(resolve2(current, ".."));
|
|
7618
7660
|
}
|
|
7619
7661
|
}
|
|
7620
7662
|
}
|
|
@@ -7670,11 +7712,11 @@ function scanGeneratedContent(content) {
|
|
|
7670
7712
|
function runtimePaths(workspaceRoot, runtime) {
|
|
7671
7713
|
const relativeTarget = runtime === "claude" ? "CLAUDE.md" : runtime === "codewith" ? ".codewith/CODEWITH.md" : "AGENTS.md";
|
|
7672
7714
|
return {
|
|
7673
|
-
target:
|
|
7674
|
-
fragment:
|
|
7675
|
-
manifest:
|
|
7676
|
-
cache:
|
|
7677
|
-
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")
|
|
7678
7720
|
};
|
|
7679
7721
|
}
|
|
7680
7722
|
function projectContextSessionGuardPaths(paths, runtime) {
|
|
@@ -7684,7 +7726,7 @@ function projectContextSessionGuardPaths(paths, runtime) {
|
|
|
7684
7726
|
paths.fragment,
|
|
7685
7727
|
paths.target,
|
|
7686
7728
|
paths.sessionManifest,
|
|
7687
|
-
...runtime === "codewith" ? [
|
|
7729
|
+
...runtime === "codewith" ? [resolve2(paths.target, "..", "CODEWITH.override.md")] : []
|
|
7688
7730
|
];
|
|
7689
7731
|
}
|
|
7690
7732
|
function sessionTargetRelativePath(runtime) {
|
|
@@ -7704,12 +7746,12 @@ function projectContextRuntimeForSessionTool(tool) {
|
|
|
7704
7746
|
return null;
|
|
7705
7747
|
}
|
|
7706
7748
|
function projectContextWorkspaceForSession(input, runtime) {
|
|
7707
|
-
const targetHome =
|
|
7749
|
+
const targetHome = resolve2(input.target_home);
|
|
7708
7750
|
if (runtime === "codewith") {
|
|
7709
7751
|
const workspaceRoot = basename(targetHome) === ".codewith" ? dirname(targetHome) : null;
|
|
7710
7752
|
if (!workspaceRoot)
|
|
7711
7753
|
return null;
|
|
7712
|
-
if (input.project_root &&
|
|
7754
|
+
if (input.project_root && resolve2(input.project_root) !== workspaceRoot) {
|
|
7713
7755
|
throw new ProjectContextError("PROJECT_CONTEXT_PATH_INVALID", "Codewith project_root must be the parent workspace of target_home");
|
|
7714
7756
|
}
|
|
7715
7757
|
if (!existsSync3(workspaceRoot) || !lstatSync(workspaceRoot).isDirectory())
|
|
@@ -7723,7 +7765,7 @@ function projectContextWorkspaceForSession(input, runtime) {
|
|
|
7723
7765
|
function assertCodewithTargetIsConsumed(workspaceRoot, runtime) {
|
|
7724
7766
|
if (runtime !== "codewith")
|
|
7725
7767
|
return;
|
|
7726
|
-
const override =
|
|
7768
|
+
const override = resolve2(workspaceRoot, ".codewith", "CODEWITH.override.md");
|
|
7727
7769
|
if (!existsSync3(override))
|
|
7728
7770
|
return;
|
|
7729
7771
|
assertNoSymlinkSegments(workspaceRoot, override);
|
|
@@ -7734,7 +7776,7 @@ function assertCodewithTargetIsConsumed(workspaceRoot, runtime) {
|
|
|
7734
7776
|
function assertSafeWorkspaceRoot(path) {
|
|
7735
7777
|
if (!isAbsolute(path))
|
|
7736
7778
|
throw new ProjectContextError("PROJECT_CONTEXT_PATH_INVALID", "workspace root must be absolute");
|
|
7737
|
-
const normalized =
|
|
7779
|
+
const normalized = resolve2(path);
|
|
7738
7780
|
if (normalized === parse(normalized).root)
|
|
7739
7781
|
throw new ProjectContextError("PROJECT_CONTEXT_PATH_INVALID", "workspace root cannot be the filesystem root");
|
|
7740
7782
|
if (!existsSync3(normalized) || !lstatSync(normalized).isDirectory())
|
|
@@ -7751,17 +7793,17 @@ function assertNoSymlinkSegments(root, target) {
|
|
|
7751
7793
|
}
|
|
7752
7794
|
let current = root;
|
|
7753
7795
|
for (const segment of rel.split(/[\\/]+/).filter(Boolean)) {
|
|
7754
|
-
current =
|
|
7796
|
+
current = join4(current, segment);
|
|
7755
7797
|
if (existsSync3(current) && lstatSync(current).isSymbolicLink()) {
|
|
7756
7798
|
throw new ProjectContextError("PROJECT_CONTEXT_SYMLINK_REJECTED", `managed path uses a symlink: ${current}`);
|
|
7757
7799
|
}
|
|
7758
7800
|
}
|
|
7759
7801
|
}
|
|
7760
7802
|
function assertNoSymlinkAncestors(path) {
|
|
7761
|
-
const normalized =
|
|
7803
|
+
const normalized = resolve2(path);
|
|
7762
7804
|
let current = parse(normalized).root;
|
|
7763
7805
|
for (const segment of relative(current, normalized).split(/[\\/]+/).filter(Boolean)) {
|
|
7764
|
-
current =
|
|
7806
|
+
current = join4(current, segment);
|
|
7765
7807
|
if (!existsSync3(current))
|
|
7766
7808
|
return;
|
|
7767
7809
|
if (lstatSync(current).isSymbolicLink())
|
|
@@ -7797,10 +7839,10 @@ function fragmentMatchesBundle(path, bundle, workspaceRoot) {
|
|
|
7797
7839
|
}
|
|
7798
7840
|
function durableSourcePath(path, workspaceRoot) {
|
|
7799
7841
|
if (!path || path.startsWith("/dev/fd/"))
|
|
7800
|
-
return
|
|
7801
|
-
const normalized = isAbsolute(path) ?
|
|
7842
|
+
return resolve2(workspaceRoot, ...PROJECT_CONTEXT_CACHE_PATH.split("/"));
|
|
7843
|
+
const normalized = isAbsolute(path) ? resolve2(path) : resolve2(workspaceRoot, path);
|
|
7802
7844
|
if (normalized.startsWith("/dev/fd/"))
|
|
7803
|
-
return
|
|
7845
|
+
return resolve2(workspaceRoot, ...PROJECT_CONTEXT_CACHE_PATH.split("/"));
|
|
7804
7846
|
return normalized;
|
|
7805
7847
|
}
|
|
7806
7848
|
function compareRevisions(incoming, previous) {
|
|
@@ -8098,7 +8140,7 @@ function applyTransform(source, output, context = {}) {
|
|
|
8098
8140
|
|
|
8099
8141
|
// src/lib/asset-plan.ts
|
|
8100
8142
|
import { createHash as createHash3 } from "crypto";
|
|
8101
|
-
import { isAbsolute as isAbsolute2, posix, resolve as
|
|
8143
|
+
import { isAbsolute as isAbsolute2, posix, resolve as resolve3 } from "path";
|
|
8102
8144
|
|
|
8103
8145
|
// src/lib/provider-version.ts
|
|
8104
8146
|
function providerVersionSatisfies(version, range) {
|
|
@@ -8408,8 +8450,8 @@ function resolveAssetDestination(item, roots) {
|
|
|
8408
8450
|
if (!isAbsolute2(root))
|
|
8409
8451
|
throw new Error(`Asset ${item.assetKey} destination root must be absolute.`);
|
|
8410
8452
|
const relativePath = safeRelativePath(item.destination.relativePath);
|
|
8411
|
-
const target =
|
|
8412
|
-
const normalizedRoot =
|
|
8453
|
+
const target = resolve3(root, ...relativePath.split("/"));
|
|
8454
|
+
const normalizedRoot = resolve3(root);
|
|
8413
8455
|
if (target === normalizedRoot)
|
|
8414
8456
|
throw new Error(`Asset ${item.assetKey} destination cannot replace its root.`);
|
|
8415
8457
|
if (!target.startsWith(`${normalizedRoot}/`))
|
|
@@ -8531,27 +8573,24 @@ function deepFreeze(value) {
|
|
|
8531
8573
|
// src/lib/cursor-authority.ts
|
|
8532
8574
|
import { createHash as createHash4 } from "crypto";
|
|
8533
8575
|
import { lstatSync as lstatSync2, readFileSync as readFileSync2 } from "fs";
|
|
8534
|
-
import { homedir as
|
|
8535
|
-
import { join as
|
|
8576
|
+
import { homedir as homedir3 } from "os";
|
|
8577
|
+
import { join as join5, resolve as resolve4 } from "path";
|
|
8536
8578
|
var CURSOR_GLOBAL_AUTHORITY_RELATIVE_PATH = ".cursor/rules/hasna-global.mdc";
|
|
8537
8579
|
var CURSOR_GLOBAL_AUTHORITY_MAX_BYTES = 256 * 1024;
|
|
8538
8580
|
var CURSOR_GLOBAL_AUTHORITY_MANAGED_MARKER = "Managed by @hasna/configs cursor global authority";
|
|
8539
8581
|
var CURSOR_GLOBAL_AUTHORITY_MARKER_PATTERN = /^<!-- Managed by @hasna\/configs cursor global authority hash=(sha256:[a-f0-9]{64}) -->$/m;
|
|
8582
|
+
var CURSOR_GLOBAL_AUTHORITY_FRONTMATTER_PATTERN = /^---\n[\s\S]*?\n---(?:\n|$)/;
|
|
8540
8583
|
function sha2564(content) {
|
|
8541
8584
|
return createHash4("sha256").update(content).digest("hex");
|
|
8542
8585
|
}
|
|
8543
8586
|
function homeDir() {
|
|
8544
|
-
return process.env["HOME"] ||
|
|
8587
|
+
return process.env["HOME"] || homedir3();
|
|
8545
8588
|
}
|
|
8546
|
-
function markerPayload(content, markerLine) {
|
|
8547
|
-
const
|
|
8548
|
-
|
|
8549
|
-
|
|
8550
|
-
|
|
8551
|
-
if (content.startsWith(markerLine))
|
|
8552
|
-
return content.slice(markerLine.length).replace(/^\n/, "");
|
|
8553
|
-
return content.replace(`${markerLine}
|
|
8554
|
-
`, "").replace(markerLine, "");
|
|
8589
|
+
function markerPayload(content, markerLine, markerIndex) {
|
|
8590
|
+
const index = markerIndex ?? content.indexOf(markerLine);
|
|
8591
|
+
if (index < 0)
|
|
8592
|
+
return content;
|
|
8593
|
+
return content.slice(0, index) + content.slice(index + markerLine.length).replace(/^\n/, "");
|
|
8555
8594
|
}
|
|
8556
8595
|
function baseObservation(path) {
|
|
8557
8596
|
return {
|
|
@@ -8561,12 +8600,12 @@ function baseObservation(path) {
|
|
|
8561
8600
|
};
|
|
8562
8601
|
}
|
|
8563
8602
|
function observeCursorGlobalAuthority(options = {}) {
|
|
8564
|
-
const authorityPath =
|
|
8603
|
+
const authorityPath = resolve4(join5(options.home ?? homeDir(), CURSOR_GLOBAL_AUTHORITY_RELATIVE_PATH));
|
|
8565
8604
|
const readFile = options.readFile ?? ((path) => readFileSync2(path, "utf8"));
|
|
8566
8605
|
return observeCursorGlobalAuthorityPath(authorityPath, readFile);
|
|
8567
8606
|
}
|
|
8568
8607
|
function observeCursorGlobalAuthorityAtPath(authorityPath) {
|
|
8569
|
-
return observeCursorGlobalAuthorityPath(
|
|
8608
|
+
return observeCursorGlobalAuthorityPath(resolve4(authorityPath), (path) => readFileSync2(path, "utf8"));
|
|
8570
8609
|
}
|
|
8571
8610
|
function observeCursorGlobalAuthorityPath(authorityPath, readFile) {
|
|
8572
8611
|
const base = baseObservation(authorityPath);
|
|
@@ -8678,7 +8717,7 @@ function observeCursorGlobalAuthorityPath(authorityPath, readFile) {
|
|
|
8678
8717
|
};
|
|
8679
8718
|
}
|
|
8680
8719
|
const markerLine = markerMatch[0];
|
|
8681
|
-
const payloadSha256 = sha2564(markerPayload(content, markerLine));
|
|
8720
|
+
const payloadSha256 = sha2564(markerPayload(content, markerLine, markerMatch.index ?? -1));
|
|
8682
8721
|
if (payloadSha256 !== markerSha256) {
|
|
8683
8722
|
return {
|
|
8684
8723
|
...base,
|
|
@@ -8698,18 +8737,34 @@ function observeCursorGlobalAuthorityPath(authorityPath, readFile) {
|
|
|
8698
8737
|
return {
|
|
8699
8738
|
...base,
|
|
8700
8739
|
fileType,
|
|
8701
|
-
status: "
|
|
8740
|
+
status: "managed",
|
|
8702
8741
|
sha256: contentSha256,
|
|
8703
8742
|
markers,
|
|
8704
8743
|
markerSha256,
|
|
8705
8744
|
provenance: {
|
|
8706
8745
|
source: "filesystem",
|
|
8707
|
-
authority: "
|
|
8746
|
+
authority: "managed",
|
|
8708
8747
|
observedPath: authorityPath,
|
|
8709
|
-
detection: "
|
|
8748
|
+
detection: "managed-marker"
|
|
8710
8749
|
}
|
|
8711
8750
|
};
|
|
8712
8751
|
}
|
|
8752
|
+
function isCursorGlobalAuthorityPath(path) {
|
|
8753
|
+
return resolve4(path) === resolve4(join5(homeDir(), CURSOR_GLOBAL_AUTHORITY_RELATIVE_PATH));
|
|
8754
|
+
}
|
|
8755
|
+
function stampCursorGlobalAuthorityMarker(content) {
|
|
8756
|
+
if (CURSOR_GLOBAL_AUTHORITY_MARKER_PATTERN.test(content))
|
|
8757
|
+
return content;
|
|
8758
|
+
const digest = sha2564(content);
|
|
8759
|
+
const markerLine = `<!-- ${CURSOR_GLOBAL_AUTHORITY_MANAGED_MARKER} hash=sha256:${digest} -->`;
|
|
8760
|
+
const frontmatter = content.match(CURSOR_GLOBAL_AUTHORITY_FRONTMATTER_PATTERN)?.[0];
|
|
8761
|
+
if (frontmatter) {
|
|
8762
|
+
return `${frontmatter}${markerLine}
|
|
8763
|
+
${content.slice(frontmatter.length)}`;
|
|
8764
|
+
}
|
|
8765
|
+
return `${markerLine}
|
|
8766
|
+
${content}`;
|
|
8767
|
+
}
|
|
8713
8768
|
function detectCursorAuthorityConflicts(observation = observeCursorGlobalAuthority()) {
|
|
8714
8769
|
if (observation.status === "absent" || observation.status === "managed")
|
|
8715
8770
|
return [];
|
|
@@ -8732,47 +8787,121 @@ function detectCursorAuthorityConflicts(observation = observeCursorGlobalAuthori
|
|
|
8732
8787
|
}];
|
|
8733
8788
|
}
|
|
8734
8789
|
|
|
8735
|
-
// src/lib/session-
|
|
8736
|
-
|
|
8737
|
-
|
|
8738
|
-
|
|
8739
|
-
var
|
|
8740
|
-
|
|
8741
|
-
|
|
8742
|
-
"
|
|
8743
|
-
"
|
|
8744
|
-
"
|
|
8745
|
-
"qwen",
|
|
8746
|
-
"aicopilot",
|
|
8747
|
-
"antigravity",
|
|
8748
|
-
"grok",
|
|
8749
|
-
"copilot",
|
|
8750
|
-
"devin",
|
|
8751
|
-
"windsurf-legacy",
|
|
8752
|
-
"cline"
|
|
8753
|
-
];
|
|
8754
|
-
var SESSION_RENDER_PROFILE_ENTRYPOINTS = [
|
|
8755
|
-
".claude/CLAUDE.md",
|
|
8756
|
-
".codex/AGENTS.md",
|
|
8757
|
-
".codewith/CODEWITH.md",
|
|
8758
|
-
".config/opencode/AGENTS.md"
|
|
8759
|
-
];
|
|
8760
|
-
var SESSION_RENDER_OWNED_CONFIG_TARGETS = [
|
|
8761
|
-
...SESSION_RENDER_PROFILE_ENTRYPOINTS,
|
|
8762
|
-
".gemini/GEMINI.md",
|
|
8763
|
-
".gemini/ANTIGRAVITY.md"
|
|
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 }
|
|
8764
8800
|
];
|
|
8765
|
-
|
|
8766
|
-
|
|
8767
|
-
|
|
8768
|
-
|
|
8769
|
-
|
|
8770
|
-
|
|
8771
|
-
|
|
8772
|
-
|
|
8773
|
-
|
|
8774
|
-
|
|
8775
|
-
|
|
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
|
+
|
|
8865
|
+
// src/lib/session-render.ts
|
|
8866
|
+
var ANTIGRAVITY_RULE_FILE_CHAR_LIMIT = 12000;
|
|
8867
|
+
var SESSION_RENDERER_OWNER_ID = "instructions-session-renderer";
|
|
8868
|
+
var SESSION_RENDER_TOOLS = [
|
|
8869
|
+
"claude",
|
|
8870
|
+
"codex",
|
|
8871
|
+
"cursor",
|
|
8872
|
+
"opencode",
|
|
8873
|
+
"codewith",
|
|
8874
|
+
"qwen",
|
|
8875
|
+
"aicopilot",
|
|
8876
|
+
"antigravity",
|
|
8877
|
+
"grok",
|
|
8878
|
+
"copilot",
|
|
8879
|
+
"devin",
|
|
8880
|
+
"windsurf-legacy",
|
|
8881
|
+
"cline"
|
|
8882
|
+
];
|
|
8883
|
+
var SESSION_RENDER_PROFILE_ENTRYPOINTS = [
|
|
8884
|
+
".claude/CLAUDE.md",
|
|
8885
|
+
".codex/AGENTS.md",
|
|
8886
|
+
".codewith/CODEWITH.md",
|
|
8887
|
+
".config/opencode/AGENTS.md"
|
|
8888
|
+
];
|
|
8889
|
+
var SESSION_RENDER_OWNED_CONFIG_TARGETS = [
|
|
8890
|
+
...SESSION_RENDER_PROFILE_ENTRYPOINTS,
|
|
8891
|
+
".gemini/GEMINI.md",
|
|
8892
|
+
".gemini/ANTIGRAVITY.md"
|
|
8893
|
+
];
|
|
8894
|
+
var IDENTITY_EXPORT_AUTHORITY = Symbol("hasna.instructions.identity-export-authority");
|
|
8895
|
+
var CODEWITH_PROTECTED_REPLACEMENT_TARGETS = new Map([
|
|
8896
|
+
[
|
|
8897
|
+
"codewith-adversarial-review-proportionality",
|
|
8898
|
+
"global-adversarial-review-proportionality-system-prompt"
|
|
8899
|
+
],
|
|
8900
|
+
[
|
|
8901
|
+
"codewith-workflow-reviewer-neutralizer",
|
|
8902
|
+
"global-workflow-construction-standard"
|
|
8903
|
+
]
|
|
8904
|
+
]);
|
|
8776
8905
|
var CODEWITH_FLATTENED_ADAPTER = {
|
|
8777
8906
|
tool: "codewith",
|
|
8778
8907
|
mode: "flattened-markdown",
|
|
@@ -8945,11 +9074,11 @@ function ensureTrailingNewline3(content) {
|
|
|
8945
9074
|
`) ? content : `${content}
|
|
8946
9075
|
`;
|
|
8947
9076
|
}
|
|
8948
|
-
function
|
|
8949
|
-
return
|
|
9077
|
+
function sha2566(content) {
|
|
9078
|
+
return createHash6("sha256").update(content).digest("hex");
|
|
8950
9079
|
}
|
|
8951
9080
|
function fingerprint(value) {
|
|
8952
|
-
return
|
|
9081
|
+
return sha2566(JSON.stringify(value));
|
|
8953
9082
|
}
|
|
8954
9083
|
function canonicalFingerprintValue(value) {
|
|
8955
9084
|
if (Array.isArray(value))
|
|
@@ -8967,7 +9096,7 @@ function ruleAttestation(rule) {
|
|
|
8967
9096
|
};
|
|
8968
9097
|
const applied = metadata["payloadFloorApplied"];
|
|
8969
9098
|
return {
|
|
8970
|
-
contentSha256:
|
|
9099
|
+
contentSha256: sha2566(rule.content ?? ""),
|
|
8971
9100
|
payloadFloorApplied: typeof applied === "boolean" ? applied : null,
|
|
8972
9101
|
flooredFromRulesVersion: read("flooredFromRulesVersion"),
|
|
8973
9102
|
flooredFromPayloadSha256: read("flooredFromPayloadSha256"),
|
|
@@ -9013,16 +9142,14 @@ function slug(value) {
|
|
|
9013
9142
|
function yamlQuote2(value) {
|
|
9014
9143
|
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`;
|
|
9015
9144
|
}
|
|
9016
|
-
function getRawStoreRoot() {
|
|
9017
|
-
return resolve4(process.env[RAW_STORE_ROOT_ENV] || join5(process.env["HOME"] || homedir3(), ".hasna", "configs"));
|
|
9018
|
-
}
|
|
9019
9145
|
function defaultTargetHome(tool, profile, sessionId) {
|
|
9020
|
-
|
|
9146
|
+
const home = process.env["HOME"] || homedir4();
|
|
9147
|
+
return join7(home, ".hasna", "accounts", "profiles", tool, slug(profile));
|
|
9021
9148
|
}
|
|
9022
9149
|
function joinTarget(targetHome, relativePath) {
|
|
9023
9150
|
const safeTargetHome = assertSafeTargetRoot(targetHome);
|
|
9024
9151
|
const safeRelativePath2 = assertSafeRelativePath(relativePath);
|
|
9025
|
-
return
|
|
9152
|
+
return join7(safeTargetHome, ...safeRelativePath2.split("/"));
|
|
9026
9153
|
}
|
|
9027
9154
|
function makeFile(targetHome, relativePath, role, content, sourceIds) {
|
|
9028
9155
|
const safeTargetHome = assertSafeTargetRoot(targetHome);
|
|
@@ -9033,7 +9160,7 @@ function makeFile(targetHome, relativePath, role, content, sourceIds) {
|
|
|
9033
9160
|
relativePath: safeRelativePath2,
|
|
9034
9161
|
role,
|
|
9035
9162
|
content: normalizedContent,
|
|
9036
|
-
sha256:
|
|
9163
|
+
sha256: sha2566(normalizedContent),
|
|
9037
9164
|
sourceIds
|
|
9038
9165
|
};
|
|
9039
9166
|
}
|
|
@@ -9067,7 +9194,7 @@ function applyAgentOperatingRulesFloor(source, content) {
|
|
|
9067
9194
|
const floored = {
|
|
9068
9195
|
payloadFloorApplied: true,
|
|
9069
9196
|
flooredFromRulesVersion: parseAgentOperatingRulesVersion(content),
|
|
9070
|
-
flooredFromPayloadSha256:
|
|
9197
|
+
flooredFromPayloadSha256: sha2566(content)
|
|
9071
9198
|
};
|
|
9072
9199
|
return {
|
|
9073
9200
|
content: payload.content,
|
|
@@ -9089,7 +9216,7 @@ function applyAgentOperatingRulesFloorToRule(source, rule, content) {
|
|
|
9089
9216
|
const floored = {
|
|
9090
9217
|
payloadFloorApplied: true,
|
|
9091
9218
|
flooredFromRulesVersion: parseAgentOperatingRulesVersion(content),
|
|
9092
|
-
flooredFromPayloadSha256:
|
|
9219
|
+
flooredFromPayloadSha256: sha2566(content)
|
|
9093
9220
|
};
|
|
9094
9221
|
return {
|
|
9095
9222
|
content: payload.content,
|
|
@@ -9108,7 +9235,7 @@ function skippedSource(source, reason) {
|
|
|
9108
9235
|
order: source.resolvedOrder,
|
|
9109
9236
|
path: source.path ?? null,
|
|
9110
9237
|
hash: source.hash ?? null,
|
|
9111
|
-
renderedPayloadSha256:
|
|
9238
|
+
renderedPayloadSha256: sha2566(source.content),
|
|
9112
9239
|
nonOverridable: source.nonOverridable === true,
|
|
9113
9240
|
provenance: source.provenance ?? null
|
|
9114
9241
|
}
|
|
@@ -9150,7 +9277,7 @@ function compareSessionInstructionSources(a, b) {
|
|
|
9150
9277
|
return SESSION_LAYER_RANK[a.resolvedLayer] - SESSION_LAYER_RANK[b.resolvedLayer] || a.resolvedOrder - b.resolvedOrder || a.id.localeCompare(b.id);
|
|
9151
9278
|
}
|
|
9152
9279
|
function semanticPolicyIntegrity(body) {
|
|
9153
|
-
return
|
|
9280
|
+
return sha2566(body) === AGENT_OPERATING_RULES_PAYLOAD_SHA256 ? "pinned-digest" : "unverified-self-declared";
|
|
9154
9281
|
}
|
|
9155
9282
|
function semanticPolicyDeclaration(source) {
|
|
9156
9283
|
const normalize = (value) => value.replace(/\r\n/g, `
|
|
@@ -9375,7 +9502,7 @@ function composeSources(sources, tool) {
|
|
|
9375
9502
|
targetSourceId: target.id,
|
|
9376
9503
|
targetNormalizedSourceId: target.normalizedId,
|
|
9377
9504
|
targetHash: target.hash ?? null,
|
|
9378
|
-
targetRenderedPayloadSha256:
|
|
9505
|
+
targetRenderedPayloadSha256: sha2566(target.content),
|
|
9379
9506
|
targetNonOverridable: protectedReplacement,
|
|
9380
9507
|
authority: protectedReplacement ? "canonical-identity-export/codewith-provider/v1" : "overridable-source/v1"
|
|
9381
9508
|
}
|
|
@@ -9557,7 +9684,7 @@ function buildOpenCodeFiles(targetHome, adapter, profile, sources, providerConfi
|
|
|
9557
9684
|
...sources.flatMap((source) => source.resolvedRules.map((rule) => rule.id))
|
|
9558
9685
|
]);
|
|
9559
9686
|
const existingConfigPath = joinTarget(targetHome, adapter.configFile);
|
|
9560
|
-
const selectedConfig = existsSync4(existingConfigPath) ? readOpenCodeConfig(
|
|
9687
|
+
const selectedConfig = existsSync4(existingConfigPath) ? readOpenCodeConfig(readFileSync4(existingConfigPath, "utf8"), existingConfigPath) : providerConfig ? readOpenCodeConfig(providerConfig.content, providerConfig.sourceId) : {};
|
|
9561
9688
|
const preservedInstructions = normalizeOpenCodeInstructions(selectedConfig["instructions"]).filter((path) => !pathIsManagedOpenCodeInstruction(path, adapter.managedDir));
|
|
9562
9689
|
const config = {
|
|
9563
9690
|
...selectedConfig,
|
|
@@ -9706,7 +9833,7 @@ function buildAssetFiles(input, targetHome, blocked) {
|
|
|
9706
9833
|
relativePath: assertSafeRelativePath(relativePath),
|
|
9707
9834
|
role: "asset",
|
|
9708
9835
|
content,
|
|
9709
|
-
sha256:
|
|
9836
|
+
sha256: sha2566(content),
|
|
9710
9837
|
sourceIds: [item.sourceConfigId, item.assetId]
|
|
9711
9838
|
};
|
|
9712
9839
|
});
|
|
@@ -9746,7 +9873,7 @@ function adapterFor(input) {
|
|
|
9746
9873
|
return gatedNativeImports ? CODEWITH_NATIVE_ADAPTER : CODEWITH_FLATTENED_ADAPTER;
|
|
9747
9874
|
}
|
|
9748
9875
|
function getHomeDir() {
|
|
9749
|
-
return process.env["CONFIGS_HOME"] || process.env["HOME"] ||
|
|
9876
|
+
return process.env["CONFIGS_HOME"] || process.env["HOME"] || homedir4();
|
|
9750
9877
|
}
|
|
9751
9878
|
function cleanSessionPathInput(path) {
|
|
9752
9879
|
const trimmed = path.trim();
|
|
@@ -9761,16 +9888,16 @@ function resolveSessionPath(path) {
|
|
|
9761
9888
|
throw new Error("Session render path cannot be empty.");
|
|
9762
9889
|
const home = getHomeDir();
|
|
9763
9890
|
if (cleaned === "~")
|
|
9764
|
-
return
|
|
9891
|
+
return resolve6(home);
|
|
9765
9892
|
if (cleaned.startsWith("~/"))
|
|
9766
|
-
return
|
|
9893
|
+
return resolve6(home, cleaned.slice(2));
|
|
9767
9894
|
if (cleaned === "{{HOME}}" || cleaned === "${HOME}")
|
|
9768
|
-
return
|
|
9895
|
+
return resolve6(home);
|
|
9769
9896
|
if (cleaned.startsWith("{{HOME}}/"))
|
|
9770
|
-
return
|
|
9897
|
+
return resolve6(home, cleaned.slice("{{HOME}}/".length));
|
|
9771
9898
|
if (cleaned.startsWith("${HOME}/"))
|
|
9772
|
-
return
|
|
9773
|
-
return
|
|
9899
|
+
return resolve6(home, cleaned.slice("${HOME}/".length));
|
|
9900
|
+
return resolve6(cleaned);
|
|
9774
9901
|
}
|
|
9775
9902
|
function assertSafeRelativePath(relativePath) {
|
|
9776
9903
|
if (!relativePath.trim())
|
|
@@ -9786,7 +9913,7 @@ function assertSafeRelativePath(relativePath) {
|
|
|
9786
9913
|
function assertSafeTargetRoot(targetHome) {
|
|
9787
9914
|
if (!isAbsolute3(targetHome))
|
|
9788
9915
|
throw new Error(`Session render target must be an absolute path: ${targetHome}`);
|
|
9789
|
-
const normalized =
|
|
9916
|
+
const normalized = resolve6(targetHome);
|
|
9790
9917
|
if (normalized === parse2(normalized).root) {
|
|
9791
9918
|
throw new Error(`Session render target cannot be the filesystem root: ${targetHome}`);
|
|
9792
9919
|
}
|
|
@@ -9884,7 +10011,7 @@ function planSessionRender(input) {
|
|
|
9884
10011
|
blockers: targetBlockers
|
|
9885
10012
|
} = resolveRenderTarget(input);
|
|
9886
10013
|
const authorityObservations = input.tool === "cursor" && targetKind !== "blocked" ? [observeCursorGlobalAuthority({ home: input.cursorAuthorityHome })] : [];
|
|
9887
|
-
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) : [];
|
|
9888
10015
|
const blockers = [
|
|
9889
10016
|
...targetBlockers,
|
|
9890
10017
|
...authorityConflicts.map((conflict) => `${conflict.relativePath}: ${conflict.reason}`)
|
|
@@ -9982,7 +10109,7 @@ function planSessionRender(input) {
|
|
|
9982
10109
|
hash: rule.hash ?? null,
|
|
9983
10110
|
...ruleAttestation(rule)
|
|
9984
10111
|
})),
|
|
9985
|
-
renderedPayloadSha256:
|
|
10112
|
+
renderedPayloadSha256: sha2566(source.content),
|
|
9986
10113
|
provenance: source.provenance ?? null,
|
|
9987
10114
|
metadata: source.metadata ?? null
|
|
9988
10115
|
})),
|
|
@@ -10020,8 +10147,8 @@ function planSessionRender(input) {
|
|
|
10020
10147
|
...input.providerConfig ? {
|
|
10021
10148
|
providerConfig: {
|
|
10022
10149
|
sourceId: input.providerConfig.sourceId,
|
|
10023
|
-
selectedPayloadSha256:
|
|
10024
|
-
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),
|
|
10025
10152
|
selected: !existsSync4(joinTarget(targetHome, adapter.configFile))
|
|
10026
10153
|
}
|
|
10027
10154
|
} : {},
|
|
@@ -10129,7 +10256,7 @@ function selectProfileConfigsForSessionRender(configs, tool) {
|
|
|
10129
10256
|
const selectedSources = [];
|
|
10130
10257
|
const equivalentSources = new Map;
|
|
10131
10258
|
for (const candidate of sources) {
|
|
10132
|
-
const key =
|
|
10259
|
+
const key = sha2566(candidate.source.content);
|
|
10133
10260
|
const existing = equivalentSources.get(key);
|
|
10134
10261
|
if (!existing) {
|
|
10135
10262
|
equivalentSources.set(key, {
|
|
@@ -10408,7 +10535,7 @@ function readIdentitySourcePath(sourcePath, baseDir, sourceId) {
|
|
|
10408
10535
|
}
|
|
10409
10536
|
return;
|
|
10410
10537
|
}
|
|
10411
|
-
const stat =
|
|
10538
|
+
const stat = statSync3(resolvedPath);
|
|
10412
10539
|
if (!stat.isFile()) {
|
|
10413
10540
|
throw new Error(`Identity instruction source path is not a file for ${sourceId}: ${sourcePath.path}`);
|
|
10414
10541
|
}
|
|
@@ -10417,7 +10544,7 @@ function readIdentitySourcePath(sourcePath, baseDir, sourceId) {
|
|
|
10417
10544
|
if (!pathIsInside(realPath, realBase)) {
|
|
10418
10545
|
throw new Error(`Identity instruction source path escapes export directory for ${sourceId}: ${sourcePath.path}`);
|
|
10419
10546
|
}
|
|
10420
|
-
return
|
|
10547
|
+
return readFileSync4(realPath, "utf-8");
|
|
10421
10548
|
}
|
|
10422
10549
|
function resolveIdentitySourcePath(path, baseDir, sourceId) {
|
|
10423
10550
|
const cleaned = cleanSessionPathInput(path);
|
|
@@ -10425,8 +10552,8 @@ function resolveIdentitySourcePath(path, baseDir, sourceId) {
|
|
|
10425
10552
|
throw new Error(`Identity instruction source path cannot be empty for ${sourceId}.`);
|
|
10426
10553
|
if (cleaned.includes("\\"))
|
|
10427
10554
|
throw new Error(`Identity instruction source path must use POSIX separators for ${sourceId}: ${path}`);
|
|
10428
|
-
const resolvedPath = isAbsolute3(cleaned) ?
|
|
10429
|
-
if (!pathIsInside(resolvedPath,
|
|
10555
|
+
const resolvedPath = isAbsolute3(cleaned) ? resolve6(cleaned) : resolve6(baseDir, cleaned);
|
|
10556
|
+
if (!pathIsInside(resolvedPath, resolve6(baseDir))) {
|
|
10430
10557
|
throw new Error(`Identity instruction source path escapes export directory for ${sourceId}: ${path}`);
|
|
10431
10558
|
}
|
|
10432
10559
|
return resolvedPath;
|
|
@@ -10822,7 +10949,7 @@ function compileInstructionGraph(input) {
|
|
|
10822
10949
|
effective_activation: effective.get(configId),
|
|
10823
10950
|
fallback: row.binding.fallback,
|
|
10824
10951
|
required: row.binding.required,
|
|
10825
|
-
content_sha256:
|
|
10952
|
+
content_sha256: sha2567(config.content),
|
|
10826
10953
|
dependencies: dependencies.get(configId) ?? []
|
|
10827
10954
|
};
|
|
10828
10955
|
});
|
|
@@ -10859,7 +10986,7 @@ function compileInstructionGraph(input) {
|
|
|
10859
10986
|
diagnostics
|
|
10860
10987
|
};
|
|
10861
10988
|
return {
|
|
10862
|
-
plan: deepFreeze2({ ...planWithoutHash, source_hash:
|
|
10989
|
+
plan: deepFreeze2({ ...planWithoutHash, source_hash: sha2567(stableJson2(planWithoutHash)) }),
|
|
10863
10990
|
sources,
|
|
10864
10991
|
capability: capability2
|
|
10865
10992
|
};
|
|
@@ -11042,8 +11169,8 @@ class InstructionGraphValidationError extends Error {
|
|
|
11042
11169
|
this.name = "InstructionGraphValidationError";
|
|
11043
11170
|
}
|
|
11044
11171
|
}
|
|
11045
|
-
function
|
|
11046
|
-
return
|
|
11172
|
+
function sha2567(value) {
|
|
11173
|
+
return createHash7("sha256").update(value).digest("hex");
|
|
11047
11174
|
}
|
|
11048
11175
|
function stableJson2(value) {
|
|
11049
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;
|
|
@@ -11262,34 +11389,6 @@ function resolveProfileForMachineRead(machine = detectMachineContext(), options
|
|
|
11262
11389
|
};
|
|
11263
11390
|
}
|
|
11264
11391
|
|
|
11265
|
-
// src/db/snapshots.ts
|
|
11266
|
-
function createSnapshot(configId, content, version, db) {
|
|
11267
|
-
const d = db || getDatabase();
|
|
11268
|
-
const id = uuid();
|
|
11269
|
-
const ts = now();
|
|
11270
|
-
d.run("INSERT INTO config_snapshots (id, config_id, content, version, created_at) VALUES (?, ?, ?, ?, ?)", [id, configId, content, version, ts]);
|
|
11271
|
-
return { id, config_id: configId, content, version, created_at: ts };
|
|
11272
|
-
}
|
|
11273
|
-
function listSnapshots(configId, db) {
|
|
11274
|
-
const d = db || getDatabase();
|
|
11275
|
-
return d.query("SELECT * FROM config_snapshots WHERE config_id = ? ORDER BY version DESC").all(configId);
|
|
11276
|
-
}
|
|
11277
|
-
function getSnapshot(id, db) {
|
|
11278
|
-
const d = db || getDatabase();
|
|
11279
|
-
return d.query("SELECT * FROM config_snapshots WHERE id = ?").get(id);
|
|
11280
|
-
}
|
|
11281
|
-
function getSnapshotByVersion(configId, version, db) {
|
|
11282
|
-
const d = db || getDatabase();
|
|
11283
|
-
return d.query("SELECT * FROM config_snapshots WHERE config_id = ? AND version = ?").get(configId, version);
|
|
11284
|
-
}
|
|
11285
|
-
function pruneSnapshots(configId, keep = 10, db) {
|
|
11286
|
-
const d = db || getDatabase();
|
|
11287
|
-
const result = d.run(`DELETE FROM config_snapshots WHERE config_id = ? AND id NOT IN (
|
|
11288
|
-
SELECT id FROM config_snapshots WHERE config_id = ? ORDER BY version DESC LIMIT ?
|
|
11289
|
-
)`, [configId, configId, keep]);
|
|
11290
|
-
return result.changes;
|
|
11291
|
-
}
|
|
11292
|
-
|
|
11293
11392
|
// src/db/machines.ts
|
|
11294
11393
|
import { arch, hostname, type } from "os";
|
|
11295
11394
|
function currentHostname2() {
|
|
@@ -11856,16 +11955,16 @@ function resolveConfigStore(env = process.env) {
|
|
|
11856
11955
|
return cloud ? new CloudConfigStore(cloud) : new LocalConfigStore;
|
|
11857
11956
|
}
|
|
11858
11957
|
// src/status.ts
|
|
11859
|
-
import { existsSync as
|
|
11958
|
+
import { existsSync as existsSync9, readFileSync as readFileSync9 } from "fs";
|
|
11860
11959
|
|
|
11861
11960
|
// src/lib/apply.ts
|
|
11862
|
-
import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as
|
|
11863
|
-
import { basename as basename4, dirname as dirname4, join as
|
|
11864
|
-
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";
|
|
11865
11964
|
|
|
11866
11965
|
// src/lib/session-render-ownership.ts
|
|
11867
|
-
import { existsSync as existsSync5, readFileSync as
|
|
11868
|
-
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";
|
|
11869
11968
|
var MANIFEST_ANCESTOR_LIMIT = 24;
|
|
11870
11969
|
var MANAGED_PATH_SEGMENTS = SESSION_RENDER_EXCLUSIVE_MANAGED_PATHS.map((managedPath) => managedPath.split("/").filter(Boolean));
|
|
11871
11970
|
var manifestCache = new Map;
|
|
@@ -11889,7 +11988,7 @@ function readManifestRelativePaths(manifestPath) {
|
|
|
11889
11988
|
try {
|
|
11890
11989
|
if (!existsSync5(manifestPath))
|
|
11891
11990
|
return null;
|
|
11892
|
-
stats =
|
|
11991
|
+
stats = statSync4(manifestPath);
|
|
11893
11992
|
} catch {
|
|
11894
11993
|
return null;
|
|
11895
11994
|
}
|
|
@@ -11899,7 +11998,7 @@ function readManifestRelativePaths(manifestPath) {
|
|
|
11899
11998
|
}
|
|
11900
11999
|
let manifest;
|
|
11901
12000
|
try {
|
|
11902
|
-
manifest = JSON.parse(
|
|
12001
|
+
manifest = JSON.parse(readFileSync5(manifestPath, "utf-8"));
|
|
11903
12002
|
} catch {
|
|
11904
12003
|
return null;
|
|
11905
12004
|
}
|
|
@@ -11916,7 +12015,7 @@ function sessionRenderManifestClaimsPath(absolutePath2) {
|
|
|
11916
12015
|
const root = parse3(absolutePath2).root;
|
|
11917
12016
|
let home = dirname3(absolutePath2);
|
|
11918
12017
|
for (let depth = 0;depth < MANIFEST_ANCESTOR_LIMIT; depth += 1) {
|
|
11919
|
-
const manifestPath =
|
|
12018
|
+
const manifestPath = join8(home, ...SESSION_RENDER_MANIFEST_RELATIVE_PATH.split("/"));
|
|
11920
12019
|
const relativePaths = readManifestRelativePaths(manifestPath);
|
|
11921
12020
|
if (relativePaths) {
|
|
11922
12021
|
const claimed = relative3(home, absolutePath2).split(sep).join("/");
|
|
@@ -11936,13 +12035,13 @@ function sessionRenderOwnsPath(absolutePath2) {
|
|
|
11936
12035
|
|
|
11937
12036
|
// src/lib/apply.ts
|
|
11938
12037
|
function getConfigHome() {
|
|
11939
|
-
return process.env["CONFIGS_HOME"] || process.env["HOME"] ||
|
|
12038
|
+
return process.env["CONFIGS_HOME"] || process.env["HOME"] || homedir5();
|
|
11940
12039
|
}
|
|
11941
12040
|
function expandPath(p) {
|
|
11942
12041
|
if (p.startsWith("~/")) {
|
|
11943
|
-
return
|
|
12042
|
+
return resolve7(getConfigHome(), p.slice(2));
|
|
11944
12043
|
}
|
|
11945
|
-
return
|
|
12044
|
+
return resolve7(p);
|
|
11946
12045
|
}
|
|
11947
12046
|
function normalizeTargetPath(p) {
|
|
11948
12047
|
const expanded = expandPath(p);
|
|
@@ -11954,7 +12053,7 @@ function normalizeTargetPath(p) {
|
|
|
11954
12053
|
while (true) {
|
|
11955
12054
|
if (existsSync6(current)) {
|
|
11956
12055
|
try {
|
|
11957
|
-
return
|
|
12056
|
+
return resolve7(realpathSync2(current), ...missingSegments);
|
|
11958
12057
|
} catch {
|
|
11959
12058
|
return expanded;
|
|
11960
12059
|
}
|
|
@@ -11982,8 +12081,9 @@ async function writeConfigResult(config, targetPath, content, opts, meta = {}) {
|
|
|
11982
12081
|
throw new ConfigApplyError(`Antigravity rule file ${renderedTargetPath} is ${renderedContent.length} characters; split it before applying because Antigravity limits rule files to ${ANTIGRAVITY_RULE_FILE_CHAR_LIMIT} characters.`);
|
|
11983
12082
|
}
|
|
11984
12083
|
const path = expandPath(renderedTargetPath);
|
|
11985
|
-
const
|
|
11986
|
-
const
|
|
12084
|
+
const renderedForTarget = isCursorGlobalAuthorityPath(path) ? stampCursorGlobalAuthorityMarker(renderedContent) : renderedContent;
|
|
12085
|
+
const previousContent = existsSync6(path) ? readFileSync6(path, "utf-8") : null;
|
|
12086
|
+
const changed = previousContent !== renderedForTarget;
|
|
11987
12087
|
if (!opts.dryRun) {
|
|
11988
12088
|
const dir = dirname4(path);
|
|
11989
12089
|
if (!existsSync6(dir)) {
|
|
@@ -11993,13 +12093,13 @@ async function writeConfigResult(config, targetPath, content, opts, meta = {}) {
|
|
|
11993
12093
|
const store = opts.store ?? resolveConfigStore();
|
|
11994
12094
|
await store.createSnapshot(config.id, previousContent, config.version);
|
|
11995
12095
|
}
|
|
11996
|
-
writeFileSync2(path,
|
|
12096
|
+
writeFileSync2(path, renderedForTarget, "utf-8");
|
|
11997
12097
|
}
|
|
11998
12098
|
return {
|
|
11999
12099
|
config_id: config.id,
|
|
12000
12100
|
path,
|
|
12001
12101
|
previous_content: previousContent,
|
|
12002
|
-
new_content:
|
|
12102
|
+
new_content: renderedForTarget,
|
|
12003
12103
|
dry_run: opts.dryRun ?? false,
|
|
12004
12104
|
changed,
|
|
12005
12105
|
primary_changed: changed,
|
|
@@ -12022,7 +12122,7 @@ function wouldDestroyACredential(targetPath, renderedContent, format) {
|
|
|
12022
12122
|
const path = expandPath(targetPath);
|
|
12023
12123
|
if (!existsSync6(path))
|
|
12024
12124
|
return [];
|
|
12025
|
-
current =
|
|
12125
|
+
current = readFileSync6(path, "utf-8");
|
|
12026
12126
|
} catch {
|
|
12027
12127
|
return secretTokens;
|
|
12028
12128
|
}
|
|
@@ -12346,14 +12446,14 @@ function sessionRendererOwnsCanonicalTarget(normalized, opts) {
|
|
|
12346
12446
|
getConfigHome(),
|
|
12347
12447
|
opts.vars?.["HOME_DIR"]
|
|
12348
12448
|
].filter((home) => typeof home === "string" && home.length > 0));
|
|
12349
|
-
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("/"))))))
|
|
12350
12450
|
return true;
|
|
12351
12451
|
return sessionRenderOwnsPath(normalized);
|
|
12352
12452
|
}
|
|
12353
12453
|
|
|
12354
12454
|
// src/lib/package-version.ts
|
|
12355
|
-
import { existsSync as existsSync7, readFileSync as
|
|
12356
|
-
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";
|
|
12357
12457
|
import { fileURLToPath } from "url";
|
|
12358
12458
|
var cached = null;
|
|
12359
12459
|
function getPackageVersion() {
|
|
@@ -12362,9 +12462,9 @@ function getPackageVersion() {
|
|
|
12362
12462
|
try {
|
|
12363
12463
|
let dir = dirname5(fileURLToPath(import.meta.url));
|
|
12364
12464
|
for (let i = 0;i < 8; i++) {
|
|
12365
|
-
const pkgPath =
|
|
12465
|
+
const pkgPath = join10(dir, "package.json");
|
|
12366
12466
|
if (existsSync7(pkgPath)) {
|
|
12367
|
-
const pkg = JSON.parse(
|
|
12467
|
+
const pkg = JSON.parse(readFileSync7(pkgPath, "utf8"));
|
|
12368
12468
|
if (pkg.name === "@hasna/instructions" && pkg.version) {
|
|
12369
12469
|
cached = pkg.version;
|
|
12370
12470
|
return cached;
|
|
@@ -12380,6 +12480,403 @@ function getPackageVersion() {
|
|
|
12380
12480
|
return cached;
|
|
12381
12481
|
}
|
|
12382
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
|
+
|
|
12383
12880
|
// src/status.ts
|
|
12384
12881
|
var PACKAGE_NAME = "@hasna/instructions";
|
|
12385
12882
|
var PACKAGE_VERSION = getPackageVersion();
|
|
@@ -12402,7 +12899,7 @@ function countBy(items, getValue) {
|
|
|
12402
12899
|
}
|
|
12403
12900
|
return counts;
|
|
12404
12901
|
}
|
|
12405
|
-
async function getConfigsStatus(store = resolveConfigStore()) {
|
|
12902
|
+
async function getConfigsStatus(store = resolveConfigStore(), options = {}) {
|
|
12406
12903
|
let databaseReachable = true;
|
|
12407
12904
|
let configs = [];
|
|
12408
12905
|
let categoryStats = { total: 0 };
|
|
@@ -12426,11 +12923,11 @@ async function getConfigsStatus(store = resolveConfigStore()) {
|
|
|
12426
12923
|
continue;
|
|
12427
12924
|
knownTargets += 1;
|
|
12428
12925
|
const targetPath = expandPath(config.target_path);
|
|
12429
|
-
if (!
|
|
12926
|
+
if (!existsSync9(targetPath)) {
|
|
12430
12927
|
missingTargets += 1;
|
|
12431
12928
|
continue;
|
|
12432
12929
|
}
|
|
12433
|
-
const disk =
|
|
12930
|
+
const disk = readFileSync9(targetPath, "utf-8");
|
|
12434
12931
|
const { content: redactedDisk } = redactContent(disk, config.format);
|
|
12435
12932
|
if (redactedDisk !== config.content) {
|
|
12436
12933
|
driftedTargets += 1;
|
|
@@ -12456,7 +12953,11 @@ async function getConfigsStatus(store = resolveConfigStore()) {
|
|
|
12456
12953
|
}
|
|
12457
12954
|
}
|
|
12458
12955
|
const byCategory = Object.fromEntries(Object.entries(categoryStats).filter(([key]) => key !== "total"));
|
|
12459
|
-
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";
|
|
12460
12961
|
return {
|
|
12461
12962
|
service: "configs",
|
|
12462
12963
|
schemaVersion: "1.0",
|
|
@@ -12486,7 +12987,12 @@ async function getConfigsStatus(store = resolveConfigStore()) {
|
|
|
12486
12987
|
profileLinks,
|
|
12487
12988
|
machines,
|
|
12488
12989
|
snapshots,
|
|
12489
|
-
knownTargets
|
|
12990
|
+
knownTargets,
|
|
12991
|
+
managedSkillRuntimes: {
|
|
12992
|
+
skillsPresent: managedSkillRuntimes.skills_present,
|
|
12993
|
+
healthy: managedSkillRuntimes.healthy,
|
|
12994
|
+
missing: managedSkillRuntimes.missing
|
|
12995
|
+
}
|
|
12490
12996
|
},
|
|
12491
12997
|
health: {
|
|
12492
12998
|
status,
|
|
@@ -12495,10 +13001,12 @@ async function getConfigsStatus(store = resolveConfigStore()) {
|
|
|
12495
13001
|
missingTargets,
|
|
12496
13002
|
unredactedSecretFindings,
|
|
12497
13003
|
retiredAgentRows,
|
|
13004
|
+
missingManagedSkillRuntimes: managedSkillRuntimes.missing,
|
|
12498
13005
|
hasDrift: driftedTargets > 0,
|
|
12499
13006
|
hasMissingTargets: missingTargets > 0,
|
|
12500
13007
|
hasUnredactedSecrets: unredactedSecretFindings > 0,
|
|
12501
|
-
hasRetiredAgentRows: retiredAgentRows > 0
|
|
13008
|
+
hasRetiredAgentRows: retiredAgentRows > 0,
|
|
13009
|
+
hasMissingManagedSkillRuntimes: managedSkillRuntimes.missing > 0
|
|
12502
13010
|
},
|
|
12503
13011
|
safety: {
|
|
12504
13012
|
includesConfigValues: false,
|
|
@@ -12583,16 +13091,16 @@ var PG_MIGRATIONS = [
|
|
|
12583
13091
|
`CREATE INDEX IF NOT EXISTS profile_assets_source_config_idx ON profile_assets (source_config_id)`
|
|
12584
13092
|
];
|
|
12585
13093
|
// src/lib/session-apply.ts
|
|
12586
|
-
import { createHash as
|
|
13094
|
+
import { createHash as createHash9, randomUUID as randomUUID4 } from "crypto";
|
|
12587
13095
|
import {
|
|
12588
|
-
existsSync as
|
|
12589
|
-
lstatSync as
|
|
12590
|
-
mkdirSync as
|
|
12591
|
-
readFileSync as
|
|
13096
|
+
existsSync as existsSync10,
|
|
13097
|
+
lstatSync as lstatSync5,
|
|
13098
|
+
mkdirSync as mkdirSync5,
|
|
13099
|
+
readFileSync as readFileSync10,
|
|
12592
13100
|
readdirSync,
|
|
12593
|
-
statSync as
|
|
13101
|
+
statSync as statSync5
|
|
12594
13102
|
} from "fs";
|
|
12595
|
-
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";
|
|
12596
13104
|
class SessionApplyError extends Error {
|
|
12597
13105
|
constructor(message) {
|
|
12598
13106
|
super(message);
|
|
@@ -12612,6 +13120,7 @@ function applySessionRenderUnlocked(plan, options, coordination) {
|
|
|
12612
13120
|
}
|
|
12613
13121
|
assertCursorAuthorityUnchanged(plan);
|
|
12614
13122
|
const targetHome = assertSafeTargetHome(plan.targetHome);
|
|
13123
|
+
assertClaudeAuthorityStillClear(plan, targetHome);
|
|
12615
13124
|
const payloadFiles = [...plan.files, ...plan.assetFiles ?? []];
|
|
12616
13125
|
const files = [...payloadFiles, plan.manifestFile];
|
|
12617
13126
|
const manifestPath = resolvePlannedFilePath(plan, plan.manifestFile, targetHome);
|
|
@@ -12712,14 +13221,23 @@ function assertCursorAuthorityUnchanged(plan) {
|
|
|
12712
13221
|
throw new SessionApplyError("Cursor fixed global authority changed after planning; refusing to apply a stale render plan.");
|
|
12713
13222
|
}
|
|
12714
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
|
+
}
|
|
12715
13233
|
function ensureSessionTargetHome(targetHome) {
|
|
12716
|
-
if (!
|
|
12717
|
-
|
|
13234
|
+
if (!existsSync10(targetHome))
|
|
13235
|
+
mkdirSync5(targetHome, { recursive: true, mode: 448 });
|
|
12718
13236
|
assertSafeTargetHome(targetHome);
|
|
12719
13237
|
}
|
|
12720
13238
|
function checkSessionRenderDrift(targetHome, manifestPath) {
|
|
12721
13239
|
const safeTargetHome = assertSafeTargetHome(targetHome);
|
|
12722
|
-
const resolvedManifestPath = manifestPath ? resolveManifestRelativePath(
|
|
13240
|
+
const resolvedManifestPath = manifestPath ? resolveManifestRelativePath(relative5(safeTargetHome, resolve9(manifestPath)), safeTargetHome) : resolve9(safeTargetHome, ".hasna", "session-render-manifest.json");
|
|
12723
13241
|
const checkedAt = new Date().toISOString();
|
|
12724
13242
|
const previousManifest = readPreviousManifest(resolvedManifestPath);
|
|
12725
13243
|
if (!previousManifest) {
|
|
@@ -12736,7 +13254,7 @@ function checkSessionRenderDrift(targetHome, manifestPath) {
|
|
|
12736
13254
|
const drifted = [];
|
|
12737
13255
|
for (const file of previousManifest.files) {
|
|
12738
13256
|
const target = resolveManifestRelativePath(file.relativePath, safeTargetHome);
|
|
12739
|
-
if (!
|
|
13257
|
+
if (!existsSync10(target)) {
|
|
12740
13258
|
missing.push({
|
|
12741
13259
|
path: target,
|
|
12742
13260
|
relativePath: file.relativePath,
|
|
@@ -12746,7 +13264,7 @@ function checkSessionRenderDrift(targetHome, manifestPath) {
|
|
|
12746
13264
|
});
|
|
12747
13265
|
continue;
|
|
12748
13266
|
}
|
|
12749
|
-
const actualSha256 =
|
|
13267
|
+
const actualSha256 = sha2569(readFileSync10(target, "utf-8"));
|
|
12750
13268
|
if (actualSha256 !== file.sha256) {
|
|
12751
13269
|
drifted.push({
|
|
12752
13270
|
path: target,
|
|
@@ -12769,8 +13287,8 @@ function checkSessionRenderDrift(targetHome, manifestPath) {
|
|
|
12769
13287
|
function restoreSessionRenderSnapshot(snapshotPath, options = {}) {
|
|
12770
13288
|
const snapshot = readSessionRenderSnapshot(snapshotPath);
|
|
12771
13289
|
const targetHome = assertSafeTargetHome(snapshot.targetHome);
|
|
12772
|
-
const resolvedSnapshotPath =
|
|
12773
|
-
const snapshotRelativePath =
|
|
13290
|
+
const resolvedSnapshotPath = resolve9(snapshotPath);
|
|
13291
|
+
const snapshotRelativePath = relative5(targetHome, resolvedSnapshotPath);
|
|
12774
13292
|
if (snapshotRelativePath === "" || snapshotRelativePath === ".." || snapshotRelativePath.startsWith("../") || isAbsolute4(snapshotRelativePath)) {
|
|
12775
13293
|
throw new SessionApplyError("Session snapshot must be stored inside its target home.");
|
|
12776
13294
|
}
|
|
@@ -12887,19 +13405,19 @@ function requiredRestoreHash(file) {
|
|
|
12887
13405
|
return file.previousSha256;
|
|
12888
13406
|
}
|
|
12889
13407
|
function readSessionRenderSnapshot(snapshotPath) {
|
|
12890
|
-
const resolved =
|
|
12891
|
-
if (!
|
|
13408
|
+
const resolved = resolve9(snapshotPath);
|
|
13409
|
+
if (!existsSync10(resolved))
|
|
12892
13410
|
throw new SessionApplyError(`Session snapshot not found: ${snapshotPath}`);
|
|
12893
|
-
const stat =
|
|
13411
|
+
const stat = lstatSync5(resolved);
|
|
12894
13412
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
12895
13413
|
throw new SessionApplyError(`Session snapshot is not a regular file: ${snapshotPath}`);
|
|
12896
13414
|
}
|
|
12897
|
-
if (
|
|
13415
|
+
if (statSync5(resolved).size > 32 * 1024 * 1024) {
|
|
12898
13416
|
throw new SessionApplyError(`Session snapshot exceeds the 32 MiB restore limit: ${snapshotPath}`);
|
|
12899
13417
|
}
|
|
12900
13418
|
let parsed;
|
|
12901
13419
|
try {
|
|
12902
|
-
parsed = JSON.parse(
|
|
13420
|
+
parsed = JSON.parse(readFileSync10(resolved, "utf8"));
|
|
12903
13421
|
} catch {
|
|
12904
13422
|
throw new SessionApplyError(`Session snapshot is not valid JSON: ${snapshotPath}`);
|
|
12905
13423
|
}
|
|
@@ -12921,7 +13439,7 @@ function readSessionRenderSnapshot(snapshotPath) {
|
|
|
12921
13439
|
const previousManifest = snapshot.previousManifest;
|
|
12922
13440
|
const previousFiles = new Map;
|
|
12923
13441
|
for (const file of snapshot.files) {
|
|
12924
|
-
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) {
|
|
12925
13443
|
throw new SessionApplyError(`Session snapshot previous file metadata is invalid: ${snapshotPath}`);
|
|
12926
13444
|
}
|
|
12927
13445
|
resolveSnapshotFilePath(file.relativePath, file.path, targetHome);
|
|
@@ -12968,8 +13486,8 @@ function readSessionRenderSnapshot(snapshotPath) {
|
|
|
12968
13486
|
}
|
|
12969
13487
|
function reconstructPreRollbackLegacyV1Snapshot(snapshot, previousFiles, previousManifestFiles, targetHome, snapshotPath) {
|
|
12970
13488
|
assertNoNewerSessionSnapshot(snapshotPath, snapshot.createdAt, targetHome);
|
|
12971
|
-
const manifestPath =
|
|
12972
|
-
const manifestRelativePath =
|
|
13489
|
+
const manifestPath = resolve9(snapshot.manifestPath);
|
|
13490
|
+
const manifestRelativePath = relative5(targetHome, manifestPath).replaceAll("\\", "/");
|
|
12973
13491
|
resolveSnapshotFilePath(manifestRelativePath, snapshot.manifestPath, targetHome);
|
|
12974
13492
|
const manifestSha256 = currentSessionFileHash(manifestPath, targetHome);
|
|
12975
13493
|
if (manifestSha256 === null) {
|
|
@@ -12977,7 +13495,7 @@ function reconstructPreRollbackLegacyV1Snapshot(snapshot, previousFiles, previou
|
|
|
12977
13495
|
}
|
|
12978
13496
|
let parsedManifest;
|
|
12979
13497
|
try {
|
|
12980
|
-
parsedManifest = JSON.parse(
|
|
13498
|
+
parsedManifest = JSON.parse(readFileSync10(manifestPath, "utf8"));
|
|
12981
13499
|
} catch {
|
|
12982
13500
|
throw new SessionApplyError(`Pre-rollback legacy v1 applied manifest is not valid JSON: ${snapshotPath}`);
|
|
12983
13501
|
}
|
|
@@ -12985,7 +13503,7 @@ function reconstructPreRollbackLegacyV1Snapshot(snapshot, previousFiles, previou
|
|
|
12985
13503
|
throw new SessionApplyError(`Pre-rollback legacy v1 applied manifest is invalid: ${snapshotPath}`);
|
|
12986
13504
|
}
|
|
12987
13505
|
const appliedManifest = parsedManifest;
|
|
12988
|
-
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)) {
|
|
12989
13507
|
throw new SessionApplyError(`Pre-rollback legacy v1 applied manifest does not match its snapshot: ${snapshotPath}`);
|
|
12990
13508
|
}
|
|
12991
13509
|
const afterFiles = [];
|
|
@@ -13069,17 +13587,17 @@ function assertNoNewerSessionSnapshot(snapshotPath, createdAt, targetHome) {
|
|
|
13069
13587
|
if (!Number.isFinite(createdAtMs)) {
|
|
13070
13588
|
throw new SessionApplyError(`Pre-rollback legacy v1 snapshot has an invalid creation time: ${snapshotPath}`);
|
|
13071
13589
|
}
|
|
13072
|
-
for (const entry of readdirSync(
|
|
13073
|
-
const candidatePath =
|
|
13074
|
-
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"))
|
|
13075
13593
|
continue;
|
|
13076
|
-
const candidateStat =
|
|
13594
|
+
const candidateStat = lstatSync5(candidatePath);
|
|
13077
13595
|
if (candidateStat.isSymbolicLink() || !candidateStat.isFile() || candidateStat.size > 32 * 1024 * 1024)
|
|
13078
13596
|
continue;
|
|
13079
13597
|
try {
|
|
13080
|
-
const candidate = JSON.parse(
|
|
13598
|
+
const candidate = JSON.parse(readFileSync10(candidatePath, "utf8"));
|
|
13081
13599
|
const candidateCreatedAtMs = typeof candidate.createdAt === "string" ? Date.parse(candidate.createdAt) : Number.NaN;
|
|
13082
|
-
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) {
|
|
13083
13601
|
throw new SessionApplyError(`Cannot restore pre-rollback legacy v1 snapshot after a newer session snapshot exists: ${candidatePath}`);
|
|
13084
13602
|
}
|
|
13085
13603
|
} catch (error) {
|
|
@@ -13137,7 +13655,7 @@ function inferLegacySnapshotAction(file, previousFiles, previousManifestFiles, p
|
|
|
13137
13655
|
return "create";
|
|
13138
13656
|
}
|
|
13139
13657
|
if (file.role === "manifest" && previousManifest) {
|
|
13140
|
-
const previousManifestSha256 =
|
|
13658
|
+
const previousManifestSha256 = sha2569(`${JSON.stringify(previousManifest, null, 2)}
|
|
13141
13659
|
`);
|
|
13142
13660
|
if (previousManifestSha256 !== file.sha256) {
|
|
13143
13661
|
throw new SessionApplyError(`Cannot infer legacy v1 manifest action without a before-image: ${file.relativePath}`);
|
|
@@ -13148,15 +13666,15 @@ function inferLegacySnapshotAction(file, previousFiles, previousManifestFiles, p
|
|
|
13148
13666
|
}
|
|
13149
13667
|
function resolveSnapshotFilePath(relativePath, recordedPath, targetHome) {
|
|
13150
13668
|
const path = resolveManifestRelativePath(relativePath, targetHome);
|
|
13151
|
-
if (
|
|
13669
|
+
if (resolve9(recordedPath) !== path) {
|
|
13152
13670
|
throw new SessionApplyError(`Session snapshot file path mismatch for ${relativePath}`);
|
|
13153
13671
|
}
|
|
13154
13672
|
return path;
|
|
13155
13673
|
}
|
|
13156
13674
|
function planFileResult(plan, file, targetHome, previousHashes, previousManifest, options) {
|
|
13157
13675
|
const target = resolvePlannedFilePath(plan, file, targetHome);
|
|
13158
|
-
const previousContent =
|
|
13159
|
-
const previousSha256 = previousContent === null ? null :
|
|
13676
|
+
const previousContent = existsSync10(target) ? readFileSync10(target, "utf-8") : null;
|
|
13677
|
+
const previousSha256 = previousContent === null ? null : sha2569(previousContent);
|
|
13160
13678
|
const previouslyManaged = isPreviouslyManaged(file, previousSha256, previousHashes, previousManifest);
|
|
13161
13679
|
const changed = previousContent !== file.content;
|
|
13162
13680
|
if (previousContent !== null && !options.force && !previouslyManaged) {
|
|
@@ -13251,10 +13769,10 @@ function planStaleFileResults(plan, targetHome, previousManifest, currentRelativ
|
|
|
13251
13769
|
}
|
|
13252
13770
|
function planStaleFileResult(file, targetHome, options) {
|
|
13253
13771
|
const target = resolveManifestRelativePath(file.relativePath, targetHome);
|
|
13254
|
-
if (!
|
|
13772
|
+
if (!existsSync10(target))
|
|
13255
13773
|
return null;
|
|
13256
|
-
const previousContent =
|
|
13257
|
-
const previousSha256 =
|
|
13774
|
+
const previousContent = readFileSync10(target, "utf-8");
|
|
13775
|
+
const previousSha256 = sha2569(previousContent);
|
|
13258
13776
|
if (!options.force && previousSha256 !== file.sha256) {
|
|
13259
13777
|
return {
|
|
13260
13778
|
path: target,
|
|
@@ -13298,20 +13816,20 @@ function isPreviouslyManaged(file, previousSha256, previousHashes, previousManif
|
|
|
13298
13816
|
return previousHashes.get(file.relativePath) === previousSha256;
|
|
13299
13817
|
}
|
|
13300
13818
|
function resolvePlannedFilePath(plan, file, targetHome) {
|
|
13301
|
-
const target =
|
|
13302
|
-
const rel =
|
|
13819
|
+
const target = resolve9(targetHome, ...file.relativePath.split("/"));
|
|
13820
|
+
const rel = relative5(targetHome, target);
|
|
13303
13821
|
if (rel === "" || rel === ".." || rel.startsWith("../") || isAbsolute4(rel)) {
|
|
13304
13822
|
throw new SessionApplyError(`Session file escapes target home: ${file.relativePath}`);
|
|
13305
13823
|
}
|
|
13306
|
-
if (
|
|
13824
|
+
if (resolve9(file.path) !== target) {
|
|
13307
13825
|
throw new SessionApplyError(`Session file path mismatch for ${file.relativePath}: ${file.path}`);
|
|
13308
13826
|
}
|
|
13309
13827
|
assertNoSymlinkSegments2(targetHome, target);
|
|
13310
13828
|
return target;
|
|
13311
13829
|
}
|
|
13312
13830
|
function resolveManifestRelativePath(relativePath, targetHome) {
|
|
13313
|
-
const target =
|
|
13314
|
-
const rel =
|
|
13831
|
+
const target = resolve9(targetHome, ...relativePath.split(/[\\/]+/));
|
|
13832
|
+
const rel = relative5(targetHome, target);
|
|
13315
13833
|
if (rel === "" || rel === ".." || rel.startsWith("../") || isAbsolute4(rel)) {
|
|
13316
13834
|
throw new SessionApplyError(`Session manifest file escapes target home: ${relativePath}`);
|
|
13317
13835
|
}
|
|
@@ -13319,10 +13837,10 @@ function resolveManifestRelativePath(relativePath, targetHome) {
|
|
|
13319
13837
|
return target;
|
|
13320
13838
|
}
|
|
13321
13839
|
function readPreviousManifest(path) {
|
|
13322
|
-
if (!
|
|
13840
|
+
if (!existsSync10(path))
|
|
13323
13841
|
return null;
|
|
13324
13842
|
try {
|
|
13325
|
-
const parsed = JSON.parse(
|
|
13843
|
+
const parsed = JSON.parse(readFileSync10(path, "utf-8"));
|
|
13326
13844
|
if (parsed.schema !== SESSION_RENDER_SCHEMA)
|
|
13327
13845
|
return null;
|
|
13328
13846
|
if (!Array.isArray(parsed.files))
|
|
@@ -13356,18 +13874,18 @@ function applyPlannedFile(plan, file, targetHome, resultsByPath, coordination, a
|
|
|
13356
13874
|
function assertExpectedSessionFileHash(path, targetHome, expectedHash) {
|
|
13357
13875
|
const actualHash = currentSessionFileHash(path, targetHome);
|
|
13358
13876
|
if (actualHash !== expectedHash) {
|
|
13359
|
-
throw new SessionApplyError(`Session apply path changed after planning: ${
|
|
13877
|
+
throw new SessionApplyError(`Session apply path changed after planning: ${relative5(targetHome, path)}`);
|
|
13360
13878
|
}
|
|
13361
13879
|
}
|
|
13362
13880
|
function currentSessionFileHash(path, targetHome) {
|
|
13363
13881
|
assertNoSymlinkSegments2(targetHome, path);
|
|
13364
|
-
if (!
|
|
13882
|
+
if (!existsSync10(path))
|
|
13365
13883
|
return null;
|
|
13366
|
-
const stat =
|
|
13884
|
+
const stat = lstatSync5(path);
|
|
13367
13885
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
13368
13886
|
throw new SessionApplyError(`Session apply path is not a regular file: ${path}`);
|
|
13369
13887
|
}
|
|
13370
|
-
return
|
|
13888
|
+
return sha2569(readFileSync10(path, "utf-8"));
|
|
13371
13889
|
}
|
|
13372
13890
|
function requiredPreviousHash(result) {
|
|
13373
13891
|
if (result.previousSha256 === null) {
|
|
@@ -13376,13 +13894,13 @@ function requiredPreviousHash(result) {
|
|
|
13376
13894
|
return result.previousSha256;
|
|
13377
13895
|
}
|
|
13378
13896
|
function writeSessionSnapshot(plan, targetHome, manifestPath, results, previousManifest, coordination, allowPortableFallback, forcePortableFileOps) {
|
|
13379
|
-
const existingFiles = results.filter((result) => result.action === "update" || result.action === "delete").filter((result) =>
|
|
13380
|
-
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");
|
|
13381
13899
|
return {
|
|
13382
13900
|
path: result.path,
|
|
13383
13901
|
relativePath: result.relativePath,
|
|
13384
13902
|
role: result.role,
|
|
13385
|
-
sha256:
|
|
13903
|
+
sha256: sha2569(content),
|
|
13386
13904
|
content
|
|
13387
13905
|
};
|
|
13388
13906
|
});
|
|
@@ -13395,7 +13913,7 @@ function writeSessionSnapshot(plan, targetHome, manifestPath, results, previousM
|
|
|
13395
13913
|
};
|
|
13396
13914
|
}
|
|
13397
13915
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
13398
|
-
const snapshotPath =
|
|
13916
|
+
const snapshotPath = resolve9(targetHome, ".hasna", "session-render-snapshots", `${timestamp}-${randomUUID4()}.json`);
|
|
13399
13917
|
const afterFiles = results.map((result) => {
|
|
13400
13918
|
if (result.action === "conflict") {
|
|
13401
13919
|
throw new SessionApplyError(`Cannot snapshot unresolved conflict: ${result.relativePath}`);
|
|
@@ -13443,43 +13961,43 @@ function writeSessionSnapshot(plan, targetHome, manifestPath, results, previousM
|
|
|
13443
13961
|
function assertSafeTargetHome(targetHome) {
|
|
13444
13962
|
if (!isAbsolute4(targetHome))
|
|
13445
13963
|
throw new SessionApplyError(`Session target home must be absolute: ${targetHome}`);
|
|
13446
|
-
const normalized =
|
|
13447
|
-
if (normalized ===
|
|
13964
|
+
const normalized = resolve9(targetHome);
|
|
13965
|
+
if (normalized === parse5(normalized).root) {
|
|
13448
13966
|
throw new SessionApplyError(`Session target home cannot be the filesystem root: ${targetHome}`);
|
|
13449
13967
|
}
|
|
13450
|
-
|
|
13451
|
-
if (
|
|
13968
|
+
assertNoSymlinkAncestors3(normalized);
|
|
13969
|
+
if (existsSync10(normalized) && lstatSync5(normalized).isSymbolicLink()) {
|
|
13452
13970
|
throw new SessionApplyError(`Session target home cannot be a symlink: ${normalized}`);
|
|
13453
13971
|
}
|
|
13454
13972
|
return normalized;
|
|
13455
13973
|
}
|
|
13456
13974
|
function assertNoSymlinkSegments2(root, target) {
|
|
13457
|
-
|
|
13458
|
-
const rel =
|
|
13975
|
+
assertNoSymlinkAncestors3(root);
|
|
13976
|
+
const rel = relative5(root, target);
|
|
13459
13977
|
let current = root;
|
|
13460
13978
|
for (const segment of rel.split(/[\\/]+/).filter(Boolean)) {
|
|
13461
|
-
current =
|
|
13462
|
-
if (
|
|
13979
|
+
current = join12(current, segment);
|
|
13980
|
+
if (existsSync10(current) && lstatSync5(current).isSymbolicLink()) {
|
|
13463
13981
|
throw new SessionApplyError(`Session apply path uses a symlink: ${current}`);
|
|
13464
13982
|
}
|
|
13465
13983
|
}
|
|
13466
13984
|
}
|
|
13467
|
-
function
|
|
13468
|
-
const normalized =
|
|
13469
|
-
const parsed =
|
|
13985
|
+
function assertNoSymlinkAncestors3(path) {
|
|
13986
|
+
const normalized = resolve9(path);
|
|
13987
|
+
const parsed = parse5(normalized);
|
|
13470
13988
|
let current = parsed.root;
|
|
13471
|
-
const rel =
|
|
13989
|
+
const rel = relative5(parsed.root, normalized);
|
|
13472
13990
|
for (const segment of rel.split(/[\\/]+/).filter(Boolean)) {
|
|
13473
|
-
current =
|
|
13474
|
-
if (!
|
|
13991
|
+
current = join12(current, segment);
|
|
13992
|
+
if (!existsSync10(current))
|
|
13475
13993
|
return;
|
|
13476
|
-
if (
|
|
13994
|
+
if (lstatSync5(current).isSymbolicLink()) {
|
|
13477
13995
|
throw new SessionApplyError(`Session apply path uses a symlink ancestor: ${current}`);
|
|
13478
13996
|
}
|
|
13479
13997
|
}
|
|
13480
13998
|
}
|
|
13481
|
-
function
|
|
13482
|
-
return
|
|
13999
|
+
function sha2569(content) {
|
|
14000
|
+
return createHash9("sha256").update(content).digest("hex");
|
|
13483
14001
|
}
|
|
13484
14002
|
// src/lib/project-dashboard-standard.ts
|
|
13485
14003
|
var PROJECT_DASHBOARD_STANDARD_SLUG = "agent-managed-project-dashboard-standard";
|
|
@@ -13782,13 +14300,13 @@ async function ensureDangerousOperationGuardStandardConfig(store = resolveConfig
|
|
|
13782
14300
|
}
|
|
13783
14301
|
}
|
|
13784
14302
|
// src/lib/sync.ts
|
|
13785
|
-
import { existsSync as
|
|
13786
|
-
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";
|
|
13787
14305
|
|
|
13788
14306
|
// src/lib/sync-dir.ts
|
|
13789
|
-
import { existsSync as
|
|
13790
|
-
import { join as
|
|
13791
|
-
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";
|
|
13792
14310
|
var SKIP = [".db", ".db-shm", ".db-wal", ".log", ".lock", ".DS_Store", "node_modules", ".git"];
|
|
13793
14311
|
function shouldSkip(p) {
|
|
13794
14312
|
return SKIP.some((s) => p.includes(s));
|
|
@@ -13796,11 +14314,11 @@ function shouldSkip(p) {
|
|
|
13796
14314
|
async function syncFromDir(dir, opts = {}) {
|
|
13797
14315
|
const store = opts.store ?? resolveConfigStore();
|
|
13798
14316
|
const absDir = expandPath(dir);
|
|
13799
|
-
if (!
|
|
14317
|
+
if (!existsSync11(absDir))
|
|
13800
14318
|
return { added: 0, updated: 0, unchanged: 0, skipped: [`Not found: ${absDir}`] };
|
|
13801
|
-
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());
|
|
13802
14320
|
const result = { added: 0, updated: 0, unchanged: 0, skipped: [] };
|
|
13803
|
-
const home =
|
|
14321
|
+
const home = homedir7();
|
|
13804
14322
|
const allConfigs = await store.listConfigs();
|
|
13805
14323
|
for (const file of files) {
|
|
13806
14324
|
if (shouldSkip(file)) {
|
|
@@ -13808,7 +14326,7 @@ async function syncFromDir(dir, opts = {}) {
|
|
|
13808
14326
|
continue;
|
|
13809
14327
|
}
|
|
13810
14328
|
try {
|
|
13811
|
-
const content =
|
|
14329
|
+
const content = readFileSync11(file, "utf-8");
|
|
13812
14330
|
if (content.length > 500000) {
|
|
13813
14331
|
result.skipped.push(file + " (too large)");
|
|
13814
14332
|
continue;
|
|
@@ -13817,7 +14335,7 @@ async function syncFromDir(dir, opts = {}) {
|
|
|
13817
14335
|
const existing = allConfigs.find((c) => c.target_path === targetPath);
|
|
13818
14336
|
if (!existing) {
|
|
13819
14337
|
if (!opts.dryRun)
|
|
13820
|
-
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 });
|
|
13821
14339
|
result.added++;
|
|
13822
14340
|
} else if (existing.content !== content) {
|
|
13823
14341
|
if (!opts.dryRun)
|
|
@@ -13834,7 +14352,7 @@ async function syncFromDir(dir, opts = {}) {
|
|
|
13834
14352
|
}
|
|
13835
14353
|
async function syncToDir(dir, opts = {}) {
|
|
13836
14354
|
const store = opts.store ?? resolveConfigStore();
|
|
13837
|
-
const home =
|
|
14355
|
+
const home = homedir7();
|
|
13838
14356
|
const absDir = expandPath(dir);
|
|
13839
14357
|
const normalized = dir.startsWith("~/") ? dir : absDir.replace(home, "~");
|
|
13840
14358
|
const configs = (await store.listConfigs()).filter((c) => c.target_path && (c.target_path.startsWith(normalized) || c.target_path.startsWith(absDir)));
|
|
@@ -13858,7 +14376,7 @@ async function syncToDir(dir, opts = {}) {
|
|
|
13858
14376
|
}
|
|
13859
14377
|
function walkDir(dir, files = []) {
|
|
13860
14378
|
for (const entry of readdirSync2(dir, { withFileTypes: true })) {
|
|
13861
|
-
const full =
|
|
14379
|
+
const full = join13(dir, entry.name);
|
|
13862
14380
|
if (shouldSkip(full))
|
|
13863
14381
|
continue;
|
|
13864
14382
|
if (entry.isDirectory())
|
|
@@ -13919,7 +14437,7 @@ function isGeneratedOutputTarget2(config, owners) {
|
|
|
13919
14437
|
return !!ownerIds && !ownerIds.has(config.id);
|
|
13920
14438
|
}
|
|
13921
14439
|
function hasClaudePromptSource() {
|
|
13922
|
-
return
|
|
14440
|
+
return existsSync12(expandPath("~/.claude/CLAUDE.md"));
|
|
13923
14441
|
}
|
|
13924
14442
|
function hasClaudeRuleSourceForCursorTarget(targetPath) {
|
|
13925
14443
|
const absoluteTargetPath = expandPath(targetPath);
|
|
@@ -13927,7 +14445,7 @@ function hasClaudeRuleSourceForCursorTarget(targetPath) {
|
|
|
13927
14445
|
if (!absoluteTargetPath.startsWith(`${absolutePrefix}/`) || !absoluteTargetPath.endsWith(".mdc"))
|
|
13928
14446
|
return false;
|
|
13929
14447
|
const stem = basename5(absoluteTargetPath, ".mdc");
|
|
13930
|
-
return
|
|
14448
|
+
return existsSync12(expandPath(`~/.claude/rules/${stem}.md`)) || existsSync12(expandPath(`~/.claude/rules/${stem}.mdc`));
|
|
13931
14449
|
}
|
|
13932
14450
|
function isKnownGeneratedTargetPath(targetPath) {
|
|
13933
14451
|
const normalizedTargetPath = normalizeTargetPath(targetPath);
|
|
@@ -13992,11 +14510,11 @@ async function syncProject(opts) {
|
|
|
13992
14510
|
const allConfigs = await store.listConfigs();
|
|
13993
14511
|
const machine = detectMachineContext();
|
|
13994
14512
|
for (const pf of PROJECT_CONFIG_FILES) {
|
|
13995
|
-
const abs =
|
|
13996
|
-
if (!
|
|
14513
|
+
const abs = join14(absDir, pf.file);
|
|
14514
|
+
if (!existsSync12(abs))
|
|
13997
14515
|
continue;
|
|
13998
14516
|
try {
|
|
13999
|
-
const rawContent =
|
|
14517
|
+
const rawContent = readFileSync12(abs, "utf-8");
|
|
14000
14518
|
if (rawContent.length > 500000) {
|
|
14001
14519
|
result.skipped.push(pf.file);
|
|
14002
14520
|
continue;
|
|
@@ -14025,20 +14543,20 @@ async function syncProject(opts) {
|
|
|
14025
14543
|
}
|
|
14026
14544
|
}
|
|
14027
14545
|
for (const ruleDir of [
|
|
14028
|
-
{ dir:
|
|
14029
|
-
{ dir:
|
|
14030
|
-
{ dir:
|
|
14031
|
-
{ dir:
|
|
14032
|
-
{ dir:
|
|
14033
|
-
{ dir:
|
|
14034
|
-
{ 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" }
|
|
14035
14553
|
]) {
|
|
14036
|
-
if (!
|
|
14554
|
+
if (!existsSync12(ruleDir.dir))
|
|
14037
14555
|
continue;
|
|
14038
14556
|
const mdFiles = readdirSync3(ruleDir.dir).filter((f) => f.endsWith(".md") || f.endsWith(".mdc"));
|
|
14039
14557
|
for (const f of mdFiles) {
|
|
14040
|
-
const abs =
|
|
14041
|
-
const raw =
|
|
14558
|
+
const abs = join14(ruleDir.dir, f);
|
|
14559
|
+
const raw = readFileSync12(abs, "utf-8");
|
|
14042
14560
|
const redacted = redactContent(raw, "markdown");
|
|
14043
14561
|
const machineAware = templateizeMachineContent(redacted.content, machine);
|
|
14044
14562
|
const content = machineAware.content;
|
|
@@ -14077,20 +14595,20 @@ async function syncKnown(opts = {}) {
|
|
|
14077
14595
|
for (const known of targets) {
|
|
14078
14596
|
if (known.rulesDir) {
|
|
14079
14597
|
const absDir = expandPath(known.rulesDir);
|
|
14080
|
-
if (!
|
|
14598
|
+
if (!existsSync12(absDir)) {
|
|
14081
14599
|
result.skipped.push(known.rulesDir);
|
|
14082
14600
|
continue;
|
|
14083
14601
|
}
|
|
14084
14602
|
const extensions = known.rulesExtensions ?? [".md", ".mdc"];
|
|
14085
14603
|
const ruleFiles = readdirSync3(absDir).filter((f) => extensions.some((ext) => f.endsWith(ext)));
|
|
14086
14604
|
for (const f of ruleFiles) {
|
|
14087
|
-
const abs2 =
|
|
14605
|
+
const abs2 = join14(absDir, f);
|
|
14088
14606
|
const targetPath = abs2.replace(home, "~");
|
|
14089
14607
|
if (existingOutputOwners.has(normalizeTargetPath(targetPath)) || isKnownGeneratedTargetPath(targetPath)) {
|
|
14090
14608
|
result.skipped.push(`${targetPath} (generated output)`);
|
|
14091
14609
|
continue;
|
|
14092
14610
|
}
|
|
14093
|
-
const raw =
|
|
14611
|
+
const raw = readFileSync12(abs2, "utf-8");
|
|
14094
14612
|
const redacted = redactContent(raw, "markdown");
|
|
14095
14613
|
const machineAware = templateizeMachineContent(redacted.content, machine);
|
|
14096
14614
|
const content = machineAware.content;
|
|
@@ -14118,12 +14636,12 @@ async function syncKnown(opts = {}) {
|
|
|
14118
14636
|
continue;
|
|
14119
14637
|
}
|
|
14120
14638
|
const abs = expandPath(known.path);
|
|
14121
|
-
if (!
|
|
14639
|
+
if (!existsSync12(abs)) {
|
|
14122
14640
|
result.skipped.push(known.path);
|
|
14123
14641
|
continue;
|
|
14124
14642
|
}
|
|
14125
14643
|
try {
|
|
14126
|
-
const rawContent = normalizeKnownConfigSource(known,
|
|
14644
|
+
const rawContent = normalizeKnownConfigSource(known, readFileSync12(abs, "utf-8"));
|
|
14127
14645
|
if (rawContent.length > 500000) {
|
|
14128
14646
|
result.skipped.push(known.path + " (too large)");
|
|
14129
14647
|
continue;
|
|
@@ -14226,9 +14744,9 @@ function storedPlaceholderIsLiteralOnDisk(storedLine, diskLine) {
|
|
|
14226
14744
|
}
|
|
14227
14745
|
function buildDiff(expectedContent, targetPath, storedFormat, showSecrets) {
|
|
14228
14746
|
const path = expandPath(targetPath);
|
|
14229
|
-
if (!
|
|
14747
|
+
if (!existsSync12(path))
|
|
14230
14748
|
return `(file not found on disk: ${path})`;
|
|
14231
|
-
const diskContent =
|
|
14749
|
+
const diskContent = readFileSync12(path, "utf-8");
|
|
14232
14750
|
if (diskContent === expectedContent)
|
|
14233
14751
|
return "(no diff \u2014 identical)";
|
|
14234
14752
|
const format = redactFormatForTarget(targetPath, storedFormat);
|
|
@@ -14386,26 +14904,26 @@ function detectFormat(filePath) {
|
|
|
14386
14904
|
return "text";
|
|
14387
14905
|
}
|
|
14388
14906
|
// src/lib/export.ts
|
|
14389
|
-
import { existsSync as
|
|
14390
|
-
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";
|
|
14391
14909
|
import { tmpdir } from "os";
|
|
14392
14910
|
async function exportConfigs(outputPath, opts = {}) {
|
|
14393
14911
|
const store = opts.store ?? resolveConfigStore();
|
|
14394
14912
|
const configs = await store.listConfigs(opts.filter);
|
|
14395
|
-
const absOutput =
|
|
14396
|
-
const tmpDir =
|
|
14397
|
-
const contentsDir =
|
|
14913
|
+
const absOutput = resolve10(outputPath);
|
|
14914
|
+
const tmpDir = join15(tmpdir(), `configs-export-${Date.now()}`);
|
|
14915
|
+
const contentsDir = join15(tmpDir, "contents");
|
|
14398
14916
|
try {
|
|
14399
|
-
|
|
14917
|
+
mkdirSync6(contentsDir, { recursive: true });
|
|
14400
14918
|
const manifest = {
|
|
14401
14919
|
version: "1.0.0",
|
|
14402
14920
|
exported_at: new Date().toISOString(),
|
|
14403
14921
|
configs: configs.map(({ content: _content, ...meta }) => meta)
|
|
14404
14922
|
};
|
|
14405
|
-
|
|
14923
|
+
writeFileSync4(join15(tmpDir, "manifest.json"), JSON.stringify(manifest, null, 2), "utf-8");
|
|
14406
14924
|
for (const config of configs) {
|
|
14407
14925
|
const fileName = `${config.slug}.${config.format === "text" ? "txt" : config.format}`;
|
|
14408
|
-
|
|
14926
|
+
writeFileSync4(join15(contentsDir, fileName), config.content, "utf-8");
|
|
14409
14927
|
}
|
|
14410
14928
|
const proc = Bun.spawn(["tar", "czf", absOutput, "-C", tmpDir, "."], {
|
|
14411
14929
|
stdout: "pipe",
|
|
@@ -14418,23 +14936,23 @@ async function exportConfigs(outputPath, opts = {}) {
|
|
|
14418
14936
|
}
|
|
14419
14937
|
return { path: absOutput, count: configs.length };
|
|
14420
14938
|
} finally {
|
|
14421
|
-
if (
|
|
14422
|
-
|
|
14939
|
+
if (existsSync13(tmpDir)) {
|
|
14940
|
+
rmSync4(tmpDir, { recursive: true, force: true });
|
|
14423
14941
|
}
|
|
14424
14942
|
}
|
|
14425
14943
|
}
|
|
14426
14944
|
// src/lib/import.ts
|
|
14427
|
-
import { existsSync as
|
|
14428
|
-
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";
|
|
14429
14947
|
import { tmpdir as tmpdir2 } from "os";
|
|
14430
14948
|
async function importConfigs(bundlePath, opts = {}) {
|
|
14431
14949
|
const store = opts.store ?? resolveConfigStore();
|
|
14432
14950
|
const conflict = opts.conflict ?? "skip";
|
|
14433
|
-
const absPath =
|
|
14434
|
-
const tmpDir =
|
|
14951
|
+
const absPath = resolve11(bundlePath);
|
|
14952
|
+
const tmpDir = join16(tmpdir2(), `configs-import-${Date.now()}`);
|
|
14435
14953
|
const result = { created: 0, updated: 0, skipped: 0, errors: [] };
|
|
14436
14954
|
try {
|
|
14437
|
-
|
|
14955
|
+
mkdirSync7(tmpDir, { recursive: true });
|
|
14438
14956
|
const proc = Bun.spawn(["tar", "xzf", absPath, "-C", tmpDir], {
|
|
14439
14957
|
stdout: "pipe",
|
|
14440
14958
|
stderr: "pipe"
|
|
@@ -14444,15 +14962,15 @@ async function importConfigs(bundlePath, opts = {}) {
|
|
|
14444
14962
|
const stderr = await new Response(proc.stderr).text();
|
|
14445
14963
|
throw new Error(`tar extraction failed: ${stderr}`);
|
|
14446
14964
|
}
|
|
14447
|
-
const manifestPath =
|
|
14448
|
-
if (!
|
|
14965
|
+
const manifestPath = join16(tmpDir, "manifest.json");
|
|
14966
|
+
if (!existsSync14(manifestPath))
|
|
14449
14967
|
throw new Error("Invalid bundle: missing manifest.json");
|
|
14450
|
-
const manifest = JSON.parse(
|
|
14968
|
+
const manifest = JSON.parse(readFileSync13(manifestPath, "utf-8"));
|
|
14451
14969
|
for (const meta of manifest.configs) {
|
|
14452
14970
|
try {
|
|
14453
14971
|
const ext = meta.format === "text" ? "txt" : meta.format;
|
|
14454
|
-
const contentFile =
|
|
14455
|
-
const content =
|
|
14972
|
+
const contentFile = join16(tmpDir, "contents", `${meta.slug}.${ext}`);
|
|
14973
|
+
const content = existsSync14(contentFile) ? readFileSync13(contentFile, "utf-8") : "";
|
|
14456
14974
|
let existing = null;
|
|
14457
14975
|
try {
|
|
14458
14976
|
existing = await store.getConfig(meta.slug);
|
|
@@ -14486,16 +15004,16 @@ async function importConfigs(bundlePath, opts = {}) {
|
|
|
14486
15004
|
}
|
|
14487
15005
|
return result;
|
|
14488
15006
|
} finally {
|
|
14489
|
-
if (
|
|
14490
|
-
|
|
15007
|
+
if (existsSync14(tmpDir)) {
|
|
15008
|
+
rmSync5(tmpDir, { recursive: true, force: true });
|
|
14491
15009
|
}
|
|
14492
15010
|
}
|
|
14493
15011
|
}
|
|
14494
15012
|
// src/lib/package-manager-guard.ts
|
|
14495
15013
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
14496
|
-
import { existsSync as
|
|
14497
|
-
import { homedir as
|
|
14498
|
-
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";
|
|
14499
15017
|
var SKIP_DIRS = new Set([
|
|
14500
15018
|
".git",
|
|
14501
15019
|
"node_modules",
|
|
@@ -14532,14 +15050,14 @@ var TOKEN_VALUE_PATTERNS = [
|
|
|
14532
15050
|
{ re: /xoxb-[0-9]+-[A-Za-z0-9-]+/, rule: "literal-slack-token", detail: "literal Slack token-like value" }
|
|
14533
15051
|
];
|
|
14534
15052
|
function scanPackageManagerSecrets(options = {}) {
|
|
14535
|
-
const cwd = options.cwd ?
|
|
14536
|
-
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));
|
|
14537
15055
|
const findings = [];
|
|
14538
15056
|
let scannedFiles = 0;
|
|
14539
15057
|
for (const root of roots) {
|
|
14540
|
-
if (!
|
|
15058
|
+
if (!existsSync15(root))
|
|
14541
15059
|
continue;
|
|
14542
|
-
const stat =
|
|
15060
|
+
const stat = lstatSync6(root);
|
|
14543
15061
|
if (stat.isFile()) {
|
|
14544
15062
|
if (!shouldScanRepoFile(root))
|
|
14545
15063
|
continue;
|
|
@@ -14547,14 +15065,14 @@ function scanPackageManagerSecrets(options = {}) {
|
|
|
14547
15065
|
if (text === null)
|
|
14548
15066
|
continue;
|
|
14549
15067
|
scannedFiles++;
|
|
14550
|
-
findings.push(...scanFile(root, text, classifyRepoFile(root), isTrackedFile(root),
|
|
15068
|
+
findings.push(...scanFile(root, text, classifyRepoFile(root), isTrackedFile(root), dirname8(root)));
|
|
14551
15069
|
continue;
|
|
14552
15070
|
}
|
|
14553
15071
|
if (!stat.isDirectory())
|
|
14554
15072
|
continue;
|
|
14555
15073
|
const tracked = trackedFiles(root);
|
|
14556
15074
|
for (const file of collectRepoFiles(root)) {
|
|
14557
|
-
const rel = toPosix(
|
|
15075
|
+
const rel = toPosix(relative7(root, file));
|
|
14558
15076
|
const isTracked = tracked.has(rel);
|
|
14559
15077
|
const text = readTextFile(file);
|
|
14560
15078
|
if (text === null)
|
|
@@ -14564,10 +15082,10 @@ function scanPackageManagerSecrets(options = {}) {
|
|
|
14564
15082
|
}
|
|
14565
15083
|
}
|
|
14566
15084
|
if (options.includeHome) {
|
|
14567
|
-
const home =
|
|
15085
|
+
const home = homedir8();
|
|
14568
15086
|
for (const name of HOME_FILES) {
|
|
14569
|
-
const file =
|
|
14570
|
-
if (!
|
|
15087
|
+
const file = join17(home, name);
|
|
15088
|
+
if (!existsSync15(file))
|
|
14571
15089
|
continue;
|
|
14572
15090
|
const text = readTextFile(file);
|
|
14573
15091
|
if (text === null)
|
|
@@ -14591,12 +15109,12 @@ function collectRepoFiles(root) {
|
|
|
14591
15109
|
if (entry.isDirectory()) {
|
|
14592
15110
|
if (SKIP_DIRS.has(entry.name))
|
|
14593
15111
|
continue;
|
|
14594
|
-
visit(
|
|
15112
|
+
visit(join17(dir, entry.name));
|
|
14595
15113
|
continue;
|
|
14596
15114
|
}
|
|
14597
15115
|
if (!entry.isFile())
|
|
14598
15116
|
continue;
|
|
14599
|
-
const file =
|
|
15117
|
+
const file = join17(dir, entry.name);
|
|
14600
15118
|
if (shouldScanRepoFile(file))
|
|
14601
15119
|
out.push(file);
|
|
14602
15120
|
}
|
|
@@ -14631,10 +15149,10 @@ function isNpmrcName(name) {
|
|
|
14631
15149
|
}
|
|
14632
15150
|
function readTextFile(file) {
|
|
14633
15151
|
try {
|
|
14634
|
-
const stat =
|
|
15152
|
+
const stat = lstatSync6(file);
|
|
14635
15153
|
if (!stat.isFile() || stat.size > 5000000)
|
|
14636
15154
|
return null;
|
|
14637
|
-
const buf =
|
|
15155
|
+
const buf = readFileSync14(file);
|
|
14638
15156
|
if (buf.includes(0))
|
|
14639
15157
|
return null;
|
|
14640
15158
|
return buf.toString("utf-8");
|
|
@@ -14834,11 +15352,11 @@ function trackedFiles(root) {
|
|
|
14834
15352
|
}
|
|
14835
15353
|
function isTrackedFile(file) {
|
|
14836
15354
|
try {
|
|
14837
|
-
const repoRoot = execFileSync2("git", ["-C",
|
|
15355
|
+
const repoRoot = execFileSync2("git", ["-C", dirname8(file), "rev-parse", "--show-toplevel"], {
|
|
14838
15356
|
encoding: "utf-8",
|
|
14839
15357
|
stdio: ["ignore", "pipe", "ignore"]
|
|
14840
15358
|
}).trim();
|
|
14841
|
-
const rel = toPosix(
|
|
15359
|
+
const rel = toPosix(relative7(repoRoot, file));
|
|
14842
15360
|
execFileSync2("git", ["-C", repoRoot, "ls-files", "--error-unmatch", "--", rel], {
|
|
14843
15361
|
stdio: ["ignore", "ignore", "ignore"]
|
|
14844
15362
|
});
|
|
@@ -14864,172 +15382,176 @@ function stripInlineComment(value) {
|
|
|
14864
15382
|
return value.replace(/\s[#;].*$/, "").trim();
|
|
14865
15383
|
}
|
|
14866
15384
|
function displayPath(file, root) {
|
|
14867
|
-
const home =
|
|
15385
|
+
const home = homedir8();
|
|
14868
15386
|
if (root === home && (file === home || file.startsWith(home + "/")))
|
|
14869
|
-
return "~/" + toPosix(
|
|
15387
|
+
return "~/" + toPosix(relative7(home, file));
|
|
14870
15388
|
if (isAbsolute5(root) && file.startsWith(root + "/"))
|
|
14871
|
-
return toPosix(
|
|
15389
|
+
return toPosix(relative7(root, file));
|
|
14872
15390
|
if (file === home || file.startsWith(home + "/"))
|
|
14873
|
-
return "~/" + toPosix(
|
|
15391
|
+
return "~/" + toPosix(relative7(home, file));
|
|
14874
15392
|
return file;
|
|
14875
15393
|
}
|
|
14876
15394
|
function toPosix(path) {
|
|
14877
15395
|
return path.split("\\").join("/");
|
|
14878
15396
|
}
|
|
14879
15397
|
export {
|
|
14880
|
-
|
|
14881
|
-
transformSkillContent,
|
|
14882
|
-
templateizeMachineContent,
|
|
14883
|
-
syncToDisk,
|
|
14884
|
-
syncToDir,
|
|
14885
|
-
syncProject,
|
|
14886
|
-
syncKnown,
|
|
14887
|
-
syncFromDir,
|
|
14888
|
-
stripClaudeOnlySections,
|
|
14889
|
-
sourcesFromIdentityExport,
|
|
14890
|
-
sourceFromFilePath,
|
|
14891
|
-
sourceFromConfig,
|
|
14892
|
-
slugify,
|
|
14893
|
-
selectProviderCapability,
|
|
14894
|
-
selectProfileConfigsForSessionRender,
|
|
14895
|
-
selectAssetCapability,
|
|
14896
|
-
scanSecrets,
|
|
14897
|
-
scanPackageManagerSecrets,
|
|
14898
|
-
restoreSessionRenderSnapshot,
|
|
14899
|
-
resolveSessionTargetOwnership,
|
|
14900
|
-
resolveSessionPath,
|
|
14901
|
-
resolveProfileVariables,
|
|
14902
|
-
resolveConfigStore,
|
|
14903
|
-
resolveCloudConfig,
|
|
14904
|
-
resolveAssetDestination,
|
|
14905
|
-
resolveAgentOperatingRulesPayload,
|
|
14906
|
-
renderTemplatePreview,
|
|
14907
|
-
renderTemplate,
|
|
14908
|
-
renderMachineAwareContentPreview,
|
|
14909
|
-
renderMachineAwareContent,
|
|
14910
|
-
redactContent,
|
|
14911
|
-
providerVersionSatisfies,
|
|
14912
|
-
previewConfigs,
|
|
14913
|
-
planSessionRender,
|
|
14914
|
-
planProjectContext,
|
|
14915
|
-
planProfileSessionRender,
|
|
14916
|
-
parseTemplateVars,
|
|
14917
|
-
parseProjectContextBundle,
|
|
14918
|
-
parseAgentOperatingRulesVersion,
|
|
14919
|
-
now,
|
|
14920
|
-
normalizeProfileConfigBinding,
|
|
14921
|
-
normalizeProfileAssetBinding,
|
|
14922
|
-
normalizeOsFamily,
|
|
14923
|
-
normalizeBoundedReadOptions,
|
|
14924
|
-
machineContextToVariables,
|
|
14925
|
-
legacyProfileConfigBinding,
|
|
14926
|
-
isTemplate,
|
|
14927
|
-
isApiTransport,
|
|
14928
|
-
importConfigs,
|
|
14929
|
-
hasSecrets,
|
|
14930
|
-
getConfigsStatus,
|
|
14931
|
-
extractTemplateVars,
|
|
14932
|
-
exportConfigs,
|
|
14933
|
-
expandPath,
|
|
14934
|
-
ensureProjectDashboardStandardConfig,
|
|
14935
|
-
ensurePlatformProfiles,
|
|
14936
|
-
ensureGlobalAgentRulesStandardConfig,
|
|
14937
|
-
ensureDangerousOperationGuardStandardConfig,
|
|
14938
|
-
ensureCodewithSharedTodosStorageStandardConfig,
|
|
14939
|
-
diffConfig,
|
|
14940
|
-
detectMachineContext,
|
|
14941
|
-
detectFormat,
|
|
14942
|
-
detectCategory,
|
|
14943
|
-
detectAgent,
|
|
14944
|
-
currentOs,
|
|
14945
|
-
currentHostname2 as currentHostname,
|
|
14946
|
-
currentArch2 as currentArch,
|
|
14947
|
-
configAssetLocator,
|
|
14948
|
-
configAssetDigest,
|
|
14949
|
-
computeProjectContextSourceHash,
|
|
14950
|
-
compileInstructionGraph,
|
|
14951
|
-
compileAssetPlan,
|
|
14952
|
-
compareAgentOperatingRulesVersions,
|
|
14953
|
-
cleanSessionPathInput,
|
|
14954
|
-
checkSessionRenderDrift,
|
|
14955
|
-
buildOpenCodeAgentsMd,
|
|
14956
|
-
buildCursorMdc,
|
|
14957
|
-
buildCodexAgentsMd,
|
|
14958
|
-
boundedReadPage,
|
|
14959
|
-
assetBundleFromConfig,
|
|
14960
|
-
applyTransform,
|
|
14961
|
-
applySessionRender,
|
|
14962
|
-
applyProjectContext,
|
|
14963
|
-
applyConfigsWithReport,
|
|
14964
|
-
applyConfigs,
|
|
14965
|
-
applyConfig,
|
|
14966
|
-
TemplateRenderError,
|
|
14967
|
-
SessionApplyError,
|
|
14968
|
-
SESSION_TOOL_ADAPTERS,
|
|
14969
|
-
SESSION_RENDER_TOOLS,
|
|
14970
|
-
SESSION_RENDER_SCHEMA,
|
|
14971
|
-
SESSION_RENDER_MANAGED_MARKER,
|
|
14972
|
-
SESSION_LAYER_RANK,
|
|
14973
|
-
SESSION_INSTRUCTION_LAYERS,
|
|
14974
|
-
RAW_STORE_ROOT_ENV,
|
|
14975
|
-
ProjectContextError,
|
|
14976
|
-
ProfileNotFoundError,
|
|
14977
|
-
PROVIDER_CAPABILITY_SCHEMA,
|
|
14978
|
-
PROVIDER_CAPABILITY_DESCRIPTORS,
|
|
14979
|
-
PROVIDER_CAPABILITIES,
|
|
14980
|
-
PROJECT_DASHBOARD_STANDARD_SLUG,
|
|
14981
|
-
PROJECT_DASHBOARD_STANDARD_CONTENT,
|
|
14982
|
-
PROJECT_DASHBOARD_PROFILE_VARIABLES,
|
|
14983
|
-
PROJECT_CONTEXT_SCHEMA,
|
|
14984
|
-
PROJECT_CONTEXT_MAX_RENDERED_BYTES,
|
|
14985
|
-
PROJECT_CONTEXT_MAX_INPUT_BYTES,
|
|
14986
|
-
PROJECT_CONTEXT_MAX_COMMANDS,
|
|
14987
|
-
PROJECT_CONTEXT_MANIFEST_PATH,
|
|
14988
|
-
PROJECT_CONTEXT_MANAGED_COMMENT,
|
|
14989
|
-
PROJECT_CONTEXT_LOCK_PATH,
|
|
14990
|
-
PROJECT_CONTEXT_FRAGMENT_PATH,
|
|
14991
|
-
PROJECT_CONTEXT_CACHE_PATH,
|
|
14992
|
-
PROJECT_CONFIG_FILES,
|
|
14993
|
-
PROFILE_CONFIG_BINDING_SCHEMA,
|
|
14994
|
-
PROFILE_ASSET_BINDING_SCHEMA,
|
|
14995
|
-
PLATFORM_PROFILE_PRESETS,
|
|
14996
|
-
PG_MIGRATIONS,
|
|
14997
|
-
LocalConfigStore,
|
|
14998
|
-
LEGACY_CONFIGS_PACKAGE,
|
|
14999
|
-
LEGACY_CONFIGS_EXECUTABLE,
|
|
15000
|
-
LEGACY_CONFIGS_COMPAT_VERSION,
|
|
15001
|
-
KNOWN_CONFIGS,
|
|
15002
|
-
InstructionGraphValidationError,
|
|
15003
|
-
INSTRUCTION_GRAPH_PLAN_SCHEMA,
|
|
15004
|
-
INSTRUCTION_FALLBACKS,
|
|
15005
|
-
INSTRUCTION_ACTIVATION_MODES,
|
|
15006
|
-
GLOBAL_AGENT_RULES_STANDARD_SLUG,
|
|
15007
|
-
GLOBAL_AGENT_RULES_STANDARD_CONTENT,
|
|
15008
|
-
DANGEROUS_OPERATION_GUARD_STANDARD_SLUG,
|
|
15009
|
-
DANGEROUS_OPERATION_GUARD_STANDARD_CONTENT,
|
|
15010
|
-
ConfigNotFoundError,
|
|
15011
|
-
ConfigApplyError,
|
|
15012
|
-
CloudHttpError,
|
|
15013
|
-
CloudConfigStore,
|
|
15014
|
-
CONFIG_TRANSFORMS,
|
|
15015
|
-
CONFIG_KINDS,
|
|
15016
|
-
CONFIG_FORMATS,
|
|
15017
|
-
CONFIG_CATEGORIES,
|
|
15018
|
-
CONFIG_AGENTS,
|
|
15019
|
-
CODEWITH_SHARED_TODOS_STORAGE_STANDARD_SLUG,
|
|
15020
|
-
CODEWITH_SHARED_TODOS_STORAGE_STANDARD_CONTENT,
|
|
15021
|
-
CODEWITH_SHARED_TODOS_STORAGE_POLICY_REFERENCE,
|
|
15022
|
-
CODEWITH_NATIVE_IMPORTS_ENV,
|
|
15023
|
-
AssetPlanValidationError,
|
|
15024
|
-
ASSET_UNINSTALL_POLICIES,
|
|
15025
|
-
ASSET_SCOPES,
|
|
15026
|
-
ASSET_ROLLBACK_POLICIES,
|
|
15027
|
-
ASSET_PLAN_SCHEMA,
|
|
15028
|
-
ASSET_KINDS,
|
|
15029
|
-
ASSET_DESTINATION_STRATEGIES,
|
|
15030
|
-
ASSET_CAPABILITY_SCHEMA,
|
|
15031
|
-
ASSET_CAPABILITY_DESCRIPTORS,
|
|
15032
|
-
ASSET_BUNDLE_SCHEMA,
|
|
15398
|
+
AGENT_OPERATING_RULES_SEMANTIC_POLICY_KEY,
|
|
15033
15399
|
AGENT_OPERATING_RULES_SENTINEL_PATTERN,
|
|
15034
|
-
|
|
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
|
|
15035
15557
|
};
|