@hasna/instructions 0.4.8 → 0.4.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -3220,37 +3220,123 @@ var init_config_agents = __esm(() => {
3220
3220
  });
3221
3221
 
3222
3222
  // src/lib/global-agent-rules-standard.ts
3223
- async function ensureGlobalAgentRulesStandardConfig(store = resolveConfigStore()) {
3224
- const input = {
3223
+ import { createHash } from "crypto";
3224
+ function parseAgentOperatingRulesVersion(content) {
3225
+ return content ? AGENT_OPERATING_RULES_SENTINEL_PATTERN.exec(content)?.[1] ?? null : null;
3226
+ }
3227
+ function compareAgentOperatingRulesVersions(left, right) {
3228
+ const leftParts = left.split(".").map(Number);
3229
+ const rightParts = right.split(".").map(Number);
3230
+ for (let i = 0;i < 3; i++) {
3231
+ const diff = (leftParts[i] ?? 0) - (rightParts[i] ?? 0);
3232
+ if (diff !== 0)
3233
+ return diff;
3234
+ }
3235
+ return 0;
3236
+ }
3237
+ function payloadDate(content) {
3238
+ const canonical = new RegExp(AGENT_OPERATING_RULES_HEADING_PATTERN.source, "m").exec(content)?.[1];
3239
+ if (canonical)
3240
+ return canonical;
3241
+ const heading = /^#[^\S\n].*$/m.exec(content)?.[0];
3242
+ return heading ? /\b([0-9]{4}-[0-9]{2}-[0-9]{2})\b/.exec(heading)?.[1] ?? null : null;
3243
+ }
3244
+ function sha256(content) {
3245
+ return createHash("sha256").update(content).digest("hex");
3246
+ }
3247
+ function resolveAgentOperatingRulesPayload(storedContent) {
3248
+ const stored = storedContent ?? "";
3249
+ const storedVersion = parseAgentOperatingRulesVersion(stored);
3250
+ const baselineOrder = storedVersion === null ? null : compareAgentOperatingRulesVersions(storedVersion, AGENT_OPERATING_RULES_VERSION);
3251
+ const storedIsCurrent = baselineOrder !== null && (baselineOrder > 0 || baselineOrder === 0 && sha256(stored) === AGENT_OPERATING_RULES_PAYLOAD_SHA256);
3252
+ const content = storedIsCurrent ? stored : GLOBAL_AGENT_RULES_STANDARD_CONTENT;
3253
+ const origin = storedIsCurrent ? "stored-config" : "embedded-baseline";
3254
+ const matchesEmbeddedBaseline = content === GLOBAL_AGENT_RULES_STANDARD_CONTENT;
3255
+ const integrity = matchesEmbeddedBaseline ? "pinned-digest" : "unverified-self-declared";
3256
+ const version = storedIsCurrent ? storedVersion : AGENT_OPERATING_RULES_VERSION;
3257
+ const payloadSha256 = matchesEmbeddedBaseline ? AGENT_OPERATING_RULES_PAYLOAD_SHA256 : sha256(content);
3258
+ const sourceSetVersion = matchesEmbeddedBaseline ? AGENT_OPERATING_RULES_SOURCE_SET_VERSION : payloadDate(content);
3259
+ const upstreamPin = matchesEmbeddedBaseline ? {
3260
+ upstreamRepository: AGENT_OPERATING_RULES_UPSTREAM.repository,
3261
+ upstreamCommit: AGENT_OPERATING_RULES_UPSTREAM.commit,
3262
+ upstreamPath: AGENT_OPERATING_RULES_UPSTREAM.path,
3263
+ upstreamFileSha256: AGENT_OPERATING_RULES_UPSTREAM_FILE_SHA256
3264
+ } : {};
3265
+ const policyReference = content.includes(SCOPED_OPERATIONAL_CONTROL_POLICY_REFERENCE) ? { policyReference: SCOPED_OPERATIONAL_CONTROL_POLICY_REFERENCE } : {};
3266
+ return {
3267
+ content,
3268
+ version,
3269
+ origin,
3270
+ matchesEmbeddedBaseline,
3271
+ integrity,
3272
+ provenance: {
3273
+ source: AGENT_OPERATING_RULES_PROVENANCE.source,
3274
+ payloadOrigin: origin,
3275
+ payloadIntegrity: integrity,
3276
+ ...upstreamPin,
3277
+ upstreamExportId: AGENT_OPERATING_RULES_SOURCE_SET_ID,
3278
+ upstreamSourceId: AGENT_OPERATING_RULES_SOURCE_ID,
3279
+ selectedPayloadSha256: payloadSha256,
3280
+ rulesVersion: version,
3281
+ sourceSetVersion,
3282
+ ...policyReference
3283
+ },
3284
+ metadata: {
3285
+ sourceSet: AGENT_OPERATING_RULES_SOURCE_SET_ID,
3286
+ role: AGENT_OPERATING_RULES_METADATA.role,
3287
+ payloadOrigin: origin,
3288
+ payloadIntegrity: integrity,
3289
+ rulesVersion: version,
3290
+ sourceSetVersion,
3291
+ plan: GLOBAL_AGENT_RULES_STANDARD_SLUG,
3292
+ contentSha256: payloadSha256,
3293
+ selectedPayloadSha256: payloadSha256,
3294
+ ...matchesEmbeddedBaseline ? { upstreamFileSha256: AGENT_OPERATING_RULES_UPSTREAM_FILE_SHA256 } : {},
3295
+ upstreamExportId: AGENT_OPERATING_RULES_SOURCE_SET_ID,
3296
+ upstreamSourceId: AGENT_OPERATING_RULES_SOURCE_ID,
3297
+ sentinel: AGENT_OPERATING_RULES_METADATA.sentinel,
3298
+ ...policyReference.policyReference ? { policyReferences: { incidentRecovery: SCOPED_OPERATIONAL_CONTROL_POLICY_REFERENCE } } : {}
3299
+ }
3300
+ };
3301
+ }
3302
+ function standardConfigInput(payload) {
3303
+ return {
3225
3304
  name: "Global Agent Rules Standard",
3226
3305
  category: "rules",
3227
3306
  agent: "global",
3228
3307
  format: "markdown",
3229
- content: GLOBAL_AGENT_RULES_STANDARD_CONTENT,
3308
+ content: payload.content,
3230
3309
  kind: "reference",
3231
- description: `Managed Hasna agent operating rules v${AGENT_OPERATING_RULES_VERSION}; accepted source ${AGENT_OPERATING_RULES_UPSTREAM.repository}@${AGENT_OPERATING_RULES_UPSTREAM.commit}:${AGENT_OPERATING_RULES_UPSTREAM.path}`,
3310
+ description: payload.matchesEmbeddedBaseline ? `Managed Hasna agent operating rules v${payload.version}; accepted source ${AGENT_OPERATING_RULES_UPSTREAM.repository}@${AGENT_OPERATING_RULES_UPSTREAM.commit}:${AGENT_OPERATING_RULES_UPSTREAM.path}` : `Managed Hasna agent operating rules v${payload.version}; stored payload sha256 ${payload.metadata["contentSha256"]}`,
3232
3311
  tags: [
3233
3312
  "global-agent-rules",
3234
3313
  "system-prompt",
3235
3314
  "coding-agent-rules",
3236
3315
  "agent-operating-rules",
3237
- `rules-version:${AGENT_OPERATING_RULES_VERSION}`,
3238
- `source-commit:${AGENT_OPERATING_RULES_UPSTREAM.commit}`
3316
+ `rules-version:${payload.version}`,
3317
+ ...payload.matchesEmbeddedBaseline ? [`source-commit:${AGENT_OPERATING_RULES_UPSTREAM.commit}`] : []
3239
3318
  ]
3240
3319
  };
3320
+ }
3321
+ async function ensureGlobalAgentRulesStandardConfig(store = resolveConfigStore()) {
3322
+ let existing;
3241
3323
  try {
3242
- const existing = await store.getConfig(GLOBAL_AGENT_RULES_STANDARD_SLUG);
3243
- if (existing.content !== input.content || existing.description !== input.description || existing.category !== input.category || existing.agent !== input.agent || existing.format !== input.format || existing.kind !== input.kind || JSON.stringify(existing.tags) !== JSON.stringify(input.tags)) {
3244
- return await store.updateConfig(existing.id, input);
3245
- }
3246
- return existing;
3324
+ existing = await store.getConfig(GLOBAL_AGENT_RULES_STANDARD_SLUG);
3247
3325
  } catch {
3248
- return await store.createConfig(input);
3326
+ return await store.createConfig(standardConfigInput(resolveAgentOperatingRulesPayload(null)));
3327
+ }
3328
+ const payload = resolveAgentOperatingRulesPayload(existing.content);
3329
+ const input = standardConfigInput(payload);
3330
+ if (existing.content !== input.content || existing.description !== input.description || existing.category !== input.category || existing.agent !== input.agent || existing.format !== input.format || existing.kind !== input.kind || JSON.stringify(existing.tags) !== JSON.stringify(input.tags)) {
3331
+ return await store.updateConfig(existing.id, input);
3249
3332
  }
3333
+ return existing;
3250
3334
  }
3251
- var GLOBAL_AGENT_RULES_STANDARD_SLUG = "global-agent-rules-standard", AGENT_OPERATING_RULES_SOURCE_SET_ID = "hasna-global-agent-rules-standard", AGENT_OPERATING_RULES_SOURCE_ID = "hasna-agent-operating-rules", AGENT_OPERATING_RULES_VERSION = "1.1.6", AGENT_OPERATING_RULES_SOURCE_SET_VERSION = "2026-07-23", AGENT_OPERATING_RULES_SENTINEL = "<!-- hasna:agent-operating-rules v=1.1.6 -->", AGENT_OPERATING_RULES_PAYLOAD_SHA256 = "8b236086b82e94490516e0b00dffa03fb5f6841b68d95f80fc3e3c8fb7087420", AGENT_OPERATING_RULES_UPSTREAM_FILE_SHA256 = "b8e89cdb49e207e5b497ac51384d67022b94fe5645cc9273db60384eb2c2fb32", SCOPED_OPERATIONAL_CONTROL_POLICY_REFERENCE = "hasna-agent-operating-rules/scoped-operational-control/v1", AGENT_OPERATING_RULES_UPSTREAM, SCOPED_OPERATIONAL_CONTROL_POLICY, AGENT_OPERATING_RULES_PROVENANCE, AGENT_OPERATING_RULES_METADATA, NO_BRITTLE_HARDCODING_RULE = "Do not hardcode brittle values, paths, provider names, config, business logic, environment-specific IDs, or one-off mappings when a source-of-truth, schema/config-driven, package-owned, reusable, or cleaner abstraction exists. This is especially strict in medium and large applications. Explicit constants, fixtures, tests, and temporary compatibility shims are allowed only when scoped, named, and justified.", GLOBAL_AGENT_RULES_STANDARD_CONTENT;
3335
+ var GLOBAL_AGENT_RULES_STANDARD_SLUG = "global-agent-rules-standard", AGENT_OPERATING_RULES_SOURCE_SET_ID = "hasna-global-agent-rules-standard", AGENT_OPERATING_RULES_SOURCE_ID = "hasna-agent-operating-rules", AGENT_OPERATING_RULES_ROLE = "agent-operating-rules", AGENT_OPERATING_RULES_VERSION = "1.1.6", AGENT_OPERATING_RULES_SOURCE_SET_VERSION = "2026-07-23", AGENT_OPERATING_RULES_SENTINEL = "<!-- hasna:agent-operating-rules v=1.1.6 -->", AGENT_OPERATING_RULES_SEMANTIC_POLICY_KEY = "hasna:agent-operating-rules", AGENT_OPERATING_RULES_SENTINEL_PATTERN, AGENT_OPERATING_RULES_HEADING_PATTERN, AGENT_OPERATING_RULES_PAYLOAD_SHA256 = "8b236086b82e94490516e0b00dffa03fb5f6841b68d95f80fc3e3c8fb7087420", AGENT_OPERATING_RULES_UPSTREAM_FILE_SHA256 = "b8e89cdb49e207e5b497ac51384d67022b94fe5645cc9273db60384eb2c2fb32", SCOPED_OPERATIONAL_CONTROL_POLICY_REFERENCE = "hasna-agent-operating-rules/scoped-operational-control/v1", AGENT_OPERATING_RULES_UPSTREAM, SCOPED_OPERATIONAL_CONTROL_POLICY, AGENT_OPERATING_RULES_PROVENANCE, AGENT_OPERATING_RULES_METADATA, NO_BRITTLE_HARDCODING_RULE = "Do not hardcode brittle values, paths, provider names, config, business logic, environment-specific IDs, or one-off mappings when a source-of-truth, schema/config-driven, package-owned, reusable, or cleaner abstraction exists. This is especially strict in medium and large applications. Explicit constants, fixtures, tests, and temporary compatibility shims are allowed only when scoped, named, and justified.", GLOBAL_AGENT_RULES_STANDARD_CONTENT;
3252
3336
  var init_global_agent_rules_standard = __esm(() => {
3253
3337
  init_config_store();
3338
+ AGENT_OPERATING_RULES_SENTINEL_PATTERN = /<!--\s*hasna:agent-operating-rules\s+v=([0-9]+\.[0-9]+\.[0-9]+)\s*-->/i;
3339
+ AGENT_OPERATING_RULES_HEADING_PATTERN = /^#\s*Hasna Agent Operating Rules\s+\u2014\s+v[0-9]+\.[0-9]+\.[0-9]+\s+\(([0-9]{4}-[0-9]{2}-[0-9]{2})\)/;
3254
3340
  AGENT_OPERATING_RULES_UPSTREAM = {
3255
3341
  repository: "hasnaxyz/iapp-identities",
3256
3342
  commit: "48168c549cc2945053a4498a9a2b11888419bc94",
@@ -3279,7 +3365,7 @@ var init_global_agent_rules_standard = __esm(() => {
3279
3365
  };
3280
3366
  AGENT_OPERATING_RULES_METADATA = {
3281
3367
  sourceSet: AGENT_OPERATING_RULES_SOURCE_SET_ID,
3282
- role: "agent-operating-rules",
3368
+ role: AGENT_OPERATING_RULES_ROLE,
3283
3369
  rulesVersion: AGENT_OPERATING_RULES_VERSION,
3284
3370
  sourceSetVersion: AGENT_OPERATING_RULES_SOURCE_SET_VERSION,
3285
3371
  plan: GLOBAL_AGENT_RULES_STANDARD_SLUG,
@@ -3288,7 +3374,7 @@ var init_global_agent_rules_standard = __esm(() => {
3288
3374
  upstreamFileSha256: AGENT_OPERATING_RULES_UPSTREAM_FILE_SHA256,
3289
3375
  upstreamExportId: AGENT_OPERATING_RULES_SOURCE_SET_ID,
3290
3376
  upstreamSourceId: AGENT_OPERATING_RULES_SOURCE_ID,
3291
- sentinel: "hasna:agent-operating-rules",
3377
+ sentinel: AGENT_OPERATING_RULES_SEMANTIC_POLICY_KEY,
3292
3378
  policyReferences: {
3293
3379
  incidentRecovery: SCOPED_OPERATIONAL_CONTROL_POLICY_REFERENCE
3294
3380
  }
@@ -7480,8 +7566,11 @@ var init_redact = __esm(() => {
7480
7566
  });
7481
7567
 
7482
7568
  // src/lib/session-render-contract.ts
7483
- var CODEWITH_NATIVE_IMPORTS_ENV = "HASNA_CONFIGS_CODEWITH_NATIVE_IMPORTS", SESSION_RENDER_MANAGED_MARKER = "Managed by @hasna/configs session render", SESSION_RENDER_SCHEMA = "hasna.configs.session-render/v1", SESSION_INSTRUCTION_LAYERS;
7569
+ var CODEWITH_NATIVE_IMPORTS_ENV = "HASNA_CONFIGS_CODEWITH_NATIVE_IMPORTS", SESSION_RENDER_MANAGED_MARKER = "Managed by @hasna/configs session render", SESSION_RENDER_SCHEMA = "hasna.configs.session-render/v1", SESSION_RENDER_MANAGED_NAMESPACE = ".hasna", SESSION_RENDER_INSTRUCTIONS_MANAGED_DIR, SESSION_RENDER_MANIFEST_RELATIVE_PATH, SESSION_RENDER_SNAPSHOT_RELATIVE_DIR, SESSION_INSTRUCTION_LAYERS;
7484
7570
  var init_session_render_contract = __esm(() => {
7571
+ SESSION_RENDER_INSTRUCTIONS_MANAGED_DIR = `${SESSION_RENDER_MANAGED_NAMESPACE}/instructions`;
7572
+ SESSION_RENDER_MANIFEST_RELATIVE_PATH = `${SESSION_RENDER_MANAGED_NAMESPACE}/session-render-manifest.json`;
7573
+ SESSION_RENDER_SNAPSHOT_RELATIVE_DIR = `${SESSION_RENDER_MANAGED_NAMESPACE}/session-render-snapshots`;
7485
7574
  SESSION_INSTRUCTION_LAYERS = [
7486
7575
  "global",
7487
7576
  "tool",
@@ -7498,7 +7587,7 @@ var init_session_render_contract = __esm(() => {
7498
7587
  });
7499
7588
 
7500
7589
  // src/lib/project-context.ts
7501
- import { createHash, randomUUID as randomUUID6 } from "crypto";
7590
+ import { createHash as createHash2, randomUUID as randomUUID6 } from "crypto";
7502
7591
  import { execFileSync } from "child_process";
7503
7592
  import { dlopen, FFIType } from "bun:ffi";
7504
7593
  import {
@@ -7520,7 +7609,7 @@ import {
7520
7609
  import { basename, dirname, isAbsolute, join as join4, parse, relative, resolve } from "path";
7521
7610
  function computeProjectContextSourceHash(value) {
7522
7611
  const normalized = removeHashForFingerprint(value);
7523
- return `sha256:${sha256(stableStringify(normalized))}`;
7612
+ return `sha256:${sha2562(stableStringify(normalized))}`;
7524
7613
  }
7525
7614
  function parseProjectContextBundle(input) {
7526
7615
  let encoded;
@@ -7690,7 +7779,7 @@ function composeProjectContextSessionRender(input) {
7690
7779
  const files = input.files.map((file) => file === index ? {
7691
7780
  ...file,
7692
7781
  content,
7693
- sha256: sha256(content),
7782
+ sha256: sha2562(content),
7694
7783
  sourceIds: [...new Set([...file.sourceIds, "project-context-bundle"])]
7695
7784
  } : file);
7696
7785
  if (observedHashes.some((observed) => currentFileHash(observed.path, workspaceRoot) !== observed.sha256)) {
@@ -7891,7 +7980,7 @@ function assertRenderedOutputsStable(plan, cacheContent, sessionOutput) {
7891
7980
  sessionOutput
7892
7981
  ];
7893
7982
  for (const output of outputs) {
7894
- if (currentFileHash(output.path, plan.workspace_root) !== sha256(output.content)) {
7983
+ if (currentFileHash(output.path, plan.workspace_root) !== sha2562(output.content)) {
7895
7984
  throw new ProjectContextHashRace(`managed path changed before manifest commit: ${relativePosix(plan.workspace_root, output.path)}`);
7896
7985
  }
7897
7986
  }
@@ -8111,7 +8200,7 @@ function findLegacyCodewithWorkspaceSection(workspaceRoot, runtime, content, bun
8111
8200
  return null;
8112
8201
  const files = Array.isArray(manifest["files"]) ? manifest["files"] : [];
8113
8202
  const codewith = files.find((file) => isRecord(file) && file["relativePath"] === "CODEWITH.md");
8114
- if (!isRecord(codewith) || codewith["sha256"] !== sha256(content)) {
8203
+ if (!isRecord(codewith) || codewith["sha256"] !== sha2562(content)) {
8115
8204
  throw new ProjectContextError("MANAGED_BLOCK_CONFLICT", "legacy /dev/fd session manifest does not match CODEWITH.md");
8116
8205
  }
8117
8206
  const section = /^## Workspace\r?\n/gm.exec(content);
@@ -8181,14 +8270,14 @@ function buildManifest(plan, now3) {
8181
8270
  path: plan.fragment_path,
8182
8271
  relativePath: PROJECT_CONTEXT_FRAGMENT_PATH,
8183
8272
  role: "fragment",
8184
- sha256: sha256(plan.fragment),
8273
+ sha256: sha2562(plan.fragment),
8185
8274
  sourceIds: ["project-context-bundle"]
8186
8275
  },
8187
8276
  {
8188
8277
  path: plan.target_path,
8189
8278
  relativePath: plan.target_relative_path,
8190
8279
  role: "index",
8191
- sha256: sha256(plan.target_content),
8280
+ sha256: sha2562(plan.target_content),
8192
8281
  sourceIds: ["project-context-bundle"]
8193
8282
  }
8194
8283
  ];
@@ -8265,7 +8354,7 @@ function buildSessionCompatibilityManifest(plan, now3) {
8265
8354
  path: plan.target_path,
8266
8355
  relativePath: targetRelativePath,
8267
8356
  role: "index",
8268
- sha256: sha256(plan.target_content),
8357
+ sha256: sha2562(plan.target_content),
8269
8358
  sourceIds: [...new Set([...previousSourceIds ?? [], "project-context-bundle"])]
8270
8359
  };
8271
8360
  const targetOwner = isRecord(existing["targetOwner"]) ? existing["targetOwner"] : {};
@@ -8293,7 +8382,7 @@ function buildSessionCompatibilityManifest(plan, now3) {
8293
8382
  blockers: [],
8294
8383
  generatedAt: now3.toISOString(),
8295
8384
  env: sanitizeLegacyEnvironment(existing["env"]),
8296
- sourceHash: sha256(stableStringify({ previous: typeof existing["sourceHash"] === "string" ? existing["sourceHash"] : null, projectContext: plan.bundle.hash })),
8385
+ sourceHash: sha2562(stableStringify({ previous: typeof existing["sourceHash"] === "string" ? existing["sourceHash"] : null, projectContext: plan.bundle.hash })),
8297
8386
  sources,
8298
8387
  skippedSources: sanitizeLegacySkippedSources(existing["skippedSources"]),
8299
8388
  files: [...files.filter((file) => file["relativePath"] !== targetRelativePath), updatedTarget],
@@ -8496,7 +8585,7 @@ function projectContextManifestSource(cachePath, runtime, bundle) {
8496
8585
  nonOverridable: true,
8497
8586
  replacementScope: "project-context",
8498
8587
  rules: [],
8499
- renderedPayloadSha256: sha256(JSON.stringify(bundle)),
8588
+ renderedPayloadSha256: sha2562(JSON.stringify(bundle)),
8500
8589
  provenance: {
8501
8590
  schema: PROJECT_CONTEXT_SCHEMA,
8502
8591
  projectId: bundle.project.id,
@@ -8618,7 +8707,7 @@ function atomicWriteFile(path, content, workspaceRoot, defaultMode, expectedHash
8618
8707
  let fd = null;
8619
8708
  let preserveTemp = false;
8620
8709
  let directoryChanged = false;
8621
- const desiredHash = sha256(content);
8710
+ const desiredHash = sha2562(content);
8622
8711
  try {
8623
8712
  fd = anchoredOpenExclusive(directory, tempName, previousMode);
8624
8713
  writeFileSync(fd, content, { encoding: "utf8" });
@@ -8728,7 +8817,7 @@ function atomicWriteFile(path, content, workspaceRoot, defaultMode, expectedHash
8728
8817
  }
8729
8818
  }
8730
8819
  function atomicWritePortable(path, content, workspaceRoot, defaultMode, expectedHash, beforeInstall, maxObservedBytes, allowReplacement = false) {
8731
- const desiredHash = sha256(content);
8820
+ const desiredHash = sha2562(content);
8732
8821
  const currentHash = portableFileHash(path, workspaceRoot, maxObservedBytes);
8733
8822
  if (expectedHash === undefined && currentHash === desiredHash)
8734
8823
  return;
@@ -8802,7 +8891,7 @@ function atomicWritePortableReplacement(path, content, workspaceRoot, expectedHa
8802
8891
  const dir = dirname(path);
8803
8892
  const directoryIdentity = captureManagedDirectoryIdentity(dir, workspaceRoot);
8804
8893
  const tempPath = join4(dir, `.project-context-${randomUUID6()}.tmp`);
8805
- const desiredHash = sha256(content);
8894
+ const desiredHash = sha2562(content);
8806
8895
  let fd = null;
8807
8896
  let tempIdentity = null;
8808
8897
  try {
@@ -8853,7 +8942,7 @@ function portableFileHash(path, workspaceRoot, maxObservedBytes) {
8853
8942
  if (maxObservedBytes !== null && stat.size > maxObservedBytes) {
8854
8943
  throw new ProjectContextHashRace(`managed output exceeds the safe read limit: ${relativePosix(workspaceRoot, path)}`);
8855
8944
  }
8856
- return createHash("sha256").update(readFileSync(path)).digest("hex");
8945
+ return createHash2("sha256").update(readFileSync(path)).digest("hex");
8857
8946
  }
8858
8947
  function writeProjectContextCoordinatedFile(input) {
8859
8948
  atomicWriteFile(resolve(input.path), input.content, assertSafeWorkspaceRoot(input.workspace_root), input.default_mode ?? 420, input.expected_hash, undefined, false, undefined, input.force_portable_file_ops ?? false, input.max_observed_bytes, input.allow_portable_replacement ?? false);
@@ -9026,7 +9115,7 @@ function anchoredFileObservation(directory, name) {
9026
9115
  return {
9027
9116
  dev: stat.dev,
9028
9117
  ino: stat.ino,
9029
- hash: createHash("sha256").update(readFileSync(fd)).digest("hex"),
9118
+ hash: createHash2("sha256").update(readFileSync(fd)).digest("hex"),
9030
9119
  mode: stat.mode & 511
9031
9120
  };
9032
9121
  } finally {
@@ -9204,7 +9293,7 @@ function acquireWorkspaceLock(workspaceRoot, lockPath, afterOpen, beforeStaleRem
9204
9293
  process_start_id: processStartIdentityLookup(process.pid)
9205
9294
  })}
9206
9295
  `;
9207
- openedContentHash = sha256(content);
9296
+ openedContentHash = sha2562(content);
9208
9297
  writeFileSync(fd, content);
9209
9298
  fsyncSync(fd);
9210
9299
  try {
@@ -9255,7 +9344,7 @@ function removeOwnedLockByInode(lockPath, identity, expectedHash) {
9255
9344
  const current = lstatSync(lockPath);
9256
9345
  if (current.isSymbolicLink() || current.dev !== identity.dev || current.ino !== identity.ino)
9257
9346
  return;
9258
- if (expectedHash !== undefined && sha256(readFileSync(lockPath, "utf8")) !== expectedHash)
9347
+ if (expectedHash !== undefined && sha2562(readFileSync(lockPath, "utf8")) !== expectedHash)
9259
9348
  return;
9260
9349
  rmSync2(lockPath);
9261
9350
  fsyncDirectory(resolve(lockPath, ".."));
@@ -9272,7 +9361,7 @@ function observeStaleWorkspaceLock(lockPath, workspaceRoot, processStartIdentity
9272
9361
  } catch {
9273
9362
  return null;
9274
9363
  }
9275
- const contentHash = sha256(content);
9364
+ const contentHash = sha2562(content);
9276
9365
  if (currentFileHash(lockPath, workspaceRoot) !== contentHash)
9277
9366
  return null;
9278
9367
  let pid = null;
@@ -9434,7 +9523,7 @@ function releaseWorkspaceLock(lockPath, lock, workspaceRoot) {
9434
9523
  created_at: new Date().toISOString()
9435
9524
  })}
9436
9525
  `;
9437
- releaseHash = sha256(releaseContent);
9526
+ releaseHash = sha2562(releaseContent);
9438
9527
  writeFileSync(releaseFd, releaseContent);
9439
9528
  fsyncSync(releaseFd);
9440
9529
  closeSync(releaseFd);
@@ -9673,7 +9762,7 @@ function currentFileHash(path, workspaceRoot) {
9673
9762
  return null;
9674
9763
  const relativePath = relativePosix(workspaceRoot, path);
9675
9764
  const maxBytes = relativePath === ".hasna/session-render-manifest.json" || relativePath === ".codewith/.hasna/session-render-manifest.json" ? SESSION_COMPATIBILITY_MANIFEST_MAX_BYTES : 256 * 1024;
9676
- return sha256(readUtf8RegularFile(path, workspaceRoot, maxBytes));
9765
+ return sha2562(readUtf8RegularFile(path, workspaceRoot, maxBytes));
9677
9766
  }
9678
9767
  function hashesStillMatch(expected, workspaceRoot) {
9679
9768
  for (const [path, hash] of expected) {
@@ -9842,8 +9931,8 @@ function removeHashForFingerprint(value) {
9842
9931
  }
9843
9932
  return copy;
9844
9933
  }
9845
- function sha256(content) {
9846
- return createHash("sha256").update(content).digest("hex");
9934
+ function sha2562(content) {
9935
+ return createHash2("sha256").update(content).digest("hex");
9847
9936
  }
9848
9937
  function isRecord(value) {
9849
9938
  return !!value && typeof value === "object" && !Array.isArray(value);
@@ -10110,7 +10199,7 @@ function applyTransform(source, output, context = {}) {
10110
10199
  var init_transforms = () => {};
10111
10200
 
10112
10201
  // src/lib/session-render.ts
10113
- import { createHash as createHash2 } from "crypto";
10202
+ import { createHash as createHash3 } from "crypto";
10114
10203
  import { existsSync as existsSync5, readFileSync as readFileSync2, realpathSync, statSync as statSync2 } from "fs";
10115
10204
  import { homedir as homedir3 } from "os";
10116
10205
  import { basename as basename3, dirname as dirname2, extname as extname2, isAbsolute as isAbsolute2, join as join5, parse as parse2, posix, relative as relative2, resolve as resolve2 } from "path";
@@ -10130,11 +10219,11 @@ function ensureTrailingNewline3(content) {
10130
10219
  `) ? content : `${content}
10131
10220
  `;
10132
10221
  }
10133
- function sha2562(content) {
10134
- return createHash2("sha256").update(content).digest("hex");
10222
+ function sha2563(content) {
10223
+ return createHash3("sha256").update(content).digest("hex");
10135
10224
  }
10136
10225
  function fingerprint(value) {
10137
- return sha2562(JSON.stringify(value));
10226
+ return sha2563(JSON.stringify(value));
10138
10227
  }
10139
10228
  function canonicalFingerprintValue(value) {
10140
10229
  if (Array.isArray(value))
@@ -10200,18 +10289,59 @@ function makeFile(targetHome, relativePath, role, content, sourceIds) {
10200
10289
  relativePath: safeRelativePath,
10201
10290
  role,
10202
10291
  content: normalizedContent,
10203
- sha256: sha2562(normalizedContent),
10292
+ sha256: sha2563(normalizedContent),
10204
10293
  sourceIds
10205
10294
  };
10206
10295
  }
10296
+ function claimsAgentOperatingRulesPolicy(source, content) {
10297
+ if (!AGENT_OPERATING_RULES_SENTINEL_PATTERN.test(content))
10298
+ return false;
10299
+ if (source.nonOverridable === true)
10300
+ return true;
10301
+ if (source.id === GLOBAL_AGENT_RULES_STANDARD_SLUG || source.id === AGENT_OPERATING_RULES_SOURCE_ID)
10302
+ return true;
10303
+ if (source.metadata?.["role"] === AGENT_OPERATING_RULES_ROLE)
10304
+ return true;
10305
+ return AGENT_OPERATING_RULES_HEADING_PATTERN.test(content.trimStart());
10306
+ }
10307
+ function applyAgentOperatingRulesFloor(source, content) {
10308
+ const unchanged = {
10309
+ content,
10310
+ provenance: source.provenance ?? null,
10311
+ metadata: source.metadata ?? null
10312
+ };
10313
+ if (!claimsAgentOperatingRulesPolicy(source, content))
10314
+ return unchanged;
10315
+ const payload = resolveAgentOperatingRulesPayload(content);
10316
+ if (payload.content === content) {
10317
+ return {
10318
+ content,
10319
+ provenance: { ...source.provenance ?? {}, payloadIntegrity: payload.integrity },
10320
+ metadata: { ...source.metadata ?? {}, payloadIntegrity: payload.integrity }
10321
+ };
10322
+ }
10323
+ const floored = {
10324
+ payloadFloorApplied: true,
10325
+ flooredFromRulesVersion: parseAgentOperatingRulesVersion(content),
10326
+ flooredFromPayloadSha256: sha2563(content)
10327
+ };
10328
+ return {
10329
+ content: payload.content,
10330
+ provenance: { ...source.provenance ?? {}, ...payload.provenance, ...floored },
10331
+ metadata: { ...source.metadata ?? {}, ...payload.metadata, ...floored }
10332
+ };
10333
+ }
10207
10334
  function normalizeSources(sources, tool, allowEmptySources) {
10208
10335
  const normalized = sources.map((source, index) => {
10209
10336
  if (!source.id.trim())
10210
10337
  throw new Error("Session instruction source id is required.");
10211
- const content = filterProviderOnlyBlocks(source.content ?? "", tool);
10338
+ const floored = applyAgentOperatingRulesFloor(source, source.content ?? "");
10339
+ const content = filterProviderOnlyBlocks(floored.content, tool);
10212
10340
  const normalized2 = {
10213
10341
  ...source,
10214
10342
  content,
10343
+ provenance: floored.provenance,
10344
+ metadata: floored.metadata,
10215
10345
  normalizedId: slug(source.id),
10216
10346
  resolvedLabel: source.label ?? source.id,
10217
10347
  resolvedLayer: source.layer === undefined ? "agent" : normalizeSessionInstructionLayer(source.layer),
@@ -10234,30 +10364,36 @@ function deduplicateSemanticPolicySources(sources) {
10234
10364
  const selected = [];
10235
10365
  const policySources = new Map;
10236
10366
  for (const source of sources) {
10237
- const sentinel = source.content.match(/<!--\s*hasna:agent-operating-rules\s+v=([0-9]+\.[0-9]+\.[0-9]+)\s*-->/i);
10367
+ const sentinel = source.content.match(AGENT_OPERATING_RULES_SENTINEL_PATTERN);
10238
10368
  if (!sentinel) {
10239
10369
  selected.push(source);
10240
10370
  continue;
10241
10371
  }
10242
- const key = `hasna:agent-operating-rules/v${sentinel[1]}`;
10372
+ const version = sentinel[1];
10373
+ const key = AGENT_OPERATING_RULES_SEMANTIC_POLICY_KEY;
10243
10374
  const normalizedContent = source.content.replace(/\r\n/g, `
10244
10375
  `).trim();
10245
10376
  const existing = policySources.get(key);
10246
10377
  if (!existing) {
10247
- policySources.set(key, { index: selected.length, normalizedContent });
10378
+ policySources.set(key, { index: selected.length, version, normalizedContent });
10248
10379
  selected.push(source);
10249
10380
  continue;
10250
10381
  }
10251
- if (existing.normalizedContent !== normalizedContent) {
10252
- throw new Error(`Conflicting semantic policy sources declare ${key} with different content.`);
10382
+ const versionOrder = compareAgentOperatingRulesVersions(version, existing.version);
10383
+ if (versionOrder === 0 && existing.normalizedContent !== normalizedContent) {
10384
+ throw new Error(`Conflicting semantic policy sources declare ${key}/v${version} with different content.`);
10253
10385
  }
10254
10386
  const current = selected[existing.index];
10255
- if (semanticPolicySourcePriority(source) <= semanticPolicySourcePriority(current))
10387
+ const priorityOrder = semanticPolicySourcePriority(source) - semanticPolicySourcePriority(current);
10388
+ if (priorityOrder < 0)
10389
+ continue;
10390
+ if (priorityOrder === 0 && versionOrder <= 0)
10256
10391
  continue;
10257
10392
  selected[existing.index] = {
10258
10393
  ...source,
10259
10394
  resolvedOrder: current.resolvedOrder
10260
10395
  };
10396
+ policySources.set(key, { index: existing.index, version, normalizedContent });
10261
10397
  }
10262
10398
  return selected;
10263
10399
  }
@@ -10267,7 +10403,7 @@ function semanticPolicySourcePriority(source) {
10267
10403
  priority += 4;
10268
10404
  if (source.id === GLOBAL_AGENT_RULES_STANDARD_SLUG)
10269
10405
  priority += 2;
10270
- if (source.metadata?.["role"] === "agent-operating-rules")
10406
+ if (source.metadata?.["role"] === AGENT_OPERATING_RULES_ROLE)
10271
10407
  priority += 1;
10272
10408
  return priority;
10273
10409
  }
@@ -10756,7 +10892,7 @@ function planSessionRender(input) {
10756
10892
  globs: rule.globs ?? [],
10757
10893
  hash: rule.hash ?? null
10758
10894
  })),
10759
- renderedPayloadSha256: sha2562(source.content),
10895
+ renderedPayloadSha256: sha2563(source.content),
10760
10896
  provenance: source.provenance ?? null,
10761
10897
  metadata: source.metadata ?? null
10762
10898
  })),
@@ -10774,8 +10910,8 @@ function planSessionRender(input) {
10774
10910
  ...input.providerConfig ? {
10775
10911
  providerConfig: {
10776
10912
  sourceId: input.providerConfig.sourceId,
10777
- selectedPayloadSha256: sha2562(input.providerConfig.content),
10778
- renderedPayloadSha256: files.find((file) => file.relativePath === adapter.configFile)?.sha256 ?? sha2562(input.providerConfig.content),
10913
+ selectedPayloadSha256: sha2563(input.providerConfig.content),
10914
+ renderedPayloadSha256: files.find((file) => file.relativePath === adapter.configFile)?.sha256 ?? sha2563(input.providerConfig.content),
10779
10915
  selected: !existsSync5(joinTarget(targetHome, adapter.configFile))
10780
10916
  }
10781
10917
  } : {},
@@ -10819,15 +10955,16 @@ function sourceFromFilePath(path, content, order = 0) {
10819
10955
  }
10820
10956
  function sourceFromConfig(config, order = 0, layer) {
10821
10957
  const isAgentOperatingRules = config.slug === GLOBAL_AGENT_RULES_STANDARD_SLUG;
10958
+ const rules = isAgentOperatingRules ? resolveAgentOperatingRulesPayload(config.content) : null;
10822
10959
  return {
10823
10960
  id: config.slug,
10824
10961
  label: config.name,
10825
- content: isAgentOperatingRules ? GLOBAL_AGENT_RULES_STANDARD_CONTENT : config.content,
10962
+ content: rules ? rules.content : config.content,
10826
10963
  layer: layer ?? (config.agent === "global" ? "global" : "agent"),
10827
10964
  order,
10828
10965
  path: config.target_path ?? undefined,
10829
- provenance: isAgentOperatingRules ? {
10830
- ...AGENT_OPERATING_RULES_PROVENANCE,
10966
+ provenance: rules ? {
10967
+ ...rules.provenance,
10831
10968
  configSlug: config.slug,
10832
10969
  configAgent: config.agent
10833
10970
  } : {
@@ -10835,7 +10972,7 @@ function sourceFromConfig(config, order = 0, layer) {
10835
10972
  configSlug: config.slug,
10836
10973
  configAgent: config.agent
10837
10974
  },
10838
- metadata: isAgentOperatingRules ? { ...AGENT_OPERATING_RULES_METADATA } : null,
10975
+ metadata: rules ? { ...rules.metadata } : null,
10839
10976
  nonOverridable: isAgentOperatingRules
10840
10977
  };
10841
10978
  }
@@ -11121,7 +11258,7 @@ function asStringArray(value) {
11121
11258
  return [];
11122
11259
  return value.filter((item) => typeof item === "string");
11123
11260
  }
11124
- var RAW_STORE_ROOT_ENV = "HASNA_CONFIGS_HOME", ANTIGRAVITY_RULE_FILE_CHAR_LIMIT = 12000, SESSION_RENDERER_OWNER_ID = "instructions-session-renderer", SESSION_RENDER_TOOLS, SESSION_RENDER_PROFILE_ENTRYPOINTS, SESSION_RENDER_OWNED_CONFIG_TARGETS, CODEWITH_FLATTENED_ADAPTER, CODEWITH_NATIVE_ADAPTER, SESSION_TOOL_ADAPTERS, SESSION_LAYER_RANK;
11261
+ var RAW_STORE_ROOT_ENV = "HASNA_CONFIGS_HOME", ANTIGRAVITY_RULE_FILE_CHAR_LIMIT = 12000, SESSION_RENDERER_OWNER_ID = "instructions-session-renderer", SESSION_RENDER_TOOLS, SESSION_RENDER_PROFILE_ENTRYPOINTS, SESSION_RENDER_OWNED_CONFIG_TARGETS, CODEWITH_FLATTENED_ADAPTER, CODEWITH_NATIVE_ADAPTER, SESSION_TOOL_ADAPTERS, SESSION_RENDER_MANAGED_DIRS, SESSION_RENDER_SHARED_MANAGED_DIRS, SESSION_RENDER_EXCLUSIVE_MANAGED_PATHS, SESSION_LAYER_RANK;
11125
11262
  var init_session_render = __esm(() => {
11126
11263
  init_global_agent_rules_standard();
11127
11264
  init_project_context();
@@ -11154,7 +11291,7 @@ var init_session_render = __esm(() => {
11154
11291
  tool: "codewith",
11155
11292
  mode: "flattened-markdown",
11156
11293
  indexFile: "CODEWITH.md",
11157
- managedDir: ".hasna/instructions",
11294
+ managedDir: SESSION_RENDER_INSTRUCTIONS_MANAGED_DIR,
11158
11295
  envVar: "CODEWITH_HOME",
11159
11296
  nativeImports: false,
11160
11297
  description: "Codewith CODEWITH.md flattened until native @ imports are implemented in Codewith."
@@ -11163,7 +11300,7 @@ var init_session_render = __esm(() => {
11163
11300
  tool: "codewith",
11164
11301
  mode: "native-imports",
11165
11302
  indexFile: "CODEWITH.md",
11166
- managedDir: ".hasna/instructions",
11303
+ managedDir: SESSION_RENDER_INSTRUCTIONS_MANAGED_DIR,
11167
11304
  envVar: "CODEWITH_HOME",
11168
11305
  nativeImports: true,
11169
11306
  description: "Codewith CODEWITH.md with gated @ imports into managed fragments."
@@ -11173,7 +11310,7 @@ var init_session_render = __esm(() => {
11173
11310
  tool: "claude",
11174
11311
  mode: "native-imports",
11175
11312
  indexFile: "CLAUDE.md",
11176
- managedDir: ".hasna/instructions",
11313
+ managedDir: SESSION_RENDER_INSTRUCTIONS_MANAGED_DIR,
11177
11314
  envVar: "CLAUDE_CONFIG_DIR",
11178
11315
  nativeImports: true,
11179
11316
  description: "Claude Code CLAUDE.md with @ imports into managed fragments."
@@ -11182,7 +11319,7 @@ var init_session_render = __esm(() => {
11182
11319
  tool: "codex",
11183
11320
  mode: "flattened-markdown",
11184
11321
  indexFile: "AGENTS.md",
11185
- managedDir: ".hasna/instructions",
11322
+ managedDir: SESSION_RENDER_INSTRUCTIONS_MANAGED_DIR,
11186
11323
  envVar: "CODEX_HOME",
11187
11324
  nativeImports: false,
11188
11325
  description: "Codex AGENTS.md flattened instruction file."
@@ -11199,7 +11336,7 @@ var init_session_render = __esm(() => {
11199
11336
  mode: "opencode-instructions",
11200
11337
  indexFile: "AGENTS.md",
11201
11338
  configFile: "opencode.json",
11202
- managedDir: ".hasna/instructions",
11339
+ managedDir: SESSION_RENDER_INSTRUCTIONS_MANAGED_DIR,
11203
11340
  envVar: "OPENCODE_CONFIG_DIR",
11204
11341
  nativeImports: false,
11205
11342
  description: "OpenCode AGENTS.md plus opencode.json instructions pointing at managed fragments."
@@ -11208,7 +11345,7 @@ var init_session_render = __esm(() => {
11208
11345
  tool: "aicopilot",
11209
11346
  mode: "flattened-markdown",
11210
11347
  indexFile: "AICOPILOT.md",
11211
- managedDir: ".hasna/instructions",
11348
+ managedDir: SESSION_RENDER_INSTRUCTIONS_MANAGED_DIR,
11212
11349
  envVar: "AICOPILOT_CONFIG_DIR",
11213
11350
  nativeImports: false,
11214
11351
  description: "AI Copilot AICOPILOT.md flattened instruction file."
@@ -11231,6 +11368,19 @@ var init_session_render = __esm(() => {
11231
11368
  },
11232
11369
  codewith: CODEWITH_FLATTENED_ADAPTER
11233
11370
  };
11371
+ SESSION_RENDER_MANAGED_DIRS = [
11372
+ ...new Set([
11373
+ CODEWITH_FLATTENED_ADAPTER,
11374
+ CODEWITH_NATIVE_ADAPTER,
11375
+ ...Object.values(SESSION_TOOL_ADAPTERS)
11376
+ ].map((adapter) => adapter.managedDir))
11377
+ ];
11378
+ SESSION_RENDER_SHARED_MANAGED_DIRS = [".cursor/rules"];
11379
+ SESSION_RENDER_EXCLUSIVE_MANAGED_PATHS = [
11380
+ ...SESSION_RENDER_MANAGED_DIRS.filter((dir) => !SESSION_RENDER_SHARED_MANAGED_DIRS.includes(dir)),
11381
+ SESSION_RENDER_MANIFEST_RELATIVE_PATH,
11382
+ SESSION_RENDER_SNAPSHOT_RELATIVE_DIR
11383
+ ];
11234
11384
  SESSION_LAYER_RANK = {
11235
11385
  global: 10,
11236
11386
  tool: 20,
@@ -11246,6 +11396,80 @@ var init_session_render = __esm(() => {
11246
11396
  };
11247
11397
  });
11248
11398
 
11399
+ // src/lib/session-render-ownership.ts
11400
+ import { existsSync as existsSync6, readFileSync as readFileSync3, statSync as statSync3 } from "fs";
11401
+ import { dirname as dirname3, join as join6, parse as parse3, relative as relative3, sep } from "path";
11402
+ function toSegments(absolutePath2) {
11403
+ return absolutePath2.replaceAll("\\", "/").split("/").filter(Boolean);
11404
+ }
11405
+ function pathIsSessionRenderManagedDir(absolutePath2) {
11406
+ const segments = toSegments(absolutePath2);
11407
+ return MANAGED_PATH_SEGMENTS.some((managed) => {
11408
+ if (managed.length === 0 || managed.length > segments.length)
11409
+ return false;
11410
+ for (let start = 0;start + managed.length <= segments.length; start += 1) {
11411
+ if (managed.every((segment, offset) => segments[start + offset] === segment))
11412
+ return true;
11413
+ }
11414
+ return false;
11415
+ });
11416
+ }
11417
+ function readManifestRelativePaths(manifestPath) {
11418
+ let stats;
11419
+ try {
11420
+ if (!existsSync6(manifestPath))
11421
+ return null;
11422
+ stats = statSync3(manifestPath);
11423
+ } catch {
11424
+ return null;
11425
+ }
11426
+ const cached = manifestCache.get(manifestPath);
11427
+ if (cached && cached.mtimeMs === stats.mtimeMs && cached.size === stats.size) {
11428
+ return cached.relativePaths;
11429
+ }
11430
+ let manifest;
11431
+ try {
11432
+ manifest = JSON.parse(readFileSync3(manifestPath, "utf-8"));
11433
+ } catch {
11434
+ return null;
11435
+ }
11436
+ if (manifest?.schema !== SESSION_RENDER_SCHEMA || !Array.isArray(manifest.files))
11437
+ return null;
11438
+ const writerId = manifest.targetOwner?.writer?.id;
11439
+ if (writerId !== undefined && writerId !== SESSION_RENDERER_OWNER_ID)
11440
+ return null;
11441
+ const relativePaths = new Set(manifest.files.map((file) => file?.relativePath).filter((relativePath) => typeof relativePath === "string").map((relativePath) => relativePath.replaceAll("\\", "/")));
11442
+ manifestCache.set(manifestPath, { mtimeMs: stats.mtimeMs, size: stats.size, relativePaths });
11443
+ return relativePaths;
11444
+ }
11445
+ function sessionRenderManifestClaimsPath(absolutePath2) {
11446
+ const root = parse3(absolutePath2).root;
11447
+ let home = dirname3(absolutePath2);
11448
+ for (let depth = 0;depth < MANIFEST_ANCESTOR_LIMIT; depth += 1) {
11449
+ const manifestPath = join6(home, ...SESSION_RENDER_MANIFEST_RELATIVE_PATH.split("/"));
11450
+ const relativePaths = readManifestRelativePaths(manifestPath);
11451
+ if (relativePaths) {
11452
+ const claimed = relative3(home, absolutePath2).split(sep).join("/");
11453
+ if (relativePaths.has(claimed))
11454
+ return true;
11455
+ }
11456
+ const parent = dirname3(home);
11457
+ if (parent === home || home === root)
11458
+ break;
11459
+ home = parent;
11460
+ }
11461
+ return false;
11462
+ }
11463
+ function sessionRenderOwnsPath(absolutePath2) {
11464
+ return pathIsSessionRenderManagedDir(absolutePath2) || sessionRenderManifestClaimsPath(absolutePath2);
11465
+ }
11466
+ var MANIFEST_ANCESTOR_LIMIT = 24, MANAGED_PATH_SEGMENTS, manifestCache;
11467
+ var init_session_render_ownership = __esm(() => {
11468
+ init_session_render();
11469
+ MANAGED_PATH_SEGMENTS = SESSION_RENDER_EXCLUSIVE_MANAGED_PATHS.map((managedPath) => managedPath.split("/").filter(Boolean));
11470
+ manifestCache = new Map;
11471
+ });
11472
+
11249
11473
  // src/lib/apply.ts
11250
11474
  var exports_apply = {};
11251
11475
  __export(exports_apply, {
@@ -11257,8 +11481,8 @@ __export(exports_apply, {
11257
11481
  applyConfigs: () => applyConfigs,
11258
11482
  applyConfig: () => applyConfig
11259
11483
  });
11260
- import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync3, realpathSync as realpathSync2, writeFileSync as writeFileSync2 } from "fs";
11261
- import { basename as basename4, dirname as dirname3, join as join6, resolve as resolve3 } from "path";
11484
+ import { existsSync as existsSync7, mkdirSync as mkdirSync3, readFileSync as readFileSync4, realpathSync as realpathSync2, writeFileSync as writeFileSync2 } from "fs";
11485
+ import { basename as basename4, dirname as dirname4, join as join7, resolve as resolve3 } from "path";
11262
11486
  import { homedir as homedir4 } from "os";
11263
11487
  function getConfigHome() {
11264
11488
  return process.env["CONFIGS_HOME"] || process.env["HOME"] || homedir4();
@@ -11277,14 +11501,14 @@ function normalizeTargetPath(p) {
11277
11501
  let current = expanded;
11278
11502
  const missingSegments = [];
11279
11503
  while (true) {
11280
- if (existsSync6(current)) {
11504
+ if (existsSync7(current)) {
11281
11505
  try {
11282
11506
  return resolve3(realpathSync2(current), ...missingSegments);
11283
11507
  } catch {
11284
11508
  return expanded;
11285
11509
  }
11286
11510
  }
11287
- const parent = dirname3(current);
11511
+ const parent = dirname4(current);
11288
11512
  const name = basename4(current);
11289
11513
  if (parent === current)
11290
11514
  return expanded;
@@ -11306,11 +11530,11 @@ async function writeConfigResult(config, targetPath, content, opts, meta = {}) {
11306
11530
  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.`);
11307
11531
  }
11308
11532
  const path = expandPath(renderedTargetPath);
11309
- const previousContent = existsSync6(path) ? readFileSync3(path, "utf-8") : null;
11533
+ const previousContent = existsSync7(path) ? readFileSync4(path, "utf-8") : null;
11310
11534
  const changed = previousContent !== renderedContent;
11311
11535
  if (!opts.dryRun) {
11312
- const dir = dirname3(path);
11313
- if (!existsSync6(dir)) {
11536
+ const dir = dirname4(path);
11537
+ if (!existsSync7(dir)) {
11314
11538
  mkdirSync3(dir, { recursive: true });
11315
11539
  }
11316
11540
  if (previousContent !== null && changed) {
@@ -11613,13 +11837,15 @@ function sessionRendererOwnsTarget(targetPath, opts) {
11613
11837
  return sessionRendererOwnsCanonicalTarget(canonicalApplyTargetPath(targetPath, opts), opts);
11614
11838
  }
11615
11839
  function sessionRendererOwnsCanonicalTarget(normalized, opts) {
11840
+ if (opts.allowSessionRendererOwned)
11841
+ return false;
11616
11842
  const homes = new Set([
11617
11843
  getConfigHome(),
11618
11844
  opts.vars?.["HOME_DIR"]
11619
11845
  ].filter((home) => typeof home === "string" && home.length > 0));
11620
- if ([...homes].some((home) => SESSION_RENDER_OWNED_CONFIG_TARGETS.some((relativePath) => normalized === normalizeTargetPath(join6(home, ...relativePath.split("/"))))))
11846
+ if ([...homes].some((home) => SESSION_RENDER_OWNED_CONFIG_TARGETS.some((relativePath) => normalized === normalizeTargetPath(join7(home, ...relativePath.split("/"))))))
11621
11847
  return true;
11622
- return normalized.replaceAll("\\", "/").includes("/.agents/rules/");
11848
+ return sessionRenderOwnsPath(normalized);
11623
11849
  }
11624
11850
  var init_apply = __esm(() => {
11625
11851
  init_types();
@@ -11627,12 +11853,13 @@ var init_apply = __esm(() => {
11627
11853
  init_config_agents();
11628
11854
  init_machine();
11629
11855
  init_session_render();
11856
+ init_session_render_ownership();
11630
11857
  init_transforms();
11631
11858
  });
11632
11859
 
11633
11860
  // src/lib/sync-dir.ts
11634
- import { existsSync as existsSync7, readdirSync, readFileSync as readFileSync4, statSync as statSync3 } from "fs";
11635
- import { join as join7, relative as relative3 } from "path";
11861
+ import { existsSync as existsSync8, readdirSync, readFileSync as readFileSync5, statSync as statSync4 } from "fs";
11862
+ import { join as join8, relative as relative4 } from "path";
11636
11863
  import { homedir as homedir5 } from "os";
11637
11864
  function shouldSkip(p) {
11638
11865
  return SKIP.some((s) => p.includes(s));
@@ -11640,9 +11867,9 @@ function shouldSkip(p) {
11640
11867
  async function syncFromDir(dir, opts = {}) {
11641
11868
  const store = opts.store ?? resolveConfigStore();
11642
11869
  const absDir = expandPath(dir);
11643
- if (!existsSync7(absDir))
11870
+ if (!existsSync8(absDir))
11644
11871
  return { added: 0, updated: 0, unchanged: 0, skipped: [`Not found: ${absDir}`] };
11645
- const files = opts.recursive !== false ? walkDir(absDir) : readdirSync(absDir).map((f) => join7(absDir, f)).filter((f) => statSync3(f).isFile());
11872
+ const files = opts.recursive !== false ? walkDir(absDir) : readdirSync(absDir).map((f) => join8(absDir, f)).filter((f) => statSync4(f).isFile());
11646
11873
  const result = { added: 0, updated: 0, unchanged: 0, skipped: [] };
11647
11874
  const home = homedir5();
11648
11875
  const allConfigs = await store.listConfigs();
@@ -11652,7 +11879,7 @@ async function syncFromDir(dir, opts = {}) {
11652
11879
  continue;
11653
11880
  }
11654
11881
  try {
11655
- const content = readFileSync4(file, "utf-8");
11882
+ const content = readFileSync5(file, "utf-8");
11656
11883
  if (content.length > 500000) {
11657
11884
  result.skipped.push(file + " (too large)");
11658
11885
  continue;
@@ -11661,7 +11888,7 @@ async function syncFromDir(dir, opts = {}) {
11661
11888
  const existing = allConfigs.find((c) => c.target_path === targetPath);
11662
11889
  if (!existing) {
11663
11890
  if (!opts.dryRun)
11664
- await store.createConfig({ name: relative3(absDir, file), category: detectCategory(file), agent: detectAgent(file), target_path: targetPath, format: detectFormat(file), content });
11891
+ await store.createConfig({ name: relative4(absDir, file), category: detectCategory(file), agent: detectAgent(file), target_path: targetPath, format: detectFormat(file), content });
11665
11892
  result.added++;
11666
11893
  } else if (existing.content !== content) {
11667
11894
  if (!opts.dryRun)
@@ -11702,7 +11929,7 @@ async function syncToDir(dir, opts = {}) {
11702
11929
  }
11703
11930
  function walkDir(dir, files = []) {
11704
11931
  for (const entry of readdirSync(dir, { withFileTypes: true })) {
11705
- const full = join7(dir, entry.name);
11932
+ const full = join8(dir, entry.name);
11706
11933
  if (shouldSkip(full))
11707
11934
  continue;
11708
11935
  if (entry.isDirectory())
@@ -11736,8 +11963,8 @@ __export(exports_sync, {
11736
11963
  KNOWN_CONFIGS: () => KNOWN_CONFIGS,
11737
11964
  CLAUDE_PROMPT_OUTPUTS: () => CLAUDE_PROMPT_OUTPUTS
11738
11965
  });
11739
- import { existsSync as existsSync8, readdirSync as readdirSync2, readFileSync as readFileSync5 } from "fs";
11740
- import { basename as basename5, extname as extname3, join as join8 } from "path";
11966
+ import { existsSync as existsSync9, readdirSync as readdirSync2, readFileSync as readFileSync6 } from "fs";
11967
+ import { basename as basename5, extname as extname3, join as join9 } from "path";
11741
11968
  function claudeRuleOutputs(fileName) {
11742
11969
  const stem = basename5(fileName, extname3(fileName));
11743
11970
  return [
@@ -11769,7 +11996,7 @@ function isGeneratedOutputTarget2(config, owners) {
11769
11996
  return !!ownerIds && !ownerIds.has(config.id);
11770
11997
  }
11771
11998
  function hasClaudePromptSource() {
11772
- return existsSync8(expandPath("~/.claude/CLAUDE.md"));
11999
+ return existsSync9(expandPath("~/.claude/CLAUDE.md"));
11773
12000
  }
11774
12001
  function hasClaudeRuleSourceForCursorTarget(targetPath) {
11775
12002
  const absoluteTargetPath = expandPath(targetPath);
@@ -11777,7 +12004,7 @@ function hasClaudeRuleSourceForCursorTarget(targetPath) {
11777
12004
  if (!absoluteTargetPath.startsWith(`${absolutePrefix}/`) || !absoluteTargetPath.endsWith(".mdc"))
11778
12005
  return false;
11779
12006
  const stem = basename5(absoluteTargetPath, ".mdc");
11780
- return existsSync8(expandPath(`~/.claude/rules/${stem}.md`)) || existsSync8(expandPath(`~/.claude/rules/${stem}.mdc`));
12007
+ return existsSync9(expandPath(`~/.claude/rules/${stem}.md`)) || existsSync9(expandPath(`~/.claude/rules/${stem}.mdc`));
11781
12008
  }
11782
12009
  function isKnownGeneratedTargetPath(targetPath) {
11783
12010
  const normalizedTargetPath = normalizeTargetPath(targetPath);
@@ -11794,11 +12021,11 @@ async function syncProject(opts) {
11794
12021
  const allConfigs = await store.listConfigs();
11795
12022
  const machine = detectMachineContext();
11796
12023
  for (const pf of PROJECT_CONFIG_FILES) {
11797
- const abs = join8(absDir, pf.file);
11798
- if (!existsSync8(abs))
12024
+ const abs = join9(absDir, pf.file);
12025
+ if (!existsSync9(abs))
11799
12026
  continue;
11800
12027
  try {
11801
- const rawContent = readFileSync5(abs, "utf-8");
12028
+ const rawContent = readFileSync6(abs, "utf-8");
11802
12029
  if (rawContent.length > 500000) {
11803
12030
  result.skipped.push(pf.file);
11804
12031
  continue;
@@ -11827,15 +12054,15 @@ async function syncProject(opts) {
11827
12054
  }
11828
12055
  }
11829
12056
  for (const ruleDir of [
11830
- { dir: join8(absDir, ".claude", "rules"), agent: "claude", namePrefix: "rules" },
11831
- { dir: join8(absDir, ".agents", "rules"), agent: "antigravity", namePrefix: "antigravity-rules" }
12057
+ { dir: join9(absDir, ".claude", "rules"), agent: "claude", namePrefix: "rules" },
12058
+ { dir: join9(absDir, ".agents", "rules"), agent: "antigravity", namePrefix: "antigravity-rules" }
11832
12059
  ]) {
11833
- if (!existsSync8(ruleDir.dir))
12060
+ if (!existsSync9(ruleDir.dir))
11834
12061
  continue;
11835
12062
  const mdFiles = readdirSync2(ruleDir.dir).filter((f) => f.endsWith(".md") || f.endsWith(".mdc"));
11836
12063
  for (const f of mdFiles) {
11837
- const abs = join8(ruleDir.dir, f);
11838
- const raw = readFileSync5(abs, "utf-8");
12064
+ const abs = join9(ruleDir.dir, f);
12065
+ const raw = readFileSync6(abs, "utf-8");
11839
12066
  const redacted = redactContent(raw, "markdown");
11840
12067
  const machineAware = templateizeMachineContent(redacted.content, machine);
11841
12068
  const content = machineAware.content;
@@ -11874,20 +12101,20 @@ async function syncKnown(opts = {}) {
11874
12101
  for (const known of targets) {
11875
12102
  if (known.rulesDir) {
11876
12103
  const absDir = expandPath(known.rulesDir);
11877
- if (!existsSync8(absDir)) {
12104
+ if (!existsSync9(absDir)) {
11878
12105
  result.skipped.push(known.rulesDir);
11879
12106
  continue;
11880
12107
  }
11881
12108
  const extensions = known.rulesExtensions ?? [".md", ".mdc"];
11882
12109
  const ruleFiles = readdirSync2(absDir).filter((f) => extensions.some((ext) => f.endsWith(ext)));
11883
12110
  for (const f of ruleFiles) {
11884
- const abs2 = join8(absDir, f);
12111
+ const abs2 = join9(absDir, f);
11885
12112
  const targetPath = abs2.replace(home, "~");
11886
12113
  if (existingOutputOwners.has(normalizeTargetPath(targetPath)) || isKnownGeneratedTargetPath(targetPath)) {
11887
12114
  result.skipped.push(`${targetPath} (generated output)`);
11888
12115
  continue;
11889
12116
  }
11890
- const raw = readFileSync5(abs2, "utf-8");
12117
+ const raw = readFileSync6(abs2, "utf-8");
11891
12118
  const redacted = redactContent(raw, "markdown");
11892
12119
  const machineAware = templateizeMachineContent(redacted.content, machine);
11893
12120
  const content = machineAware.content;
@@ -11915,12 +12142,12 @@ async function syncKnown(opts = {}) {
11915
12142
  continue;
11916
12143
  }
11917
12144
  const abs = expandPath(known.path);
11918
- if (!existsSync8(abs)) {
12145
+ if (!existsSync9(abs)) {
11919
12146
  result.skipped.push(known.path);
11920
12147
  continue;
11921
12148
  }
11922
12149
  try {
11923
- const rawContent = readFileSync5(abs, "utf-8");
12150
+ const rawContent = readFileSync6(abs, "utf-8");
11924
12151
  if (rawContent.length > 500000) {
11925
12152
  result.skipped.push(known.path + " (too large)");
11926
12153
  continue;
@@ -12008,9 +12235,9 @@ async function syncToDisk(opts = {}) {
12008
12235
  }
12009
12236
  function buildDiff(expectedContent, targetPath) {
12010
12237
  const path = expandPath(targetPath);
12011
- if (!existsSync8(path))
12238
+ if (!existsSync9(path))
12012
12239
  return `(file not found on disk: ${path})`;
12013
- const diskContent = readFileSync5(path, "utf-8");
12240
+ const diskContent = readFileSync6(path, "utf-8");
12014
12241
  if (diskContent === expectedContent)
12015
12242
  return "(no diff \u2014 identical)";
12016
12243
  const stored = expectedContent.split(`
@@ -12195,16 +12422,16 @@ __export(exports_package_manager_guard, {
12195
12422
  scanPackageManagerSecrets: () => scanPackageManagerSecrets
12196
12423
  });
12197
12424
  import { execFileSync as execFileSync2 } from "child_process";
12198
- import { existsSync as existsSync14, lstatSync as lstatSync3, readdirSync as readdirSync4, readFileSync as readFileSync10 } from "fs";
12425
+ import { existsSync as existsSync15, lstatSync as lstatSync3, readdirSync as readdirSync4, readFileSync as readFileSync11 } from "fs";
12199
12426
  import { homedir as homedir6 } from "os";
12200
- import { basename as basename6, dirname as dirname6, isAbsolute as isAbsolute4, join as join13, relative as relative5, resolve as resolve7 } from "path";
12427
+ import { basename as basename6, dirname as dirname7, isAbsolute as isAbsolute4, join as join14, relative as relative6, resolve as resolve7 } from "path";
12201
12428
  function scanPackageManagerSecrets(options = {}) {
12202
12429
  const cwd = options.cwd ? resolve7(options.cwd) : process.cwd();
12203
12430
  const roots = (options.roots && options.roots.length > 0 ? options.roots : [cwd]).map((root) => resolve7(cwd, root));
12204
12431
  const findings = [];
12205
12432
  let scannedFiles = 0;
12206
12433
  for (const root of roots) {
12207
- if (!existsSync14(root))
12434
+ if (!existsSync15(root))
12208
12435
  continue;
12209
12436
  const stat = lstatSync3(root);
12210
12437
  if (stat.isFile()) {
@@ -12214,14 +12441,14 @@ function scanPackageManagerSecrets(options = {}) {
12214
12441
  if (text === null)
12215
12442
  continue;
12216
12443
  scannedFiles++;
12217
- findings.push(...scanFile(root, text, classifyRepoFile(root), isTrackedFile(root), dirname6(root)));
12444
+ findings.push(...scanFile(root, text, classifyRepoFile(root), isTrackedFile(root), dirname7(root)));
12218
12445
  continue;
12219
12446
  }
12220
12447
  if (!stat.isDirectory())
12221
12448
  continue;
12222
12449
  const tracked = trackedFiles(root);
12223
12450
  for (const file of collectRepoFiles(root)) {
12224
- const rel = toPosix(relative5(root, file));
12451
+ const rel = toPosix(relative6(root, file));
12225
12452
  const isTracked = tracked.has(rel);
12226
12453
  const text = readTextFile(file);
12227
12454
  if (text === null)
@@ -12233,8 +12460,8 @@ function scanPackageManagerSecrets(options = {}) {
12233
12460
  if (options.includeHome) {
12234
12461
  const home = homedir6();
12235
12462
  for (const name of HOME_FILES) {
12236
- const file = join13(home, name);
12237
- if (!existsSync14(file))
12463
+ const file = join14(home, name);
12464
+ if (!existsSync15(file))
12238
12465
  continue;
12239
12466
  const text = readTextFile(file);
12240
12467
  if (text === null)
@@ -12258,12 +12485,12 @@ function collectRepoFiles(root) {
12258
12485
  if (entry.isDirectory()) {
12259
12486
  if (SKIP_DIRS.has(entry.name))
12260
12487
  continue;
12261
- visit(join13(dir, entry.name));
12488
+ visit(join14(dir, entry.name));
12262
12489
  continue;
12263
12490
  }
12264
12491
  if (!entry.isFile())
12265
12492
  continue;
12266
- const file = join13(dir, entry.name);
12493
+ const file = join14(dir, entry.name);
12267
12494
  if (shouldScanRepoFile(file))
12268
12495
  out.push(file);
12269
12496
  }
@@ -12301,7 +12528,7 @@ function readTextFile(file) {
12301
12528
  const stat = lstatSync3(file);
12302
12529
  if (!stat.isFile() || stat.size > 5000000)
12303
12530
  return null;
12304
- const buf = readFileSync10(file);
12531
+ const buf = readFileSync11(file);
12305
12532
  if (buf.includes(0))
12306
12533
  return null;
12307
12534
  return buf.toString("utf-8");
@@ -12501,11 +12728,11 @@ function trackedFiles(root) {
12501
12728
  }
12502
12729
  function isTrackedFile(file) {
12503
12730
  try {
12504
- const repoRoot = execFileSync2("git", ["-C", dirname6(file), "rev-parse", "--show-toplevel"], {
12731
+ const repoRoot = execFileSync2("git", ["-C", dirname7(file), "rev-parse", "--show-toplevel"], {
12505
12732
  encoding: "utf-8",
12506
12733
  stdio: ["ignore", "pipe", "ignore"]
12507
12734
  }).trim();
12508
- const rel = toPosix(relative5(repoRoot, file));
12735
+ const rel = toPosix(relative6(repoRoot, file));
12509
12736
  execFileSync2("git", ["-C", repoRoot, "ls-files", "--error-unmatch", "--", rel], {
12510
12737
  stdio: ["ignore", "ignore", "ignore"]
12511
12738
  });
@@ -12533,11 +12760,11 @@ function stripInlineComment(value) {
12533
12760
  function displayPath(file, root) {
12534
12761
  const home = homedir6();
12535
12762
  if (root === home && (file === home || file.startsWith(home + "/")))
12536
- return "~/" + toPosix(relative5(home, file));
12763
+ return "~/" + toPosix(relative6(home, file));
12537
12764
  if (isAbsolute4(root) && file.startsWith(root + "/"))
12538
- return toPosix(relative5(root, file));
12765
+ return toPosix(relative6(root, file));
12539
12766
  if (file === home || file.startsWith(home + "/"))
12540
- return "~/" + toPosix(relative5(home, file));
12767
+ return "~/" + toPosix(relative6(home, file));
12541
12768
  return file;
12542
12769
  }
12543
12770
  function toPosix(path) {
@@ -13286,21 +13513,21 @@ init_apply();
13286
13513
  init_sync();
13287
13514
  init_redact();
13288
13515
  import chalk from "chalk";
13289
- import { existsSync as existsSync15, lstatSync as lstatSync4, readFileSync as readFileSync11, readSync, writeSync } from "fs";
13516
+ import { existsSync as existsSync16, lstatSync as lstatSync4, readFileSync as readFileSync12, readSync, writeSync } from "fs";
13290
13517
  import { homedir as homedir7 } from "os";
13291
- import { basename as basename7, join as join14, resolve as resolve8 } from "path";
13518
+ import { basename as basename7, join as join15, resolve as resolve8 } from "path";
13292
13519
 
13293
13520
  // src/lib/export.ts
13294
13521
  init_config_store();
13295
- import { existsSync as existsSync9, mkdirSync as mkdirSync4, rmSync as rmSync3, writeFileSync as writeFileSync3 } from "fs";
13296
- import { join as join9, resolve as resolve4 } from "path";
13522
+ import { existsSync as existsSync10, mkdirSync as mkdirSync4, rmSync as rmSync3, writeFileSync as writeFileSync3 } from "fs";
13523
+ import { join as join10, resolve as resolve4 } from "path";
13297
13524
  import { tmpdir } from "os";
13298
13525
  async function exportConfigs(outputPath, opts = {}) {
13299
13526
  const store = opts.store ?? resolveConfigStore();
13300
13527
  const configs = await store.listConfigs(opts.filter);
13301
13528
  const absOutput = resolve4(outputPath);
13302
- const tmpDir = join9(tmpdir(), `configs-export-${Date.now()}`);
13303
- const contentsDir = join9(tmpDir, "contents");
13529
+ const tmpDir = join10(tmpdir(), `configs-export-${Date.now()}`);
13530
+ const contentsDir = join10(tmpDir, "contents");
13304
13531
  try {
13305
13532
  mkdirSync4(contentsDir, { recursive: true });
13306
13533
  const manifest = {
@@ -13308,10 +13535,10 @@ async function exportConfigs(outputPath, opts = {}) {
13308
13535
  exported_at: new Date().toISOString(),
13309
13536
  configs: configs.map(({ content: _content, ...meta }) => meta)
13310
13537
  };
13311
- writeFileSync3(join9(tmpDir, "manifest.json"), JSON.stringify(manifest, null, 2), "utf-8");
13538
+ writeFileSync3(join10(tmpDir, "manifest.json"), JSON.stringify(manifest, null, 2), "utf-8");
13312
13539
  for (const config of configs) {
13313
13540
  const fileName = `${config.slug}.${config.format === "text" ? "txt" : config.format}`;
13314
- writeFileSync3(join9(contentsDir, fileName), config.content, "utf-8");
13541
+ writeFileSync3(join10(contentsDir, fileName), config.content, "utf-8");
13315
13542
  }
13316
13543
  const proc = Bun.spawn(["tar", "czf", absOutput, "-C", tmpDir, "."], {
13317
13544
  stdout: "pipe",
@@ -13324,7 +13551,7 @@ async function exportConfigs(outputPath, opts = {}) {
13324
13551
  }
13325
13552
  return { path: absOutput, count: configs.length };
13326
13553
  } finally {
13327
- if (existsSync9(tmpDir)) {
13554
+ if (existsSync10(tmpDir)) {
13328
13555
  rmSync3(tmpDir, { recursive: true, force: true });
13329
13556
  }
13330
13557
  }
@@ -13332,14 +13559,14 @@ async function exportConfigs(outputPath, opts = {}) {
13332
13559
 
13333
13560
  // src/lib/import.ts
13334
13561
  init_config_store();
13335
- import { existsSync as existsSync10, mkdirSync as mkdirSync5, readFileSync as readFileSync6, rmSync as rmSync4 } from "fs";
13336
- import { join as join10, resolve as resolve5 } from "path";
13562
+ import { existsSync as existsSync11, mkdirSync as mkdirSync5, readFileSync as readFileSync7, rmSync as rmSync4 } from "fs";
13563
+ import { join as join11, resolve as resolve5 } from "path";
13337
13564
  import { tmpdir as tmpdir2 } from "os";
13338
13565
  async function importConfigs(bundlePath, opts = {}) {
13339
13566
  const store = opts.store ?? resolveConfigStore();
13340
13567
  const conflict = opts.conflict ?? "skip";
13341
13568
  const absPath = resolve5(bundlePath);
13342
- const tmpDir = join10(tmpdir2(), `configs-import-${Date.now()}`);
13569
+ const tmpDir = join11(tmpdir2(), `configs-import-${Date.now()}`);
13343
13570
  const result = { created: 0, updated: 0, skipped: 0, errors: [] };
13344
13571
  try {
13345
13572
  mkdirSync5(tmpDir, { recursive: true });
@@ -13352,15 +13579,15 @@ async function importConfigs(bundlePath, opts = {}) {
13352
13579
  const stderr = await new Response(proc.stderr).text();
13353
13580
  throw new Error(`tar extraction failed: ${stderr}`);
13354
13581
  }
13355
- const manifestPath = join10(tmpDir, "manifest.json");
13356
- if (!existsSync10(manifestPath))
13582
+ const manifestPath = join11(tmpDir, "manifest.json");
13583
+ if (!existsSync11(manifestPath))
13357
13584
  throw new Error("Invalid bundle: missing manifest.json");
13358
- const manifest = JSON.parse(readFileSync6(manifestPath, "utf-8"));
13585
+ const manifest = JSON.parse(readFileSync7(manifestPath, "utf-8"));
13359
13586
  for (const meta of manifest.configs) {
13360
13587
  try {
13361
13588
  const ext = meta.format === "text" ? "txt" : meta.format;
13362
- const contentFile = join10(tmpDir, "contents", `${meta.slug}.${ext}`);
13363
- const content = existsSync10(contentFile) ? readFileSync6(contentFile, "utf-8") : "";
13589
+ const contentFile = join11(tmpDir, "contents", `${meta.slug}.${ext}`);
13590
+ const content = existsSync11(contentFile) ? readFileSync7(contentFile, "utf-8") : "";
13364
13591
  let existing = null;
13365
13592
  try {
13366
13593
  existing = await store.getConfig(meta.slug);
@@ -13394,7 +13621,7 @@ async function importConfigs(bundlePath, opts = {}) {
13394
13621
  }
13395
13622
  return result;
13396
13623
  } finally {
13397
- if (existsSync10(tmpDir)) {
13624
+ if (existsSync11(tmpDir)) {
13398
13625
  rmSync4(tmpDir, { recursive: true, force: true });
13399
13626
  }
13400
13627
  }
@@ -13407,16 +13634,16 @@ init_machine();
13407
13634
  // src/lib/session-apply.ts
13408
13635
  init_project_context();
13409
13636
  init_session_render();
13410
- import { createHash as createHash3, randomUUID as randomUUID7 } from "crypto";
13637
+ import { createHash as createHash4, randomUUID as randomUUID7 } from "crypto";
13411
13638
  import {
13412
- existsSync as existsSync11,
13639
+ existsSync as existsSync12,
13413
13640
  lstatSync as lstatSync2,
13414
13641
  mkdirSync as mkdirSync6,
13415
- readFileSync as readFileSync7,
13642
+ readFileSync as readFileSync8,
13416
13643
  readdirSync as readdirSync3,
13417
- statSync as statSync4
13644
+ statSync as statSync5
13418
13645
  } from "fs";
13419
- import { dirname as dirname4, isAbsolute as isAbsolute3, join as join11, parse as parse3, relative as relative4, resolve as resolve6 } from "path";
13646
+ import { dirname as dirname5, isAbsolute as isAbsolute3, join as join12, parse as parse4, relative as relative5, resolve as resolve6 } from "path";
13420
13647
 
13421
13648
  class SessionApplyError extends Error {
13422
13649
  constructor(message) {
@@ -13497,13 +13724,13 @@ function applySessionRenderUnlocked(plan, options, coordination) {
13497
13724
  };
13498
13725
  }
13499
13726
  function ensureSessionTargetHome(targetHome) {
13500
- if (!existsSync11(targetHome))
13727
+ if (!existsSync12(targetHome))
13501
13728
  mkdirSync6(targetHome, { recursive: true, mode: 448 });
13502
13729
  assertSafeTargetHome(targetHome);
13503
13730
  }
13504
13731
  function checkSessionRenderDrift(targetHome, manifestPath) {
13505
13732
  const safeTargetHome = assertSafeTargetHome(targetHome);
13506
- const resolvedManifestPath = manifestPath ? resolveManifestRelativePath(relative4(safeTargetHome, resolve6(manifestPath)), safeTargetHome) : resolve6(safeTargetHome, ".hasna", "session-render-manifest.json");
13733
+ const resolvedManifestPath = manifestPath ? resolveManifestRelativePath(relative5(safeTargetHome, resolve6(manifestPath)), safeTargetHome) : resolve6(safeTargetHome, ".hasna", "session-render-manifest.json");
13507
13734
  const checkedAt = new Date().toISOString();
13508
13735
  const previousManifest = readPreviousManifest(resolvedManifestPath);
13509
13736
  if (!previousManifest) {
@@ -13520,7 +13747,7 @@ function checkSessionRenderDrift(targetHome, manifestPath) {
13520
13747
  const drifted = [];
13521
13748
  for (const file of previousManifest.files) {
13522
13749
  const target = resolveManifestRelativePath(file.relativePath, safeTargetHome);
13523
- if (!existsSync11(target)) {
13750
+ if (!existsSync12(target)) {
13524
13751
  missing.push({
13525
13752
  path: target,
13526
13753
  relativePath: file.relativePath,
@@ -13530,7 +13757,7 @@ function checkSessionRenderDrift(targetHome, manifestPath) {
13530
13757
  });
13531
13758
  continue;
13532
13759
  }
13533
- const actualSha256 = sha2563(readFileSync7(target, "utf-8"));
13760
+ const actualSha256 = sha2564(readFileSync8(target, "utf-8"));
13534
13761
  if (actualSha256 !== file.sha256) {
13535
13762
  drifted.push({
13536
13763
  path: target,
@@ -13554,7 +13781,7 @@ function restoreSessionRenderSnapshot(snapshotPath, options = {}) {
13554
13781
  const snapshot = readSessionRenderSnapshot(snapshotPath);
13555
13782
  const targetHome = assertSafeTargetHome(snapshot.targetHome);
13556
13783
  const resolvedSnapshotPath = resolve6(snapshotPath);
13557
- const snapshotRelativePath = relative4(targetHome, resolvedSnapshotPath);
13784
+ const snapshotRelativePath = relative5(targetHome, resolvedSnapshotPath);
13558
13785
  if (snapshotRelativePath === "" || snapshotRelativePath === ".." || snapshotRelativePath.startsWith("../") || isAbsolute3(snapshotRelativePath)) {
13559
13786
  throw new SessionApplyError("Session snapshot must be stored inside its target home.");
13560
13787
  }
@@ -13672,18 +13899,18 @@ function requiredRestoreHash(file) {
13672
13899
  }
13673
13900
  function readSessionRenderSnapshot(snapshotPath) {
13674
13901
  const resolved = resolve6(snapshotPath);
13675
- if (!existsSync11(resolved))
13902
+ if (!existsSync12(resolved))
13676
13903
  throw new SessionApplyError(`Session snapshot not found: ${snapshotPath}`);
13677
13904
  const stat = lstatSync2(resolved);
13678
13905
  if (stat.isSymbolicLink() || !stat.isFile()) {
13679
13906
  throw new SessionApplyError(`Session snapshot is not a regular file: ${snapshotPath}`);
13680
13907
  }
13681
- if (statSync4(resolved).size > 32 * 1024 * 1024) {
13908
+ if (statSync5(resolved).size > 32 * 1024 * 1024) {
13682
13909
  throw new SessionApplyError(`Session snapshot exceeds the 32 MiB restore limit: ${snapshotPath}`);
13683
13910
  }
13684
13911
  let parsed;
13685
13912
  try {
13686
- parsed = JSON.parse(readFileSync7(resolved, "utf8"));
13913
+ parsed = JSON.parse(readFileSync8(resolved, "utf8"));
13687
13914
  } catch {
13688
13915
  throw new SessionApplyError(`Session snapshot is not valid JSON: ${snapshotPath}`);
13689
13916
  }
@@ -13705,7 +13932,7 @@ function readSessionRenderSnapshot(snapshotPath) {
13705
13932
  const previousManifest = snapshot.previousManifest;
13706
13933
  const previousFiles = new Map;
13707
13934
  for (const file of snapshot.files) {
13708
- if (!file || typeof file.relativePath !== "string" || typeof file.path !== "string" || typeof file.sha256 !== "string" || typeof file.content !== "string" || sha2563(file.content) !== file.sha256) {
13935
+ if (!file || typeof file.relativePath !== "string" || typeof file.path !== "string" || typeof file.sha256 !== "string" || typeof file.content !== "string" || sha2564(file.content) !== file.sha256) {
13709
13936
  throw new SessionApplyError(`Session snapshot previous file metadata is invalid: ${snapshotPath}`);
13710
13937
  }
13711
13938
  resolveSnapshotFilePath(file.relativePath, file.path, targetHome);
@@ -13753,7 +13980,7 @@ function readSessionRenderSnapshot(snapshotPath) {
13753
13980
  function reconstructPreRollbackLegacyV1Snapshot(snapshot, previousFiles, previousManifestFiles, targetHome, snapshotPath) {
13754
13981
  assertNoNewerSessionSnapshot(snapshotPath, snapshot.createdAt, targetHome);
13755
13982
  const manifestPath = resolve6(snapshot.manifestPath);
13756
- const manifestRelativePath = relative4(targetHome, manifestPath).replaceAll("\\", "/");
13983
+ const manifestRelativePath = relative5(targetHome, manifestPath).replaceAll("\\", "/");
13757
13984
  resolveSnapshotFilePath(manifestRelativePath, snapshot.manifestPath, targetHome);
13758
13985
  const manifestSha256 = currentSessionFileHash(manifestPath, targetHome);
13759
13986
  if (manifestSha256 === null) {
@@ -13761,7 +13988,7 @@ function reconstructPreRollbackLegacyV1Snapshot(snapshot, previousFiles, previou
13761
13988
  }
13762
13989
  let parsedManifest;
13763
13990
  try {
13764
- parsedManifest = JSON.parse(readFileSync7(manifestPath, "utf8"));
13991
+ parsedManifest = JSON.parse(readFileSync8(manifestPath, "utf8"));
13765
13992
  } catch {
13766
13993
  throw new SessionApplyError(`Pre-rollback legacy v1 applied manifest is not valid JSON: ${snapshotPath}`);
13767
13994
  }
@@ -13853,15 +14080,15 @@ function assertNoNewerSessionSnapshot(snapshotPath, createdAt, targetHome) {
13853
14080
  if (!Number.isFinite(createdAtMs)) {
13854
14081
  throw new SessionApplyError(`Pre-rollback legacy v1 snapshot has an invalid creation time: ${snapshotPath}`);
13855
14082
  }
13856
- for (const entry of readdirSync3(dirname4(snapshotPath))) {
13857
- const candidatePath = resolve6(dirname4(snapshotPath), entry);
14083
+ for (const entry of readdirSync3(dirname5(snapshotPath))) {
14084
+ const candidatePath = resolve6(dirname5(snapshotPath), entry);
13858
14085
  if (candidatePath === resolve6(snapshotPath) || !entry.endsWith(".json"))
13859
14086
  continue;
13860
14087
  const candidateStat = lstatSync2(candidatePath);
13861
14088
  if (candidateStat.isSymbolicLink() || !candidateStat.isFile() || candidateStat.size > 32 * 1024 * 1024)
13862
14089
  continue;
13863
14090
  try {
13864
- const candidate = JSON.parse(readFileSync7(candidatePath, "utf8"));
14091
+ const candidate = JSON.parse(readFileSync8(candidatePath, "utf8"));
13865
14092
  const candidateCreatedAtMs = typeof candidate.createdAt === "string" ? Date.parse(candidate.createdAt) : Number.NaN;
13866
14093
  if ((candidate.schema === "hasna.configs.session-render-snapshot/v1" || candidate.schema === "hasna.configs.session-render-snapshot/v2") && typeof candidate.targetHome === "string" && resolve6(candidate.targetHome) === targetHome && Number.isFinite(candidateCreatedAtMs) && candidateCreatedAtMs >= createdAtMs) {
13867
14094
  throw new SessionApplyError(`Cannot restore pre-rollback legacy v1 snapshot after a newer session snapshot exists: ${candidatePath}`);
@@ -13921,7 +14148,7 @@ function inferLegacySnapshotAction(file, previousFiles, previousManifestFiles, p
13921
14148
  return "create";
13922
14149
  }
13923
14150
  if (file.role === "manifest" && previousManifest) {
13924
- const previousManifestSha256 = sha2563(`${JSON.stringify(previousManifest, null, 2)}
14151
+ const previousManifestSha256 = sha2564(`${JSON.stringify(previousManifest, null, 2)}
13925
14152
  `);
13926
14153
  if (previousManifestSha256 !== file.sha256) {
13927
14154
  throw new SessionApplyError(`Cannot infer legacy v1 manifest action without a before-image: ${file.relativePath}`);
@@ -13939,8 +14166,8 @@ function resolveSnapshotFilePath(relativePath, recordedPath, targetHome) {
13939
14166
  }
13940
14167
  function planFileResult(plan, file, targetHome, previousHashes, previousManifest, options) {
13941
14168
  const target = resolvePlannedFilePath(plan, file, targetHome);
13942
- const previousContent = existsSync11(target) ? readFileSync7(target, "utf-8") : null;
13943
- const previousSha256 = previousContent === null ? null : sha2563(previousContent);
14169
+ const previousContent = existsSync12(target) ? readFileSync8(target, "utf-8") : null;
14170
+ const previousSha256 = previousContent === null ? null : sha2564(previousContent);
13944
14171
  const previouslyManaged = isPreviouslyManaged(file, previousSha256, previousHashes, previousManifest);
13945
14172
  const changed = previousContent !== file.content;
13946
14173
  if (previousContent !== null && !options.force && !previouslyManaged) {
@@ -14022,10 +14249,10 @@ function planStaleFileResults(plan, targetHome, previousManifest, currentRelativ
14022
14249
  }
14023
14250
  function planStaleFileResult(file, targetHome, options) {
14024
14251
  const target = resolveManifestRelativePath(file.relativePath, targetHome);
14025
- if (!existsSync11(target))
14252
+ if (!existsSync12(target))
14026
14253
  return null;
14027
- const previousContent = readFileSync7(target, "utf-8");
14028
- const previousSha256 = sha2563(previousContent);
14254
+ const previousContent = readFileSync8(target, "utf-8");
14255
+ const previousSha256 = sha2564(previousContent);
14029
14256
  if (!options.force && previousSha256 !== file.sha256) {
14030
14257
  return {
14031
14258
  path: target,
@@ -14070,7 +14297,7 @@ function isPreviouslyManaged(file, previousSha256, previousHashes, previousManif
14070
14297
  }
14071
14298
  function resolvePlannedFilePath(plan, file, targetHome) {
14072
14299
  const target = resolve6(targetHome, ...file.relativePath.split("/"));
14073
- const rel = relative4(targetHome, target);
14300
+ const rel = relative5(targetHome, target);
14074
14301
  if (rel === "" || rel === ".." || rel.startsWith("../") || isAbsolute3(rel)) {
14075
14302
  throw new SessionApplyError(`Session file escapes target home: ${file.relativePath}`);
14076
14303
  }
@@ -14082,7 +14309,7 @@ function resolvePlannedFilePath(plan, file, targetHome) {
14082
14309
  }
14083
14310
  function resolveManifestRelativePath(relativePath, targetHome) {
14084
14311
  const target = resolve6(targetHome, ...relativePath.split(/[\\/]+/));
14085
- const rel = relative4(targetHome, target);
14312
+ const rel = relative5(targetHome, target);
14086
14313
  if (rel === "" || rel === ".." || rel.startsWith("../") || isAbsolute3(rel)) {
14087
14314
  throw new SessionApplyError(`Session manifest file escapes target home: ${relativePath}`);
14088
14315
  }
@@ -14090,10 +14317,10 @@ function resolveManifestRelativePath(relativePath, targetHome) {
14090
14317
  return target;
14091
14318
  }
14092
14319
  function readPreviousManifest(path) {
14093
- if (!existsSync11(path))
14320
+ if (!existsSync12(path))
14094
14321
  return null;
14095
14322
  try {
14096
- const parsed = JSON.parse(readFileSync7(path, "utf-8"));
14323
+ const parsed = JSON.parse(readFileSync8(path, "utf-8"));
14097
14324
  if (parsed.schema !== SESSION_RENDER_SCHEMA)
14098
14325
  return null;
14099
14326
  if (!Array.isArray(parsed.files))
@@ -14127,18 +14354,18 @@ function applyPlannedFile(plan, file, targetHome, resultsByPath, coordination, a
14127
14354
  function assertExpectedSessionFileHash(path, targetHome, expectedHash) {
14128
14355
  const actualHash = currentSessionFileHash(path, targetHome);
14129
14356
  if (actualHash !== expectedHash) {
14130
- throw new SessionApplyError(`Session apply path changed after planning: ${relative4(targetHome, path)}`);
14357
+ throw new SessionApplyError(`Session apply path changed after planning: ${relative5(targetHome, path)}`);
14131
14358
  }
14132
14359
  }
14133
14360
  function currentSessionFileHash(path, targetHome) {
14134
14361
  assertNoSymlinkSegments2(targetHome, path);
14135
- if (!existsSync11(path))
14362
+ if (!existsSync12(path))
14136
14363
  return null;
14137
14364
  const stat = lstatSync2(path);
14138
14365
  if (stat.isSymbolicLink() || !stat.isFile()) {
14139
14366
  throw new SessionApplyError(`Session apply path is not a regular file: ${path}`);
14140
14367
  }
14141
- return sha2563(readFileSync7(path, "utf-8"));
14368
+ return sha2564(readFileSync8(path, "utf-8"));
14142
14369
  }
14143
14370
  function requiredPreviousHash(result) {
14144
14371
  if (result.previousSha256 === null) {
@@ -14147,13 +14374,13 @@ function requiredPreviousHash(result) {
14147
14374
  return result.previousSha256;
14148
14375
  }
14149
14376
  function writeSessionSnapshot(plan, targetHome, manifestPath, results, previousManifest, coordination, allowPortableFallback, forcePortableFileOps) {
14150
- const existingFiles = results.filter((result) => result.action === "update" || result.action === "delete").filter((result) => existsSync11(result.path)).map((result) => {
14151
- const content = readFileSync7(result.path, "utf-8");
14377
+ const existingFiles = results.filter((result) => result.action === "update" || result.action === "delete").filter((result) => existsSync12(result.path)).map((result) => {
14378
+ const content = readFileSync8(result.path, "utf-8");
14152
14379
  return {
14153
14380
  path: result.path,
14154
14381
  relativePath: result.relativePath,
14155
14382
  role: result.role,
14156
- sha256: sha2563(content),
14383
+ sha256: sha2564(content),
14157
14384
  content
14158
14385
  };
14159
14386
  });
@@ -14204,42 +14431,42 @@ function assertSafeTargetHome(targetHome) {
14204
14431
  if (!isAbsolute3(targetHome))
14205
14432
  throw new SessionApplyError(`Session target home must be absolute: ${targetHome}`);
14206
14433
  const normalized = resolve6(targetHome);
14207
- if (normalized === parse3(normalized).root) {
14434
+ if (normalized === parse4(normalized).root) {
14208
14435
  throw new SessionApplyError(`Session target home cannot be the filesystem root: ${targetHome}`);
14209
14436
  }
14210
14437
  assertNoSymlinkAncestors2(normalized);
14211
- if (existsSync11(normalized) && lstatSync2(normalized).isSymbolicLink()) {
14438
+ if (existsSync12(normalized) && lstatSync2(normalized).isSymbolicLink()) {
14212
14439
  throw new SessionApplyError(`Session target home cannot be a symlink: ${normalized}`);
14213
14440
  }
14214
14441
  return normalized;
14215
14442
  }
14216
14443
  function assertNoSymlinkSegments2(root, target) {
14217
14444
  assertNoSymlinkAncestors2(root);
14218
- const rel = relative4(root, target);
14445
+ const rel = relative5(root, target);
14219
14446
  let current = root;
14220
14447
  for (const segment of rel.split(/[\\/]+/).filter(Boolean)) {
14221
- current = join11(current, segment);
14222
- if (existsSync11(current) && lstatSync2(current).isSymbolicLink()) {
14448
+ current = join12(current, segment);
14449
+ if (existsSync12(current) && lstatSync2(current).isSymbolicLink()) {
14223
14450
  throw new SessionApplyError(`Session apply path uses a symlink: ${current}`);
14224
14451
  }
14225
14452
  }
14226
14453
  }
14227
14454
  function assertNoSymlinkAncestors2(path) {
14228
14455
  const normalized = resolve6(path);
14229
- const parsed = parse3(normalized);
14456
+ const parsed = parse4(normalized);
14230
14457
  let current = parsed.root;
14231
- const rel = relative4(parsed.root, normalized);
14458
+ const rel = relative5(parsed.root, normalized);
14232
14459
  for (const segment of rel.split(/[\\/]+/).filter(Boolean)) {
14233
- current = join11(current, segment);
14234
- if (!existsSync11(current))
14460
+ current = join12(current, segment);
14461
+ if (!existsSync12(current))
14235
14462
  return;
14236
14463
  if (lstatSync2(current).isSymbolicLink()) {
14237
14464
  throw new SessionApplyError(`Session apply path uses a symlink ancestor: ${current}`);
14238
14465
  }
14239
14466
  }
14240
14467
  }
14241
- function sha2563(content) {
14242
- return createHash3("sha256").update(content).digest("hex");
14468
+ function sha2564(content) {
14469
+ return createHash4("sha256").update(content).digest("hex");
14243
14470
  }
14244
14471
 
14245
14472
  // src/cli/index.tsx
@@ -14557,28 +14784,28 @@ init_project_context();
14557
14784
  init_config_store();
14558
14785
  init_apply();
14559
14786
  init_config_agents();
14560
- import { existsSync as existsSync13, readFileSync as readFileSync9 } from "fs";
14787
+ import { existsSync as existsSync14, readFileSync as readFileSync10 } from "fs";
14561
14788
 
14562
14789
  // src/lib/package-version.ts
14563
- import { existsSync as existsSync12, readFileSync as readFileSync8 } from "fs";
14564
- import { dirname as dirname5, join as join12 } from "path";
14790
+ import { existsSync as existsSync13, readFileSync as readFileSync9 } from "fs";
14791
+ import { dirname as dirname6, join as join13 } from "path";
14565
14792
  import { fileURLToPath } from "url";
14566
14793
  var cached = null;
14567
14794
  function getPackageVersion() {
14568
14795
  if (cached)
14569
14796
  return cached;
14570
14797
  try {
14571
- let dir = dirname5(fileURLToPath(import.meta.url));
14798
+ let dir = dirname6(fileURLToPath(import.meta.url));
14572
14799
  for (let i = 0;i < 8; i++) {
14573
- const pkgPath = join12(dir, "package.json");
14574
- if (existsSync12(pkgPath)) {
14575
- const pkg = JSON.parse(readFileSync8(pkgPath, "utf8"));
14800
+ const pkgPath = join13(dir, "package.json");
14801
+ if (existsSync13(pkgPath)) {
14802
+ const pkg = JSON.parse(readFileSync9(pkgPath, "utf8"));
14576
14803
  if (pkg.name === "@hasna/instructions" && pkg.version) {
14577
14804
  cached = pkg.version;
14578
14805
  return cached;
14579
14806
  }
14580
14807
  }
14581
- const parent = dirname5(dir);
14808
+ const parent = dirname6(dir);
14582
14809
  if (parent === dir)
14583
14810
  break;
14584
14811
  dir = parent;
@@ -14635,11 +14862,11 @@ async function getConfigsStatus(store = resolveConfigStore()) {
14635
14862
  continue;
14636
14863
  knownTargets += 1;
14637
14864
  const targetPath = expandPath(config.target_path);
14638
- if (!existsSync13(targetPath)) {
14865
+ if (!existsSync14(targetPath)) {
14639
14866
  missingTargets += 1;
14640
14867
  continue;
14641
14868
  }
14642
- const disk = readFileSync9(targetPath, "utf-8");
14869
+ const disk = readFileSync10(targetPath, "utf-8");
14643
14870
  const { content: redactedDisk } = redactContent(disk, config.format);
14644
14871
  if (redactedDisk !== config.content) {
14645
14872
  driftedTargets += 1;
@@ -14865,9 +15092,9 @@ function parseSessionSource(value, order, replaceIds) {
14865
15092
  if (!path)
14866
15093
  throw new Error(`Invalid --source "${value}" (expected path or id=path)`);
14867
15094
  const absPath = resolveSessionPath(path);
14868
- if (!existsSync15(absPath))
15095
+ if (!existsSync16(absPath))
14869
15096
  throw new Error(`Instruction source file not found: ${absPath}`);
14870
- const content = readFileSync11(absPath, "utf-8");
15097
+ const content = readFileSync12(absPath, "utf-8");
14871
15098
  const source = sourceFromFilePath(absPath, content, order);
14872
15099
  const resolvedId = id || source.id || basename7(absPath);
14873
15100
  return {
@@ -14903,9 +15130,9 @@ async function collectSessionSources(opts, tool, store) {
14903
15130
  }
14904
15131
  for (const value of opts.identityExport ?? []) {
14905
15132
  const path = resolveSessionPath(value);
14906
- if (!existsSync15(path))
15133
+ if (!existsSync16(path))
14907
15134
  throw new Error(`Identity instruction export not found: ${path}`);
14908
- const parsed = JSON.parse(readFileSync11(path, "utf-8"));
15135
+ const parsed = JSON.parse(readFileSync12(path, "utf-8"));
14909
15136
  sources.push(...sourcesFromIdentityExport(parsed, { path, tool, orderOffset: sources.length }));
14910
15137
  }
14911
15138
  return sources.map((source) => replaceIds.has(source.id) ? { ...source, merge: "replace" } : source);
@@ -14935,7 +15162,7 @@ function readProjectContextBundleOption(value, allowMissing = false) {
14935
15162
  if (value === "-")
14936
15163
  return { json: readBoundedProjectContextStdin() };
14937
15164
  const path = resolveSessionPath(value);
14938
- if (!existsSync15(path)) {
15165
+ if (!existsSync16(path)) {
14939
15166
  if (allowMissing)
14940
15167
  return {};
14941
15168
  throw new ProjectContextError("PROJECT_CONTEXT_INPUT_MISSING", `bundle file not found: ${path}`);
@@ -14947,7 +15174,7 @@ function readProjectContextBundleOption(value, allowMissing = false) {
14947
15174
  if (stat.size > PROJECT_CONTEXT_MAX_INPUT_BYTES) {
14948
15175
  throw new ProjectContextError("PROJECT_CONTEXT_INPUT_TOO_LARGE", `bundle exceeds ${PROJECT_CONTEXT_MAX_INPUT_BYTES} bytes`);
14949
15176
  }
14950
- return { json: readFileSync11(path, "utf8"), sourcePath: path };
15177
+ return { json: readFileSync12(path, "utf8"), sourcePath: path };
14951
15178
  }
14952
15179
  function readBoundedProjectContextStdin() {
14953
15180
  const chunks = [];
@@ -15075,11 +15302,11 @@ program.command("show <id>").alias("inspect").description("Show a config's conte
15075
15302
  });
15076
15303
  program.command("add <path>").description("Ingest a file into the config DB").option("-n, --name <name>", "config name (defaults to filename)").option("-c, --category <cat>", "category override").option("-a, --agent <agent>", "agent override").option("-k, --kind <kind>", "kind: file|reference", "file").option("--template", "mark as template (has {{VAR}} placeholders)").action(async (filePath, opts) => {
15077
15304
  const abs = resolve8(filePath);
15078
- if (!existsSync15(abs)) {
15305
+ if (!existsSync16(abs)) {
15079
15306
  console.error(chalk.red(`File not found: ${abs}`));
15080
15307
  process.exit(1);
15081
15308
  }
15082
- const rawContent = readFileSync11(abs, "utf-8");
15309
+ const rawContent = readFileSync12(abs, "utf-8");
15083
15310
  const fmt = detectFormat(abs);
15084
15311
  const { content, redacted, isTemplate: isTemplate2 } = redactContent(rawContent, fmt);
15085
15312
  const targetPath = abs.startsWith(homedir7()) ? abs.replace(homedir7(), "~") : abs;
@@ -15117,11 +15344,15 @@ program.command("delete <id>").alias("rm").description("Delete a config record (
15117
15344
  process.exit(1);
15118
15345
  }
15119
15346
  });
15120
- program.command("apply <id>").description("Apply a config to its target_path and output targets on disk").option("--dry-run", "preview without writing").option("--force", "overwrite even if unchanged").action(async (id, opts) => {
15347
+ program.command("apply <id>").description("Apply a config to its target_path and output targets on disk").option("--dry-run", "preview without writing").option("--force", "overwrite even if unchanged").option("--allow-renderer-owned", "write even when the target is owned by the Instructions session renderer (opt-in; normally use `instructions session apply`)").action(async (id, opts) => {
15121
15348
  try {
15122
15349
  const store = resolveConfigStore();
15123
15350
  const config = await store.getConfig(id);
15124
- const report = await applyConfigsWithReport([config], { dryRun: opts.dryRun, store });
15351
+ const report = await applyConfigsWithReport([config], {
15352
+ dryRun: opts.dryRun,
15353
+ store,
15354
+ allowSessionRendererOwned: opts.allowRendererOwned
15355
+ });
15125
15356
  if (report.failures.length > 0) {
15126
15357
  throw new Error(report.failures.map((failure) => failure.message).join("; "));
15127
15358
  }
@@ -15199,7 +15430,7 @@ program.command("sync").description("Sync known AI coding configs from disk into
15199
15430
  for (const entry of entries) {
15200
15431
  if (!entry.isDirectory())
15201
15432
  continue;
15202
- const projDir = join14(absDir, entry.name);
15433
+ const projDir = join15(absDir, entry.name);
15203
15434
  const hasAgentConfig = [
15204
15435
  "CLAUDE.md",
15205
15436
  ".mcp.json",
@@ -15212,7 +15443,7 @@ program.command("sync").description("Sync known AI coding configs from disk into
15212
15443
  ".aicopilot",
15213
15444
  ".cursor",
15214
15445
  ".agents"
15215
- ].some((marker) => existsSync15(join14(projDir, marker)));
15446
+ ].some((marker) => existsSync16(join15(projDir, marker)));
15216
15447
  if (!hasAgentConfig)
15217
15448
  continue;
15218
15449
  const result2 = await syncProject({ projectDir: projDir, dryRun: opts.dryRun, store });
@@ -15263,7 +15494,7 @@ program.command("import <file>").description("Import configs from a tar.gz bundl
15263
15494
  });
15264
15495
  program.command("whoami").description("Show setup summary").action(async () => {
15265
15496
  const store = resolveConfigStore();
15266
- const dbPath = isCloudMode() ? `${process.env["HASNA_INSTRUCTIONS_API_URL"]}/v1 (self_hosted)` : process.env["HASNA_INSTRUCTIONS_DB_PATH"] || join14(homedir7(), ".hasna", "instructions", "instructions.db");
15497
+ const dbPath = isCloudMode() ? `${process.env["HASNA_INSTRUCTIONS_API_URL"]}/v1 (self_hosted)` : process.env["HASNA_INSTRUCTIONS_DB_PATH"] || join15(homedir7(), ".hasna", "instructions", "instructions.db");
15267
15498
  const stats = await store.getConfigStats();
15268
15499
  console.log(chalk.bold("@hasna/instructions") + chalk.dim(" v" + pkg.version));
15269
15500
  console.log(chalk.cyan(isCloudMode() ? "API:" : "DB:") + " " + dbPath);
@@ -15889,7 +16120,7 @@ command = "${mcpBinary}"
15889
16120
  args = []
15890
16121
  `;
15891
16122
  if (ex(configPath)) {
15892
- const content = readFileSync11(configPath, "utf-8");
16123
+ const content = readFileSync12(configPath, "utf-8");
15893
16124
  if (content.includes("[mcp_servers.configs]")) {
15894
16125
  console.log(chalk.dim("= Already installed in Codex"));
15895
16126
  continue;
@@ -15983,7 +16214,7 @@ DB stats:`));
15983
16214
  if (count > 0)
15984
16215
  console.log(` ${key.padEnd(18)} ${count}`);
15985
16216
  }
15986
- const location = isCloudMode() ? `${process.env["HASNA_INSTRUCTIONS_API_URL"]}/v1 (self_hosted)` : process.env["HASNA_INSTRUCTIONS_DB_PATH"] || join14(homedir7(), ".hasna", "instructions", "instructions.db");
16217
+ const location = isCloudMode() ? `${process.env["HASNA_INSTRUCTIONS_API_URL"]}/v1 (self_hosted)` : process.env["HASNA_INSTRUCTIONS_DB_PATH"] || join15(homedir7(), ".hasna", "instructions", "instructions.db");
15987
16218
  console.log(chalk.dim(`
15988
16219
  ${isCloudMode() ? "API" : "DB"}: ${location}`));
15989
16220
  });
@@ -16005,10 +16236,10 @@ program.command("status").description("Health check: total configs, drift from d
16005
16236
  });
16006
16237
  program.command("backup").description("Export configs to a timestamped backup file").action(async () => {
16007
16238
  const { mkdirSync: mk } = await import("fs");
16008
- const backupDir = join14(homedir7(), ".hasna", "instructions", "backups");
16239
+ const backupDir = join15(homedir7(), ".hasna", "instructions", "backups");
16009
16240
  mk(backupDir, { recursive: true });
16010
16241
  const ts = new Date().toISOString().replace(/[:.]/g, "-").replace("T", "-").slice(0, 19);
16011
- const outPath = join14(backupDir, `configs-${ts}.tar.gz`);
16242
+ const outPath = join15(backupDir, `configs-${ts}.tar.gz`);
16012
16243
  const result = await exportConfigs(outPath, { store: resolveConfigStore() });
16013
16244
  const { statSync: st } = await import("fs");
16014
16245
  const size = st(outPath).size;
@@ -16036,9 +16267,9 @@ program.command("doctor").description("Validate configs: syntax, permissions, mi
16036
16267
  console.log(chalk.cyan("Known files on disk:"));
16037
16268
  for (const k of KNOWN_CONFIGS) {
16038
16269
  if (k.rulesDir) {
16039
- existsSync15(expandPath(k.rulesDir)) ? pass(`${k.rulesDir}/ exists`) : k.optional ? skip(`${k.rulesDir}/ (optional)`) : fail(`${k.rulesDir}/ not found`);
16270
+ existsSync16(expandPath(k.rulesDir)) ? pass(`${k.rulesDir}/ exists`) : k.optional ? skip(`${k.rulesDir}/ (optional)`) : fail(`${k.rulesDir}/ not found`);
16040
16271
  } else {
16041
- existsSync15(expandPath(k.path)) ? pass(k.path) : k.optional ? skip(`${k.path} (optional)`) : fail(`${k.path} not found`);
16272
+ existsSync16(expandPath(k.path)) ? pass(k.path) : k.optional ? skip(`${k.path} (optional)`) : fail(`${k.path} not found`);
16042
16273
  }
16043
16274
  }
16044
16275
  const allConfigs = await store.listConfigs();
@@ -16163,16 +16394,16 @@ program.command("watch").description("Watch known config files for changes and a
16163
16394
  for (const k of KNOWN_CONFIGS) {
16164
16395
  if (k.rulesDir) {
16165
16396
  const absDir = expandPath2(k.rulesDir);
16166
- if (!existsSync15(absDir))
16397
+ if (!existsSync16(absDir))
16167
16398
  continue;
16168
16399
  const { readdirSync: readdirSync5 } = await import("fs");
16169
16400
  for (const f of readdirSync5(absDir).filter((f2) => f2.endsWith(".md"))) {
16170
- const abs = join14(absDir, f);
16401
+ const abs = join15(absDir, f);
16171
16402
  mtimes.set(abs, st(abs).mtimeMs);
16172
16403
  }
16173
16404
  } else {
16174
16405
  const abs = expandPath2(k.path);
16175
- if (existsSync15(abs))
16406
+ if (existsSync16(abs))
16176
16407
  mtimes.set(abs, st(abs).mtimeMs);
16177
16408
  }
16178
16409
  }
@@ -16180,7 +16411,7 @@ program.command("watch").description("Watch known config files for changes and a
16180
16411
  const tick = async () => {
16181
16412
  let changed = 0;
16182
16413
  for (const [abs, oldMtime] of mtimes) {
16183
- if (!existsSync15(abs))
16414
+ if (!existsSync16(abs))
16184
16415
  continue;
16185
16416
  const newMtime = st(abs).mtimeMs;
16186
16417
  if (newMtime !== oldMtime) {
@@ -16192,10 +16423,10 @@ program.command("watch").description("Watch known config files for changes and a
16192
16423
  for (const k of KNOWN_CONFIGS) {
16193
16424
  if (k.rulesDir) {
16194
16425
  const absDir = expandPath2(k.rulesDir);
16195
- if (!existsSync15(absDir))
16426
+ if (!existsSync16(absDir))
16196
16427
  continue;
16197
16428
  for (const f of rd(absDir).filter((f2) => f2.endsWith(".md"))) {
16198
- const abs = join14(absDir, f);
16429
+ const abs = join15(absDir, f);
16199
16430
  if (!mtimes.has(abs)) {
16200
16431
  mtimes.set(abs, st(abs).mtimeMs);
16201
16432
  changed++;
@@ -16203,7 +16434,7 @@ program.command("watch").description("Watch known config files for changes and a
16203
16434
  }
16204
16435
  } else {
16205
16436
  const abs = expandPath2(k.path);
16206
- if (existsSync15(abs) && !mtimes.has(abs)) {
16437
+ if (existsSync16(abs) && !mtimes.has(abs)) {
16207
16438
  mtimes.set(abs, st(abs).mtimeMs);
16208
16439
  changed++;
16209
16440
  }
@@ -16231,11 +16462,11 @@ program.command("report").description("Summary of stored configs, drift, and eco
16231
16462
  if (!c.target_path)
16232
16463
  continue;
16233
16464
  const abs = expandPath(c.target_path);
16234
- if (!existsSync15(abs)) {
16465
+ if (!existsSync16(abs)) {
16235
16466
  missing++;
16236
16467
  continue;
16237
16468
  }
16238
- const disk = readFileSync11(abs, "utf-8");
16469
+ const disk = readFileSync12(abs, "utf-8");
16239
16470
  const { content: redactedDisk } = redactContent(disk, c.format);
16240
16471
  if (redactedDisk !== c.content)
16241
16472
  drifted++;
@@ -16276,7 +16507,7 @@ program.command("clean").description("Remove configs from DB whose target files
16276
16507
  if (!c.target_path)
16277
16508
  continue;
16278
16509
  const abs = expandPath(c.target_path);
16279
- if (!existsSync15(abs)) {
16510
+ if (!existsSync16(abs)) {
16280
16511
  if (printed < maxPrinted) {
16281
16512
  if (opts.dryRun) {
16282
16513
  console.log(chalk.yellow(" would remove:") + ` ${c.slug} ${chalk.dim(`(${truncateMiddle(c.target_path, 88)})`)}`);