@hasna/instructions 0.7.0 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -11
- package/dist/chunks/{apply-7svah2qm.js → apply-ps6jjt6k.js} +3 -3
- package/dist/chunks/{apply-jp13sa1e.js → apply-wj7wh5km.js} +3 -3
- package/dist/chunks/{index-1cnyjnd7.js → index-18j7x3xw.js} +2 -2
- package/dist/chunks/{index-3djthcm6.js → index-27az1qb1.js} +28 -1
- package/dist/chunks/{index-fwbs6tma.js → index-ape24zc0.js} +2 -2
- package/dist/chunks/{index-bzyxvwcd.js → index-ek15201v.js} +2 -2
- package/dist/chunks/{index-arrrx0ed.js → index-mvckkf15.js} +39 -20
- package/dist/chunks/{index-7m4j8a33.js → index-n6nh6f5r.js} +235 -20
- package/dist/chunks/{index-4pfq42t5.js → index-pq18fdbj.js} +146 -32
- package/dist/chunks/{index-n3fjspr0.js → index-preyvj8n.js} +28 -1
- package/dist/chunks/{index-z3ma4aqk.js → index-y8410ve0.js} +3 -3
- package/dist/chunks/{local-5wvv5xv3.js → local-1c1qxzvx.js} +155 -4
- package/dist/chunks/{local-zxa5dpf4.js → local-hc67bynj.js} +155 -4
- package/dist/chunks/{s3-backup-n2z4fwyh.js → s3-backup-hxe3zpfz.js} +1 -1
- package/dist/chunks/{s3-object-store-90tgbh6k.js → s3-object-store-n0s82swt.js} +1 -1
- package/dist/chunks/{sync-r8t7zsp3.js → sync-12m3vs6g.js} +4 -4
- package/dist/chunks/{sync-2075deve.js → sync-azd9t4p8.js} +4 -4
- package/dist/chunks/{template-wgnzdn7h.js → template-e4qrxs8p.js} +1 -1
- package/dist/chunks/{template-fsfxpe4p.js → template-nhn124zd.js} +1 -1
- package/dist/cli/index.js +860 -181
- package/dist/data/config-store.d.ts +22 -6
- package/dist/data/config-store.d.ts.map +1 -1
- package/dist/db/configs.d.ts +4 -1
- package/dist/db/configs.d.ts.map +1 -1
- package/dist/db/local.d.ts +1 -1
- package/dist/db/local.d.ts.map +1 -1
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +940 -134
- package/dist/lib/asset-plan.d.ts.map +1 -1
- package/dist/lib/codewith-shared-todos-storage-standard.d.ts.map +1 -1
- package/dist/lib/compact-output.d.ts +2 -18
- package/dist/lib/compact-output.d.ts.map +1 -1
- package/dist/lib/dangerous-operation-guard-standard.d.ts.map +1 -1
- package/dist/lib/export.d.ts.map +1 -1
- package/dist/lib/global-agent-rules-standard.d.ts.map +1 -1
- package/dist/lib/global-source-coverage.d.ts +12 -7
- package/dist/lib/global-source-coverage.d.ts.map +1 -1
- package/dist/lib/import.d.ts.map +1 -1
- package/dist/lib/instruction-graph.d.ts +1 -1
- package/dist/lib/instruction-graph.d.ts.map +1 -1
- package/dist/lib/instruction-source-policy.d.ts +6 -0
- package/dist/lib/instruction-source-policy.d.ts.map +1 -0
- package/dist/lib/platform-profiles.d.ts.map +1 -1
- package/dist/lib/project-dashboard-standard.d.ts.map +1 -1
- package/dist/lib/session-apply.d.ts +24 -0
- package/dist/lib/session-apply.d.ts.map +1 -1
- package/dist/lib/session-refresh.d.ts +30 -0
- package/dist/lib/session-refresh.d.ts.map +1 -0
- package/dist/lib/session-render.d.ts +34 -1
- package/dist/lib/session-render.d.ts.map +1 -1
- package/dist/lib/transforms.d.ts +1 -0
- package/dist/lib/transforms.d.ts.map +1 -1
- package/dist/mcp/index.js +23 -22
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/sdk/index.js +46 -3
- package/dist/sdk/v1-client.d.ts +10 -3
- package/dist/sdk/v1-client.d.ts.map +1 -1
- package/dist/sdk/v1.generated.d.ts +52 -2
- package/dist/sdk/v1.generated.d.ts.map +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +215 -15
- package/dist/server/openapi.d.ts +240 -3
- package/dist/server/openapi.d.ts.map +1 -1
- package/dist/server/v1.d.ts.map +1 -1
- package/dist/storage/cloud-store.d.ts +2 -15
- package/dist/storage/cloud-store.d.ts.map +1 -1
- package/dist/storage/index.js +39 -20
- package/dist/storage/s3-object-store.d.ts.map +1 -1
- package/dist/types/index.d.ts +49 -2
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -16,7 +16,12 @@ var __export = (target, all) => {
|
|
|
16
16
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
17
17
|
|
|
18
18
|
// src/types/index.ts
|
|
19
|
-
|
|
19
|
+
function validateExpectedConfigVersion(value) {
|
|
20
|
+
if (value !== undefined && (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1)) {
|
|
21
|
+
throw new InvalidExpectedVersionError;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
var CONFIG_KINDS, CONFIG_CATEGORIES, CONFIG_AGENTS, CONFIG_TRANSFORMS, CONFIG_FORMATS, PROFILE_CONFIG_BINDING_SCHEMA = "hasna.instructions.profile-config-binding/v1", INSTRUCTION_ACTIVATION_MODES, INSTRUCTION_FALLBACKS, PROFILE_ASSET_BINDING_SCHEMA = "hasna.instructions.profile-asset-binding/v1", ASSET_KINDS, ASSET_DESTINATION_STRATEGIES, ASSET_SCOPES, ASSET_UNINSTALL_POLICIES, ASSET_ROLLBACK_POLICIES, INSTRUCTIONS_DOMAIN_ARCHIVE_SCHEMA = "hasna.instructions.domain-archive/v2", InvalidExpectedVersionError, ConfigVersionConflictError, ConfigNotFoundError, ProfileNotFoundError, ConfigApplyError, TemplateRenderError;
|
|
20
25
|
var init_types = __esm(() => {
|
|
21
26
|
CONFIG_KINDS = ["file", "reference"];
|
|
22
27
|
CONFIG_CATEGORIES = [
|
|
@@ -33,6 +38,7 @@ var init_types = __esm(() => {
|
|
|
33
38
|
"claude",
|
|
34
39
|
"codex",
|
|
35
40
|
"opencode",
|
|
41
|
+
"sumi",
|
|
36
42
|
"cursor",
|
|
37
43
|
"codewith",
|
|
38
44
|
"aicopilot",
|
|
@@ -53,6 +59,7 @@ var init_types = __esm(() => {
|
|
|
53
59
|
"claude-passthrough",
|
|
54
60
|
"codex-flat",
|
|
55
61
|
"opencode-flat",
|
|
62
|
+
"sumi-flat",
|
|
56
63
|
"cursor-mdc",
|
|
57
64
|
"skill-neutral"
|
|
58
65
|
];
|
|
@@ -71,6 +78,25 @@ var init_types = __esm(() => {
|
|
|
71
78
|
ASSET_SCOPES = ["global", "project", "session"];
|
|
72
79
|
ASSET_UNINSTALL_POLICIES = ["remove-managed", "retain"];
|
|
73
80
|
ASSET_ROLLBACK_POLICIES = ["snapshot", "installer-receipt", "none"];
|
|
81
|
+
InvalidExpectedVersionError = class InvalidExpectedVersionError extends Error {
|
|
82
|
+
code = "INVALID_EXPECTED_VERSION";
|
|
83
|
+
constructor() {
|
|
84
|
+
super("expected_version must be a positive safe integer");
|
|
85
|
+
this.name = "InvalidExpectedVersionError";
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
ConfigVersionConflictError = class ConfigVersionConflictError extends Error {
|
|
89
|
+
config_id;
|
|
90
|
+
expected_version;
|
|
91
|
+
code = "CONFIG_VERSION_CONFLICT";
|
|
92
|
+
status = 409;
|
|
93
|
+
constructor(config_id, expected_version) {
|
|
94
|
+
super(`Config version conflict: ${config_id} no longer has expected version ${expected_version}`);
|
|
95
|
+
this.config_id = config_id;
|
|
96
|
+
this.expected_version = expected_version;
|
|
97
|
+
this.name = "ConfigVersionConflictError";
|
|
98
|
+
}
|
|
99
|
+
};
|
|
74
100
|
ConfigNotFoundError = class ConfigNotFoundError extends Error {
|
|
75
101
|
constructor(id) {
|
|
76
102
|
super(`Config not found: ${id}`);
|
|
@@ -143,6 +169,31 @@ function boundedReadPage(items, total, options = {}) {
|
|
|
143
169
|
}
|
|
144
170
|
var init_bounded_read = () => {};
|
|
145
171
|
|
|
172
|
+
// src/lib/instruction-source-policy.ts
|
|
173
|
+
function isRetiredInstructionSource(config) {
|
|
174
|
+
return config.tags.some((tag) => tag === "retired-global-source" || tag === "retired-instruction-source");
|
|
175
|
+
}
|
|
176
|
+
function instructionSourceRejection(config) {
|
|
177
|
+
if (isRetiredInstructionSource(config) || config.tags.includes("config-only")) {
|
|
178
|
+
return "source is retired or explicitly configuration-only";
|
|
179
|
+
}
|
|
180
|
+
if (config.category !== "rules")
|
|
181
|
+
return `category ${config.category} is not an instruction source; classify reviewed prose as rules`;
|
|
182
|
+
if (config.format !== "markdown" && config.format !== "text")
|
|
183
|
+
return `format ${config.format} is not instruction prose`;
|
|
184
|
+
if (config.is_template)
|
|
185
|
+
return "unresolved templates must be rendered and reviewed before prompt injection";
|
|
186
|
+
if (!config.content.trim())
|
|
187
|
+
return "instruction source is empty";
|
|
188
|
+
if (config.content.includes("\x00"))
|
|
189
|
+
return "instruction source contains binary content";
|
|
190
|
+
const target = config.target_path?.split(/[\\/]/).pop() ?? "";
|
|
191
|
+
if (/\.(?:json|toml|yaml|yml|ini|sh|bash|zsh|fish|js|ts|py|rules)$/i.test(target)) {
|
|
192
|
+
return "target is an executable, provider policy, or settings file rather than a prompt";
|
|
193
|
+
}
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
|
|
146
197
|
// src/lib/global-agent-rules-standard.ts
|
|
147
198
|
import { createHash } from "crypto";
|
|
148
199
|
function parseAgentOperatingRulesVersion(content) {
|
|
@@ -246,9 +297,13 @@ async function ensureGlobalAgentRulesStandardConfig(store = resolveConfigStore()
|
|
|
246
297
|
let existing;
|
|
247
298
|
try {
|
|
248
299
|
existing = await store.getConfig(GLOBAL_AGENT_RULES_STANDARD_SLUG);
|
|
249
|
-
} catch {
|
|
300
|
+
} catch (error) {
|
|
301
|
+
if (!(error instanceof ConfigNotFoundError))
|
|
302
|
+
throw error;
|
|
250
303
|
return await store.createConfig(standardConfigInput(resolveAgentOperatingRulesPayload(null)));
|
|
251
304
|
}
|
|
305
|
+
if (isRetiredInstructionSource(existing))
|
|
306
|
+
return existing;
|
|
252
307
|
const payload = resolveAgentOperatingRulesPayload(existing.content);
|
|
253
308
|
const input = standardConfigInput(payload);
|
|
254
309
|
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)) {
|
|
@@ -258,6 +313,7 @@ async function ensureGlobalAgentRulesStandardConfig(store = resolveConfigStore()
|
|
|
258
313
|
}
|
|
259
314
|
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.26", AGENT_OPERATING_RULES_SOURCE_SET_VERSION = "2026-08-11", 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 = "486844a3d869e3dabc2f33fd66479d4e2fb0a0d1864a3d8a3dd05669eb3f1b77", 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, GLOBAL_AGENT_RULES_STANDARD_CONTENT;
|
|
260
315
|
var init_global_agent_rules_standard = __esm(() => {
|
|
316
|
+
init_types();
|
|
261
317
|
init_config_store();
|
|
262
318
|
AGENT_OPERATING_RULES_SENTINEL_PATTERN = /<!--\s*hasna:agent-operating-rules\s+v=([0-9]+\.[0-9]+\.[0-9]+)\s*-->/i;
|
|
263
319
|
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})\)/;
|
|
@@ -384,21 +440,23 @@ async function ensureCodewithSharedTodosStorageStandardConfig(store = resolveCon
|
|
|
384
440
|
let config;
|
|
385
441
|
try {
|
|
386
442
|
const existing = await store.getConfig(CODEWITH_SHARED_TODOS_STORAGE_STANDARD_SLUG);
|
|
443
|
+
if (isRetiredInstructionSource(existing))
|
|
444
|
+
return existing;
|
|
387
445
|
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)) {
|
|
388
446
|
config = await store.updateConfig(existing.id, input);
|
|
389
447
|
} else {
|
|
390
448
|
config = existing;
|
|
391
449
|
}
|
|
392
|
-
} catch {
|
|
450
|
+
} catch (error) {
|
|
451
|
+
if (!(error instanceof ConfigNotFoundError))
|
|
452
|
+
throw error;
|
|
393
453
|
config = await store.createConfig(input);
|
|
394
454
|
}
|
|
395
|
-
for (const profile of await store.listProfiles()) {
|
|
396
|
-
await store.addConfigToProfile(profile.id, config.id);
|
|
397
|
-
}
|
|
398
455
|
return config;
|
|
399
456
|
}
|
|
400
457
|
var CODEWITH_SHARED_TODOS_STORAGE_STANDARD_SLUG = "codewith-shared-todos-storage-standard", CODEWITH_SHARED_TODOS_STORAGE_POLICY_REFERENCE = "codewith/shared-todos-storage/v1", CODEWITH_SHARED_TODOS_STORAGE_STANDARD_CONTENT;
|
|
401
458
|
var init_codewith_shared_todos_storage_standard = __esm(() => {
|
|
459
|
+
init_types();
|
|
402
460
|
init_config_store();
|
|
403
461
|
CODEWITH_SHARED_TODOS_STORAGE_STANDARD_CONTENT = `# Codewith Shared Todos Storage Standard
|
|
404
462
|
|
|
@@ -7292,7 +7350,7 @@ function sha2562(content) {
|
|
|
7292
7350
|
function isRecord(value) {
|
|
7293
7351
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
7294
7352
|
}
|
|
7295
|
-
var PROJECT_CONTEXT_SCHEMA = "hasna.projects.project_context_bundle.v1", PROJECT_CONTEXT_SCHEMA_V2 = "hasna.projects.project_context_bundle.v2", PROJECT_CONTEXT_SUPPORTED_SCHEMAS, projectContextSchema, 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/projects/project-context-manifest.json", PROJECT_CONTEXT_CACHE_PATH = ".hasna/projects/project-context-cache.json", PROJECT_CONTEXT_LOCK_PATH = ".hasna/projects/project-context.lock", PROJECT_CONTEXT_SNAPSHOT_DIR = ".hasna/projects/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_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, financeText, financeLegalEntity, financeProjectMetadataSchema, commandSchema, projectContextBundleSchema, storedManifestProjectContextSchema, storedManifestFileSchema, storedManifestObservationSchema, projectContextMetadataSnapshotSchema, projectContextCacheSchema, ProjectContextError, ProjectContextHashRace, anchoredFsOps, atomicExchange, atomicExchangeLibraries;
|
|
7353
|
+
var PROJECT_CONTEXT_SCHEMA = "hasna.projects.project_context_bundle.v1", PROJECT_CONTEXT_SCHEMA_V2 = "hasna.projects.project_context_bundle.v2", PROJECT_CONTEXT_SUPPORTED_SCHEMAS, projectContextSchema, 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/projects/project-context-manifest.json", PROJECT_CONTEXT_CACHE_PATH = ".hasna/projects/project-context-cache.json", PROJECT_CONTEXT_LOCK_PATH = ".hasna/projects/project-context.lock", PROJECT_CONTEXT_SNAPSHOT_DIR = ".hasna/projects/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, financeText, financeLegalEntity, financeProjectMetadataSchema, commandSchema, projectContextBundleSchema, storedManifestProjectContextSchema, storedManifestFileSchema, storedManifestObservationSchema, projectContextMetadataSnapshotSchema, projectContextCacheSchema, ProjectContextError, ProjectContextHashRace, anchoredFsOps, atomicExchange, atomicExchangeLibraries;
|
|
7296
7354
|
var init_project_context = __esm(() => {
|
|
7297
7355
|
init_zod();
|
|
7298
7356
|
init_redact();
|
|
@@ -7305,6 +7363,7 @@ var init_project_context = __esm(() => {
|
|
|
7305
7363
|
SESSION_COMPATIBILITY_MANIFEST_MAX_BYTES = 8 * 1024 * 1024;
|
|
7306
7364
|
FOREIGN_INPUT_MAX_BYTES = 256 * 1024;
|
|
7307
7365
|
SESSION_MANAGED_OUTPUT_MAX_BYTES = SESSION_COMPATIBILITY_MANIFEST_MAX_BYTES;
|
|
7366
|
+
SESSION_MANAGED_INPUT_MAX_BYTES = SESSION_MANAGED_OUTPUT_MAX_BYTES;
|
|
7308
7367
|
SESSION_MANAGED_OUTPUT_PATHS = [
|
|
7309
7368
|
".hasna/session-render-manifest.json",
|
|
7310
7369
|
".codewith/.hasna/session-render-manifest.json",
|
|
@@ -7604,6 +7663,9 @@ function buildCodexAgentsMd(source, context = {}) {
|
|
|
7604
7663
|
function buildOpenCodeAgentsMd(source, context = {}) {
|
|
7605
7664
|
return flattenWithRules(source, context);
|
|
7606
7665
|
}
|
|
7666
|
+
function buildSumiAgentsMd(source, context = {}) {
|
|
7667
|
+
return flattenWithRules(source, context);
|
|
7668
|
+
}
|
|
7607
7669
|
function buildCursorMdc(source) {
|
|
7608
7670
|
const stem = source.target_path ? basename2(source.target_path, extname(source.target_path)) : source.slug;
|
|
7609
7671
|
const description = source.name || stem;
|
|
@@ -7632,6 +7694,8 @@ function applyTransform(source, output, context = {}) {
|
|
|
7632
7694
|
return buildCodexAgentsMd(source, context);
|
|
7633
7695
|
case "opencode-flat":
|
|
7634
7696
|
return buildOpenCodeAgentsMd(source, context);
|
|
7697
|
+
case "sumi-flat":
|
|
7698
|
+
return buildSumiAgentsMd(source, context);
|
|
7635
7699
|
case "cursor-mdc":
|
|
7636
7700
|
return buildCursorMdc(source);
|
|
7637
7701
|
case "skill-neutral":
|
|
@@ -8050,6 +8114,7 @@ var init_asset_plan = __esm(() => {
|
|
|
8050
8114
|
codex: "cli",
|
|
8051
8115
|
cursor: "ide",
|
|
8052
8116
|
opencode: "cli",
|
|
8117
|
+
sumi: "cli",
|
|
8053
8118
|
codewith: "cli",
|
|
8054
8119
|
qwen: "cli",
|
|
8055
8120
|
aicopilot: "cli",
|
|
@@ -8698,9 +8763,19 @@ function skippedSource(source, reason) {
|
|
|
8698
8763
|
};
|
|
8699
8764
|
}
|
|
8700
8765
|
function normalizeSources(sources, tool, allowEmptySources) {
|
|
8701
|
-
const
|
|
8766
|
+
const providerSkipped = [];
|
|
8767
|
+
const normalized = sources.flatMap((source, index) => {
|
|
8702
8768
|
if (!source.id.trim())
|
|
8703
8769
|
throw new Error("Session instruction source id is required.");
|
|
8770
|
+
if (source.targetProviders?.length && !providerTargetsTool(source.targetProviders, tool)) {
|
|
8771
|
+
providerSkipped.push({
|
|
8772
|
+
id: source.id,
|
|
8773
|
+
label: source.label ?? source.id,
|
|
8774
|
+
targetProviders: source.targetProviders,
|
|
8775
|
+
reason: "instruction source targets a different provider"
|
|
8776
|
+
});
|
|
8777
|
+
return [];
|
|
8778
|
+
}
|
|
8704
8779
|
const floored = applyAgentOperatingRulesFloor(source, source.content ?? "");
|
|
8705
8780
|
const content = filterProviderOnlyBlocks(floored.content, tool);
|
|
8706
8781
|
const normalized2 = {
|
|
@@ -8719,7 +8794,7 @@ function normalizeSources(sources, tool, allowEmptySources) {
|
|
|
8719
8794
|
if (!allowEmptySources && !normalized2.content.trim() && normalized2.resolvedRules.length === 0 && !hasPathReferences) {
|
|
8720
8795
|
throw new Error(`Session instruction source "${source.id}" is empty. Pass --allow-empty-sources only for explicit empty renders.`);
|
|
8721
8796
|
}
|
|
8722
|
-
return normalized2;
|
|
8797
|
+
return [normalized2];
|
|
8723
8798
|
});
|
|
8724
8799
|
const originalOrder = [...normalized].sort(compareSessionInstructionSources);
|
|
8725
8800
|
const deduplicated = deduplicateSemanticPolicySources(normalized);
|
|
@@ -8727,7 +8802,7 @@ function normalizeSources(sources, tool, allowEmptySources) {
|
|
|
8727
8802
|
validateTargetedReplacementSources(originalOrder, ordered, deduplicated.skipped, tool);
|
|
8728
8803
|
rejectDuplicateSourceSlugs(ordered);
|
|
8729
8804
|
rejectDuplicateRulePaths(ordered);
|
|
8730
|
-
return { sources: ordered, skipped: deduplicated.skipped };
|
|
8805
|
+
return { sources: ordered, skipped: [...providerSkipped, ...deduplicated.skipped] };
|
|
8731
8806
|
}
|
|
8732
8807
|
function compareSessionInstructionSources(a, b) {
|
|
8733
8808
|
return SESSION_LAYER_RANK[a.resolvedLayer] - SESSION_LAYER_RANK[b.resolvedLayer] || a.resolvedOrder - b.resolvedOrder || a.id.localeCompare(b.id);
|
|
@@ -9332,6 +9407,11 @@ function isNativeProfileSessionTarget(input) {
|
|
|
9332
9407
|
return (input.tool === "grok" || input.tool === "devin") && Boolean(input.targetHome?.trim()) && !input.projectRoot;
|
|
9333
9408
|
}
|
|
9334
9409
|
function adapterFor(input) {
|
|
9410
|
+
if (input.tool === "sumi" && input.projectRoot) {
|
|
9411
|
+
if (input.providerSurface)
|
|
9412
|
+
throw new Error(`Provider surface ${input.providerSurface} is not valid for Sumi.`);
|
|
9413
|
+
return Object.freeze({ ...SESSION_TOOL_ADAPTERS.sumi, projectScoped: true, envVar: undefined });
|
|
9414
|
+
}
|
|
9335
9415
|
if (input.tool === "opencode" && input.providerSurface) {
|
|
9336
9416
|
if (input.providerSurface !== "opencode-config-instructions" && input.providerSurface !== "opencode-agents-md") {
|
|
9337
9417
|
throw new Error(`Provider surface ${input.providerSurface} is not valid for OpenCode.`);
|
|
@@ -9373,7 +9453,7 @@ function adapterFor(input) {
|
|
|
9373
9453
|
}
|
|
9374
9454
|
if (input.tool !== "codewith")
|
|
9375
9455
|
return SESSION_TOOL_ADAPTERS[input.tool];
|
|
9376
|
-
const gatedNativeImports = input.codewithNativeImports
|
|
9456
|
+
const gatedNativeImports = input.codewithNativeImports ?? (process.env[CODEWITH_NATIVE_IMPORTS_ENV] === "1" || process.env[CODEWITH_NATIVE_IMPORTS_ENV] === "true");
|
|
9377
9457
|
return gatedNativeImports ? CODEWITH_NATIVE_ADAPTER : CODEWITH_FLATTENED_ADAPTER;
|
|
9378
9458
|
}
|
|
9379
9459
|
function getHomeDir() {
|
|
@@ -9424,6 +9504,13 @@ function assertSafeTargetRoot(targetHome) {
|
|
|
9424
9504
|
return normalized;
|
|
9425
9505
|
}
|
|
9426
9506
|
function resolveRenderTarget(input, adapter) {
|
|
9507
|
+
if (input.tool === "sumi" && !input.projectRoot && !input.targetHome?.trim()) {
|
|
9508
|
+
return {
|
|
9509
|
+
targetHome: defaultTargetHome(input.tool, input.profile, input.sessionId),
|
|
9510
|
+
targetKind: "blocked",
|
|
9511
|
+
blockers: ["Sumi requires --target-home from `sumi debug paths config`, or --project-root for repository AGENTS.md."]
|
|
9512
|
+
};
|
|
9513
|
+
}
|
|
9427
9514
|
if (adapter.projectScoped) {
|
|
9428
9515
|
if (!input.projectRoot) {
|
|
9429
9516
|
const label = input.tool === "cursor" ? "Cursor rules" : input.tool === "antigravity" ? "Antigravity rules" : `${adapter.description.split(".")[0]} files`;
|
|
@@ -9525,6 +9612,14 @@ function planSessionRender(input) {
|
|
|
9525
9612
|
const normalized = normalizeSources(input.sources, input.tool, allowEmptySources);
|
|
9526
9613
|
const composed = composeSources(normalized.sources, input.tool);
|
|
9527
9614
|
const orderedSources = composed.sources;
|
|
9615
|
+
if (input.tool === "sumi") {
|
|
9616
|
+
for (const source of orderedSources) {
|
|
9617
|
+
const activation = source.metadata?.["activation"];
|
|
9618
|
+
if (source.globs?.length || source.resolvedRules.some((rule) => rule.globs?.length) || activation?.mode && activation.mode !== "always") {
|
|
9619
|
+
throw new Error(`Sumi AGENTS.md cannot preserve conditional activation for source ${source.id}; compile a profile with an explicit supported fallback.`);
|
|
9620
|
+
}
|
|
9621
|
+
}
|
|
9622
|
+
}
|
|
9528
9623
|
const skippedSources = [
|
|
9529
9624
|
...input.skippedSources ?? [],
|
|
9530
9625
|
...normalized.skipped,
|
|
@@ -9568,6 +9663,7 @@ function planSessionRender(input) {
|
|
|
9568
9663
|
adapterMode: adapter.mode,
|
|
9569
9664
|
profile: input.profile,
|
|
9570
9665
|
sessionId: input.sessionId ?? null,
|
|
9666
|
+
...input.refreshSelector ? { refreshSelector: input.refreshSelector } : {},
|
|
9571
9667
|
targetHome,
|
|
9572
9668
|
targetKind,
|
|
9573
9669
|
targetOwner,
|
|
@@ -9741,8 +9837,9 @@ function selectProfileConfigsForSessionRender(configs, tool) {
|
|
|
9741
9837
|
skippedSources.push(skippedProfileConfig(config, ["opencode"], "provider settings belong to OpenCode"));
|
|
9742
9838
|
continue;
|
|
9743
9839
|
}
|
|
9744
|
-
|
|
9745
|
-
|
|
9840
|
+
const sourceRejection = instructionSourceRejection(config);
|
|
9841
|
+
if (sourceRejection) {
|
|
9842
|
+
skippedSources.push(skippedProfileConfig(config, [], sourceRejection));
|
|
9746
9843
|
continue;
|
|
9747
9844
|
}
|
|
9748
9845
|
const output = config.outputs.find((candidate) => candidate.agent === tool);
|
|
@@ -9750,7 +9847,7 @@ function selectProfileConfigsForSessionRender(configs, tool) {
|
|
|
9750
9847
|
skippedSources.push(skippedProfileConfig(config, [config.agent], "rule targets a different provider"));
|
|
9751
9848
|
continue;
|
|
9752
9849
|
}
|
|
9753
|
-
const selectedContent = output ? applyTransform(config, output, { configs }) : config.content;
|
|
9850
|
+
const selectedContent = output ? applyTransform(config, output, { configs: [config] }) : config.content;
|
|
9754
9851
|
sources.push({
|
|
9755
9852
|
config,
|
|
9756
9853
|
source: sourceFromConfig({ ...config, content: selectedContent }, sources.length)
|
|
@@ -10159,6 +10256,7 @@ var init_session_render = __esm(() => {
|
|
|
10159
10256
|
"codex",
|
|
10160
10257
|
"cursor",
|
|
10161
10258
|
"opencode",
|
|
10259
|
+
"sumi",
|
|
10162
10260
|
"codewith",
|
|
10163
10261
|
"qwen",
|
|
10164
10262
|
"aicopilot",
|
|
@@ -10247,6 +10345,15 @@ var init_session_render = __esm(() => {
|
|
|
10247
10345
|
description: "OpenCode AGENTS.md plus opencode.json instructions pointing at managed fragments.",
|
|
10248
10346
|
providerSurface: "legacy-dual"
|
|
10249
10347
|
},
|
|
10348
|
+
sumi: {
|
|
10349
|
+
tool: "sumi",
|
|
10350
|
+
mode: "flattened-markdown",
|
|
10351
|
+
indexFile: "AGENTS.md",
|
|
10352
|
+
managedDir: SESSION_RENDER_INSTRUCTIONS_MANAGED_DIR,
|
|
10353
|
+
envVar: "SUMI_CONFIG_DIR",
|
|
10354
|
+
nativeImports: false,
|
|
10355
|
+
description: "Sumi native AGENTS.md in the explicit resolved config directory or project root."
|
|
10356
|
+
},
|
|
10250
10357
|
aicopilot: {
|
|
10251
10358
|
tool: "aicopilot",
|
|
10252
10359
|
mode: "flattened-markdown",
|
|
@@ -10535,12 +10642,22 @@ function compileInstructionGraph(input) {
|
|
|
10535
10642
|
const selector = binding.providers?.find((entry) => entry.provider === input.context.provider || entry.provider === "global");
|
|
10536
10643
|
if (binding.providers?.length && !selector)
|
|
10537
10644
|
continue;
|
|
10645
|
+
const output = config.outputs.find((entry) => entry.agent === input.context.provider);
|
|
10646
|
+
if (!binding.providers?.length && config.agent !== "global" && config.agent !== input.context.provider && !output) {
|
|
10647
|
+
diagnostics.push({ severity: "info", code: "SOURCE_PROVIDER_NOT_SELECTED", config_id: configId, message: `${config.slug} targets ${config.agent}, not ${input.context.provider}.` });
|
|
10648
|
+
continue;
|
|
10649
|
+
}
|
|
10538
10650
|
if (selector?.version_range && !providerVersionSatisfies(input.context.provider_version, selector.version_range)) {
|
|
10539
10651
|
diagnostics.push({ severity: binding.required ? "error" : "warning", code: "PROVIDER_SELECTOR_VERSION_MISMATCH", config_id: configId, message: `${config.slug} requires ${input.context.provider} ${selector.version_range}; current version is ${input.context.provider_version}.` });
|
|
10540
10652
|
continue;
|
|
10541
10653
|
}
|
|
10542
10654
|
if (!activationMatches(binding.activation, config, input.context))
|
|
10543
10655
|
continue;
|
|
10656
|
+
const rejection = instructionSourceRejection(config);
|
|
10657
|
+
if (rejection) {
|
|
10658
|
+
diagnostics.push({ severity: !binding.required && binding.fallback === "omit" ? "warning" : "error", code: "SOURCE_NOT_INSTRUCTION", config_id: configId, message: `${config.slug}: ${rejection}.` });
|
|
10659
|
+
continue;
|
|
10660
|
+
}
|
|
10544
10661
|
if (capability2.activation_modes.includes(binding.activation.mode)) {
|
|
10545
10662
|
selected.add(configId);
|
|
10546
10663
|
effective.set(configId, binding.activation);
|
|
@@ -10615,7 +10732,9 @@ function compileInstructionGraph(input) {
|
|
|
10615
10732
|
assertExactOnce(units, artifacts);
|
|
10616
10733
|
const sources = units.map((unit, index) => {
|
|
10617
10734
|
const config = configs.get(unit.config_id);
|
|
10618
|
-
|
|
10735
|
+
const output = config.outputs.find((entry) => entry.agent === input.context.provider);
|
|
10736
|
+
const content = output ? applyTransform(config, output, { configs: [config] }) : config.content;
|
|
10737
|
+
return sourceForUnit({ ...config, content }, unit, index);
|
|
10619
10738
|
});
|
|
10620
10739
|
const planWithoutHash = {
|
|
10621
10740
|
schema: INSTRUCTION_GRAPH_PLAN_SCHEMA,
|
|
@@ -10843,6 +10962,7 @@ var init_instruction_graph = __esm(() => {
|
|
|
10843
10962
|
init_types();
|
|
10844
10963
|
init_session_render();
|
|
10845
10964
|
init_asset_plan();
|
|
10965
|
+
init_transforms();
|
|
10846
10966
|
COMMON_FALLBACKS = ["fail", "flatten", "promote-always", "omit"];
|
|
10847
10967
|
DEFAULT_PROVIDER_CAPABILITIES = Object.freeze({
|
|
10848
10968
|
claude: capability("claude", ">=1.0.0", "native-import", "CLAUDE.md @ imports plus path-gated rules", {
|
|
@@ -10854,6 +10974,7 @@ var init_instruction_graph = __esm(() => {
|
|
|
10854
10974
|
codex: capability("codex", ">=0.1.0", "flattened", "AGENTS.md", { asset_surface: "cli" }),
|
|
10855
10975
|
cursor: capability("cursor", ">=1.0.0", "cursor-rule", ".cursor/rules/*.mdc", { activation_modes: ["always", "glob"], conditional_artifacts: true, asset_surface: "ide" }),
|
|
10856
10976
|
opencode: capability("opencode", ">=1.0.0", "managed-fragment", "opencode.json instructions", { provider_variant: "v1-instructions", session_surface: "opencode-config-instructions" }),
|
|
10977
|
+
sumi: capability("sumi", ">=0.2.22 <0.3.0", "flattened", "AGENTS.md"),
|
|
10857
10978
|
codewith: capability("codewith", ">=0.1.0", "flattened", "CODEWITH.md"),
|
|
10858
10979
|
qwen: capability("qwen", ">=0.1.0", "flattened", "QWEN.md"),
|
|
10859
10980
|
aicopilot: capability("aicopilot", ">=0.1.0", "flattened", "AICOPILOT.md"),
|
|
@@ -13326,7 +13447,145 @@ function listConfigs(filter, db) {
|
|
|
13326
13447
|
const rows = d.query(`SELECT * FROM configs ${where} ORDER BY category, name`).all(...params);
|
|
13327
13448
|
return rows.map(rowToConfig);
|
|
13328
13449
|
}
|
|
13450
|
+
function listConfigsPage(filter = {}, options = {}, db) {
|
|
13451
|
+
const d = db || getDatabase();
|
|
13452
|
+
const conditions = [];
|
|
13453
|
+
const params = [];
|
|
13454
|
+
if (filter.category) {
|
|
13455
|
+
conditions.push("category = ?");
|
|
13456
|
+
params.push(filter.category);
|
|
13457
|
+
}
|
|
13458
|
+
if (filter.agent) {
|
|
13459
|
+
conditions.push("agent = ?");
|
|
13460
|
+
params.push(filter.agent);
|
|
13461
|
+
}
|
|
13462
|
+
if (filter.kind) {
|
|
13463
|
+
conditions.push("kind = ?");
|
|
13464
|
+
params.push(filter.kind);
|
|
13465
|
+
}
|
|
13466
|
+
if (filter.is_template !== undefined) {
|
|
13467
|
+
conditions.push("is_template = ?");
|
|
13468
|
+
params.push(filter.is_template ? 1 : 0);
|
|
13469
|
+
}
|
|
13470
|
+
if (filter.search) {
|
|
13471
|
+
conditions.push("(name LIKE ? OR description LIKE ? OR content LIKE ?)");
|
|
13472
|
+
const q = `%${filter.search}%`;
|
|
13473
|
+
params.push(q, q, q);
|
|
13474
|
+
}
|
|
13475
|
+
if (filter.tags?.length) {
|
|
13476
|
+
conditions.push(`(${filter.tags.map(() => "tags LIKE ?").join(" AND ")})`);
|
|
13477
|
+
for (const tag of filter.tags)
|
|
13478
|
+
params.push(`%"${tag}"%`);
|
|
13479
|
+
}
|
|
13480
|
+
const where = conditions.length ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
13481
|
+
const normalized = normalizeBoundedReadOptions(options);
|
|
13482
|
+
const total = d.query(`SELECT COUNT(*) AS total FROM configs ${where}`).get(...params)?.total ?? 0;
|
|
13483
|
+
const pageParams = [...params, normalized.limit, normalized.cursor];
|
|
13484
|
+
const rows = d.query(`SELECT * FROM configs ${where} ORDER BY id LIMIT ? OFFSET ?`).all(...pageParams);
|
|
13485
|
+
return boundedReadPage(rows.map(rowToConfig), total, normalized);
|
|
13486
|
+
}
|
|
13487
|
+
function listConfigIdentitiesPage(filter = {}, options = {}, db) {
|
|
13488
|
+
const d = db || getDatabase();
|
|
13489
|
+
const conditions = [];
|
|
13490
|
+
const params = [];
|
|
13491
|
+
if (filter.category) {
|
|
13492
|
+
conditions.push("category = ?");
|
|
13493
|
+
params.push(filter.category);
|
|
13494
|
+
}
|
|
13495
|
+
if (filter.agent) {
|
|
13496
|
+
conditions.push("agent = ?");
|
|
13497
|
+
params.push(filter.agent);
|
|
13498
|
+
}
|
|
13499
|
+
if (filter.kind) {
|
|
13500
|
+
conditions.push("kind = ?");
|
|
13501
|
+
params.push(filter.kind);
|
|
13502
|
+
}
|
|
13503
|
+
if (filter.is_template !== undefined) {
|
|
13504
|
+
conditions.push("is_template = ?");
|
|
13505
|
+
params.push(filter.is_template ? 1 : 0);
|
|
13506
|
+
}
|
|
13507
|
+
if (filter.search) {
|
|
13508
|
+
conditions.push("(name LIKE ? OR description LIKE ? OR content LIKE ?)");
|
|
13509
|
+
const q = `%${filter.search}%`;
|
|
13510
|
+
params.push(q, q, q);
|
|
13511
|
+
}
|
|
13512
|
+
if (filter.tags?.length) {
|
|
13513
|
+
conditions.push(`(${filter.tags.map(() => "tags LIKE ?").join(" AND ")})`);
|
|
13514
|
+
for (const tag of filter.tags)
|
|
13515
|
+
params.push(`%"${tag}"%`);
|
|
13516
|
+
}
|
|
13517
|
+
const where = conditions.length ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
13518
|
+
const normalized = normalizeBoundedReadOptions(options);
|
|
13519
|
+
const total = d.query(`SELECT COUNT(*) AS total FROM configs ${where}`).get(...params)?.total ?? 0;
|
|
13520
|
+
const pageParams = [...params, normalized.limit, normalized.cursor];
|
|
13521
|
+
const rows = d.query(`SELECT id, name, slug, kind, category, agent, format, is_template, version, created_at, updated_at, synced_at
|
|
13522
|
+
FROM configs ${where} ORDER BY id LIMIT ? OFFSET ?`).all(...pageParams);
|
|
13523
|
+
return boundedReadPage(rows.map((row) => ({
|
|
13524
|
+
...row,
|
|
13525
|
+
kind: row.kind,
|
|
13526
|
+
category: row.category,
|
|
13527
|
+
agent: row.agent,
|
|
13528
|
+
format: row.format,
|
|
13529
|
+
is_template: Boolean(row.is_template)
|
|
13530
|
+
})), total, normalized);
|
|
13531
|
+
}
|
|
13532
|
+
function listConfigSummariesPage(filter = {}, options = {}, db) {
|
|
13533
|
+
const d = db || getDatabase();
|
|
13534
|
+
const conditions = [];
|
|
13535
|
+
const params = [];
|
|
13536
|
+
if (filter.category) {
|
|
13537
|
+
conditions.push("category = ?");
|
|
13538
|
+
params.push(filter.category);
|
|
13539
|
+
}
|
|
13540
|
+
if (filter.agent) {
|
|
13541
|
+
conditions.push("agent = ?");
|
|
13542
|
+
params.push(filter.agent);
|
|
13543
|
+
}
|
|
13544
|
+
if (filter.kind) {
|
|
13545
|
+
conditions.push("kind = ?");
|
|
13546
|
+
params.push(filter.kind);
|
|
13547
|
+
}
|
|
13548
|
+
if (filter.is_template !== undefined) {
|
|
13549
|
+
conditions.push("is_template = ?");
|
|
13550
|
+
params.push(filter.is_template ? 1 : 0);
|
|
13551
|
+
}
|
|
13552
|
+
if (filter.search) {
|
|
13553
|
+
conditions.push("(name LIKE ? OR description LIKE ? OR content LIKE ?)");
|
|
13554
|
+
const q = `%${filter.search}%`;
|
|
13555
|
+
params.push(q, q, q);
|
|
13556
|
+
}
|
|
13557
|
+
if (filter.tags && filter.tags.length > 0) {
|
|
13558
|
+
conditions.push(`(${filter.tags.map(() => "tags LIKE ?").join(" AND ")})`);
|
|
13559
|
+
for (const tag of filter.tags)
|
|
13560
|
+
params.push(`%"${tag}"%`);
|
|
13561
|
+
}
|
|
13562
|
+
const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
13563
|
+
const normalized = normalizeBoundedReadOptions(options);
|
|
13564
|
+
const total = d.query(`SELECT COUNT(*) AS total FROM configs ${where}`).get(...params)?.total ?? 0;
|
|
13565
|
+
const pageParams = [...params, normalized.limit, normalized.cursor];
|
|
13566
|
+
const rows = d.query(`SELECT id, name, slug, kind, category, agent, target_path, format,
|
|
13567
|
+
CASE WHEN json_valid(outputs) AND json_type(outputs) = 'array' THEN json_array_length(outputs) ELSE 0 END AS output_count, description, tags,
|
|
13568
|
+
is_template, version, updated_at
|
|
13569
|
+
FROM configs ${where} ORDER BY category, name, id LIMIT ? OFFSET ?`).all(...pageParams);
|
|
13570
|
+
return boundedReadPage(rows.map((row) => ({
|
|
13571
|
+
id: row.id,
|
|
13572
|
+
slug: row.slug,
|
|
13573
|
+
name: row.name,
|
|
13574
|
+
category: row.category,
|
|
13575
|
+
agent: row.agent,
|
|
13576
|
+
kind: row.kind,
|
|
13577
|
+
format: row.format,
|
|
13578
|
+
target_path: row.target_path,
|
|
13579
|
+
output_count: Number(row.output_count ?? 0),
|
|
13580
|
+
version: row.version,
|
|
13581
|
+
is_template: Boolean(row.is_template),
|
|
13582
|
+
updated_at: row.updated_at,
|
|
13583
|
+
description: row.description,
|
|
13584
|
+
tags: JSON.parse(row.tags || "[]")
|
|
13585
|
+
})), total, normalized);
|
|
13586
|
+
}
|
|
13329
13587
|
function updateConfig(idOrSlug, input, db) {
|
|
13588
|
+
validateExpectedConfigVersion(input.expected_version);
|
|
13330
13589
|
const d = db || getDatabase();
|
|
13331
13590
|
const existing = getConfig(idOrSlug, d);
|
|
13332
13591
|
const ts = now();
|
|
@@ -13382,7 +13641,15 @@ function updateConfig(idOrSlug, input, db) {
|
|
|
13382
13641
|
}
|
|
13383
13642
|
return d.transaction(() => {
|
|
13384
13643
|
params.push(existing.id);
|
|
13385
|
-
|
|
13644
|
+
const condition = input.expected_version === undefined ? "" : " AND version = ?";
|
|
13645
|
+
if (input.expected_version !== undefined)
|
|
13646
|
+
params.push(input.expected_version);
|
|
13647
|
+
const result = d.run(`UPDATE configs SET ${updates.join(", ")} WHERE id = ?${condition}`, params);
|
|
13648
|
+
if (result.changes !== 1) {
|
|
13649
|
+
if (input.expected_version !== undefined)
|
|
13650
|
+
throw new ConfigVersionConflictError(existing.id, input.expected_version);
|
|
13651
|
+
throw new ConfigNotFoundError(existing.id);
|
|
13652
|
+
}
|
|
13386
13653
|
const updated = getConfigById(existing.id, d);
|
|
13387
13654
|
createSnapshot(updated.id, updated.content, updated.version, d);
|
|
13388
13655
|
return updated;
|
|
@@ -13407,6 +13674,7 @@ var init_configs = __esm(() => {
|
|
|
13407
13674
|
init_types();
|
|
13408
13675
|
init_database();
|
|
13409
13676
|
init_snapshots();
|
|
13677
|
+
init_bounded_read();
|
|
13410
13678
|
});
|
|
13411
13679
|
|
|
13412
13680
|
// src/lib/template.ts
|
|
@@ -13847,7 +14115,10 @@ __export(exports_local, {
|
|
|
13847
14115
|
listSnapshots: () => listSnapshots,
|
|
13848
14116
|
listProfilesPage: () => listProfilesPage,
|
|
13849
14117
|
listMachines: () => listMachines,
|
|
14118
|
+
listConfigsPage: () => listConfigsPage,
|
|
13850
14119
|
listConfigs: () => listConfigs,
|
|
14120
|
+
listConfigSummariesPage: () => listConfigSummariesPage,
|
|
14121
|
+
listConfigIdentitiesPage: () => listConfigIdentitiesPage,
|
|
13851
14122
|
insertFeedback: () => insertFeedback,
|
|
13852
14123
|
getSnapshotByVersion: () => getSnapshotByVersion,
|
|
13853
14124
|
getSnapshot: () => getSnapshot,
|
|
@@ -13902,6 +14173,19 @@ function parseBoundedOrLegacyPage(value, legacyItems, options, label) {
|
|
|
13902
14173
|
const page = boundedReadPage(legacyItems.slice(normalized.cursor, normalized.cursor + normalized.limit), legacyItems.length, normalized);
|
|
13903
14174
|
return { ...page, source_bounded: false };
|
|
13904
14175
|
}
|
|
14176
|
+
function projectBoundedPage(page, project) {
|
|
14177
|
+
return {
|
|
14178
|
+
items: page.items.map(project),
|
|
14179
|
+
total: page.total,
|
|
14180
|
+
limit: page.limit,
|
|
14181
|
+
cursor: page.cursor,
|
|
14182
|
+
next_cursor: page.next_cursor,
|
|
14183
|
+
has_more: page.has_more,
|
|
14184
|
+
complete: page.complete,
|
|
14185
|
+
truncated: page.truncated,
|
|
14186
|
+
source_bounded: page.source_bounded
|
|
14187
|
+
};
|
|
14188
|
+
}
|
|
13905
14189
|
async function aggregateBoundedCollection(label, readPage, identity, options = {}) {
|
|
13906
14190
|
let lastError = null;
|
|
13907
14191
|
for (let attempt = 0;attempt < COLLECTION_READ_ATTEMPTS; attempt += 1) {
|
|
@@ -13997,6 +14281,15 @@ class LocalConfigStore {
|
|
|
13997
14281
|
async listConfigs(filter) {
|
|
13998
14282
|
return (await localStoreModule()).listConfigs(filter, this.db);
|
|
13999
14283
|
}
|
|
14284
|
+
async listConfigsPage(filter = {}, options = {}) {
|
|
14285
|
+
return (await localStoreModule()).listConfigsPage(filter, options, this.db);
|
|
14286
|
+
}
|
|
14287
|
+
async listConfigIdentitiesPage(filter = {}, options = {}) {
|
|
14288
|
+
return (await localStoreModule()).listConfigIdentitiesPage(filter, options, this.db);
|
|
14289
|
+
}
|
|
14290
|
+
async listConfigSummariesPage(filter = {}, options = {}) {
|
|
14291
|
+
return (await localStoreModule()).listConfigSummariesPage(filter, options, this.db);
|
|
14292
|
+
}
|
|
14000
14293
|
async getConfig(idOrSlug) {
|
|
14001
14294
|
return (await localStoreModule()).getConfig(idOrSlug, this.db);
|
|
14002
14295
|
}
|
|
@@ -14100,6 +14393,43 @@ class LocalConfigStore {
|
|
|
14100
14393
|
(await localStoreModule()).resetLocalDatabase();
|
|
14101
14394
|
}
|
|
14102
14395
|
}
|
|
14396
|
+
function toConfigIdentity(value) {
|
|
14397
|
+
const record = value && typeof value === "object" ? value : {};
|
|
14398
|
+
return {
|
|
14399
|
+
id: String(record.id ?? ""),
|
|
14400
|
+
name: String(record.name ?? ""),
|
|
14401
|
+
slug: String(record.slug ?? ""),
|
|
14402
|
+
kind: String(record.kind ?? ""),
|
|
14403
|
+
category: String(record.category ?? ""),
|
|
14404
|
+
agent: String(record.agent ?? ""),
|
|
14405
|
+
format: String(record.format ?? ""),
|
|
14406
|
+
is_template: Boolean(record.is_template),
|
|
14407
|
+
version: Number(record.version ?? 0),
|
|
14408
|
+
created_at: String(record.created_at ?? ""),
|
|
14409
|
+
updated_at: String(record.updated_at ?? ""),
|
|
14410
|
+
synced_at: record.synced_at == null ? null : String(record.synced_at)
|
|
14411
|
+
};
|
|
14412
|
+
}
|
|
14413
|
+
function toConfigSummary(value) {
|
|
14414
|
+
const record = value && typeof value === "object" ? value : {};
|
|
14415
|
+
const outputs = Array.isArray(record.outputs) ? record.outputs : [];
|
|
14416
|
+
return {
|
|
14417
|
+
id: String(record.id ?? ""),
|
|
14418
|
+
slug: String(record.slug ?? ""),
|
|
14419
|
+
name: String(record.name ?? ""),
|
|
14420
|
+
category: String(record.category ?? ""),
|
|
14421
|
+
agent: String(record.agent ?? ""),
|
|
14422
|
+
kind: String(record.kind ?? ""),
|
|
14423
|
+
format: String(record.format ?? ""),
|
|
14424
|
+
target_path: record.target_path == null ? null : String(record.target_path),
|
|
14425
|
+
output_count: Number(record.output_count ?? outputs.length),
|
|
14426
|
+
version: Number(record.version ?? 0),
|
|
14427
|
+
is_template: Boolean(record.is_template),
|
|
14428
|
+
...record.updated_at !== undefined ? { updated_at: String(record.updated_at) } : {},
|
|
14429
|
+
...record.description !== undefined ? { description: record.description == null ? null : String(record.description) } : {},
|
|
14430
|
+
...Array.isArray(record.tags) ? { tags: record.tags.map(String) } : {}
|
|
14431
|
+
};
|
|
14432
|
+
}
|
|
14103
14433
|
|
|
14104
14434
|
class CloudConfigStore {
|
|
14105
14435
|
mode = "api";
|
|
@@ -14121,7 +14451,7 @@ class CloudConfigStore {
|
|
|
14121
14451
|
throw err;
|
|
14122
14452
|
}
|
|
14123
14453
|
}
|
|
14124
|
-
async
|
|
14454
|
+
async listConfigsPage(filter = {}, options = {}) {
|
|
14125
14455
|
const normalized = normalizeBoundedReadOptions(options);
|
|
14126
14456
|
const params = new URLSearchParams;
|
|
14127
14457
|
if (filter.category)
|
|
@@ -14132,13 +14462,67 @@ class CloudConfigStore {
|
|
|
14132
14462
|
params.set("kind", filter.kind);
|
|
14133
14463
|
if (filter.search)
|
|
14134
14464
|
params.set("search", filter.search);
|
|
14465
|
+
for (const tag of filter.tags ?? [])
|
|
14466
|
+
params.append("tag", tag);
|
|
14135
14467
|
params.set("limit", String(normalized.limit));
|
|
14136
14468
|
params.set("cursor", String(normalized.cursor));
|
|
14137
14469
|
const { data } = await this.request("GET", `/configs?${params.toString()}`);
|
|
14138
14470
|
return parseBoundedOrLegacyPage(data, data?.configs, normalized, "config list");
|
|
14139
14471
|
}
|
|
14472
|
+
async listConfigIdentitiesPage(filter = {}, options = {}) {
|
|
14473
|
+
const normalized = normalizeBoundedReadOptions(options);
|
|
14474
|
+
const params = new URLSearchParams;
|
|
14475
|
+
if (filter.category)
|
|
14476
|
+
params.set("category", filter.category);
|
|
14477
|
+
if (filter.agent)
|
|
14478
|
+
params.set("agent", filter.agent);
|
|
14479
|
+
if (filter.kind)
|
|
14480
|
+
params.set("kind", filter.kind);
|
|
14481
|
+
if (filter.search)
|
|
14482
|
+
params.set("search", filter.search);
|
|
14483
|
+
for (const tag of filter.tags ?? [])
|
|
14484
|
+
params.append("tag", tag);
|
|
14485
|
+
params.set("view", "identity");
|
|
14486
|
+
params.set("limit", String(normalized.limit));
|
|
14487
|
+
params.set("cursor", String(normalized.cursor));
|
|
14488
|
+
const { data } = await this.request("GET", `/configs?${params.toString()}`);
|
|
14489
|
+
const page = parseBoundedOrLegacyPage(data, data?.configs, normalized, "config identity list");
|
|
14490
|
+
if (page.items.some((item) => {
|
|
14491
|
+
const record = item && typeof item === "object" ? item : {};
|
|
14492
|
+
return ["content", "target_path", "outputs", "description", "tags"].some((field) => Object.prototype.hasOwnProperty.call(record, field));
|
|
14493
|
+
})) {
|
|
14494
|
+
throw new Error("Instructions /v1 config identity projection is unavailable; deploy the identity endpoint before using compact lists");
|
|
14495
|
+
}
|
|
14496
|
+
return projectBoundedPage(page, toConfigIdentity);
|
|
14497
|
+
}
|
|
14498
|
+
async listConfigSummariesPage(filter = {}, options = {}) {
|
|
14499
|
+
const normalized = normalizeBoundedReadOptions(options);
|
|
14500
|
+
const params = new URLSearchParams;
|
|
14501
|
+
if (filter.category)
|
|
14502
|
+
params.set("category", filter.category);
|
|
14503
|
+
if (filter.agent)
|
|
14504
|
+
params.set("agent", filter.agent);
|
|
14505
|
+
if (filter.kind)
|
|
14506
|
+
params.set("kind", filter.kind);
|
|
14507
|
+
if (filter.search)
|
|
14508
|
+
params.set("search", filter.search);
|
|
14509
|
+
for (const tag of filter.tags ?? [])
|
|
14510
|
+
params.append("tag", tag);
|
|
14511
|
+
params.set("view", "summary");
|
|
14512
|
+
params.set("limit", String(normalized.limit));
|
|
14513
|
+
params.set("cursor", String(normalized.cursor));
|
|
14514
|
+
const { data } = await this.request("GET", `/configs?${params.toString()}`);
|
|
14515
|
+
const page = parseBoundedOrLegacyPage(data, data?.configs, normalized, "config summary list");
|
|
14516
|
+
if (page.items.some((item) => {
|
|
14517
|
+
const record = item && typeof item === "object" ? item : {};
|
|
14518
|
+
return Object.prototype.hasOwnProperty.call(record, "content") || Object.prototype.hasOwnProperty.call(record, "outputs");
|
|
14519
|
+
})) {
|
|
14520
|
+
throw new Error("Instructions /v1 config summary projection is unavailable; deploy the summary endpoint before using summary lists");
|
|
14521
|
+
}
|
|
14522
|
+
return projectBoundedPage(page, toConfigSummary);
|
|
14523
|
+
}
|
|
14140
14524
|
async listConfigs(filter = {}) {
|
|
14141
|
-
const configs = await aggregateBoundedCollection("config list", (cursor) => this.
|
|
14525
|
+
const configs = await aggregateBoundedCollection("config list", (cursor) => this.listConfigsPage(filter, { limit: 100, cursor }), (config) => config.id, { requireAscendingIdentity: true });
|
|
14142
14526
|
let filtered = configs;
|
|
14143
14527
|
if (filter.tags && filter.tags.length > 0) {
|
|
14144
14528
|
filtered = filtered.filter((config) => filter.tags.every((tag) => config.tags.includes(tag)));
|
|
@@ -14164,7 +14548,9 @@ class CloudConfigStore {
|
|
|
14164
14548
|
return data.config;
|
|
14165
14549
|
}
|
|
14166
14550
|
async updateConfig(idOrSlug, input) {
|
|
14167
|
-
|
|
14551
|
+
validateExpectedConfigVersion(input.expected_version);
|
|
14552
|
+
const conditional = input.expected_version !== undefined;
|
|
14553
|
+
const { data } = await this.request(conditional ? "POST" : "PATCH", `/configs/${encodeURIComponent(idOrSlug)}${conditional ? "/conditional-update" : ""}`, input);
|
|
14168
14554
|
return data.config;
|
|
14169
14555
|
}
|
|
14170
14556
|
async deleteConfig(idOrSlug) {
|
|
@@ -14204,7 +14590,7 @@ class CloudConfigStore {
|
|
|
14204
14590
|
return data?.pruned ?? 0;
|
|
14205
14591
|
}
|
|
14206
14592
|
async listProfiles() {
|
|
14207
|
-
return aggregateBoundedCollection("profile list", (cursor) => this.listProfilesPage({ limit: 100, cursor }), (profile) => profile.id
|
|
14593
|
+
return aggregateBoundedCollection("profile list", (cursor) => this.listProfilesPage({ limit: 100, cursor }), (profile) => profile.id);
|
|
14208
14594
|
}
|
|
14209
14595
|
async listProfilesPage(options = {}) {
|
|
14210
14596
|
const normalized = normalizeBoundedReadOptions(options);
|
|
@@ -14241,7 +14627,7 @@ class CloudConfigStore {
|
|
|
14241
14627
|
throw new ProfileNotFoundError(idOrSlug);
|
|
14242
14628
|
return parseBoundedOrLegacyPage(data.configs, data.profile.configs, normalized, "profile membership");
|
|
14243
14629
|
}
|
|
14244
|
-
async getProfileConfigBindings(idOrSlug) {
|
|
14630
|
+
async getProfileConfigBindings(idOrSlug, options = {}) {
|
|
14245
14631
|
let routeMissing = false;
|
|
14246
14632
|
const bindings = await aggregateBoundedCollection("profile config bindings", async (cursor) => {
|
|
14247
14633
|
const normalized = normalizeBoundedReadOptions({ limit: 100, cursor });
|
|
@@ -14254,6 +14640,8 @@ class CloudConfigStore {
|
|
|
14254
14640
|
}, (binding) => `${binding.profile_id}\x00${binding.config_id}`);
|
|
14255
14641
|
if (!routeMissing)
|
|
14256
14642
|
return bindings;
|
|
14643
|
+
if (options.requireExplicit)
|
|
14644
|
+
throw new Error("HOSTED_BINDINGS_REQUIRED: profile config binding route is unavailable; refusing legacy activation fallback.");
|
|
14257
14645
|
const profile = await this.getProfile(idOrSlug);
|
|
14258
14646
|
const configs = await this.getProfileConfigs(idOrSlug);
|
|
14259
14647
|
return configs.map((config, sort_order) => ({
|
|
@@ -14318,7 +14706,7 @@ class CloudConfigStore {
|
|
|
14318
14706
|
async removeConfigFromProfile(profileIdOrSlug, configId) {
|
|
14319
14707
|
await this.request("DELETE", `/profiles/${encodeURIComponent(profileIdOrSlug)}/configs/${encodeURIComponent(configId)}`, undefined, { allow404: true });
|
|
14320
14708
|
}
|
|
14321
|
-
async getProfileAssetBindings(profileIdOrSlug) {
|
|
14709
|
+
async getProfileAssetBindings(profileIdOrSlug, options = {}) {
|
|
14322
14710
|
let routeMissing = false;
|
|
14323
14711
|
const assets = await aggregateBoundedCollection("profile asset bindings", async (cursor) => {
|
|
14324
14712
|
const normalized = normalizeBoundedReadOptions({ limit: 100, cursor });
|
|
@@ -14331,6 +14719,8 @@ class CloudConfigStore {
|
|
|
14331
14719
|
}, (asset) => `${asset.profile_id}\x00${asset.binding.assetKey}`);
|
|
14332
14720
|
if (!routeMissing)
|
|
14333
14721
|
return assets;
|
|
14722
|
+
if (options.requireExplicit)
|
|
14723
|
+
throw new Error("HOSTED_ASSETS_REQUIRED: profile asset binding route is unavailable; refusing an empty asset fallback.");
|
|
14334
14724
|
await this.getProfile(profileIdOrSlug);
|
|
14335
14725
|
return [];
|
|
14336
14726
|
}
|
|
@@ -16080,7 +16470,6 @@ import {
|
|
|
16080
16470
|
statSync as statSync5
|
|
16081
16471
|
} from "fs";
|
|
16082
16472
|
import { dirname as dirname10, isAbsolute as isAbsolute7, join as join17, parse as parse5, relative as relative6, resolve as resolve11 } from "path";
|
|
16083
|
-
|
|
16084
16473
|
class SessionApplyError extends Error {
|
|
16085
16474
|
constructor(message) {
|
|
16086
16475
|
super(message);
|
|
@@ -16102,14 +16491,20 @@ function applySessionRenderUnlocked(plan, options, coordination) {
|
|
|
16102
16491
|
const targetHome = assertSafeTargetHome(plan.targetHome);
|
|
16103
16492
|
assertClaudeAuthorityStillClear(plan, targetHome, options.ownedClaudeAuthorities);
|
|
16104
16493
|
const payloadFiles = [...plan.files, ...plan.assetFiles ?? []];
|
|
16105
|
-
const files = [...payloadFiles, plan.manifestFile];
|
|
16106
16494
|
const manifestPath = resolvePlannedFilePath(plan, plan.manifestFile, targetHome);
|
|
16495
|
+
assertManifestPrecondition(manifestPath, targetHome, options.expectedManifestSha256);
|
|
16107
16496
|
const previousManifest = readPreviousManifest(manifestPath);
|
|
16108
16497
|
const previousHashes = previousManifest ? new Map(previousManifest.files.map((file) => [file.relativePath, file.sha256])) : new Map;
|
|
16498
|
+
const adoptions = validateFileAdoptions(plan, targetHome, previousHashes, options);
|
|
16499
|
+
const adoptedHashes = new Map(adoptions.map((entry) => [entry.relativePath, entry.preimageSha256]));
|
|
16500
|
+
const reconciliations = validateFileReconciliations(plan, targetHome, previousManifest, options);
|
|
16501
|
+
const reconciledHashes = new Map(reconciliations.map((entry) => [entry.relativePath, entry.preimageSha256]));
|
|
16502
|
+
const manifestFile = manifestWithFileProvenance(plan, previousManifest, adoptions, reconciliations);
|
|
16503
|
+
const files = [...payloadFiles, manifestFile];
|
|
16109
16504
|
const currentRelativePaths = new Set(files.map((file) => file.relativePath));
|
|
16110
16505
|
const drift = checkSessionRenderDrift(targetHome, manifestPath);
|
|
16111
16506
|
const results = [
|
|
16112
|
-
...files.map((file) => planFileResult(plan, file, targetHome, previousHashes, previousManifest, options)),
|
|
16507
|
+
...files.map((file) => planFileResult(plan, file, targetHome, previousHashes, previousManifest, options, adoptedHashes, reconciledHashes)),
|
|
16113
16508
|
...planStaleFileResults(plan, targetHome, previousManifest, currentRelativePaths, options)
|
|
16114
16509
|
];
|
|
16115
16510
|
assertNotSilentManagedWipeout(plan, results);
|
|
@@ -16132,7 +16527,9 @@ function applySessionRenderUnlocked(plan, options, coordination) {
|
|
|
16132
16527
|
skippedSources: plan.manifest.skippedSources,
|
|
16133
16528
|
files: results,
|
|
16134
16529
|
conflicts,
|
|
16135
|
-
drift
|
|
16530
|
+
drift,
|
|
16531
|
+
adoptions,
|
|
16532
|
+
reconciliations
|
|
16136
16533
|
};
|
|
16137
16534
|
}
|
|
16138
16535
|
let snapshotPath = null;
|
|
@@ -16145,10 +16542,12 @@ function applySessionRenderUnlocked(plan, options, coordination) {
|
|
|
16145
16542
|
if (!options.dryRun) {
|
|
16146
16543
|
const allowPortableFallback = coordination === null;
|
|
16147
16544
|
const forcePortableFileOps = options.test_hooks?.force_portable_file_ops ?? false;
|
|
16545
|
+
assertManifestPrecondition(manifestPath, targetHome, options.expectedManifestSha256);
|
|
16148
16546
|
ensureSessionTargetHome(targetHome);
|
|
16149
|
-
rollback = writeSessionSnapshot(plan, targetHome, manifestPath, results, previousManifest, coordination, allowPortableFallback, forcePortableFileOps);
|
|
16547
|
+
rollback = writeSessionSnapshot(plan, targetHome, manifestPath, results, previousManifest, coordination, allowPortableFallback, forcePortableFileOps, adoptions, reconciliations);
|
|
16150
16548
|
snapshotPath = rollback.snapshotPath;
|
|
16151
16549
|
options.test_hooks?.before_apply_writes?.({ plan, results });
|
|
16550
|
+
assertManifestPrecondition(manifestPath, targetHome, options.expectedManifestSha256);
|
|
16152
16551
|
const resultsByPath = new Map(results.map((result) => [result.path, result]));
|
|
16153
16552
|
for (const file of payloadFiles) {
|
|
16154
16553
|
applyPlannedFile(plan, file, targetHome, resultsByPath, coordination, allowPortableFallback, forcePortableFileOps);
|
|
@@ -16168,7 +16567,7 @@ function applySessionRenderUnlocked(plan, options, coordination) {
|
|
|
16168
16567
|
});
|
|
16169
16568
|
coordination?.assert_held();
|
|
16170
16569
|
}
|
|
16171
|
-
applyPlannedFile(plan,
|
|
16570
|
+
applyPlannedFile(plan, manifestFile, targetHome, resultsByPath, coordination, allowPortableFallback, forcePortableFileOps);
|
|
16172
16571
|
}
|
|
16173
16572
|
return {
|
|
16174
16573
|
dryRun: options.dryRun ?? false,
|
|
@@ -16182,9 +16581,171 @@ function applySessionRenderUnlocked(plan, options, coordination) {
|
|
|
16182
16581
|
skippedSources: plan.manifest.skippedSources,
|
|
16183
16582
|
files: results,
|
|
16184
16583
|
conflicts,
|
|
16185
|
-
drift
|
|
16584
|
+
drift,
|
|
16585
|
+
adoptions,
|
|
16586
|
+
reconciliations
|
|
16186
16587
|
};
|
|
16187
16588
|
}
|
|
16589
|
+
function assertManifestPrecondition(path, targetHome, expected) {
|
|
16590
|
+
if (expected === undefined)
|
|
16591
|
+
return;
|
|
16592
|
+
if (!/^[a-f0-9]{64}$/.test(expected)) {
|
|
16593
|
+
throw new SessionApplyError("Expected session manifest SHA-256 must contain 64 lowercase hexadecimal characters.");
|
|
16594
|
+
}
|
|
16595
|
+
if (currentSessionFileHash(path, targetHome) !== expected) {
|
|
16596
|
+
throw new SessionApplyError("Session manifest SHA-256 precondition failed; reload the manifest and resolve a new plan.");
|
|
16597
|
+
}
|
|
16598
|
+
}
|
|
16599
|
+
function validateFileAdoptions(plan, targetHome, previousHashes, options) {
|
|
16600
|
+
const requests = options.adoptFiles ?? [];
|
|
16601
|
+
if (!Array.isArray(requests))
|
|
16602
|
+
throw new SessionApplyError("Session file adoptions must be an array.");
|
|
16603
|
+
if (requests.length > 0 && options.force) {
|
|
16604
|
+
throw new SessionApplyError("Exact file adoption cannot be combined with force.");
|
|
16605
|
+
}
|
|
16606
|
+
const seen = new Set;
|
|
16607
|
+
return requests.map((request) => {
|
|
16608
|
+
if (!request || typeof request.relativePath !== "string" || typeof request.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(request.sha256)) {
|
|
16609
|
+
throw new SessionApplyError("Each file adoption requires a plan-relative path and a 64-character lowercase SHA-256.");
|
|
16610
|
+
}
|
|
16611
|
+
if (seen.has(request.relativePath)) {
|
|
16612
|
+
throw new SessionApplyError(`Duplicate file adoption target: ${request.relativePath}`);
|
|
16613
|
+
}
|
|
16614
|
+
seen.add(request.relativePath);
|
|
16615
|
+
const candidates = plan.files.filter((file2) => file2.relativePath === request.relativePath);
|
|
16616
|
+
if (candidates.length !== 1 || candidates[0].role === "manifest") {
|
|
16617
|
+
throw new SessionApplyError(`File adoption target is not a unique planned instruction output: ${request.relativePath}`);
|
|
16618
|
+
}
|
|
16619
|
+
const file = candidates[0];
|
|
16620
|
+
const path = resolvePlannedFilePath(plan, file, targetHome);
|
|
16621
|
+
if (previousHashes.has(file.relativePath) || sessionRenderOwnsPath(path)) {
|
|
16622
|
+
throw new SessionApplyError(`File adoption target is already managed: ${request.relativePath}`);
|
|
16623
|
+
}
|
|
16624
|
+
const observedSha256 = readExactFilePreimage(path, targetHome, request, "adoption");
|
|
16625
|
+
return {
|
|
16626
|
+
path,
|
|
16627
|
+
relativePath: file.relativePath,
|
|
16628
|
+
preimageSha256: observedSha256,
|
|
16629
|
+
renderedSha256: file.sha256,
|
|
16630
|
+
sourceIds: [...file.sourceIds]
|
|
16631
|
+
};
|
|
16632
|
+
});
|
|
16633
|
+
}
|
|
16634
|
+
function readExactFilePreimage(path, targetHome, request, operation) {
|
|
16635
|
+
if (currentSessionFileHash(path, targetHome) === null) {
|
|
16636
|
+
throw new SessionApplyError(`File ${operation} target does not exist: ${request.relativePath}`);
|
|
16637
|
+
}
|
|
16638
|
+
const bytes = readFileSync14(path);
|
|
16639
|
+
if (!bytes.equals(Buffer.from(bytes.toString("utf8"), "utf8"))) {
|
|
16640
|
+
throw new SessionApplyError(`File ${operation} target must contain losslessly restorable UTF-8: ${request.relativePath}`);
|
|
16641
|
+
}
|
|
16642
|
+
const observedSha256 = createHash10("sha256").update(bytes).digest("hex");
|
|
16643
|
+
if (observedSha256 !== request.sha256) {
|
|
16644
|
+
throw new SessionApplyError(`File ${operation} SHA-256 precondition failed: ${request.relativePath}`);
|
|
16645
|
+
}
|
|
16646
|
+
return observedSha256;
|
|
16647
|
+
}
|
|
16648
|
+
function validateFileReconciliations(plan, targetHome, previousManifest, options) {
|
|
16649
|
+
const requests = options.reconcileFiles ?? [];
|
|
16650
|
+
if (!Array.isArray(requests))
|
|
16651
|
+
throw new SessionApplyError("Session file reconciliations must be an array.");
|
|
16652
|
+
if (requests.length === 0)
|
|
16653
|
+
return [];
|
|
16654
|
+
if (options.force)
|
|
16655
|
+
throw new SessionApplyError("Exact file reconciliation cannot be combined with force.");
|
|
16656
|
+
if (options.expectedManifestSha256 === undefined) {
|
|
16657
|
+
throw new SessionApplyError("Exact file reconciliation requires an expected manifest SHA-256 precondition.");
|
|
16658
|
+
}
|
|
16659
|
+
if (!previousManifest || previousManifest.targetOwner?.writer?.id !== SESSION_RENDERER_OWNER_ID || previousManifest.tool !== plan.tool || previousManifest.targetHome !== targetHome) {
|
|
16660
|
+
throw new SessionApplyError("File reconciliation requires this renderer's manifest for the same tool and target home.");
|
|
16661
|
+
}
|
|
16662
|
+
const seen = new Set;
|
|
16663
|
+
return requests.map((request) => {
|
|
16664
|
+
if (!request || typeof request.relativePath !== "string" || typeof request.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(request.sha256)) {
|
|
16665
|
+
throw new SessionApplyError("Each file reconciliation requires a plan-relative path and a 64-character lowercase SHA-256.");
|
|
16666
|
+
}
|
|
16667
|
+
if (seen.has(request.relativePath)) {
|
|
16668
|
+
throw new SessionApplyError(`Duplicate file reconciliation target: ${request.relativePath}`);
|
|
16669
|
+
}
|
|
16670
|
+
seen.add(request.relativePath);
|
|
16671
|
+
const candidates = plan.files.filter((file2) => file2.relativePath === request.relativePath);
|
|
16672
|
+
if (candidates.length !== 1 || candidates[0].role === "manifest") {
|
|
16673
|
+
throw new SessionApplyError(`File reconciliation target is not a unique planned instruction output: ${request.relativePath}`);
|
|
16674
|
+
}
|
|
16675
|
+
const file = candidates[0];
|
|
16676
|
+
const path = resolvePlannedFilePath(plan, file, targetHome);
|
|
16677
|
+
const owned = previousManifest.files.filter((entry) => entry.relativePath === file.relativePath);
|
|
16678
|
+
if (owned.length !== 1 || owned[0].path !== path || owned[0].role !== file.role || !/^[a-f0-9]{64}$/.test(owned[0].sha256)) {
|
|
16679
|
+
throw new SessionApplyError(`File reconciliation target is not owned by the observed manifest: ${request.relativePath}`);
|
|
16680
|
+
}
|
|
16681
|
+
const observedSha256 = readExactFilePreimage(path, targetHome, request, "reconciliation");
|
|
16682
|
+
if (observedSha256 === owned[0].sha256) {
|
|
16683
|
+
throw new SessionApplyError(`File reconciliation target has no managed drift: ${request.relativePath}`);
|
|
16684
|
+
}
|
|
16685
|
+
if (observedSha256 === file.sha256) {
|
|
16686
|
+
throw new SessionApplyError(`File reconciliation target already matches the planned output: ${request.relativePath}`);
|
|
16687
|
+
}
|
|
16688
|
+
return {
|
|
16689
|
+
path,
|
|
16690
|
+
relativePath: file.relativePath,
|
|
16691
|
+
preimageSha256: observedSha256,
|
|
16692
|
+
renderedSha256: file.sha256,
|
|
16693
|
+
previousManagedSha256: owned[0].sha256,
|
|
16694
|
+
sourceIds: [...file.sourceIds]
|
|
16695
|
+
};
|
|
16696
|
+
});
|
|
16697
|
+
}
|
|
16698
|
+
function manifestWithFileProvenance(plan, previousManifest, adoptions, reconciliations) {
|
|
16699
|
+
if (adoptions.length === 0 && previousManifest?.adoptions === undefined && reconciliations.length === 0 && previousManifest?.reconciliations === undefined)
|
|
16700
|
+
return plan.manifestFile;
|
|
16701
|
+
if (previousManifest?.adoptions !== undefined && !Array.isArray(previousManifest.adoptions)) {
|
|
16702
|
+
throw new SessionApplyError("Previous session manifest adoption provenance is invalid.");
|
|
16703
|
+
}
|
|
16704
|
+
const entries = new Map;
|
|
16705
|
+
for (const entry of [
|
|
16706
|
+
...previousManifest?.adoptions ?? [],
|
|
16707
|
+
...adoptions.map(({ path: _path, ...receipt }) => receipt)
|
|
16708
|
+
]) {
|
|
16709
|
+
if (!entry || typeof entry.relativePath !== "string" || !/^[a-f0-9]{64}$/.test(entry.preimageSha256) || !/^[a-f0-9]{64}$/.test(entry.renderedSha256) || !Array.isArray(entry.sourceIds) || entry.sourceIds.some((id) => typeof id !== "string")) {
|
|
16710
|
+
throw new SessionApplyError("Previous session manifest adoption provenance is invalid.");
|
|
16711
|
+
}
|
|
16712
|
+
resolveManifestRelativePath(entry.relativePath, plan.targetHome);
|
|
16713
|
+
const previous = entries.get(entry.relativePath);
|
|
16714
|
+
if (previous && JSON.stringify(previous) !== JSON.stringify(entry)) {
|
|
16715
|
+
throw new SessionApplyError(`Conflicting session file adoption provenance: ${entry.relativePath}`);
|
|
16716
|
+
}
|
|
16717
|
+
entries.set(entry.relativePath, entry);
|
|
16718
|
+
}
|
|
16719
|
+
if (previousManifest?.reconciliations !== undefined && !Array.isArray(previousManifest.reconciliations)) {
|
|
16720
|
+
throw new SessionApplyError("Previous session manifest reconciliation provenance is invalid.");
|
|
16721
|
+
}
|
|
16722
|
+
const reconciledEntries = new Map;
|
|
16723
|
+
for (const entry of [
|
|
16724
|
+
...previousManifest?.reconciliations ?? [],
|
|
16725
|
+
...reconciliations.map(({ path: _path, ...receipt }) => receipt)
|
|
16726
|
+
]) {
|
|
16727
|
+
if (!entry || typeof entry.relativePath !== "string" || !/^[a-f0-9]{64}$/.test(entry.preimageSha256) || !/^[a-f0-9]{64}$/.test(entry.renderedSha256) || !/^[a-f0-9]{64}$/.test(entry.previousManagedSha256) || !Array.isArray(entry.sourceIds) || entry.sourceIds.some((id) => typeof id !== "string")) {
|
|
16728
|
+
throw new SessionApplyError("Previous session manifest reconciliation provenance is invalid.");
|
|
16729
|
+
}
|
|
16730
|
+
resolveManifestRelativePath(entry.relativePath, plan.targetHome);
|
|
16731
|
+
const canonical = {
|
|
16732
|
+
relativePath: entry.relativePath,
|
|
16733
|
+
preimageSha256: entry.preimageSha256,
|
|
16734
|
+
renderedSha256: entry.renderedSha256,
|
|
16735
|
+
previousManagedSha256: entry.previousManagedSha256,
|
|
16736
|
+
sourceIds: [...entry.sourceIds]
|
|
16737
|
+
};
|
|
16738
|
+
reconciledEntries.set(JSON.stringify(canonical), canonical);
|
|
16739
|
+
}
|
|
16740
|
+
const manifest = {
|
|
16741
|
+
...plan.manifest,
|
|
16742
|
+
...adoptions.length > 0 || previousManifest?.adoptions !== undefined ? { adoptions: [...entries.values()] } : {},
|
|
16743
|
+
...reconciliations.length > 0 || previousManifest?.reconciliations !== undefined ? { reconciliations: [...reconciledEntries.values()] } : {}
|
|
16744
|
+
};
|
|
16745
|
+
const content = `${JSON.stringify(manifest, null, 2)}
|
|
16746
|
+
`;
|
|
16747
|
+
return { ...plan.manifestFile, content, sha256: sha25610(content) };
|
|
16748
|
+
}
|
|
16188
16749
|
function assertCursorAuthorityUnchanged(plan) {
|
|
16189
16750
|
if (plan.tool !== "cursor" || plan.targetKind === "blocked")
|
|
16190
16751
|
return;
|
|
@@ -16656,12 +17217,29 @@ function resolveSnapshotFilePath(relativePath, recordedPath, targetHome) {
|
|
|
16656
17217
|
}
|
|
16657
17218
|
return path;
|
|
16658
17219
|
}
|
|
16659
|
-
function planFileResult(plan, file, targetHome, previousHashes, previousManifest, options) {
|
|
17220
|
+
function planFileResult(plan, file, targetHome, previousHashes, previousManifest, options, adoptedHashes, reconciledHashes) {
|
|
16660
17221
|
const target = resolvePlannedFilePath(plan, file, targetHome);
|
|
16661
17222
|
const previousContent = existsSync15(target) ? readFileSync14(target, "utf-8") : null;
|
|
16662
17223
|
const previousSha256 = previousContent === null ? null : sha25610(previousContent);
|
|
16663
17224
|
const previouslyManaged = isPreviouslyManaged(file, previousSha256, previousHashes, previousManifest);
|
|
16664
17225
|
const changed = previousContent !== file.content;
|
|
17226
|
+
const exactSha256 = adoptedHashes.get(file.relativePath) ?? reconciledHashes.get(file.relativePath);
|
|
17227
|
+
if (exactSha256 !== undefined) {
|
|
17228
|
+
const operation = adoptedHashes.has(file.relativePath) ? "adoption" : "reconciliation";
|
|
17229
|
+
if (previousSha256 !== exactSha256) {
|
|
17230
|
+
throw new SessionApplyError(`File ${operation} SHA-256 precondition failed: ${file.relativePath}`);
|
|
17231
|
+
}
|
|
17232
|
+
return {
|
|
17233
|
+
path: target,
|
|
17234
|
+
relativePath: file.relativePath,
|
|
17235
|
+
role: file.role,
|
|
17236
|
+
action: "update",
|
|
17237
|
+
changed,
|
|
17238
|
+
previousSha256,
|
|
17239
|
+
newSha256: file.sha256,
|
|
17240
|
+
reason: `exact observed SHA-256 ${operation}`
|
|
17241
|
+
};
|
|
17242
|
+
}
|
|
16665
17243
|
if (previousContent !== null && !options.force && !previouslyManaged) {
|
|
16666
17244
|
return {
|
|
16667
17245
|
path: target,
|
|
@@ -16881,9 +17459,13 @@ function requiredPreviousHash(result) {
|
|
|
16881
17459
|
}
|
|
16882
17460
|
return result.previousSha256;
|
|
16883
17461
|
}
|
|
16884
|
-
function writeSessionSnapshot(plan, targetHome, manifestPath, results, previousManifest, coordination, allowPortableFallback, forcePortableFileOps) {
|
|
16885
|
-
const existingFiles = results.filter((result) => result.action === "update" || result.action === "delete").
|
|
17462
|
+
function writeSessionSnapshot(plan, targetHome, manifestPath, results, previousManifest, coordination, allowPortableFallback, forcePortableFileOps, adoptions, reconciliations) {
|
|
17463
|
+
const existingFiles = results.filter((result) => result.action === "update" || result.action === "delete").map((result) => {
|
|
17464
|
+
assertExpectedSessionFileHash(result.path, targetHome, result.previousSha256);
|
|
16886
17465
|
const content = readFileSync14(result.path, "utf-8");
|
|
17466
|
+
if (sha25610(content) !== result.previousSha256) {
|
|
17467
|
+
throw new SessionApplyError(`Session snapshot preimage changed after planning: ${result.relativePath}`);
|
|
17468
|
+
}
|
|
16887
17469
|
return {
|
|
16888
17470
|
path: result.path,
|
|
16889
17471
|
relativePath: result.relativePath,
|
|
@@ -16924,13 +17506,19 @@ function writeSessionSnapshot(plan, targetHome, manifestPath, results, previousM
|
|
|
16924
17506
|
manifestPath,
|
|
16925
17507
|
previousManifest,
|
|
16926
17508
|
files: existingFiles,
|
|
16927
|
-
afterFiles
|
|
17509
|
+
afterFiles,
|
|
17510
|
+
...adoptions.length > 0 ? { adoptions } : {},
|
|
17511
|
+
...reconciliations.length > 0 ? { reconciliations } : {}
|
|
16928
17512
|
};
|
|
17513
|
+
const snapshotContent = `${JSON.stringify(snapshot, null, 2)}
|
|
17514
|
+
`;
|
|
17515
|
+
if ((adoptions.length > 0 || reconciliations.length > 0) && Buffer.byteLength(snapshotContent, "utf8") > 32 * 1024 * 1024) {
|
|
17516
|
+
throw new SessionApplyError("Exact file preimage snapshot exceeds the 32 MiB restore limit.");
|
|
17517
|
+
}
|
|
16929
17518
|
coordination?.assert_held();
|
|
16930
17519
|
writeProjectContextCoordinatedFile({
|
|
16931
17520
|
path: snapshotPath,
|
|
16932
|
-
content:
|
|
16933
|
-
`,
|
|
17521
|
+
content: snapshotContent,
|
|
16934
17522
|
workspace_root: sessionRenderSnapshotWorkspaceRoot(targetHome),
|
|
16935
17523
|
default_mode: 384,
|
|
16936
17524
|
expected_hash: null,
|
|
@@ -16987,6 +17575,211 @@ function assertNoSymlinkAncestors3(path) {
|
|
|
16987
17575
|
function sha25610(content) {
|
|
16988
17576
|
return createHash10("sha256").update(content).digest("hex");
|
|
16989
17577
|
}
|
|
17578
|
+
// src/lib/session-refresh.ts
|
|
17579
|
+
init_zod();
|
|
17580
|
+
import { createHash as createHash11 } from "crypto";
|
|
17581
|
+
import { closeSync as closeSync4, constants as constants2, fstatSync as fstatSync4, lstatSync as lstatSync7, openSync as openSync4, readFileSync as readFileSync15 } from "fs";
|
|
17582
|
+
import { dirname as dirname11, join as join18, parse as parse6, resolve as resolve12 } from "path";
|
|
17583
|
+
|
|
17584
|
+
// src/lib/global-source-coverage.ts
|
|
17585
|
+
var GLOBAL_SOURCE_SLUG_PREFIX = "global-";
|
|
17586
|
+
function expectedGlobalSourceSlugs(registryConfigs) {
|
|
17587
|
+
return registryConfigs.filter((c) => c.slug.startsWith(GLOBAL_SOURCE_SLUG_PREFIX)).filter((c) => instructionSourceRejection(c) === null).map((c) => c.slug).sort();
|
|
17588
|
+
}
|
|
17589
|
+
function accountedGlobalSourceSlugs(manifest) {
|
|
17590
|
+
return [...manifest.sources, ...manifest.skippedSources].map((source) => source.id).filter((id) => id.startsWith(GLOBAL_SOURCE_SLUG_PREFIX));
|
|
17591
|
+
}
|
|
17592
|
+
function computeGlobalSourceCoverage(registryConfigs, configuredSlugs) {
|
|
17593
|
+
const expected = expectedGlobalSourceSlugs(registryConfigs);
|
|
17594
|
+
const expectedSet = new Set(expected);
|
|
17595
|
+
const configuredSet = new Set(configuredSlugs);
|
|
17596
|
+
const missing = expected.filter((slug2) => !configuredSet.has(slug2));
|
|
17597
|
+
const unexpected = [...configuredSet].filter((slug2) => slug2.startsWith(GLOBAL_SOURCE_SLUG_PREFIX) && !expectedSet.has(slug2)).sort();
|
|
17598
|
+
return {
|
|
17599
|
+
expectedSlugs: expected,
|
|
17600
|
+
excludedSources: registryConfigs.filter((config) => config.slug.startsWith(GLOBAL_SOURCE_SLUG_PREFIX)).flatMap((config) => {
|
|
17601
|
+
const reason = instructionSourceRejection(config);
|
|
17602
|
+
return reason ? [{ slug: config.slug, reason }] : [];
|
|
17603
|
+
}).sort((left, right) => left.slug.localeCompare(right.slug)),
|
|
17604
|
+
configuredSlugs: [...configuredSet].sort(),
|
|
17605
|
+
missingSlugs: missing,
|
|
17606
|
+
unexpectedSlugs: unexpected,
|
|
17607
|
+
complete: missing.length === 0
|
|
17608
|
+
};
|
|
17609
|
+
}
|
|
17610
|
+
|
|
17611
|
+
// src/lib/session-refresh.ts
|
|
17612
|
+
init_instruction_graph();
|
|
17613
|
+
init_project_context();
|
|
17614
|
+
init_session_render();
|
|
17615
|
+
import { basename as basename6 } from "path";
|
|
17616
|
+
var nonempty = exports_external.string().min(1).max(4096);
|
|
17617
|
+
var selectorSchema = exports_external.object({
|
|
17618
|
+
schema: exports_external.literal("hasna.instructions.hosted-profile-selector/v1"),
|
|
17619
|
+
authority: nonempty,
|
|
17620
|
+
profileId: nonempty,
|
|
17621
|
+
providerVersion: nonempty,
|
|
17622
|
+
providerVariant: nonempty.optional(),
|
|
17623
|
+
model: nonempty.optional(),
|
|
17624
|
+
path: nonempty.optional(),
|
|
17625
|
+
manual: exports_external.array(nonempty).max(256),
|
|
17626
|
+
codewithNativeImports: exports_external.boolean(),
|
|
17627
|
+
allowEmptySources: exports_external.boolean(),
|
|
17628
|
+
stationProfile: exports_external.boolean(),
|
|
17629
|
+
checkGlobalCoverage: exports_external.boolean(),
|
|
17630
|
+
assetSurface: nonempty.optional(),
|
|
17631
|
+
assetScope: exports_external.enum(["global", "project", "session"]).optional()
|
|
17632
|
+
}).strict();
|
|
17633
|
+
function authority(value) {
|
|
17634
|
+
const url = new URL(value);
|
|
17635
|
+
if (url.username || url.password || url.search || url.hash || !["https:", "http:"].includes(url.protocol)) {
|
|
17636
|
+
throw new Error("SESSION_REFRESH_AUTHORITY_INVALID: expected a credential-free Instructions API authority.");
|
|
17637
|
+
}
|
|
17638
|
+
return url.toString().replace(/\/$/, "");
|
|
17639
|
+
}
|
|
17640
|
+
function normalizeSessionHostedProfileSelector(value) {
|
|
17641
|
+
const parsed = selectorSchema.parse(value);
|
|
17642
|
+
return { ...parsed, authority: authority(parsed.authority) };
|
|
17643
|
+
}
|
|
17644
|
+
function assertHostedProfileBindings(profileId, configs, bindings) {
|
|
17645
|
+
const configIds = new Set(configs.map((config) => config.id));
|
|
17646
|
+
const bindingIds = new Set(bindings.map((binding) => binding.config_id));
|
|
17647
|
+
if (configIds.size !== configs.length || bindingIds.size !== bindings.length || bindings.some((binding) => binding.profile_id !== profileId || !configIds.has(binding.config_id)) || [...configIds].some((id) => !bindingIds.has(id))) {
|
|
17648
|
+
throw new Error("HOSTED_PROFILE_BINDINGS_INCOMPLETE: exact one-to-one config membership and explicit profile bindings are required; refusing legacy activation fallback.");
|
|
17649
|
+
}
|
|
17650
|
+
for (const row of bindings) {
|
|
17651
|
+
const raw = row.binding;
|
|
17652
|
+
const invalid = () => new Error("HOSTED_PROFILE_BINDINGS_INVALID: each hosted binding must contain a complete explicit schema, activation, required flag and fallback; refusing legacy activation defaults.");
|
|
17653
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
17654
|
+
throw invalid();
|
|
17655
|
+
const record = raw;
|
|
17656
|
+
if (!["schema", "activation", "required", "fallback"].every((key) => Object.hasOwn(record, key)) || typeof record["required"] !== "boolean")
|
|
17657
|
+
throw invalid();
|
|
17658
|
+
try {
|
|
17659
|
+
normalizeProfileConfigBinding(record);
|
|
17660
|
+
} catch {
|
|
17661
|
+
throw invalid();
|
|
17662
|
+
}
|
|
17663
|
+
}
|
|
17664
|
+
}
|
|
17665
|
+
function readManagedManifest(targetHome) {
|
|
17666
|
+
const path = join18(targetHome, SESSION_RENDER_MANIFEST_RELATIVE_PATH);
|
|
17667
|
+
let ancestor = dirname11(path);
|
|
17668
|
+
while (true) {
|
|
17669
|
+
const stat = lstatSync7(ancestor);
|
|
17670
|
+
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
17671
|
+
throw new Error("SESSION_REFRESH_PATH_INVALID: managed target uses a symlink or non-directory ancestor.");
|
|
17672
|
+
const parent = dirname11(ancestor);
|
|
17673
|
+
if (parent === ancestor)
|
|
17674
|
+
break;
|
|
17675
|
+
ancestor = parent;
|
|
17676
|
+
}
|
|
17677
|
+
const fd = openSync4(path, constants2.O_RDONLY | constants2.O_NOFOLLOW);
|
|
17678
|
+
let raw;
|
|
17679
|
+
try {
|
|
17680
|
+
const stat = fstatSync4(fd);
|
|
17681
|
+
if (!stat.isFile() || stat.size > SESSION_MANAGED_INPUT_MAX_BYTES)
|
|
17682
|
+
throw new Error("SESSION_REFRESH_MANIFEST_INVALID: expected a bounded regular manifest file.");
|
|
17683
|
+
raw = readFileSync15(fd);
|
|
17684
|
+
if (raw.byteLength > SESSION_MANAGED_INPUT_MAX_BYTES)
|
|
17685
|
+
throw new Error("SESSION_REFRESH_MANIFEST_INVALID: manifest grew beyond the read limit.");
|
|
17686
|
+
} finally {
|
|
17687
|
+
closeSync4(fd);
|
|
17688
|
+
}
|
|
17689
|
+
const manifest = JSON.parse(raw.toString("utf8"));
|
|
17690
|
+
if (manifest.schema !== SESSION_RENDER_SCHEMA || !SESSION_RENDER_TOOLS.includes(manifest.tool) || manifest.targetHome !== targetHome || !manifest.profile?.trim() || !["session-home", "project-root"].includes(manifest.targetKind) || !Array.isArray(manifest.files) || !manifest.refreshSelector || manifest.targetOwner?.writer?.id !== SESSION_RENDERER_OWNER_ID || manifest.targetOwner?.targetHome !== targetHome) {
|
|
17691
|
+
throw new Error("SESSION_REFRESH_MANIFEST_INVALID: target is not an owned hosted profile render; apply a hosted --compile-profile first.");
|
|
17692
|
+
}
|
|
17693
|
+
manifest.refreshSelector = normalizeSessionHostedProfileSelector(manifest.refreshSelector);
|
|
17694
|
+
return { manifest, sha256: createHash11("sha256").update(raw).digest("hex") };
|
|
17695
|
+
}
|
|
17696
|
+
async function refreshSessionRender(input) {
|
|
17697
|
+
const { store } = input;
|
|
17698
|
+
if (store.mode !== "api" || !store.v1BaseUrl)
|
|
17699
|
+
throw new Error("SESSION_REFRESH_HOSTED_REQUIRED: refresh requires the configured hosted Instructions API.");
|
|
17700
|
+
const targetHome = resolve12(input.targetHome);
|
|
17701
|
+
if (targetHome === parse6(targetHome).root)
|
|
17702
|
+
throw new Error("SESSION_REFRESH_PATH_INVALID: filesystem root is not a managed target.");
|
|
17703
|
+
const previous = readManagedManifest(targetHome);
|
|
17704
|
+
const selector = previous.manifest.refreshSelector;
|
|
17705
|
+
if (authority(store.v1BaseUrl) !== selector.authority)
|
|
17706
|
+
throw new Error("SESSION_REFRESH_AUTHORITY_MISMATCH: configured API differs from the recorded profile authority.");
|
|
17707
|
+
const profile = await store.getProfile(selector.profileId);
|
|
17708
|
+
if (profile.id !== selector.profileId)
|
|
17709
|
+
throw new Error("SESSION_REFRESH_PROFILE_MISMATCH: hosted profile identity changed.");
|
|
17710
|
+
const [configs, bindings, assetBindings] = await Promise.all([
|
|
17711
|
+
store.getProfileConfigs(profile.id),
|
|
17712
|
+
store.getProfileConfigBindings(profile.id, { requireExplicit: true }),
|
|
17713
|
+
store.getProfileAssetBindings(profile.id, { requireExplicit: true })
|
|
17714
|
+
]);
|
|
17715
|
+
assertHostedProfileBindings(profile.id, configs, bindings);
|
|
17716
|
+
if (configs.length > 2048 || bindings.length > 8192 || assetBindings.length > 1024)
|
|
17717
|
+
throw new Error("SESSION_REFRESH_INPUT_LIMIT: hosted profile exceeds refresh bounds.");
|
|
17718
|
+
const totalBytes = configs.reduce((sum, config) => sum + Buffer.byteLength(config.content), 0);
|
|
17719
|
+
if (totalBytes > SESSION_MANAGED_INPUT_MAX_BYTES)
|
|
17720
|
+
throw new Error("SESSION_REFRESH_INPUT_LIMIT: hosted instruction payload exceeds refresh byte bounds.");
|
|
17721
|
+
const assetConfigs = await Promise.all([...new Set(assetBindings.map((binding) => binding.source_config_id))].map((id) => store.getConfigById(id)));
|
|
17722
|
+
if (assetConfigs.reduce((sum, config) => sum + Buffer.byteLength(config.content), totalBytes) > SESSION_MANAGED_INPUT_MAX_BYTES)
|
|
17723
|
+
throw new Error("SESSION_REFRESH_INPUT_LIMIT: hosted source and asset payload exceeds refresh byte bounds.");
|
|
17724
|
+
let ownedClaudeAuthorities;
|
|
17725
|
+
if (previous.manifest.tool === "claude") {
|
|
17726
|
+
ownedClaudeAuthorities = (await store.listConfigs({ category: "rules", agent: "claude", kind: "file" })).filter((config) => config.target_path && basename6(normalizeTargetPath(config.target_path)) === "AGENTS.md").map((config) => ({ slug: config.slug, targetPath: config.target_path, content: config.content }));
|
|
17727
|
+
}
|
|
17728
|
+
const station = selector.stationProfile ? stationProfileSource() : null;
|
|
17729
|
+
const plan = planProfileSessionRender({
|
|
17730
|
+
tool: previous.manifest.tool,
|
|
17731
|
+
profile: previous.manifest.profile,
|
|
17732
|
+
profile_id: profile.id,
|
|
17733
|
+
provider_version: selector.providerVersion,
|
|
17734
|
+
targetHome,
|
|
17735
|
+
...previous.manifest.targetKind === "project-root" ? { projectRoot: targetHome } : {},
|
|
17736
|
+
sessionId: previous.manifest.sessionId ?? undefined,
|
|
17737
|
+
refreshSelector: selector,
|
|
17738
|
+
codewithNativeImports: selector.codewithNativeImports,
|
|
17739
|
+
allowEmptySources: selector.allowEmptySources,
|
|
17740
|
+
configs,
|
|
17741
|
+
bindings,
|
|
17742
|
+
asset_configs: assetConfigs,
|
|
17743
|
+
asset_bindings: assetBindings,
|
|
17744
|
+
asset_plan_mode: input.dryRun ? "dry-run" : "apply",
|
|
17745
|
+
asset_scope: selector.assetScope,
|
|
17746
|
+
asset_surface: selector.assetSurface,
|
|
17747
|
+
extra_sources: station ? [station] : undefined,
|
|
17748
|
+
ownedClaudeAuthorities,
|
|
17749
|
+
graph_context: {
|
|
17750
|
+
...selector.providerVariant ? { provider_variant: selector.providerVariant } : {},
|
|
17751
|
+
...selector.model ? { model: selector.model } : {},
|
|
17752
|
+
...selector.path ? { path: selector.path } : {},
|
|
17753
|
+
...selector.manual.length ? { manual: selector.manual } : {}
|
|
17754
|
+
}
|
|
17755
|
+
});
|
|
17756
|
+
if (selector.checkGlobalCoverage) {
|
|
17757
|
+
const coverage = computeGlobalSourceCoverage(await store.listConfigs({}), accountedGlobalSourceSlugs(plan.manifest));
|
|
17758
|
+
if (!coverage.complete)
|
|
17759
|
+
throw new Error(`SESSION_REFRESH_COVERAGE_INCOMPLETE: ${coverage.missingSlugs.length} registered global sources are absent.`);
|
|
17760
|
+
}
|
|
17761
|
+
const preview = applySessionRender(plan, { dryRun: true, expectedManifestSha256: previous.sha256, ownedClaudeAuthorities });
|
|
17762
|
+
const common = { checkedAt: new Date().toISOString(), targetHome, selector, sourceHash: plan.manifest.sourceHash };
|
|
17763
|
+
if (preview.conflicts.length)
|
|
17764
|
+
return { ...common, status: "blocked", apply: preview };
|
|
17765
|
+
if (!preview.drift.clean)
|
|
17766
|
+
throw new Error("SESSION_REFRESH_DRIFT: generated files changed or disappeared since their last managed render.");
|
|
17767
|
+
const sameSources = previous.manifest.sourceHash === plan.manifest.sourceHash;
|
|
17768
|
+
const samePayloads = preview.files.filter((file) => file.role !== "manifest").every((file) => file.action === "unchanged");
|
|
17769
|
+
if (sameSources && samePayloads) {
|
|
17770
|
+
if (readManagedManifest(targetHome).sha256 !== previous.sha256 || !checkSessionRenderDrift(targetHome).clean)
|
|
17771
|
+
throw new Error("SESSION_REFRESH_DRIFT: managed target changed during refresh.");
|
|
17772
|
+
return { ...common, status: "unchanged", apply: { ...preview, files: preview.files.map((file) => file.role === "manifest" ? { ...file, action: "unchanged", changed: false, newSha256: previous.sha256, reason: "hosted sources and generated payloads unchanged" } : file) } };
|
|
17773
|
+
}
|
|
17774
|
+
if (input.dryRun)
|
|
17775
|
+
return { ...common, status: "dry-run", apply: preview };
|
|
17776
|
+
const applied = applySessionRender(plan, { expectedManifestSha256: previous.sha256, ownedClaudeAuthorities });
|
|
17777
|
+
if (applied.conflicts.length)
|
|
17778
|
+
return { ...common, status: "blocked", apply: applied };
|
|
17779
|
+
if (!applied.applied || !checkSessionRenderDrift(targetHome).clean)
|
|
17780
|
+
throw new Error("SESSION_REFRESH_READBACK_FAILED: applied instructions did not verify against their manifest.");
|
|
17781
|
+
return { ...common, status: "updated", apply: applied };
|
|
17782
|
+
}
|
|
16990
17783
|
|
|
16991
17784
|
// src/index.ts
|
|
16992
17785
|
init_project_context();
|
|
@@ -16994,9 +17787,11 @@ init_transforms();
|
|
|
16994
17787
|
init_machine();
|
|
16995
17788
|
|
|
16996
17789
|
// src/lib/platform-profiles.ts
|
|
17790
|
+
init_types();
|
|
16997
17791
|
init_config_store();
|
|
16998
17792
|
|
|
16999
17793
|
// src/lib/project-dashboard-standard.ts
|
|
17794
|
+
init_types();
|
|
17000
17795
|
init_config_store();
|
|
17001
17796
|
var PROJECT_DASHBOARD_STANDARD_SLUG = "agent-managed-project-dashboard-standard";
|
|
17002
17797
|
var PROJECT_DASHBOARD_PROFILE_VARIABLES = {
|
|
@@ -17089,11 +17884,15 @@ async function ensureProjectDashboardStandardConfig(store = resolveConfigStore()
|
|
|
17089
17884
|
};
|
|
17090
17885
|
try {
|
|
17091
17886
|
const existing = await store.getConfig(PROJECT_DASHBOARD_STANDARD_SLUG);
|
|
17887
|
+
if (isRetiredInstructionSource(existing))
|
|
17888
|
+
return existing;
|
|
17092
17889
|
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) {
|
|
17093
17890
|
return await store.updateConfig(existing.id, input);
|
|
17094
17891
|
}
|
|
17095
17892
|
return existing;
|
|
17096
|
-
} catch {
|
|
17893
|
+
} catch (error) {
|
|
17894
|
+
if (!(error instanceof ConfigNotFoundError))
|
|
17895
|
+
throw error;
|
|
17097
17896
|
return await store.createConfig(input);
|
|
17098
17897
|
}
|
|
17099
17898
|
}
|
|
@@ -17106,10 +17905,9 @@ function profileHasSelectors2(profile) {
|
|
|
17106
17905
|
var PLATFORM_PROFILE_PRESETS = [
|
|
17107
17906
|
{
|
|
17108
17907
|
name: "linux-arm64",
|
|
17109
|
-
description: "Default
|
|
17110
|
-
selectors: { os: ["linux"], arch: ["arm64"]
|
|
17908
|
+
description: "Default reviewed instruction profile for Linux arm64",
|
|
17909
|
+
selectors: { os: ["linux"], arch: ["arm64"] },
|
|
17111
17910
|
variables: {
|
|
17112
|
-
WORKSPACE_ROOT: "{{HOME_DIR}}/workspace",
|
|
17113
17911
|
BUN_BIN_DIR: "{{HOME_DIR}}/.bun/bin",
|
|
17114
17912
|
BUN_PATH: "{{BUN_BIN_DIR}}/bun",
|
|
17115
17913
|
PATH_PREFIX: "{{BUN_BIN_DIR}}",
|
|
@@ -17118,10 +17916,9 @@ var PLATFORM_PROFILE_PRESETS = [
|
|
|
17118
17916
|
},
|
|
17119
17917
|
{
|
|
17120
17918
|
name: "macos-arm64",
|
|
17121
|
-
description: "Default
|
|
17122
|
-
selectors: { os: ["macos"], arch: ["arm64"]
|
|
17919
|
+
description: "Default reviewed instruction profile for macOS arm64",
|
|
17920
|
+
selectors: { os: ["macos"], arch: ["arm64"] },
|
|
17123
17921
|
variables: {
|
|
17124
|
-
WORKSPACE_ROOT: "{{HOME_DIR}}/Workspace",
|
|
17125
17922
|
BUN_BIN_DIR: "{{HOME_DIR}}/.bun/bin",
|
|
17126
17923
|
BUN_PATH: "/opt/homebrew/bin/bun",
|
|
17127
17924
|
PATH_PREFIX: "/opt/homebrew/bin:{{BUN_BIN_DIR}}",
|
|
@@ -17130,12 +17927,21 @@ var PLATFORM_PROFILE_PRESETS = [
|
|
|
17130
17927
|
}
|
|
17131
17928
|
];
|
|
17132
17929
|
async function ensurePlatformProfiles(store = resolveConfigStore()) {
|
|
17133
|
-
const configs = await store.listConfigs();
|
|
17134
17930
|
const ensured = [];
|
|
17135
|
-
|
|
17136
|
-
let profile;
|
|
17931
|
+
const existingProfiles = await Promise.all(PLATFORM_PROFILE_PRESETS.map(async (preset) => {
|
|
17137
17932
|
try {
|
|
17138
|
-
|
|
17933
|
+
return await store.getProfile(preset.name);
|
|
17934
|
+
} catch (error) {
|
|
17935
|
+
if (error instanceof ProfileNotFoundError)
|
|
17936
|
+
return null;
|
|
17937
|
+
throw error;
|
|
17938
|
+
}
|
|
17939
|
+
}));
|
|
17940
|
+
for (const [index, preset] of PLATFORM_PROFILE_PRESETS.entries()) {
|
|
17941
|
+
let profile;
|
|
17942
|
+
const existing = existingProfiles[index];
|
|
17943
|
+
if (existing) {
|
|
17944
|
+
profile = existing;
|
|
17139
17945
|
const selectors = mergeProfileSelectors(preset.selectors, profile.selectors);
|
|
17140
17946
|
const variables = mergeProfileVariables(preset.variables, profile.variables);
|
|
17141
17947
|
if (JSON.stringify(selectors) !== JSON.stringify(profile.selectors) || JSON.stringify(variables) !== JSON.stringify(profile.variables)) {
|
|
@@ -17145,12 +17951,9 @@ async function ensurePlatformProfiles(store = resolveConfigStore()) {
|
|
|
17145
17951
|
variables
|
|
17146
17952
|
});
|
|
17147
17953
|
}
|
|
17148
|
-
}
|
|
17954
|
+
} else {
|
|
17149
17955
|
profile = await store.createProfile(preset);
|
|
17150
17956
|
}
|
|
17151
|
-
for (const config of configs) {
|
|
17152
|
-
await store.addConfigToProfile(profile.id, config.id);
|
|
17153
|
-
}
|
|
17154
17957
|
ensured.push(profile);
|
|
17155
17958
|
}
|
|
17156
17959
|
return ensured;
|
|
@@ -17184,6 +17987,7 @@ function mergeUnique(preset, existing) {
|
|
|
17184
17987
|
init_global_agent_rules_standard();
|
|
17185
17988
|
|
|
17186
17989
|
// src/lib/dangerous-operation-guard-standard.ts
|
|
17990
|
+
init_types();
|
|
17187
17991
|
init_config_store();
|
|
17188
17992
|
var DANGEROUS_OPERATION_GUARD_STANDARD_SLUG = "dangerous-operation-guard-standard";
|
|
17189
17993
|
var DANGEROUS_OPERATION_GUARD_STANDARD_CONTENT = `# Dangerous Operation Guard Standard
|
|
@@ -17295,11 +18099,15 @@ async function ensureDangerousOperationGuardStandardConfig(store = resolveConfig
|
|
|
17295
18099
|
};
|
|
17296
18100
|
try {
|
|
17297
18101
|
const existing = await store.getConfig(DANGEROUS_OPERATION_GUARD_STANDARD_SLUG);
|
|
18102
|
+
if (isRetiredInstructionSource(existing))
|
|
18103
|
+
return existing;
|
|
17298
18104
|
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)) {
|
|
17299
18105
|
return await store.updateConfig(existing.id, input);
|
|
17300
18106
|
}
|
|
17301
18107
|
return existing;
|
|
17302
|
-
} catch {
|
|
18108
|
+
} catch (error) {
|
|
18109
|
+
if (!(error instanceof ConfigNotFoundError))
|
|
18110
|
+
throw error;
|
|
17303
18111
|
return await store.createConfig(input);
|
|
17304
18112
|
}
|
|
17305
18113
|
}
|
|
@@ -17309,8 +18117,8 @@ init_codewith_shared_todos_storage_standard();
|
|
|
17309
18117
|
|
|
17310
18118
|
// src/lib/sync.ts
|
|
17311
18119
|
init_config_store();
|
|
17312
|
-
import { existsSync as existsSync17, readdirSync as readdirSync5, readFileSync as
|
|
17313
|
-
import { basename as
|
|
18120
|
+
import { existsSync as existsSync17, readdirSync as readdirSync5, readFileSync as readFileSync17 } from "fs";
|
|
18121
|
+
import { basename as basename7, extname as extname3, join as join20 } from "path";
|
|
17314
18122
|
init_config_agents();
|
|
17315
18123
|
init_redact();
|
|
17316
18124
|
init_machine();
|
|
@@ -17318,8 +18126,8 @@ init_transforms();
|
|
|
17318
18126
|
|
|
17319
18127
|
// src/lib/sync-dir.ts
|
|
17320
18128
|
init_config_store();
|
|
17321
|
-
import { existsSync as existsSync16, readdirSync as readdirSync4, readFileSync as
|
|
17322
|
-
import { join as
|
|
18129
|
+
import { existsSync as existsSync16, readdirSync as readdirSync4, readFileSync as readFileSync16, statSync as statSync6 } from "fs";
|
|
18130
|
+
import { join as join19, relative as relative7 } from "path";
|
|
17323
18131
|
init_redact();
|
|
17324
18132
|
var SKIP = [".db", ".db-shm", ".db-wal", ".log", ".lock", ".DS_Store", "node_modules", ".git"];
|
|
17325
18133
|
function shouldSkip(p) {
|
|
@@ -17330,7 +18138,7 @@ async function syncFromDir(dir, opts = {}) {
|
|
|
17330
18138
|
const absDir = expandPath(dir);
|
|
17331
18139
|
if (!existsSync16(absDir))
|
|
17332
18140
|
return { added: 0, updated: 0, unchanged: 0, skipped: [`Not found: ${absDir}`] };
|
|
17333
|
-
const files = opts.recursive !== false ? walkDir(absDir) : readdirSync4(absDir).map((f) =>
|
|
18141
|
+
const files = opts.recursive !== false ? walkDir(absDir) : readdirSync4(absDir).map((f) => join19(absDir, f)).filter((f) => statSync6(f).isFile());
|
|
17334
18142
|
const result = { added: 0, updated: 0, unchanged: 0, skipped: [] };
|
|
17335
18143
|
const allConfigs = await store.listConfigs();
|
|
17336
18144
|
for (const file of files) {
|
|
@@ -17339,7 +18147,7 @@ async function syncFromDir(dir, opts = {}) {
|
|
|
17339
18147
|
continue;
|
|
17340
18148
|
}
|
|
17341
18149
|
try {
|
|
17342
|
-
const content =
|
|
18150
|
+
const content = readFileSync16(file, "utf-8");
|
|
17343
18151
|
if (content.length > 500000) {
|
|
17344
18152
|
result.skipped.push(file + " (too large)");
|
|
17345
18153
|
continue;
|
|
@@ -17389,7 +18197,7 @@ async function syncToDir(dir, opts = {}) {
|
|
|
17389
18197
|
}
|
|
17390
18198
|
function walkDir(dir, files = []) {
|
|
17391
18199
|
for (const entry of readdirSync4(dir, { withFileTypes: true })) {
|
|
17392
|
-
const full =
|
|
18200
|
+
const full = join19(dir, entry.name);
|
|
17393
18201
|
if (shouldSkip(full))
|
|
17394
18202
|
continue;
|
|
17395
18203
|
if (entry.isDirectory())
|
|
@@ -17411,7 +18219,7 @@ var CLAUDE_PROMPT_OUTPUTS = [
|
|
|
17411
18219
|
{ agent: "qwen", target_path: "~/.qwen/QWEN.md", transform: "codex-flat" }
|
|
17412
18220
|
];
|
|
17413
18221
|
function claudeRuleOutputs(fileName) {
|
|
17414
|
-
const stem =
|
|
18222
|
+
const stem = basename7(fileName, extname3(fileName));
|
|
17415
18223
|
return [
|
|
17416
18224
|
{ agent: "cursor", target_path: `~/.cursor/rules/${stem}.mdc`, transform: "cursor-mdc" }
|
|
17417
18225
|
];
|
|
@@ -17457,7 +18265,7 @@ function hasClaudeRuleSourceForCursorTarget(targetPath) {
|
|
|
17457
18265
|
const absolutePrefix = expandPath("~/.cursor/rules");
|
|
17458
18266
|
if (!absoluteTargetPath.startsWith(`${absolutePrefix}/`) || !absoluteTargetPath.endsWith(".mdc"))
|
|
17459
18267
|
return false;
|
|
17460
|
-
const stem =
|
|
18268
|
+
const stem = basename7(absoluteTargetPath, ".mdc");
|
|
17461
18269
|
return existsSync17(expandPath(`~/.claude/rules/${stem}.md`)) || existsSync17(expandPath(`~/.claude/rules/${stem}.mdc`));
|
|
17462
18270
|
}
|
|
17463
18271
|
function isKnownGeneratedTargetPath(targetPath) {
|
|
@@ -17523,11 +18331,11 @@ async function syncProject(opts) {
|
|
|
17523
18331
|
const allConfigs = await store.listConfigs();
|
|
17524
18332
|
const machine = detectMachineContext();
|
|
17525
18333
|
for (const pf of PROJECT_CONFIG_FILES) {
|
|
17526
|
-
const abs =
|
|
18334
|
+
const abs = join20(absDir, pf.file);
|
|
17527
18335
|
if (!existsSync17(abs))
|
|
17528
18336
|
continue;
|
|
17529
18337
|
try {
|
|
17530
|
-
const rawContent =
|
|
18338
|
+
const rawContent = readFileSync17(abs, "utf-8");
|
|
17531
18339
|
if (rawContent.length > 500000) {
|
|
17532
18340
|
result.skipped.push(pf.file);
|
|
17533
18341
|
continue;
|
|
@@ -17556,20 +18364,20 @@ async function syncProject(opts) {
|
|
|
17556
18364
|
}
|
|
17557
18365
|
}
|
|
17558
18366
|
for (const ruleDir of [
|
|
17559
|
-
{ dir:
|
|
17560
|
-
{ dir:
|
|
17561
|
-
{ dir:
|
|
17562
|
-
{ dir:
|
|
17563
|
-
{ dir:
|
|
17564
|
-
{ dir:
|
|
17565
|
-
{ dir:
|
|
18367
|
+
{ dir: join20(absDir, ".claude", "rules"), agent: "claude", namePrefix: "rules" },
|
|
18368
|
+
{ dir: join20(absDir, ".agents", "rules"), agent: "antigravity", namePrefix: "antigravity-rules" },
|
|
18369
|
+
{ dir: join20(absDir, ".cursor", "rules"), agent: "cursor", namePrefix: "cursor-rules" },
|
|
18370
|
+
{ dir: join20(absDir, ".github", "instructions"), agent: "copilot", namePrefix: "copilot-instructions" },
|
|
18371
|
+
{ dir: join20(absDir, ".devin", "rules"), agent: "devin", namePrefix: "devin-rules" },
|
|
18372
|
+
{ dir: join20(absDir, ".windsurf", "rules"), agent: "windsurf-legacy", namePrefix: "windsurf-rules" },
|
|
18373
|
+
{ dir: join20(absDir, ".clinerules"), agent: "cline", namePrefix: "cline-rules" }
|
|
17566
18374
|
]) {
|
|
17567
18375
|
if (!existsSync17(ruleDir.dir))
|
|
17568
18376
|
continue;
|
|
17569
18377
|
const mdFiles = readdirSync5(ruleDir.dir).filter((f) => f.endsWith(".md") || f.endsWith(".mdc"));
|
|
17570
18378
|
for (const f of mdFiles) {
|
|
17571
|
-
const abs =
|
|
17572
|
-
const raw =
|
|
18379
|
+
const abs = join20(ruleDir.dir, f);
|
|
18380
|
+
const raw = readFileSync17(abs, "utf-8");
|
|
17573
18381
|
const redacted = redactContent(raw, "markdown");
|
|
17574
18382
|
const machineAware = templateizeMachineContent(redacted.content, machine);
|
|
17575
18383
|
const content = machineAware.content;
|
|
@@ -17615,13 +18423,13 @@ async function syncKnown(opts = {}) {
|
|
|
17615
18423
|
const extensions = known.rulesExtensions ?? [".md", ".mdc"];
|
|
17616
18424
|
const ruleFiles = readdirSync5(absDir).filter((f) => extensions.some((ext) => f.endsWith(ext)));
|
|
17617
18425
|
for (const f of ruleFiles) {
|
|
17618
|
-
const abs2 =
|
|
18426
|
+
const abs2 = join20(absDir, f);
|
|
17619
18427
|
const targetPath = abs2.replace(home, "~");
|
|
17620
18428
|
if (existingOutputOwners.has(normalizeTargetPath(targetPath)) || isKnownGeneratedTargetPath(targetPath)) {
|
|
17621
18429
|
result.skipped.push(`${targetPath} (generated output)`);
|
|
17622
18430
|
continue;
|
|
17623
18431
|
}
|
|
17624
|
-
const raw =
|
|
18432
|
+
const raw = readFileSync17(abs2, "utf-8");
|
|
17625
18433
|
const redacted = redactContent(raw, "markdown");
|
|
17626
18434
|
const machineAware = templateizeMachineContent(redacted.content, machine);
|
|
17627
18435
|
const content = machineAware.content;
|
|
@@ -17654,7 +18462,7 @@ async function syncKnown(opts = {}) {
|
|
|
17654
18462
|
continue;
|
|
17655
18463
|
}
|
|
17656
18464
|
try {
|
|
17657
|
-
const rawContent = normalizeKnownConfigSource(known,
|
|
18465
|
+
const rawContent = normalizeKnownConfigSource(known, readFileSync17(abs, "utf-8"));
|
|
17658
18466
|
if (rawContent.length > 500000) {
|
|
17659
18467
|
result.skipped.push(known.path + " (too large)");
|
|
17660
18468
|
continue;
|
|
@@ -17759,7 +18567,7 @@ function buildDiff(expectedContent, targetPath, storedFormat, showSecrets) {
|
|
|
17759
18567
|
const path = expandPath(targetPath);
|
|
17760
18568
|
if (!existsSync17(path))
|
|
17761
18569
|
return `(file not found on disk: ${path})`;
|
|
17762
|
-
const diskContent =
|
|
18570
|
+
const diskContent = readFileSync17(path, "utf-8");
|
|
17763
18571
|
if (diskContent === expectedContent)
|
|
17764
18572
|
return "(no diff \u2014 identical)";
|
|
17765
18573
|
const format = redactFormatForTarget(targetPath, storedFormat);
|
|
@@ -17919,9 +18727,9 @@ function detectFormat(filePath) {
|
|
|
17919
18727
|
// src/lib/export.ts
|
|
17920
18728
|
init_types();
|
|
17921
18729
|
init_config_store();
|
|
17922
|
-
import { createHash as
|
|
18730
|
+
import { createHash as createHash12 } from "crypto";
|
|
17923
18731
|
import { existsSync as existsSync18, mkdirSync as mkdirSync8, mkdtempSync, rmSync as rmSync4, writeFileSync as writeFileSync6 } from "fs";
|
|
17924
|
-
import { dirname as
|
|
18732
|
+
import { dirname as dirname12, join as join21, resolve as resolve13 } from "path";
|
|
17925
18733
|
import { tmpdir } from "os";
|
|
17926
18734
|
var ARCHIVE_EXCLUSIONS = [
|
|
17927
18735
|
{
|
|
@@ -17944,7 +18752,7 @@ function compareText(left, right) {
|
|
|
17944
18752
|
return left < right ? -1 : left > right ? 1 : 0;
|
|
17945
18753
|
}
|
|
17946
18754
|
function sha25611(value) {
|
|
17947
|
-
return
|
|
18755
|
+
return createHash12("sha256").update(value).digest("hex");
|
|
17948
18756
|
}
|
|
17949
18757
|
function canonicalize(value) {
|
|
17950
18758
|
if (Array.isArray(value))
|
|
@@ -17972,7 +18780,12 @@ function logicalAssetLocator(locator, idToSlug) {
|
|
|
17972
18780
|
}
|
|
17973
18781
|
function logicalCollections(domain, options) {
|
|
17974
18782
|
const configs = [...domain.configs].sort((left, right) => compareText(left.slug, right.slug));
|
|
17975
|
-
const snapshots =
|
|
18783
|
+
const snapshots = domain.config_snapshots.map((snapshot) => ({
|
|
18784
|
+
config_slug: snapshot.config_slug,
|
|
18785
|
+
version: snapshot.version,
|
|
18786
|
+
content: snapshot.content,
|
|
18787
|
+
...options.includeOperationalTimestamps ? { created_at: snapshot.created_at } : {}
|
|
18788
|
+
})).sort((left, right) => compareText(left.config_slug, right.config_slug) || left.version - right.version || compareText(left.content, right.content) || compareText("created_at" in left ? left.created_at ?? "" : "", "created_at" in right ? right.created_at ?? "" : ""));
|
|
17976
18789
|
const profiles = [...domain.profiles].sort((left, right) => compareText(left.slug, right.slug));
|
|
17977
18790
|
const configBindings = [...domain.profile_config_bindings].sort((left, right) => compareText(left.profile_slug, right.profile_slug) || left.sort_order - right.sort_order || compareText(left.config_slug, right.config_slug));
|
|
17978
18791
|
const assetBindings = [...domain.profile_asset_bindings].sort((left, right) => compareText(left.profile_slug, right.profile_slug) || left.sort_order - right.sort_order || compareText(left.binding.assetKey, right.binding.assetKey));
|
|
@@ -18001,12 +18814,7 @@ function logicalCollections(domain, options) {
|
|
|
18001
18814
|
synced_at: config.synced_at
|
|
18002
18815
|
} : {}
|
|
18003
18816
|
})),
|
|
18004
|
-
config_snapshots: snapshots
|
|
18005
|
-
config_slug: snapshot.config_slug,
|
|
18006
|
-
version: snapshot.version,
|
|
18007
|
-
content: snapshot.content,
|
|
18008
|
-
...options.includeOperationalTimestamps ? { created_at: snapshot.created_at } : {}
|
|
18009
|
-
})),
|
|
18817
|
+
config_snapshots: snapshots,
|
|
18010
18818
|
profiles: profiles.map((profile) => ({
|
|
18011
18819
|
slug: profile.slug,
|
|
18012
18820
|
name: profile.name,
|
|
@@ -18130,10 +18938,11 @@ function validateInstructionsDomainArchive(value) {
|
|
|
18130
18938
|
assertUnique(typed.configs.map((row) => row.slug), "config slug");
|
|
18131
18939
|
assertUnique(typed.profiles.map((row) => row.slug), "profile slug");
|
|
18132
18940
|
assertUnique(typed.machines.map((row) => row.hostname), "machine hostname");
|
|
18133
|
-
assertUnique(typed.config_snapshots.map((row) =>
|
|
18941
|
+
assertUnique(typed.config_snapshots.map((row) => row.id), "config snapshot id");
|
|
18134
18942
|
assertUnique(typed.profile_config_bindings.map((row) => `${row.profile_slug}:${row.config_slug}`), "profile config binding");
|
|
18135
18943
|
assertUnique(typed.profile_asset_bindings.map((row) => `${row.profile_slug}:${row.binding.assetKey}`), "profile asset binding");
|
|
18136
|
-
const
|
|
18944
|
+
const configsBySlug = new Map(typed.configs.map((row) => [row.slug, row]));
|
|
18945
|
+
const configSlugs = new Set(configsBySlug.keys());
|
|
18137
18946
|
const profileSlugs = new Set(typed.profiles.map((row) => row.slug));
|
|
18138
18947
|
for (const config of typed.configs) {
|
|
18139
18948
|
assertTimestamp(config.created_at, `config ${config.slug} created_at`);
|
|
@@ -18141,24 +18950,15 @@ function validateInstructionsDomainArchive(value) {
|
|
|
18141
18950
|
assertTimestamp(config.synced_at, `config ${config.slug} synced_at`, true);
|
|
18142
18951
|
if (!Number.isSafeInteger(config.version) || config.version < 1)
|
|
18143
18952
|
throw new Error(`Invalid v2 archive: config ${config.slug} has invalid version`);
|
|
18144
|
-
const snapshots = typed.config_snapshots.filter((row) => row.config_slug === config.slug).sort((a, b) => a.version - b.version);
|
|
18145
|
-
if (snapshots.some((row) => !Number.isSafeInteger(row.version) || row.version < 1 || row.version > config.version)) {
|
|
18146
|
-
throw new Error(`Invalid v2 archive: config ${config.slug} has an invalid snapshot version`);
|
|
18147
|
-
}
|
|
18148
|
-
if (snapshots.length) {
|
|
18149
|
-
const first = snapshots[0].version;
|
|
18150
|
-
const expected = Array.from({ length: config.version - first + 1 }, (_, index) => first + index);
|
|
18151
|
-
if (canonicalDomainJson(snapshots.map((row) => row.version)) !== canonicalDomainJson(expected) || snapshots.at(-1).version !== config.version) {
|
|
18152
|
-
throw new Error(`Invalid v2 archive: snapshots for ${config.slug} must be a contiguous suffix ending at version ${config.version}`);
|
|
18153
|
-
}
|
|
18154
|
-
if (snapshots.at(-1).content !== config.content) {
|
|
18155
|
-
throw new Error(`Invalid v2 archive: latest snapshot content differs from config ${config.slug}`);
|
|
18156
|
-
}
|
|
18157
|
-
}
|
|
18158
18953
|
}
|
|
18159
18954
|
for (const row of typed.config_snapshots) {
|
|
18160
|
-
|
|
18955
|
+
const config = configsBySlug.get(row.config_slug);
|
|
18956
|
+
if (!config) {
|
|
18161
18957
|
throw new Error(`Invalid v2 archive: snapshot references missing config ${row.config_slug}`);
|
|
18958
|
+
}
|
|
18959
|
+
if (!Number.isSafeInteger(row.version) || row.version < 1 || row.version > config.version) {
|
|
18960
|
+
throw new Error(`Invalid v2 archive: config ${row.config_slug} has an invalid snapshot version`);
|
|
18961
|
+
}
|
|
18162
18962
|
assertTimestamp(row.created_at, `snapshot ${row.config_slug}@${row.version} created_at`);
|
|
18163
18963
|
}
|
|
18164
18964
|
for (const profile of typed.profiles) {
|
|
@@ -18265,13 +19065,13 @@ async function exportConfigs(outputPath, opts = {}) {
|
|
|
18265
19065
|
integrity,
|
|
18266
19066
|
exclusions: ARCHIVE_EXCLUSIONS
|
|
18267
19067
|
};
|
|
18268
|
-
const absOutput =
|
|
18269
|
-
mkdirSync8(
|
|
18270
|
-
const stagingDir = mkdtempSync(
|
|
19068
|
+
const absOutput = resolve13(outputPath);
|
|
19069
|
+
mkdirSync8(dirname12(absOutput), { recursive: true });
|
|
19070
|
+
const stagingDir = mkdtempSync(join21(tmpdir(), "instructions-domain-export-"));
|
|
18271
19071
|
try {
|
|
18272
|
-
writeFileSync6(
|
|
19072
|
+
writeFileSync6(join21(stagingDir, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
|
|
18273
19073
|
`, "utf-8");
|
|
18274
|
-
writeFileSync6(
|
|
19074
|
+
writeFileSync6(join21(stagingDir, "domain.json"), payload, "utf-8");
|
|
18275
19075
|
const proc = Bun.spawn(["tar", "czf", absOutput, "-C", stagingDir, "manifest.json", "domain.json"], {
|
|
18276
19076
|
stdout: "pipe",
|
|
18277
19077
|
stderr: "pipe"
|
|
@@ -18290,8 +19090,8 @@ async function exportConfigs(outputPath, opts = {}) {
|
|
|
18290
19090
|
// src/lib/import.ts
|
|
18291
19091
|
init_types();
|
|
18292
19092
|
init_config_store();
|
|
18293
|
-
import { createHash as
|
|
18294
|
-
import { resolve as
|
|
19093
|
+
import { createHash as createHash13 } from "crypto";
|
|
19094
|
+
import { resolve as resolve14 } from "path";
|
|
18295
19095
|
function compareText2(left, right) {
|
|
18296
19096
|
return left < right ? -1 : left > right ? 1 : 0;
|
|
18297
19097
|
}
|
|
@@ -18316,7 +19116,7 @@ function emptyResult() {
|
|
|
18316
19116
|
};
|
|
18317
19117
|
}
|
|
18318
19118
|
function sha25612(value) {
|
|
18319
|
-
return
|
|
19119
|
+
return createHash13("sha256").update(value).digest("hex");
|
|
18320
19120
|
}
|
|
18321
19121
|
function normalizeMemberName(name) {
|
|
18322
19122
|
let normalized = name;
|
|
@@ -18413,14 +19213,11 @@ function configInput(config, content) {
|
|
|
18413
19213
|
};
|
|
18414
19214
|
}
|
|
18415
19215
|
async function restoreNewConfig(store, archived, domain) {
|
|
18416
|
-
const snapshots = domain.config_snapshots.filter((row) => row.config_slug === archived.slug).sort((left, right) => left.version - right.version);
|
|
18417
|
-
|
|
18418
|
-
let content = byVersion.get(1) ?? snapshots[0]?.content ?? archived.content;
|
|
18419
|
-
let restored = await store.createConfig(configInput(archived, content));
|
|
19216
|
+
const snapshots = domain.config_snapshots.filter((row) => row.config_slug === archived.slug).sort((left, right) => left.version - right.version || compareText2(left.content, right.content) || compareText2(left.id, right.id));
|
|
19217
|
+
let restored = await store.createConfig(configInput(archived, archived.content));
|
|
18420
19218
|
for (let version = 2;version <= archived.version; version++) {
|
|
18421
|
-
content = byVersion.get(version) ?? (version === archived.version ? archived.content : content);
|
|
18422
19219
|
restored = await store.updateConfig(restored.id, {
|
|
18423
|
-
content,
|
|
19220
|
+
content: archived.content,
|
|
18424
19221
|
...version === archived.version ? {
|
|
18425
19222
|
name: archived.name,
|
|
18426
19223
|
kind: archived.kind,
|
|
@@ -18436,9 +19233,12 @@ async function restoreNewConfig(store, archived, domain) {
|
|
|
18436
19233
|
} : {}
|
|
18437
19234
|
});
|
|
18438
19235
|
}
|
|
18439
|
-
await store.pruneSnapshots(restored.id,
|
|
18440
|
-
|
|
18441
|
-
|
|
19236
|
+
await store.pruneSnapshots(restored.id, 0);
|
|
19237
|
+
for (const snapshot of snapshots) {
|
|
19238
|
+
await store.createSnapshot(restored.id, snapshot.content, snapshot.version);
|
|
19239
|
+
}
|
|
19240
|
+
const restoredSnapshots = (await store.listSnapshots(restored.id)).map(({ version, content: snapshotContent }) => ({ version, content: snapshotContent })).sort((left, right) => left.version - right.version || compareText2(left.content, right.content));
|
|
19241
|
+
const expectedSnapshots = snapshots.map(({ version, content: snapshotContent }) => ({ version, content: snapshotContent })).sort((left, right) => left.version - right.version || compareText2(left.content, right.content));
|
|
18442
19242
|
if (restored.version !== archived.version || restored.content !== archived.content || canonicalDomainJson(restoredSnapshots) !== canonicalDomainJson(expectedSnapshots)) {
|
|
18443
19243
|
throw new Error(`restored config or snapshot history did not match archive for ${archived.slug}`);
|
|
18444
19244
|
}
|
|
@@ -18579,7 +19379,7 @@ async function importV1(reader, manifest, store, conflict) {
|
|
|
18579
19379
|
async function importConfigs(bundlePath, opts = {}) {
|
|
18580
19380
|
const store = opts.store ?? resolveConfigStore();
|
|
18581
19381
|
const conflict = opts.conflict ?? "skip";
|
|
18582
|
-
const reader = await openArchive(
|
|
19382
|
+
const reader = await openArchive(resolve14(bundlePath));
|
|
18583
19383
|
const manifestText = await reader.read("manifest.json");
|
|
18584
19384
|
let manifest;
|
|
18585
19385
|
try {
|
|
@@ -18607,9 +19407,9 @@ init_redact();
|
|
|
18607
19407
|
|
|
18608
19408
|
// src/lib/package-manager-guard.ts
|
|
18609
19409
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
18610
|
-
import { existsSync as existsSync19, lstatSync as
|
|
19410
|
+
import { existsSync as existsSync19, lstatSync as lstatSync8, readdirSync as readdirSync6, readFileSync as readFileSync18 } from "fs";
|
|
18611
19411
|
import { homedir as homedir10 } from "os";
|
|
18612
|
-
import { basename as
|
|
19412
|
+
import { basename as basename8, dirname as dirname13, isAbsolute as isAbsolute8, join as join22, relative as relative8, resolve as resolve15 } from "path";
|
|
18613
19413
|
var SKIP_DIRS = new Set([
|
|
18614
19414
|
".git",
|
|
18615
19415
|
"node_modules",
|
|
@@ -18646,14 +19446,14 @@ var TOKEN_VALUE_PATTERNS = [
|
|
|
18646
19446
|
{ re: /xoxb-[0-9]+-[A-Za-z0-9-]+/, rule: "literal-slack-token", detail: "literal Slack token-like value" }
|
|
18647
19447
|
];
|
|
18648
19448
|
function scanPackageManagerSecrets(options = {}) {
|
|
18649
|
-
const cwd = options.cwd ?
|
|
18650
|
-
const roots = (options.roots && options.roots.length > 0 ? options.roots : [cwd]).map((root) =>
|
|
19449
|
+
const cwd = options.cwd ? resolve15(options.cwd) : process.cwd();
|
|
19450
|
+
const roots = (options.roots && options.roots.length > 0 ? options.roots : [cwd]).map((root) => resolve15(cwd, root));
|
|
18651
19451
|
const findings = [];
|
|
18652
19452
|
let scannedFiles = 0;
|
|
18653
19453
|
for (const root of roots) {
|
|
18654
19454
|
if (!existsSync19(root))
|
|
18655
19455
|
continue;
|
|
18656
|
-
const stat =
|
|
19456
|
+
const stat = lstatSync8(root);
|
|
18657
19457
|
if (stat.isFile()) {
|
|
18658
19458
|
if (!shouldScanRepoFile(root))
|
|
18659
19459
|
continue;
|
|
@@ -18661,7 +19461,7 @@ function scanPackageManagerSecrets(options = {}) {
|
|
|
18661
19461
|
if (text === null)
|
|
18662
19462
|
continue;
|
|
18663
19463
|
scannedFiles++;
|
|
18664
|
-
findings.push(...scanFile(root, text, classifyRepoFile(root), isTrackedFile(root),
|
|
19464
|
+
findings.push(...scanFile(root, text, classifyRepoFile(root), isTrackedFile(root), dirname13(root)));
|
|
18665
19465
|
continue;
|
|
18666
19466
|
}
|
|
18667
19467
|
if (!stat.isDirectory())
|
|
@@ -18680,7 +19480,7 @@ function scanPackageManagerSecrets(options = {}) {
|
|
|
18680
19480
|
if (options.includeHome) {
|
|
18681
19481
|
const home = homedir10();
|
|
18682
19482
|
for (const name of HOME_FILES) {
|
|
18683
|
-
const file =
|
|
19483
|
+
const file = join22(home, name);
|
|
18684
19484
|
if (!existsSync19(file))
|
|
18685
19485
|
continue;
|
|
18686
19486
|
const text = readTextFile(file);
|
|
@@ -18705,12 +19505,12 @@ function collectRepoFiles(root) {
|
|
|
18705
19505
|
if (entry.isDirectory()) {
|
|
18706
19506
|
if (SKIP_DIRS.has(entry.name))
|
|
18707
19507
|
continue;
|
|
18708
|
-
visit(
|
|
19508
|
+
visit(join22(dir, entry.name));
|
|
18709
19509
|
continue;
|
|
18710
19510
|
}
|
|
18711
19511
|
if (!entry.isFile())
|
|
18712
19512
|
continue;
|
|
18713
|
-
const file =
|
|
19513
|
+
const file = join22(dir, entry.name);
|
|
18714
19514
|
if (shouldScanRepoFile(file))
|
|
18715
19515
|
out.push(file);
|
|
18716
19516
|
}
|
|
@@ -18719,11 +19519,11 @@ function collectRepoFiles(root) {
|
|
|
18719
19519
|
return out;
|
|
18720
19520
|
}
|
|
18721
19521
|
function shouldScanRepoFile(file) {
|
|
18722
|
-
const name =
|
|
19522
|
+
const name = basename8(file);
|
|
18723
19523
|
return isNpmrcName(name) || isBunConfigName(name) || LOCKFILE_NAMES.has(name);
|
|
18724
19524
|
}
|
|
18725
19525
|
function classifyRepoFile(file) {
|
|
18726
|
-
const name =
|
|
19526
|
+
const name = basename8(file);
|
|
18727
19527
|
if (isNpmrcName(name))
|
|
18728
19528
|
return "repo-npmrc";
|
|
18729
19529
|
if (isBunConfigName(name))
|
|
@@ -18745,10 +19545,10 @@ function isNpmrcName(name) {
|
|
|
18745
19545
|
}
|
|
18746
19546
|
function readTextFile(file) {
|
|
18747
19547
|
try {
|
|
18748
|
-
const stat =
|
|
19548
|
+
const stat = lstatSync8(file);
|
|
18749
19549
|
if (!stat.isFile() || stat.size > 5000000)
|
|
18750
19550
|
return null;
|
|
18751
|
-
const buf =
|
|
19551
|
+
const buf = readFileSync18(file);
|
|
18752
19552
|
if (buf.includes(0))
|
|
18753
19553
|
return null;
|
|
18754
19554
|
return buf.toString("utf-8");
|
|
@@ -18948,7 +19748,7 @@ function trackedFiles(root) {
|
|
|
18948
19748
|
}
|
|
18949
19749
|
function isTrackedFile(file) {
|
|
18950
19750
|
try {
|
|
18951
|
-
const repoRoot = execFileSync2("git", ["-C",
|
|
19751
|
+
const repoRoot = execFileSync2("git", ["-C", dirname13(file), "rev-parse", "--show-toplevel"], {
|
|
18952
19752
|
encoding: "utf-8",
|
|
18953
19753
|
stdio: ["ignore", "pipe", "ignore"]
|
|
18954
19754
|
}).trim();
|
|
@@ -18991,6 +19791,7 @@ function toPosix(path) {
|
|
|
18991
19791
|
return path.split("\\").join("/");
|
|
18992
19792
|
}
|
|
18993
19793
|
export {
|
|
19794
|
+
validateExpectedConfigVersion,
|
|
18994
19795
|
uuid,
|
|
18995
19796
|
transformSkillContent,
|
|
18996
19797
|
templateizeMachineContent,
|
|
@@ -19026,6 +19827,7 @@ export {
|
|
|
19026
19827
|
renderMachineAwareContentPreview,
|
|
19027
19828
|
renderMachineAwareContent,
|
|
19028
19829
|
refreshStationProfile,
|
|
19830
|
+
refreshSessionRender,
|
|
19029
19831
|
redactContent,
|
|
19030
19832
|
reconcileManagedSkillRuntimes,
|
|
19031
19833
|
readStationProfile,
|
|
@@ -19039,6 +19841,7 @@ export {
|
|
|
19039
19841
|
parseProjectContextBundle,
|
|
19040
19842
|
parseAgentOperatingRulesVersion,
|
|
19041
19843
|
now,
|
|
19844
|
+
normalizeSessionHostedProfileSelector,
|
|
19042
19845
|
normalizeProfileConfigBinding,
|
|
19043
19846
|
normalizeProfileAssetBinding,
|
|
19044
19847
|
normalizeOsFamily,
|
|
@@ -19085,6 +19888,7 @@ export {
|
|
|
19085
19888
|
compareAgentOperatingRulesVersions,
|
|
19086
19889
|
cleanSessionPathInput,
|
|
19087
19890
|
checkSessionRenderDrift,
|
|
19891
|
+
buildSumiAgentsMd,
|
|
19088
19892
|
buildStationProfileBlock,
|
|
19089
19893
|
buildOpenCodeAgentsMd,
|
|
19090
19894
|
buildCursorMdc,
|
|
@@ -19144,6 +19948,7 @@ export {
|
|
|
19144
19948
|
LEGACY_CONFIGS_EXECUTABLE,
|
|
19145
19949
|
LEGACY_CONFIGS_COMPAT_VERSION,
|
|
19146
19950
|
KNOWN_CONFIGS,
|
|
19951
|
+
InvalidExpectedVersionError,
|
|
19147
19952
|
InstructionGraphValidationError,
|
|
19148
19953
|
INSTRUCTION_GRAPH_PLAN_SCHEMA,
|
|
19149
19954
|
INSTRUCTION_FALLBACKS,
|
|
@@ -19156,6 +19961,7 @@ export {
|
|
|
19156
19961
|
GLOBAL_AGENT_RULES_STANDARD_CONTENT,
|
|
19157
19962
|
DANGEROUS_OPERATION_GUARD_STANDARD_SLUG,
|
|
19158
19963
|
DANGEROUS_OPERATION_GUARD_STANDARD_CONTENT,
|
|
19964
|
+
ConfigVersionConflictError,
|
|
19159
19965
|
ConfigNotFoundError,
|
|
19160
19966
|
ConfigApplyError,
|
|
19161
19967
|
CloudConfigStore,
|