@hasna/instructions 0.4.25 → 0.4.26

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
@@ -7930,6 +7930,9 @@ function computeProjectContextSourceHash(value) {
7930
7930
  return `sha256:${sha2562(stableStringify(normalized))}`;
7931
7931
  }
7932
7932
  function parseProjectContextBundle(input) {
7933
+ return parseProjectContextBundleInternal(input, true, true);
7934
+ }
7935
+ function parseProjectContextBundleInternal(input, allowLegacyHash, normalizeLegacyHash = false) {
7933
7936
  let encoded;
7934
7937
  try {
7935
7938
  const serialized = typeof input === "string" ? input : JSON.stringify(input);
@@ -7966,10 +7969,11 @@ function parseProjectContextBundle(input) {
7966
7969
  validateIdentityConsistency(bundle);
7967
7970
  rejectCredentialLikeBundle(bundle);
7968
7971
  const expected = computeProjectContextSourceHash(bundle);
7969
- if (bundle.hash !== expected) {
7972
+ const matchesLegacyHash = bundle.hash !== expected && allowLegacyHash && bundle.hash === computeLegacyProjectContextSourceHash(bundle);
7973
+ if (bundle.hash !== expected && !matchesLegacyHash) {
7970
7974
  throw new ProjectContextError("PROJECT_CONTEXT_HASH_MISMATCH", "bundle hash does not match its canonical allowlisted payload");
7971
7975
  }
7972
- return bundle;
7976
+ return matchesLegacyHash && normalizeLegacyHash ? { ...bundle, hash: expected } : bundle;
7973
7977
  }
7974
7978
  function planProjectContext(input) {
7975
7979
  const workspaceRoot = assertSafeWorkspaceRoot(input.workspace_root);
@@ -8217,6 +8221,8 @@ function applyProjectContext(options) {
8217
8221
  content: `${JSON.stringify(sessionManifest, null, 2)}
8218
8222
  `
8219
8223
  };
8224
+ const manifestContent = `${JSON.stringify(buildManifest(plan, now3), null, 2)}
8225
+ `;
8220
8226
  options.test_hooks?.before_compare?.({ attempt, plan });
8221
8227
  if (!hashesStillMatch(plan.expected_hashes, workspaceRoot)) {
8222
8228
  if (attempt === 0) {
@@ -8229,7 +8235,15 @@ function applyProjectContext(options) {
8229
8235
  return resultForPlan(plan, true, raceRetries, null);
8230
8236
  assertWorkspaceLockHeld(lockPath, lock, workspaceRoot);
8231
8237
  try {
8232
- snapshotPath = writeMetadataSnapshot(plan, now3);
8238
+ const metadataSnapshotPath = writeMetadataSnapshot(plan, now3);
8239
+ const rollbackSnapshotPath = writeProjectContextRollbackSnapshot(plan, now3, [
8240
+ { path: plan.fragment_path, content: plan.fragment, role: "fragment" },
8241
+ { path: plan.target_path, content: plan.target_content, role: "index" },
8242
+ { path: plan.cache_path, content: cacheContent, role: "config" },
8243
+ { path: sessionOutput.path, content: sessionOutput.content, role: "manifest" },
8244
+ { path: plan.manifest_path, content: manifestContent, role: "manifest" }
8245
+ ]);
8246
+ snapshotPath = rollbackSnapshotPath ?? metadataSnapshotPath;
8233
8247
  atomicWriteFile(plan.fragment_path, plan.fragment, workspaceRoot, 420, expectedPlanHash(plan, plan.fragment_path), undefined, options.test_hooks?.atomic_exchange_unavailable, undefined, options.test_hooks?.portable_create_only);
8234
8248
  options.test_hooks?.after_fragment?.({ attempt, plan });
8235
8249
  assertWorkspaceLockHeld(lockPath, lock, workspaceRoot);
@@ -8243,9 +8257,7 @@ function applyProjectContext(options) {
8243
8257
  options.test_hooks?.before_manifest?.({ attempt, plan });
8244
8258
  assertWorkspaceLockHeld(lockPath, lock, workspaceRoot);
8245
8259
  assertRenderedOutputsStable(plan, cacheContent, sessionOutput);
8246
- const manifest = buildManifest(plan, now3);
8247
- atomicWriteFile(plan.manifest_path, `${JSON.stringify(manifest, null, 2)}
8248
- `, workspaceRoot, 384, expectedPlanHash(plan, plan.manifest_path), undefined, options.test_hooks?.atomic_exchange_unavailable, undefined, options.test_hooks?.portable_create_only);
8260
+ atomicWriteFile(plan.manifest_path, manifestContent, workspaceRoot, 384, expectedPlanHash(plan, plan.manifest_path), undefined, options.test_hooks?.atomic_exchange_unavailable, undefined, options.test_hooks?.portable_create_only);
8249
8261
  return resultForPlan(plan, false, raceRetries, snapshotPath);
8250
8262
  } catch (error) {
8251
8263
  if (error instanceof ProjectContextHashRace && attempt === 0) {
@@ -8336,10 +8348,12 @@ function resolveBundleForApply(options, workspaceRoot, now3) {
8336
8348
  if (cache.project_id !== options.expected_project_id || cache.bundle.project.id !== options.expected_project_id) {
8337
8349
  throw new ProjectContextError("PROJECT_CONTEXT_CACHE_ID_MISMATCH", "cached project context belongs to a different project");
8338
8350
  }
8339
- const bundle = parseProjectContextBundle(cache.bundle);
8340
- if (bundle.revision !== cache.revision || bundle.hash !== cache.hash) {
8351
+ const cachedBundle = cache.bundle;
8352
+ if (cachedBundle.revision !== cache.revision || cachedBundle.hash !== cache.hash) {
8341
8353
  throw new ProjectContextError("PROJECT_CONTEXT_CACHE_INVALID", "cached revision or hash metadata is inconsistent");
8342
8354
  }
8355
+ const canonicalHash = computeProjectContextSourceHash(cachedBundle);
8356
+ const bundle = cachedBundle.hash === canonicalHash ? cachedBundle : { ...cachedBundle, hash: canonicalHash };
8343
8357
  const ageSeconds = Math.max(staleCacheAgeInSeconds(bundle.generated_at, now3, "bundle generated_at"), staleCacheAgeInSeconds(cache.cached_at, now3, "cache cached_at"));
8344
8358
  const maxAge = normalizeMaxStaleAge(options.max_stale_age_seconds);
8345
8359
  if (ageSeconds > maxAge) {
@@ -8436,11 +8450,13 @@ function parseManagedBlock(content, force) {
8436
8450
  if (structurallyInvalid) {
8437
8451
  if (!force)
8438
8452
  throw new ProjectContextError("MANAGED_BLOCK_INVALID", "managed project-context markers are duplicate, nested, malformed, or unbalanced");
8453
+ const firstMarkerRange = markerCommentRange(markerLines[0]);
8454
+ const lastMarkerRange = markerCommentRange(markerLines[markerLines.length - 1]);
8439
8455
  return {
8440
8456
  block: null,
8441
8457
  forceRange: {
8442
- start: markerLines[0].start,
8443
- end: lineContentEnd(markerLines[markerLines.length - 1])
8458
+ start: firstMarkerRange?.start ?? markerLines[0].start,
8459
+ end: lastMarkerRange?.end ?? lineContentEnd(markerLines[markerLines.length - 1])
8444
8460
  }
8445
8461
  };
8446
8462
  }
@@ -8471,6 +8487,21 @@ function parseManagedBlock(content, force) {
8471
8487
  forceRange: null
8472
8488
  };
8473
8489
  }
8490
+ function markerCommentRange(line) {
8491
+ const canonicalMarker = line.text.indexOf(PROJECT_CONTEXT_MANAGED_COMMENT);
8492
+ const legacyMarker = /@hasna\/configs project context/i.exec(line.text)?.index ?? -1;
8493
+ const marker = canonicalMarker >= 0 ? canonicalMarker : legacyMarker;
8494
+ if (marker < 0)
8495
+ return null;
8496
+ const commentStart = line.text.lastIndexOf("<!--", marker);
8497
+ const commentEnd = line.text.indexOf("-->", marker);
8498
+ if (commentStart < 0 || commentEnd < 0)
8499
+ return null;
8500
+ return {
8501
+ start: line.start + commentStart,
8502
+ end: line.start + commentEnd + "-->".length
8503
+ };
8504
+ }
8474
8505
  function parseMarkerLine(text) {
8475
8506
  const line = text.replace(/[\r\n]+$/, "");
8476
8507
  const canonical = line.match(/^<!-- Managed by @hasna\/configs project context (BEGIN|END) id=([A-Za-z0-9][A-Za-z0-9._:@+-]*) revision=([A-Za-z0-9%._~+-]+) hash=(sha256:[a-f0-9]{64}) -->$/);
@@ -8492,8 +8523,14 @@ function parseMarkerLine(text) {
8492
8523
  }
8493
8524
  function replaceOrAppendManagedBlock(content, block, parsed, legacy) {
8494
8525
  const range = parsed.block ?? parsed.forceRange ?? legacy;
8495
- if (range)
8496
- return `${content.slice(0, range.start)}${block}${content.slice(range.end)}`;
8526
+ if (range) {
8527
+ const before = content.slice(0, range.start);
8528
+ const after = content.slice(range.end);
8529
+ const eol2 = preferredEol(content);
8530
+ const beforeSeparator = before && !/[\r\n]$/.test(before) ? eol2 : "";
8531
+ const afterSeparator = after && !/^[\r\n]/.test(after) ? eol2 : "";
8532
+ return `${before}${beforeSeparator}${block}${afterSeparator}${after}`;
8533
+ }
8497
8534
  if (!content)
8498
8535
  return `${block}
8499
8536
  `;
@@ -8537,13 +8574,18 @@ function findLegacyCodewithWorkspaceSection(workspaceRoot, runtime, content, bun
8537
8574
  }
8538
8575
  function assertRevisionOrdering(plan, force) {
8539
8576
  const observations = [];
8577
+ const cache = readProjectContextCache(plan.cache_path, plan.workspace_root);
8578
+ const canonicalCacheHash = cache === null ? null : computeProjectContextSourceHash(cache.bundle);
8579
+ const normalizePersistedHash = (revision, hash) => cache !== null && canonicalCacheHash !== null && revision === cache.revision && hash === cache.hash ? canonicalCacheHash : hash;
8540
8580
  const manifest = readProjectContextManifest(plan.manifest_path, plan.workspace_root);
8541
8581
  if (manifest) {
8582
+ const manifestHashHasRecoveryProof = manifest.projectContext.hash === plan.bundle.hash || metadataSnapshotMatchesManifest(plan, manifest);
8583
+ const canonicalStateAlreadyInstalled = cache !== null && canonicalCacheHash === plan.bundle.hash && cache.project_id === plan.bundle.project.id && cache.revision === plan.bundle.revision && plan.marker !== null && plan.marker.id === plan.bundle.project.id && plan.marker.revision === plan.bundle.revision && plan.marker.hash === plan.bundle.hash && existsSync4(plan.fragment_path) && fragmentMatchesBundle(plan.fragment_path, plan.bundle, plan.workspace_root) && manifestHashHasRecoveryProof;
8542
8584
  observations.push({
8543
8585
  source: "manifest",
8544
8586
  id: manifest.projectContext.projectId,
8545
8587
  revision: manifest.projectContext.revision,
8546
- hash: manifest.projectContext.hash
8588
+ hash: canonicalStateAlreadyInstalled && manifest.projectContext.projectId === plan.bundle.project.id && manifest.projectContext.revision === plan.bundle.revision ? plan.bundle.hash : normalizePersistedHash(manifest.projectContext.revision, manifest.projectContext.hash)
8547
8589
  });
8548
8590
  const fragmentEntry = manifest.files.find((file) => file.relativePath === PROJECT_CONTEXT_FRAGMENT_PATH);
8549
8591
  if (fragmentEntry && existsSync4(plan.fragment_path)) {
@@ -8553,11 +8595,16 @@ function assertRevisionOrdering(plan, force) {
8553
8595
  }
8554
8596
  }
8555
8597
  }
8556
- const cache = readProjectContextCache(plan.cache_path, plan.workspace_root);
8557
8598
  if (cache)
8558
- observations.push({ source: "cache", id: cache.project_id, revision: cache.revision, hash: cache.hash });
8559
- if (plan.marker)
8560
- observations.push({ source: "marker", id: plan.marker.id, revision: plan.marker.revision, hash: plan.marker.hash });
8599
+ observations.push({ source: "cache", id: cache.project_id, revision: cache.revision, hash: canonicalCacheHash });
8600
+ if (plan.marker) {
8601
+ observations.push({
8602
+ source: "marker",
8603
+ id: plan.marker.id,
8604
+ revision: plan.marker.revision,
8605
+ hash: normalizePersistedHash(plan.marker.revision, plan.marker.hash)
8606
+ });
8607
+ }
8561
8608
  for (const observation of observations) {
8562
8609
  if (observation.id !== plan.bundle.project.id) {
8563
8610
  throw new ProjectContextError("PROJECT_CONTEXT_IDENTITY_CONFLICT", `${observation.source} belongs to another project`);
@@ -8677,6 +8724,10 @@ function buildSessionCompatibilityManifest(plan, now3) {
8677
8724
  };
8678
8725
  const targetOwner = isRecord(existing["targetOwner"]) ? existing["targetOwner"] : {};
8679
8726
  const adapterMode = plan.native_imports ? "native-imports" : "flattened-markdown";
8727
+ const existingProjectContext = isRecord(existing["projectContext"]) ? existing["projectContext"] : null;
8728
+ const existingProjectContextHash = existingProjectContext === null ? null : safeLegacyMetadataString(existingProjectContext["hash"], null);
8729
+ const existingSourceHash = typeof existing["sourceHash"] === "string" ? existing["sourceHash"] : null;
8730
+ const sourceHash = existingProjectContextHash === plan.bundle.hash && existingSourceHash !== null ? existingSourceHash : sha2562(stableStringify({ previous: existingSourceHash, projectContext: plan.bundle.hash }));
8680
8731
  return credentialSafeSessionManifest({
8681
8732
  schema: SESSION_RENDER_SCHEMA,
8682
8733
  tool,
@@ -8700,7 +8751,7 @@ function buildSessionCompatibilityManifest(plan, now3) {
8700
8751
  blockers: [],
8701
8752
  generatedAt: now3.toISOString(),
8702
8753
  env: sanitizeLegacyEnvironment(existing["env"]),
8703
- sourceHash: sha2562(stableStringify({ previous: typeof existing["sourceHash"] === "string" ? existing["sourceHash"] : null, projectContext: plan.bundle.hash })),
8754
+ sourceHash,
8704
8755
  sources,
8705
8756
  skippedSources: sanitizeLegacySkippedSources(existing["skippedSources"]),
8706
8757
  files: [...files.filter((file) => file["relativePath"] !== targetRelativePath), updatedTarget],
@@ -8956,6 +9007,77 @@ function writeMetadataSnapshot(plan, now3) {
8956
9007
  `, plan.workspace_root, 384);
8957
9008
  return snapshotPath;
8958
9009
  }
9010
+ function metadataSnapshotMatchesManifest(plan, manifest) {
9011
+ const snapshotDir = resolve(plan.workspace_root, ...PROJECT_CONTEXT_SNAPSHOT_DIR.split("/"));
9012
+ const snapshotPath = resolve(snapshotDir, `${safeFilename(manifest.projectContext.revision)}-${manifest.projectContext.hash.slice(-12)}.json`);
9013
+ if (!existsSync4(snapshotPath))
9014
+ return false;
9015
+ const record = readJsonRecord(snapshotPath, plan.workspace_root);
9016
+ const result = projectContextMetadataSnapshotSchema.safeParse(record);
9017
+ if (!result.success)
9018
+ return false;
9019
+ if (result.data.projectId !== manifest.projectContext.projectId || result.data.revision !== manifest.projectContext.revision || result.data.hash !== manifest.projectContext.hash || result.data.status !== manifest.projectContext.status)
9020
+ return false;
9021
+ const sortFiles = (files) => [...files].sort((left, right) => left.relativePath.localeCompare(right.relativePath));
9022
+ const snapshotFiles = sortFiles(result.data.files);
9023
+ const manifestFiles = sortFiles(manifest.files.map((file) => ({
9024
+ relativePath: file.relativePath,
9025
+ role: file.role,
9026
+ sha256: file.sha256
9027
+ })));
9028
+ return JSON.stringify(snapshotFiles) === JSON.stringify(manifestFiles);
9029
+ }
9030
+ function writeProjectContextRollbackSnapshot(plan, now3, outputs) {
9031
+ const targetExpectedHash = expectedPlanHash(plan, plan.target_path);
9032
+ if (targetExpectedHash === sha2562(plan.target_content))
9033
+ return null;
9034
+ const files = outputs.flatMap((output) => {
9035
+ const expectedHash = expectedPlanHash(plan, output.path);
9036
+ if (expectedHash === null)
9037
+ return [];
9038
+ const content = readUtf8RegularFile(output.path, plan.workspace_root, managedObservationMaxBytes(relativePosix(plan.workspace_root, output.path)));
9039
+ if (sha2562(content) !== expectedHash) {
9040
+ throw new ProjectContextHashRace(`managed path changed while creating rollback evidence: ${relativePosix(plan.workspace_root, output.path)}`);
9041
+ }
9042
+ return [{
9043
+ path: output.path,
9044
+ relativePath: relativePosix(plan.workspace_root, output.path),
9045
+ role: output.role,
9046
+ sha256: expectedHash,
9047
+ content
9048
+ }];
9049
+ });
9050
+ const afterFiles = outputs.map((output) => {
9051
+ const previousHash = expectedPlanHash(plan, output.path);
9052
+ const nextHash = sha2562(output.content);
9053
+ return {
9054
+ path: output.path,
9055
+ relativePath: relativePosix(plan.workspace_root, output.path),
9056
+ role: output.role,
9057
+ action: previousHash === null ? "create" : previousHash === nextHash ? "unchanged" : "update",
9058
+ sha256: nextHash
9059
+ };
9060
+ });
9061
+ const snapshotDir = resolve(plan.workspace_root, ...SESSION_RENDER_SNAPSHOT_RELATIVE_DIR.split("/"));
9062
+ ensureSafeDirectory(snapshotDir, plan.workspace_root, 448);
9063
+ const timestamp = now3.toISOString().replace(/[:.]/g, "-");
9064
+ const snapshotPath = resolve(snapshotDir, `${timestamp}-${randomUUID6()}.json`);
9065
+ const snapshot = {
9066
+ schema: "hasna.configs.session-render-snapshot/v2",
9067
+ createdAt: now3.toISOString(),
9068
+ tool: manifestTool(plan.runtime),
9069
+ profile: "project-context",
9070
+ targetHome: plan.workspace_root,
9071
+ targetKind: "project-root",
9072
+ manifestPath: plan.manifest_path,
9073
+ previousManifest: null,
9074
+ files,
9075
+ afterFiles
9076
+ };
9077
+ atomicWriteFile(snapshotPath, `${JSON.stringify(snapshot, null, 2)}
9078
+ `, plan.workspace_root, 384, null);
9079
+ return snapshotPath;
9080
+ }
8959
9081
  function readProjectContextManifest(path, workspaceRoot) {
8960
9082
  if (!existsSync4(path))
8961
9083
  return null;
@@ -8979,7 +9101,7 @@ function readProjectContextCache(path, workspaceRoot) {
8979
9101
  if (!result.success) {
8980
9102
  throw new ProjectContextError("PROJECT_CONTEXT_CACHE_INVALID", "cache is malformed or incompatible");
8981
9103
  }
8982
- const bundle = parseProjectContextBundle(result.data.bundle);
9104
+ const bundle = parseProjectContextBundleInternal(result.data.bundle, true);
8983
9105
  if (result.data.project_id !== bundle.project.id || result.data.revision !== bundle.revision || result.data.hash !== bundle.hash) {
8984
9106
  throw new ProjectContextError("PROJECT_CONTEXT_CACHE_INVALID", "cache metadata does not match its bundle");
8985
9107
  }
@@ -10292,19 +10414,30 @@ function removeHashForFingerprint(value) {
10292
10414
  return value;
10293
10415
  const copy = {};
10294
10416
  for (const [key, item] of Object.entries(value)) {
10295
- if (key === "hash")
10417
+ if (key === "generated_at" || key === "hash")
10296
10418
  continue;
10297
10419
  copy[key] = item;
10298
10420
  }
10299
10421
  return copy;
10300
10422
  }
10423
+ function computeLegacyProjectContextSourceHash(value) {
10424
+ if (!isRecord(value))
10425
+ return `sha256:${sha2562(stableStringify(value))}`;
10426
+ const copy = {};
10427
+ for (const [key, item] of Object.entries(value)) {
10428
+ if (key === "hash")
10429
+ continue;
10430
+ copy[key] = item;
10431
+ }
10432
+ return `sha256:${sha2562(stableStringify(copy))}`;
10433
+ }
10301
10434
  function sha2562(content) {
10302
10435
  return createHash2("sha256").update(content).digest("hex");
10303
10436
  }
10304
10437
  function isRecord(value) {
10305
10438
  return !!value && typeof value === "object" && !Array.isArray(value);
10306
10439
  }
10307
- var PROJECT_CONTEXT_SCHEMA = "hasna.projects.project_context_bundle.v1", PROJECT_CONTEXT_MAX_INPUT_BYTES, PROJECT_CONTEXT_MAX_RENDERED_BYTES, PROJECT_CONTEXT_MAX_APPROX_TOKENS = 1000, PROJECT_CONTEXT_MAX_COMMANDS = 6, PROJECT_CONTEXT_MAX_WARNINGS = 3, PROJECT_CONTEXT_FRAGMENT_PATH = ".hasna/instructions/project-context.md", PROJECT_CONTEXT_MANIFEST_PATH = ".hasna/project-context-manifest.json", PROJECT_CONTEXT_CACHE_PATH = ".hasna/project-context-cache.json", PROJECT_CONTEXT_LOCK_PATH = ".hasna/project-context.lock", PROJECT_CONTEXT_SNAPSHOT_DIR = ".hasna/project-context-snapshots", PROJECT_CONTEXT_CACHE_SCHEMA = "hasna.instructions.project-context-cache/v1", PROJECT_CONTEXT_MANAGED_COMMENT = "Managed by @hasna/configs project context", SESSION_COMPATIBILITY_MANIFEST_MAX_BYTES, FOREIGN_INPUT_MAX_BYTES, SESSION_MANAGED_OUTPUT_MAX_BYTES, SESSION_MANAGED_INPUT_MAX_BYTES, SESSION_MANAGED_OUTPUT_PATHS, SESSION_MANAGED_OUTPUT_WARN_BYTES, PROJECT_CONTEXT_LOCK_STALE_MS, LEGACY_CONFIGS_PACKAGE = "@hasna/configs", LEGACY_CONFIGS_COMPAT_VERSION = "0.2.45", LEGACY_CONFIGS_EXECUTABLE = "configs", PROJECT_KINDS, PROJECT_STATUSES, LINK_STATES, RESOLUTION_SOURCES, safeId, nullableId, producerSlug, producerName, safeOptionalDisplay, isoTimestamp, revisionSchema, hashSchema, absolutePath, commandArg, commandSchema, projectContextBundleSchema, storedManifestProjectContextSchema, storedManifestFileSchema, storedManifestObservationSchema, projectContextCacheSchema, ProjectContextError, ProjectContextHashRace, anchoredFsOps, atomicExchange, atomicExchangeLibraries;
10440
+ var PROJECT_CONTEXT_SCHEMA = "hasna.projects.project_context_bundle.v1", PROJECT_CONTEXT_MAX_INPUT_BYTES, PROJECT_CONTEXT_MAX_RENDERED_BYTES, PROJECT_CONTEXT_MAX_APPROX_TOKENS = 1000, PROJECT_CONTEXT_MAX_COMMANDS = 6, PROJECT_CONTEXT_MAX_WARNINGS = 3, PROJECT_CONTEXT_FRAGMENT_PATH = ".hasna/instructions/project-context.md", PROJECT_CONTEXT_MANIFEST_PATH = ".hasna/project-context-manifest.json", PROJECT_CONTEXT_CACHE_PATH = ".hasna/project-context-cache.json", PROJECT_CONTEXT_LOCK_PATH = ".hasna/project-context.lock", PROJECT_CONTEXT_SNAPSHOT_DIR = ".hasna/project-context-snapshots", PROJECT_CONTEXT_CACHE_SCHEMA = "hasna.instructions.project-context-cache/v1", PROJECT_CONTEXT_MANAGED_COMMENT = "Managed by @hasna/configs project context", SESSION_COMPATIBILITY_MANIFEST_MAX_BYTES, FOREIGN_INPUT_MAX_BYTES, SESSION_MANAGED_OUTPUT_MAX_BYTES, SESSION_MANAGED_INPUT_MAX_BYTES, SESSION_MANAGED_OUTPUT_PATHS, SESSION_MANAGED_OUTPUT_WARN_BYTES, PROJECT_CONTEXT_LOCK_STALE_MS, LEGACY_CONFIGS_PACKAGE = "@hasna/configs", LEGACY_CONFIGS_COMPAT_VERSION = "0.2.45", LEGACY_CONFIGS_EXECUTABLE = "configs", PROJECT_KINDS, PROJECT_STATUSES, LINK_STATES, RESOLUTION_SOURCES, safeId, nullableId, producerSlug, producerName, safeOptionalDisplay, isoTimestamp, revisionSchema, hashSchema, absolutePath, commandArg, commandSchema, projectContextBundleSchema, storedManifestProjectContextSchema, storedManifestFileSchema, storedManifestObservationSchema, projectContextMetadataSnapshotSchema, projectContextCacheSchema, ProjectContextError, ProjectContextHashRace, anchoredFsOps, atomicExchange, atomicExchangeLibraries;
10308
10441
  var init_project_context = __esm(() => {
10309
10442
  init_zod();
10310
10443
  init_redact();
@@ -10444,6 +10577,25 @@ var init_project_context = __esm(() => {
10444
10577
  });
10445
10578
  }
10446
10579
  });
10580
+ projectContextMetadataSnapshotSchema = exports_external.object({
10581
+ schema: exports_external.literal("hasna.configs.session-render-snapshot/v1"),
10582
+ kind: exports_external.literal("project-context-metadata"),
10583
+ createdAt: isoTimestamp,
10584
+ projectId: safeId,
10585
+ revision: revisionSchema,
10586
+ hash: hashSchema,
10587
+ status: exports_external.enum(["fresh", "stale-source", "stale-cache"]),
10588
+ files: exports_external.array(exports_external.object({
10589
+ relativePath: exports_external.enum([
10590
+ PROJECT_CONTEXT_FRAGMENT_PATH,
10591
+ "CLAUDE.md",
10592
+ ".codewith/CODEWITH.md",
10593
+ "AGENTS.md"
10594
+ ]),
10595
+ role: exports_external.enum(["fragment", "index"]),
10596
+ sha256: exports_external.string().regex(/^[a-f0-9]{64}$/)
10597
+ }).strict()).min(1).max(2)
10598
+ }).strict();
10447
10599
  projectContextCacheSchema = exports_external.object({
10448
10600
  schema: exports_external.literal(PROJECT_CONTEXT_CACHE_SCHEMA),
10449
10601
  cached_at: isoTimestamp,
package/dist/index.js CHANGED
@@ -5972,6 +5972,25 @@ var storedManifestObservationSchema = exports_external.object({
5972
5972
  });
5973
5973
  }
5974
5974
  });
5975
+ var projectContextMetadataSnapshotSchema = exports_external.object({
5976
+ schema: exports_external.literal("hasna.configs.session-render-snapshot/v1"),
5977
+ kind: exports_external.literal("project-context-metadata"),
5978
+ createdAt: isoTimestamp,
5979
+ projectId: safeId,
5980
+ revision: revisionSchema,
5981
+ hash: hashSchema,
5982
+ status: exports_external.enum(["fresh", "stale-source", "stale-cache"]),
5983
+ files: exports_external.array(exports_external.object({
5984
+ relativePath: exports_external.enum([
5985
+ PROJECT_CONTEXT_FRAGMENT_PATH,
5986
+ "CLAUDE.md",
5987
+ ".codewith/CODEWITH.md",
5988
+ "AGENTS.md"
5989
+ ]),
5990
+ role: exports_external.enum(["fragment", "index"]),
5991
+ sha256: exports_external.string().regex(/^[a-f0-9]{64}$/)
5992
+ }).strict()).min(1).max(2)
5993
+ }).strict();
5975
5994
  var projectContextCacheSchema = exports_external.object({
5976
5995
  schema: exports_external.literal(PROJECT_CONTEXT_CACHE_SCHEMA),
5977
5996
  cached_at: isoTimestamp,
@@ -5999,6 +6018,9 @@ function computeProjectContextSourceHash(value) {
5999
6018
  return `sha256:${sha2562(stableStringify(normalized))}`;
6000
6019
  }
6001
6020
  function parseProjectContextBundle(input) {
6021
+ return parseProjectContextBundleInternal(input, true, true);
6022
+ }
6023
+ function parseProjectContextBundleInternal(input, allowLegacyHash, normalizeLegacyHash = false) {
6002
6024
  let encoded;
6003
6025
  try {
6004
6026
  const serialized = typeof input === "string" ? input : JSON.stringify(input);
@@ -6035,10 +6057,11 @@ function parseProjectContextBundle(input) {
6035
6057
  validateIdentityConsistency(bundle);
6036
6058
  rejectCredentialLikeBundle(bundle);
6037
6059
  const expected = computeProjectContextSourceHash(bundle);
6038
- if (bundle.hash !== expected) {
6060
+ const matchesLegacyHash = bundle.hash !== expected && allowLegacyHash && bundle.hash === computeLegacyProjectContextSourceHash(bundle);
6061
+ if (bundle.hash !== expected && !matchesLegacyHash) {
6039
6062
  throw new ProjectContextError("PROJECT_CONTEXT_HASH_MISMATCH", "bundle hash does not match its canonical allowlisted payload");
6040
6063
  }
6041
- return bundle;
6064
+ return matchesLegacyHash && normalizeLegacyHash ? { ...bundle, hash: expected } : bundle;
6042
6065
  }
6043
6066
  function planProjectContext(input) {
6044
6067
  const workspaceRoot = assertSafeWorkspaceRoot(input.workspace_root);
@@ -6286,6 +6309,8 @@ function applyProjectContext(options) {
6286
6309
  content: `${JSON.stringify(sessionManifest, null, 2)}
6287
6310
  `
6288
6311
  };
6312
+ const manifestContent = `${JSON.stringify(buildManifest(plan, now2), null, 2)}
6313
+ `;
6289
6314
  options.test_hooks?.before_compare?.({ attempt, plan });
6290
6315
  if (!hashesStillMatch(plan.expected_hashes, workspaceRoot)) {
6291
6316
  if (attempt === 0) {
@@ -6298,7 +6323,15 @@ function applyProjectContext(options) {
6298
6323
  return resultForPlan(plan, true, raceRetries, null);
6299
6324
  assertWorkspaceLockHeld(lockPath, lock, workspaceRoot);
6300
6325
  try {
6301
- snapshotPath = writeMetadataSnapshot(plan, now2);
6326
+ const metadataSnapshotPath = writeMetadataSnapshot(plan, now2);
6327
+ const rollbackSnapshotPath = writeProjectContextRollbackSnapshot(plan, now2, [
6328
+ { path: plan.fragment_path, content: plan.fragment, role: "fragment" },
6329
+ { path: plan.target_path, content: plan.target_content, role: "index" },
6330
+ { path: plan.cache_path, content: cacheContent, role: "config" },
6331
+ { path: sessionOutput.path, content: sessionOutput.content, role: "manifest" },
6332
+ { path: plan.manifest_path, content: manifestContent, role: "manifest" }
6333
+ ]);
6334
+ snapshotPath = rollbackSnapshotPath ?? metadataSnapshotPath;
6302
6335
  atomicWriteFile(plan.fragment_path, plan.fragment, workspaceRoot, 420, expectedPlanHash(plan, plan.fragment_path), undefined, options.test_hooks?.atomic_exchange_unavailable, undefined, options.test_hooks?.portable_create_only);
6303
6336
  options.test_hooks?.after_fragment?.({ attempt, plan });
6304
6337
  assertWorkspaceLockHeld(lockPath, lock, workspaceRoot);
@@ -6312,9 +6345,7 @@ function applyProjectContext(options) {
6312
6345
  options.test_hooks?.before_manifest?.({ attempt, plan });
6313
6346
  assertWorkspaceLockHeld(lockPath, lock, workspaceRoot);
6314
6347
  assertRenderedOutputsStable(plan, cacheContent, sessionOutput);
6315
- const manifest = buildManifest(plan, now2);
6316
- atomicWriteFile(plan.manifest_path, `${JSON.stringify(manifest, null, 2)}
6317
- `, workspaceRoot, 384, expectedPlanHash(plan, plan.manifest_path), undefined, options.test_hooks?.atomic_exchange_unavailable, undefined, options.test_hooks?.portable_create_only);
6348
+ atomicWriteFile(plan.manifest_path, manifestContent, workspaceRoot, 384, expectedPlanHash(plan, plan.manifest_path), undefined, options.test_hooks?.atomic_exchange_unavailable, undefined, options.test_hooks?.portable_create_only);
6318
6349
  return resultForPlan(plan, false, raceRetries, snapshotPath);
6319
6350
  } catch (error) {
6320
6351
  if (error instanceof ProjectContextHashRace && attempt === 0) {
@@ -6405,10 +6436,12 @@ function resolveBundleForApply(options, workspaceRoot, now2) {
6405
6436
  if (cache.project_id !== options.expected_project_id || cache.bundle.project.id !== options.expected_project_id) {
6406
6437
  throw new ProjectContextError("PROJECT_CONTEXT_CACHE_ID_MISMATCH", "cached project context belongs to a different project");
6407
6438
  }
6408
- const bundle = parseProjectContextBundle(cache.bundle);
6409
- if (bundle.revision !== cache.revision || bundle.hash !== cache.hash) {
6439
+ const cachedBundle = cache.bundle;
6440
+ if (cachedBundle.revision !== cache.revision || cachedBundle.hash !== cache.hash) {
6410
6441
  throw new ProjectContextError("PROJECT_CONTEXT_CACHE_INVALID", "cached revision or hash metadata is inconsistent");
6411
6442
  }
6443
+ const canonicalHash = computeProjectContextSourceHash(cachedBundle);
6444
+ const bundle = cachedBundle.hash === canonicalHash ? cachedBundle : { ...cachedBundle, hash: canonicalHash };
6412
6445
  const ageSeconds = Math.max(staleCacheAgeInSeconds(bundle.generated_at, now2, "bundle generated_at"), staleCacheAgeInSeconds(cache.cached_at, now2, "cache cached_at"));
6413
6446
  const maxAge = normalizeMaxStaleAge(options.max_stale_age_seconds);
6414
6447
  if (ageSeconds > maxAge) {
@@ -6505,11 +6538,13 @@ function parseManagedBlock(content, force) {
6505
6538
  if (structurallyInvalid) {
6506
6539
  if (!force)
6507
6540
  throw new ProjectContextError("MANAGED_BLOCK_INVALID", "managed project-context markers are duplicate, nested, malformed, or unbalanced");
6541
+ const firstMarkerRange = markerCommentRange(markerLines[0]);
6542
+ const lastMarkerRange = markerCommentRange(markerLines[markerLines.length - 1]);
6508
6543
  return {
6509
6544
  block: null,
6510
6545
  forceRange: {
6511
- start: markerLines[0].start,
6512
- end: lineContentEnd(markerLines[markerLines.length - 1])
6546
+ start: firstMarkerRange?.start ?? markerLines[0].start,
6547
+ end: lastMarkerRange?.end ?? lineContentEnd(markerLines[markerLines.length - 1])
6513
6548
  }
6514
6549
  };
6515
6550
  }
@@ -6540,6 +6575,21 @@ function parseManagedBlock(content, force) {
6540
6575
  forceRange: null
6541
6576
  };
6542
6577
  }
6578
+ function markerCommentRange(line) {
6579
+ const canonicalMarker = line.text.indexOf(PROJECT_CONTEXT_MANAGED_COMMENT);
6580
+ const legacyMarker = /@hasna\/configs project context/i.exec(line.text)?.index ?? -1;
6581
+ const marker = canonicalMarker >= 0 ? canonicalMarker : legacyMarker;
6582
+ if (marker < 0)
6583
+ return null;
6584
+ const commentStart = line.text.lastIndexOf("<!--", marker);
6585
+ const commentEnd = line.text.indexOf("-->", marker);
6586
+ if (commentStart < 0 || commentEnd < 0)
6587
+ return null;
6588
+ return {
6589
+ start: line.start + commentStart,
6590
+ end: line.start + commentEnd + "-->".length
6591
+ };
6592
+ }
6543
6593
  function parseMarkerLine(text) {
6544
6594
  const line = text.replace(/[\r\n]+$/, "");
6545
6595
  const canonical = line.match(/^<!-- Managed by @hasna\/configs project context (BEGIN|END) id=([A-Za-z0-9][A-Za-z0-9._:@+-]*) revision=([A-Za-z0-9%._~+-]+) hash=(sha256:[a-f0-9]{64}) -->$/);
@@ -6561,8 +6611,14 @@ function parseMarkerLine(text) {
6561
6611
  }
6562
6612
  function replaceOrAppendManagedBlock(content, block, parsed, legacy) {
6563
6613
  const range = parsed.block ?? parsed.forceRange ?? legacy;
6564
- if (range)
6565
- return `${content.slice(0, range.start)}${block}${content.slice(range.end)}`;
6614
+ if (range) {
6615
+ const before = content.slice(0, range.start);
6616
+ const after = content.slice(range.end);
6617
+ const eol2 = preferredEol(content);
6618
+ const beforeSeparator = before && !/[\r\n]$/.test(before) ? eol2 : "";
6619
+ const afterSeparator = after && !/^[\r\n]/.test(after) ? eol2 : "";
6620
+ return `${before}${beforeSeparator}${block}${afterSeparator}${after}`;
6621
+ }
6566
6622
  if (!content)
6567
6623
  return `${block}
6568
6624
  `;
@@ -6606,13 +6662,18 @@ function findLegacyCodewithWorkspaceSection(workspaceRoot, runtime, content, bun
6606
6662
  }
6607
6663
  function assertRevisionOrdering(plan, force) {
6608
6664
  const observations = [];
6665
+ const cache = readProjectContextCache(plan.cache_path, plan.workspace_root);
6666
+ const canonicalCacheHash = cache === null ? null : computeProjectContextSourceHash(cache.bundle);
6667
+ const normalizePersistedHash = (revision, hash) => cache !== null && canonicalCacheHash !== null && revision === cache.revision && hash === cache.hash ? canonicalCacheHash : hash;
6609
6668
  const manifest = readProjectContextManifest(plan.manifest_path, plan.workspace_root);
6610
6669
  if (manifest) {
6670
+ const manifestHashHasRecoveryProof = manifest.projectContext.hash === plan.bundle.hash || metadataSnapshotMatchesManifest(plan, manifest);
6671
+ const canonicalStateAlreadyInstalled = cache !== null && canonicalCacheHash === plan.bundle.hash && cache.project_id === plan.bundle.project.id && cache.revision === plan.bundle.revision && plan.marker !== null && plan.marker.id === plan.bundle.project.id && plan.marker.revision === plan.bundle.revision && plan.marker.hash === plan.bundle.hash && existsSync3(plan.fragment_path) && fragmentMatchesBundle(plan.fragment_path, plan.bundle, plan.workspace_root) && manifestHashHasRecoveryProof;
6611
6672
  observations.push({
6612
6673
  source: "manifest",
6613
6674
  id: manifest.projectContext.projectId,
6614
6675
  revision: manifest.projectContext.revision,
6615
- hash: manifest.projectContext.hash
6676
+ hash: canonicalStateAlreadyInstalled && manifest.projectContext.projectId === plan.bundle.project.id && manifest.projectContext.revision === plan.bundle.revision ? plan.bundle.hash : normalizePersistedHash(manifest.projectContext.revision, manifest.projectContext.hash)
6616
6677
  });
6617
6678
  const fragmentEntry = manifest.files.find((file) => file.relativePath === PROJECT_CONTEXT_FRAGMENT_PATH);
6618
6679
  if (fragmentEntry && existsSync3(plan.fragment_path)) {
@@ -6622,11 +6683,16 @@ function assertRevisionOrdering(plan, force) {
6622
6683
  }
6623
6684
  }
6624
6685
  }
6625
- const cache = readProjectContextCache(plan.cache_path, plan.workspace_root);
6626
6686
  if (cache)
6627
- observations.push({ source: "cache", id: cache.project_id, revision: cache.revision, hash: cache.hash });
6628
- if (plan.marker)
6629
- observations.push({ source: "marker", id: plan.marker.id, revision: plan.marker.revision, hash: plan.marker.hash });
6687
+ observations.push({ source: "cache", id: cache.project_id, revision: cache.revision, hash: canonicalCacheHash });
6688
+ if (plan.marker) {
6689
+ observations.push({
6690
+ source: "marker",
6691
+ id: plan.marker.id,
6692
+ revision: plan.marker.revision,
6693
+ hash: normalizePersistedHash(plan.marker.revision, plan.marker.hash)
6694
+ });
6695
+ }
6630
6696
  for (const observation of observations) {
6631
6697
  if (observation.id !== plan.bundle.project.id) {
6632
6698
  throw new ProjectContextError("PROJECT_CONTEXT_IDENTITY_CONFLICT", `${observation.source} belongs to another project`);
@@ -6746,6 +6812,10 @@ function buildSessionCompatibilityManifest(plan, now2) {
6746
6812
  };
6747
6813
  const targetOwner = isRecord(existing["targetOwner"]) ? existing["targetOwner"] : {};
6748
6814
  const adapterMode = plan.native_imports ? "native-imports" : "flattened-markdown";
6815
+ const existingProjectContext = isRecord(existing["projectContext"]) ? existing["projectContext"] : null;
6816
+ const existingProjectContextHash = existingProjectContext === null ? null : safeLegacyMetadataString(existingProjectContext["hash"], null);
6817
+ const existingSourceHash = typeof existing["sourceHash"] === "string" ? existing["sourceHash"] : null;
6818
+ const sourceHash = existingProjectContextHash === plan.bundle.hash && existingSourceHash !== null ? existingSourceHash : sha2562(stableStringify({ previous: existingSourceHash, projectContext: plan.bundle.hash }));
6749
6819
  return credentialSafeSessionManifest({
6750
6820
  schema: SESSION_RENDER_SCHEMA,
6751
6821
  tool,
@@ -6769,7 +6839,7 @@ function buildSessionCompatibilityManifest(plan, now2) {
6769
6839
  blockers: [],
6770
6840
  generatedAt: now2.toISOString(),
6771
6841
  env: sanitizeLegacyEnvironment(existing["env"]),
6772
- sourceHash: sha2562(stableStringify({ previous: typeof existing["sourceHash"] === "string" ? existing["sourceHash"] : null, projectContext: plan.bundle.hash })),
6842
+ sourceHash,
6773
6843
  sources,
6774
6844
  skippedSources: sanitizeLegacySkippedSources(existing["skippedSources"]),
6775
6845
  files: [...files.filter((file) => file["relativePath"] !== targetRelativePath), updatedTarget],
@@ -7025,6 +7095,77 @@ function writeMetadataSnapshot(plan, now2) {
7025
7095
  `, plan.workspace_root, 384);
7026
7096
  return snapshotPath;
7027
7097
  }
7098
+ function metadataSnapshotMatchesManifest(plan, manifest) {
7099
+ const snapshotDir = resolve(plan.workspace_root, ...PROJECT_CONTEXT_SNAPSHOT_DIR.split("/"));
7100
+ const snapshotPath = resolve(snapshotDir, `${safeFilename(manifest.projectContext.revision)}-${manifest.projectContext.hash.slice(-12)}.json`);
7101
+ if (!existsSync3(snapshotPath))
7102
+ return false;
7103
+ const record = readJsonRecord(snapshotPath, plan.workspace_root);
7104
+ const result = projectContextMetadataSnapshotSchema.safeParse(record);
7105
+ if (!result.success)
7106
+ return false;
7107
+ if (result.data.projectId !== manifest.projectContext.projectId || result.data.revision !== manifest.projectContext.revision || result.data.hash !== manifest.projectContext.hash || result.data.status !== manifest.projectContext.status)
7108
+ return false;
7109
+ const sortFiles = (files) => [...files].sort((left, right) => left.relativePath.localeCompare(right.relativePath));
7110
+ const snapshotFiles = sortFiles(result.data.files);
7111
+ const manifestFiles = sortFiles(manifest.files.map((file) => ({
7112
+ relativePath: file.relativePath,
7113
+ role: file.role,
7114
+ sha256: file.sha256
7115
+ })));
7116
+ return JSON.stringify(snapshotFiles) === JSON.stringify(manifestFiles);
7117
+ }
7118
+ function writeProjectContextRollbackSnapshot(plan, now2, outputs) {
7119
+ const targetExpectedHash = expectedPlanHash(plan, plan.target_path);
7120
+ if (targetExpectedHash === sha2562(plan.target_content))
7121
+ return null;
7122
+ const files = outputs.flatMap((output) => {
7123
+ const expectedHash = expectedPlanHash(plan, output.path);
7124
+ if (expectedHash === null)
7125
+ return [];
7126
+ const content = readUtf8RegularFile(output.path, plan.workspace_root, managedObservationMaxBytes(relativePosix(plan.workspace_root, output.path)));
7127
+ if (sha2562(content) !== expectedHash) {
7128
+ throw new ProjectContextHashRace(`managed path changed while creating rollback evidence: ${relativePosix(plan.workspace_root, output.path)}`);
7129
+ }
7130
+ return [{
7131
+ path: output.path,
7132
+ relativePath: relativePosix(plan.workspace_root, output.path),
7133
+ role: output.role,
7134
+ sha256: expectedHash,
7135
+ content
7136
+ }];
7137
+ });
7138
+ const afterFiles = outputs.map((output) => {
7139
+ const previousHash = expectedPlanHash(plan, output.path);
7140
+ const nextHash = sha2562(output.content);
7141
+ return {
7142
+ path: output.path,
7143
+ relativePath: relativePosix(plan.workspace_root, output.path),
7144
+ role: output.role,
7145
+ action: previousHash === null ? "create" : previousHash === nextHash ? "unchanged" : "update",
7146
+ sha256: nextHash
7147
+ };
7148
+ });
7149
+ const snapshotDir = resolve(plan.workspace_root, ...SESSION_RENDER_SNAPSHOT_RELATIVE_DIR.split("/"));
7150
+ ensureSafeDirectory(snapshotDir, plan.workspace_root, 448);
7151
+ const timestamp = now2.toISOString().replace(/[:.]/g, "-");
7152
+ const snapshotPath = resolve(snapshotDir, `${timestamp}-${randomUUID3()}.json`);
7153
+ const snapshot = {
7154
+ schema: "hasna.configs.session-render-snapshot/v2",
7155
+ createdAt: now2.toISOString(),
7156
+ tool: manifestTool(plan.runtime),
7157
+ profile: "project-context",
7158
+ targetHome: plan.workspace_root,
7159
+ targetKind: "project-root",
7160
+ manifestPath: plan.manifest_path,
7161
+ previousManifest: null,
7162
+ files,
7163
+ afterFiles
7164
+ };
7165
+ atomicWriteFile(snapshotPath, `${JSON.stringify(snapshot, null, 2)}
7166
+ `, plan.workspace_root, 384, null);
7167
+ return snapshotPath;
7168
+ }
7028
7169
  function readProjectContextManifest(path, workspaceRoot) {
7029
7170
  if (!existsSync3(path))
7030
7171
  return null;
@@ -7048,7 +7189,7 @@ function readProjectContextCache(path, workspaceRoot) {
7048
7189
  if (!result.success) {
7049
7190
  throw new ProjectContextError("PROJECT_CONTEXT_CACHE_INVALID", "cache is malformed or incompatible");
7050
7191
  }
7051
- const bundle = parseProjectContextBundle(result.data.bundle);
7192
+ const bundle = parseProjectContextBundleInternal(result.data.bundle, true);
7052
7193
  if (result.data.project_id !== bundle.project.id || result.data.revision !== bundle.revision || result.data.hash !== bundle.hash) {
7053
7194
  throw new ProjectContextError("PROJECT_CONTEXT_CACHE_INVALID", "cache metadata does not match its bundle");
7054
7195
  }
@@ -8364,12 +8505,23 @@ function removeHashForFingerprint(value) {
8364
8505
  return value;
8365
8506
  const copy = {};
8366
8507
  for (const [key, item] of Object.entries(value)) {
8367
- if (key === "hash")
8508
+ if (key === "generated_at" || key === "hash")
8368
8509
  continue;
8369
8510
  copy[key] = item;
8370
8511
  }
8371
8512
  return copy;
8372
8513
  }
8514
+ function computeLegacyProjectContextSourceHash(value) {
8515
+ if (!isRecord(value))
8516
+ return `sha256:${sha2562(stableStringify(value))}`;
8517
+ const copy = {};
8518
+ for (const [key, item] of Object.entries(value)) {
8519
+ if (key === "hash")
8520
+ continue;
8521
+ copy[key] = item;
8522
+ }
8523
+ return `sha256:${sha2562(stableStringify(copy))}`;
8524
+ }
8373
8525
  function sha2562(content) {
8374
8526
  return createHash2("sha256").update(content).digest("hex");
8375
8527
  }
@@ -1 +1 @@
1
- {"version":3,"file":"project-context.d.ts","sourceRoot":"","sources":["../../src/lib/project-context.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"project-context.d.ts","sourceRoot":"","sources":["../../src/lib/project-context.ts"],"names":[],"mappings":"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"}
package/dist/mcp/index.js CHANGED
@@ -5729,7 +5729,7 @@ function isSafeSingleLine(value) {
5729
5729
  function isSafeCommandArgument(value) {
5730
5730
  return /^[A-Za-z0-9_./:@+=,-]+$/.test(value) && !value.includes("://") && !value.startsWith("-") || /^--[a-z][a-z0-9-]*$/.test(value);
5731
5731
  }
5732
- var PROJECT_CONTEXT_SCHEMA = "hasna.projects.project_context_bundle.v1", PROJECT_CONTEXT_MAX_INPUT_BYTES, PROJECT_CONTEXT_MAX_RENDERED_BYTES, PROJECT_CONTEXT_MAX_COMMANDS = 6, PROJECT_CONTEXT_FRAGMENT_PATH = ".hasna/instructions/project-context.md", PROJECT_CONTEXT_CACHE_SCHEMA = "hasna.instructions.project-context-cache/v1", SESSION_COMPATIBILITY_MANIFEST_MAX_BYTES, FOREIGN_INPUT_MAX_BYTES, SESSION_MANAGED_OUTPUT_MAX_BYTES, SESSION_MANAGED_OUTPUT_WARN_BYTES, PROJECT_CONTEXT_LOCK_STALE_MS, PROJECT_KINDS, PROJECT_STATUSES, LINK_STATES, RESOLUTION_SOURCES, safeId, nullableId, producerSlug, producerName, safeOptionalDisplay, isoTimestamp, revisionSchema, hashSchema, absolutePath, commandArg, commandSchema, projectContextBundleSchema, storedManifestProjectContextSchema, storedManifestFileSchema, storedManifestObservationSchema, projectContextCacheSchema;
5732
+ var PROJECT_CONTEXT_SCHEMA = "hasna.projects.project_context_bundle.v1", PROJECT_CONTEXT_MAX_INPUT_BYTES, PROJECT_CONTEXT_MAX_RENDERED_BYTES, PROJECT_CONTEXT_MAX_COMMANDS = 6, PROJECT_CONTEXT_FRAGMENT_PATH = ".hasna/instructions/project-context.md", PROJECT_CONTEXT_CACHE_SCHEMA = "hasna.instructions.project-context-cache/v1", SESSION_COMPATIBILITY_MANIFEST_MAX_BYTES, FOREIGN_INPUT_MAX_BYTES, SESSION_MANAGED_OUTPUT_MAX_BYTES, SESSION_MANAGED_OUTPUT_WARN_BYTES, PROJECT_CONTEXT_LOCK_STALE_MS, PROJECT_KINDS, PROJECT_STATUSES, LINK_STATES, RESOLUTION_SOURCES, safeId, nullableId, producerSlug, producerName, safeOptionalDisplay, isoTimestamp, revisionSchema, hashSchema, absolutePath, commandArg, commandSchema, projectContextBundleSchema, storedManifestProjectContextSchema, storedManifestFileSchema, storedManifestObservationSchema, projectContextMetadataSnapshotSchema, projectContextCacheSchema;
5733
5733
  var init_project_context = __esm(() => {
5734
5734
  init_zod();
5735
5735
  init_redact();
@@ -5860,6 +5860,25 @@ var init_project_context = __esm(() => {
5860
5860
  });
5861
5861
  }
5862
5862
  });
5863
+ projectContextMetadataSnapshotSchema = exports_external.object({
5864
+ schema: exports_external.literal("hasna.configs.session-render-snapshot/v1"),
5865
+ kind: exports_external.literal("project-context-metadata"),
5866
+ createdAt: isoTimestamp,
5867
+ projectId: safeId,
5868
+ revision: revisionSchema,
5869
+ hash: hashSchema,
5870
+ status: exports_external.enum(["fresh", "stale-source", "stale-cache"]),
5871
+ files: exports_external.array(exports_external.object({
5872
+ relativePath: exports_external.enum([
5873
+ PROJECT_CONTEXT_FRAGMENT_PATH,
5874
+ "CLAUDE.md",
5875
+ ".codewith/CODEWITH.md",
5876
+ "AGENTS.md"
5877
+ ]),
5878
+ role: exports_external.enum(["fragment", "index"]),
5879
+ sha256: exports_external.string().regex(/^[a-f0-9]{64}$/)
5880
+ }).strict()).min(1).max(2)
5881
+ }).strict();
5863
5882
  projectContextCacheSchema = exports_external.object({
5864
5883
  schema: exports_external.literal(PROJECT_CONTEXT_CACHE_SCHEMA),
5865
5884
  cached_at: isoTimestamp,
@@ -7239,7 +7258,7 @@ var init_sync_dir = __esm(() => {
7239
7258
  var require_package = __commonJS((exports, module) => {
7240
7259
  module.exports = {
7241
7260
  name: "@hasna/instructions",
7242
- version: "0.4.25",
7261
+ version: "0.4.26",
7243
7262
  description: "AI coding agent instruction & configuration manager \u2014 store, version, apply, and share all your AI coding configs. CLI + MCP + HTTP API (instructions-serve) + generated SDK + Dashboard.",
7244
7263
  type: "module",
7245
7264
  main: "dist/index.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/instructions",
3
- "version": "0.4.25",
3
+ "version": "0.4.26",
4
4
  "description": "AI coding agent instruction & configuration manager \u2014 store, version, apply, and share all your AI coding configs. CLI + MCP + HTTP API (instructions-serve) + generated SDK + Dashboard.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",