@hasna/instructions 0.6.1 → 0.7.0
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 +123 -6
- package/dist/chunks/{apply-ynfn1av7.js → apply-7svah2qm.js} +5 -3
- package/dist/chunks/{apply-sfzja1f3.js → apply-jp13sa1e.js} +6 -3
- package/dist/chunks/database-wstmr56z.js +23 -0
- package/dist/chunks/{index-85n5wnd8.js → index-1cnyjnd7.js} +5 -7
- package/dist/chunks/{index-pkscjnj5.js → index-3djthcm6.js} +0 -1
- package/dist/chunks/{index-v7dkb384.js → index-4pfq42t5.js} +129 -77
- package/dist/chunks/index-5d7zdftc.js +186 -0
- package/dist/chunks/{index-1hpwskwd.js → index-7m4j8a33.js} +205 -329
- package/dist/chunks/index-8rb7ng2y.js +148 -0
- package/dist/chunks/index-arrrx0ed.js +344 -0
- package/dist/chunks/{index-9p9gn7gh.js → index-bzyxvwcd.js} +5 -7
- package/dist/chunks/index-fpeyzn3n.js +186 -0
- package/dist/chunks/{index-axhwg61p.js → index-fwbs6tma.js} +15 -4
- package/dist/chunks/index-n3fjspr0.js +119 -0
- package/dist/chunks/{index-e9epbsvs.js → index-z3ma4aqk.js} +15 -4
- package/dist/chunks/legacy-store-migration-z2m5yzyk.js +322 -0
- package/dist/chunks/{local-a9nen65z.js → local-5wvv5xv3.js} +2 -2
- package/dist/chunks/{local-0d8qrc92.js → local-zxa5dpf4.js} +13 -188
- package/dist/chunks/s3-backup-n2z4fwyh.js +240 -0
- package/dist/chunks/s3-config-hhght91k.js +14 -0
- package/dist/chunks/s3-object-store-90tgbh6k.js +14 -0
- package/dist/chunks/{sync-m46fc257.js → sync-2075deve.js} +5 -4
- package/dist/chunks/{sync-vy1yjvs6.js → sync-r8t7zsp3.js} +4 -4
- package/dist/chunks/{template-02wjvv05.js → template-fsfxpe4p.js} +1 -1
- package/dist/chunks/{template-ke972qqe.js → template-wgnzdn7h.js} +1 -1
- package/dist/cli/index.js +1011 -247
- package/dist/data/config-store.d.ts +1 -0
- package/dist/data/config-store.d.ts.map +1 -1
- package/dist/index.js +840 -215
- package/dist/lib/apply.d.ts +7 -0
- package/dist/lib/apply.d.ts.map +1 -1
- package/dist/lib/compact-output.d.ts +1 -0
- package/dist/lib/compact-output.d.ts.map +1 -1
- package/dist/lib/export.d.ts +22 -3
- package/dist/lib/export.d.ts.map +1 -1
- package/dist/lib/import.d.ts +18 -0
- package/dist/lib/import.d.ts.map +1 -1
- package/dist/lib/legacy-store-migration.d.ts +39 -0
- package/dist/lib/legacy-store-migration.d.ts.map +1 -0
- package/dist/lib/managed-skill-runtimes.d.ts +1 -0
- package/dist/lib/managed-skill-runtimes.d.ts.map +1 -1
- package/dist/lib/sync-dir.d.ts.map +1 -1
- package/dist/mcp/index.js +31 -20
- package/dist/sdk/index.d.ts +2 -0
- package/dist/sdk/index.d.ts.map +1 -1
- package/dist/sdk/index.js +205 -10
- package/dist/sdk/resolve.d.ts +1 -1
- package/dist/sdk/resolve.d.ts.map +1 -1
- package/dist/sdk/v1-client.d.ts +57 -0
- package/dist/sdk/v1-client.d.ts.map +1 -0
- package/dist/sdk/v1.generated.d.ts +212 -21
- package/dist/sdk/v1.generated.d.ts.map +1 -1
- package/dist/server/cloud.d.ts.map +1 -1
- package/dist/server/index.d.ts +13 -5
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1180 -432
- package/dist/server/openapi.d.ts +1264 -92
- package/dist/server/openapi.d.ts.map +1 -1
- package/dist/server/v1.d.ts +25 -1
- package/dist/server/v1.d.ts.map +1 -1
- package/dist/storage/cloud-store.d.ts +57 -1
- package/dist/storage/cloud-store.d.ts.map +1 -1
- package/dist/storage/index.d.ts +7 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +725 -0
- package/dist/storage/s3-backup.d.ts +76 -0
- package/dist/storage/s3-backup.d.ts.map +1 -0
- package/dist/storage/s3-config.d.ts +46 -0
- package/dist/storage/s3-config.d.ts.map +1 -0
- package/dist/storage/s3-object-store.d.ts +70 -0
- package/dist/storage/s3-object-store.d.ts.map +1 -0
- package/dist/types/index.d.ts +65 -3
- package/dist/types/index.d.ts.map +1 -1
- package/hasna.contract.json +110 -0
- package/migrations/0001_instructions.sql +63 -0
- package/migrations/0002_api_keys.sql +20 -0
- package/migrations/0003_idempotency_receipts.sql +24 -0
- package/package.json +22 -11
- package/assets/skills/inbox/SKILL.md +0 -86
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// src/lib/raw-store-root.ts
|
|
3
|
+
import { resolve as resolve2 } from "path";
|
|
4
|
+
|
|
5
|
+
// src/lib/app-home.ts
|
|
6
|
+
import { existsSync } from "fs";
|
|
7
|
+
import { homedir } from "os";
|
|
8
|
+
import { join, resolve } from "path";
|
|
9
|
+
import { homedir as pathsResolverHomedir } from "os";
|
|
10
|
+
import { join as pathsResolverJoin } from "path";
|
|
11
|
+
var PATHS_RESOLVER_KIND_ENV = {
|
|
12
|
+
config: "HASNA_CONFIG_HOME",
|
|
13
|
+
data: "HASNA_DATA_HOME",
|
|
14
|
+
state: "HASNA_STATE_HOME",
|
|
15
|
+
cache: "HASNA_CACHE_HOME"
|
|
16
|
+
};
|
|
17
|
+
var PATHS_RESOLVER_APP_SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
18
|
+
function pathsResolverAssertApp(app) {
|
|
19
|
+
if (typeof app !== "string" || app.length === 0) {
|
|
20
|
+
throw new TypeError("paths: app must be a non-empty string");
|
|
21
|
+
}
|
|
22
|
+
if (!PATHS_RESOLVER_APP_SLUG_RE.test(app)) {
|
|
23
|
+
throw new TypeError(`paths: invalid app slug "${app}" \u2014 expected lowercase kebab-case ([a-z0-9]+(-[a-z0-9]+)*)`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function pathsResolverAssertKind(kind) {
|
|
27
|
+
if (!Object.keys(PATHS_RESOLVER_KIND_ENV).includes(kind)) {
|
|
28
|
+
throw new TypeError(`paths: invalid path kind "${kind}" \u2014 expected one of ${Object.keys(PATHS_RESOLVER_KIND_ENV).join(", ")}`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function pathsResolverBaseDir(kind, options) {
|
|
32
|
+
pathsResolverAssertKind(kind);
|
|
33
|
+
const env = options.env ?? process.env;
|
|
34
|
+
const override = env[PATHS_RESOLVER_KIND_ENV[kind]];
|
|
35
|
+
if (typeof override === "string" && override.length > 0)
|
|
36
|
+
return override;
|
|
37
|
+
const home = options.home ?? pathsResolverHomedir();
|
|
38
|
+
const platform = options.platform ?? process.platform;
|
|
39
|
+
if (platform === "darwin") {
|
|
40
|
+
switch (kind) {
|
|
41
|
+
case "config":
|
|
42
|
+
case "data":
|
|
43
|
+
return pathsResolverJoin(home, "Library", "Application Support", "Hasna");
|
|
44
|
+
case "cache":
|
|
45
|
+
return pathsResolverJoin(home, "Library", "Caches", "Hasna");
|
|
46
|
+
case "state":
|
|
47
|
+
return pathsResolverJoin(home, "Library", "Logs", "Hasna");
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
switch (kind) {
|
|
51
|
+
case "config":
|
|
52
|
+
return pathsResolverJoin(home, ".config", "hasna");
|
|
53
|
+
case "data":
|
|
54
|
+
return pathsResolverJoin(home, ".local", "share", "hasna");
|
|
55
|
+
case "state":
|
|
56
|
+
return pathsResolverJoin(home, ".local", "state", "hasna");
|
|
57
|
+
case "cache":
|
|
58
|
+
return pathsResolverJoin(home, ".cache", "hasna");
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function pathsResolverResolve(kind, options) {
|
|
62
|
+
pathsResolverAssertApp(options.app);
|
|
63
|
+
const appSegment = options.internal === true ? pathsResolverJoin("internal", options.app) : options.app;
|
|
64
|
+
return pathsResolverJoin(pathsResolverBaseDir(kind, options), appSegment);
|
|
65
|
+
}
|
|
66
|
+
function configDir(options) {
|
|
67
|
+
return pathsResolverResolve("config", options);
|
|
68
|
+
}
|
|
69
|
+
var HASNA_CONFIGS_HOME_ENV = "HASNA_CONFIGS_HOME";
|
|
70
|
+
function homeDir(env = process.env) {
|
|
71
|
+
return env["HOME"] || env["USERPROFILE"] || homedir();
|
|
72
|
+
}
|
|
73
|
+
function legacyStoreHome(env = process.env) {
|
|
74
|
+
return resolve(join(homeDir(env), ".hasna", "instructions"));
|
|
75
|
+
}
|
|
76
|
+
function resolverStoreHome(env = process.env) {
|
|
77
|
+
return configDir({ app: "configs", env, home: env.HOME || env.USERPROFILE || homedir() });
|
|
78
|
+
}
|
|
79
|
+
function adoptResolverStoreHome(resolved, env = process.env) {
|
|
80
|
+
const override = env.HASNA_CONFIG_HOME;
|
|
81
|
+
if (typeof override === "string" && override.trim().length > 0)
|
|
82
|
+
return true;
|
|
83
|
+
return existsSync(join(resolved, "instructions.db"));
|
|
84
|
+
}
|
|
85
|
+
function exactStoreHome(env = process.env) {
|
|
86
|
+
const v = env[HASNA_CONFIGS_HOME_ENV];
|
|
87
|
+
return v && v.trim() ? v.trim() : undefined;
|
|
88
|
+
}
|
|
89
|
+
function getConfigsStoreHome(env = process.env) {
|
|
90
|
+
const exact = exactStoreHome(env);
|
|
91
|
+
if (exact)
|
|
92
|
+
return resolve(exact);
|
|
93
|
+
const resolved = resolverStoreHome(env);
|
|
94
|
+
return adoptResolverStoreHome(resolved, env) ? resolve(resolved) : legacyStoreHome(env);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// src/lib/raw-store-root.ts
|
|
98
|
+
function getRawStoreRoot(env = process.env) {
|
|
99
|
+
return resolve2(getConfigsStoreHome(env));
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// ../../node_modules/.bun/@hasna+contracts@1.0.2+e8014c875821e0be/node_modules/@hasna/contracts/dist/client/transport.js
|
|
103
|
+
import { createRequire } from "module";
|
|
104
|
+
function envToken(name) {
|
|
105
|
+
return name.toUpperCase().replace(/-/g, "_");
|
|
106
|
+
}
|
|
107
|
+
function clientTransportEnvKeys(name) {
|
|
108
|
+
const envSegment = envToken(name);
|
|
109
|
+
return {
|
|
110
|
+
apiUrlKeys: [`HASNA_${envSegment}_API_URL`, `${envSegment}_API_URL`],
|
|
111
|
+
apiKeyKeys: [`HASNA_${envSegment}_API_KEY`, `${envSegment}_API_KEY`]
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
function credentialOverrideEnvKey(name) {
|
|
115
|
+
return `HASNA_${envToken(name)}_API_KEY_OVERRIDE`;
|
|
116
|
+
}
|
|
117
|
+
var CREDENTIAL_PROFILE_ENV_KEY = "HASNA_PROFILE";
|
|
118
|
+
function credentialPointerEnvKey(name) {
|
|
119
|
+
return `HASNA_${envToken(name)}_API_KEY_REF`;
|
|
120
|
+
}
|
|
121
|
+
var MAX_CREDENTIAL_FILE_BYTES = 64 * 1024;
|
|
122
|
+
var INSPECT_CUSTOM = Symbol.for("nodejs.util.inspect.custom");
|
|
123
|
+
var CREDENTIAL_SEAL = Symbol.for("hasna:contracts:sealedCredential");
|
|
124
|
+
var AMBIENT_ENVIRONMENT = Symbol.for("hasna:contracts:ambientClientEnvironment");
|
|
125
|
+
var SECRETS_PACKAGE_SPECIFIER = "@hasna/" + "secrets";
|
|
126
|
+
var requireSecretsSdk = createRequire(import.meta.url);
|
|
127
|
+
var IDEMPOTENT_METHODS = new Set(["GET", "HEAD", "PUT", "DELETE", "OPTIONS"]);
|
|
128
|
+
var AUTHORITY_OVERRIDE_HEADERS = new Set([
|
|
129
|
+
"host",
|
|
130
|
+
":authority",
|
|
131
|
+
"forwarded",
|
|
132
|
+
"x-forwarded-host",
|
|
133
|
+
"x-original-host"
|
|
134
|
+
]);
|
|
135
|
+
|
|
136
|
+
// src/lib/local-opt-in.ts
|
|
137
|
+
var INSTRUCTIONS_LOCAL_OPT_IN_ENV_KEYS = ["HASNA_INSTRUCTIONS_LOCAL"];
|
|
138
|
+
function instructionsLocalModeNotice() {
|
|
139
|
+
return `instructions: local mode \u2014 ${INSTRUCTIONS_LOCAL_OPT_IN_ENV_KEYS[0]}=1 selects the on-box SQLite store, ` + `and no hosted authority was configured. Set HASNA_INSTRUCTIONS_API_KEY (or add the Keychain item ` + `hasna.credentials.instructions.api-key, or write ~/.hasna/instructions/config/credentials) to go hosted.`;
|
|
140
|
+
}
|
|
141
|
+
function isInstructionsLocalOptIn(env = process.env) {
|
|
142
|
+
return INSTRUCTIONS_LOCAL_OPT_IN_ENV_KEYS.some((key) => (env[key] ?? "").trim() === "1");
|
|
143
|
+
}
|
|
144
|
+
function instructionsAuthorityEnvKeys() {
|
|
145
|
+
const keys = clientTransportEnvKeys("instructions");
|
|
146
|
+
return [
|
|
147
|
+
...keys.apiUrlKeys,
|
|
148
|
+
...keys.apiKeyKeys,
|
|
149
|
+
credentialOverrideEnvKey("instructions"),
|
|
150
|
+
credentialPointerEnvKey("instructions"),
|
|
151
|
+
CREDENTIAL_PROFILE_ENV_KEY
|
|
152
|
+
];
|
|
153
|
+
}
|
|
154
|
+
function hasInstructionsEnvAuthorityIntent(env = process.env) {
|
|
155
|
+
return instructionsAuthorityEnvKeys().some((key) => (env[key] ?? "").trim() !== "");
|
|
156
|
+
}
|
|
157
|
+
function selectsInstructionsLocalStore(env = process.env) {
|
|
158
|
+
return !hasInstructionsEnvAuthorityIntent(env) && isInstructionsLocalOptIn(env);
|
|
159
|
+
}
|
|
160
|
+
function instructionsResolverEnv(env) {
|
|
161
|
+
const blanks = instructionsAuthorityEnvKeys().filter((key) => (key in env) && (env[key] ?? "").trim() === "");
|
|
162
|
+
if (blanks.length === 0)
|
|
163
|
+
return env;
|
|
164
|
+
const next = { ...env };
|
|
165
|
+
for (const key of blanks)
|
|
166
|
+
delete next[key];
|
|
167
|
+
return next;
|
|
168
|
+
}
|
|
169
|
+
var CONTRACTS_AMBIENT_ENVIRONMENT = Symbol.for("hasna:contracts:ambientClientEnvironment");
|
|
170
|
+
function isAmbientInstructionsEnv(env) {
|
|
171
|
+
if (typeof process !== "undefined" && env === process.env)
|
|
172
|
+
return true;
|
|
173
|
+
return env[CONTRACTS_AMBIENT_ENVIRONMENT] === true;
|
|
174
|
+
}
|
|
175
|
+
function instructionsResolverInputs(env, credentials = {}) {
|
|
176
|
+
const normalised = instructionsResolverEnv(env);
|
|
177
|
+
if (normalised === env)
|
|
178
|
+
return { env: normalised, credentials };
|
|
179
|
+
const keychain = { ...credentials.keychain };
|
|
180
|
+
if (keychain.enabled === undefined && keychain.run === undefined) {
|
|
181
|
+
keychain.enabled = isAmbientInstructionsEnv(env);
|
|
182
|
+
}
|
|
183
|
+
return { env: normalised, credentials: { ...credentials, keychain } };
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export { getRawStoreRoot, clientTransportEnvKeys, INSTRUCTIONS_LOCAL_OPT_IN_ENV_KEYS, instructionsLocalModeNotice, hasInstructionsEnvAuthorityIntent, selectsInstructionsLocalStore, instructionsResolverInputs };
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
resolveConfigStore,
|
|
16
16
|
resolveProfileVariables,
|
|
17
17
|
stampCursorGlobalAuthorityMarker
|
|
18
|
-
} from "./index-
|
|
18
|
+
} from "./index-4pfq42t5.js";
|
|
19
19
|
import {
|
|
20
20
|
isSecretVarName,
|
|
21
21
|
redactFormatForTarget,
|
|
@@ -24,11 +24,11 @@ import {
|
|
|
24
24
|
import {
|
|
25
25
|
ConfigApplyError,
|
|
26
26
|
parseTemplateVars
|
|
27
|
-
} from "./index-
|
|
27
|
+
} from "./index-3djthcm6.js";
|
|
28
28
|
|
|
29
29
|
// src/lib/apply.ts
|
|
30
30
|
import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, realpathSync, writeFileSync } from "fs";
|
|
31
|
-
import { basename, dirname as dirname2, join as join2, resolve } from "path";
|
|
31
|
+
import { basename, dirname as dirname2, isAbsolute, join as join2, relative as relative2, resolve, sep as sep2 } from "path";
|
|
32
32
|
import { homedir } from "os";
|
|
33
33
|
|
|
34
34
|
// src/lib/session-render-ownership.ts
|
|
@@ -112,6 +112,17 @@ function expandPath(p) {
|
|
|
112
112
|
}
|
|
113
113
|
return resolve(p);
|
|
114
114
|
}
|
|
115
|
+
function compactPathForConfigHome(p) {
|
|
116
|
+
const absolute = resolve(p);
|
|
117
|
+
const configHome = resolve(getConfigHome());
|
|
118
|
+
const conventionalHome = resolve(process.env["HOME"] || homedir());
|
|
119
|
+
if (configHome !== conventionalHome)
|
|
120
|
+
return absolute;
|
|
121
|
+
const rel = relative2(configHome, absolute);
|
|
122
|
+
if (!rel || rel === ".." || rel.startsWith(`..${sep2}`) || isAbsolute(rel))
|
|
123
|
+
return absolute;
|
|
124
|
+
return `~/${rel}`;
|
|
125
|
+
}
|
|
115
126
|
function normalizeTargetPath(p) {
|
|
116
127
|
const expanded = expandPath(p);
|
|
117
128
|
try {
|
|
@@ -520,4 +531,4 @@ function sessionRendererOwnsCanonicalTarget(normalized, opts) {
|
|
|
520
531
|
return sessionRenderOwnsPath(normalized);
|
|
521
532
|
}
|
|
522
533
|
|
|
523
|
-
export { getConfigHome, expandPath, normalizeTargetPath, applyConfig, applyConfigs, applyConfigsWithReport, previewConfigs };
|
|
534
|
+
export { getConfigHome, expandPath, compactPathForConfigHome, normalizeTargetPath, applyConfig, applyConfigs, applyConfigsWithReport, previewConfigs };
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// src/types/index.ts
|
|
3
|
+
var CONFIG_AGENTS = [
|
|
4
|
+
"claude",
|
|
5
|
+
"codex",
|
|
6
|
+
"opencode",
|
|
7
|
+
"cursor",
|
|
8
|
+
"codewith",
|
|
9
|
+
"aicopilot",
|
|
10
|
+
"antigravity",
|
|
11
|
+
"qwen",
|
|
12
|
+
"grok",
|
|
13
|
+
"copilot",
|
|
14
|
+
"devin",
|
|
15
|
+
"windsurf-legacy",
|
|
16
|
+
"cline",
|
|
17
|
+
"zsh",
|
|
18
|
+
"git",
|
|
19
|
+
"npm",
|
|
20
|
+
"global"
|
|
21
|
+
];
|
|
22
|
+
var PROFILE_CONFIG_BINDING_SCHEMA = "hasna.instructions.profile-config-binding/v1";
|
|
23
|
+
var INSTRUCTION_ACTIVATION_MODES = ["always", "glob", "model", "manual"];
|
|
24
|
+
var INSTRUCTION_FALLBACKS = ["fail", "flatten", "promote-always", "omit"];
|
|
25
|
+
var PROFILE_ASSET_BINDING_SCHEMA = "hasna.instructions.profile-asset-binding/v1";
|
|
26
|
+
var ASSET_KINDS = ["skill", "workflow", "plugin", "extension", "hook", "custom-agent"];
|
|
27
|
+
var ASSET_DESTINATION_STRATEGIES = ["emit-file", "install-local", "install-marketplace", "unsupported"];
|
|
28
|
+
var ASSET_SCOPES = ["global", "project", "session"];
|
|
29
|
+
var ASSET_UNINSTALL_POLICIES = ["remove-managed", "retain"];
|
|
30
|
+
var ASSET_ROLLBACK_POLICIES = ["snapshot", "installer-receipt", "none"];
|
|
31
|
+
var INSTRUCTIONS_DOMAIN_ARCHIVE_SCHEMA = "hasna.instructions.domain-archive/v2";
|
|
32
|
+
|
|
33
|
+
class ConfigNotFoundError extends Error {
|
|
34
|
+
constructor(id) {
|
|
35
|
+
super(`Config not found: ${id}`);
|
|
36
|
+
this.name = "ConfigNotFoundError";
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
class ProfileNotFoundError extends Error {
|
|
41
|
+
constructor(id) {
|
|
42
|
+
super(`Profile not found: ${id}`);
|
|
43
|
+
this.name = "ProfileNotFoundError";
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
class ConfigApplyError extends Error {
|
|
48
|
+
constructor(message) {
|
|
49
|
+
super(message);
|
|
50
|
+
this.name = "ConfigApplyError";
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
class TemplateRenderError extends Error {
|
|
55
|
+
constructor(message) {
|
|
56
|
+
super(message);
|
|
57
|
+
this.name = "TemplateRenderError";
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// src/lib/template.ts
|
|
62
|
+
var VAR_PATTERN = /\{\{([A-Z0-9_]+)(?::([^}]*))?\}\}/g;
|
|
63
|
+
function parseTemplateVars(content) {
|
|
64
|
+
const names = new Set;
|
|
65
|
+
let match;
|
|
66
|
+
VAR_PATTERN.lastIndex = 0;
|
|
67
|
+
while ((match = VAR_PATTERN.exec(content)) !== null) {
|
|
68
|
+
names.add(match[1]);
|
|
69
|
+
}
|
|
70
|
+
return Array.from(names);
|
|
71
|
+
}
|
|
72
|
+
function extractTemplateVars(content) {
|
|
73
|
+
const vars = new Map;
|
|
74
|
+
let match;
|
|
75
|
+
VAR_PATTERN.lastIndex = 0;
|
|
76
|
+
while ((match = VAR_PATTERN.exec(content)) !== null) {
|
|
77
|
+
const name = match[1];
|
|
78
|
+
const description = match[2] ?? null;
|
|
79
|
+
if (!vars.has(name)) {
|
|
80
|
+
vars.set(name, { name, description, required: true });
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return Array.from(vars.values());
|
|
84
|
+
}
|
|
85
|
+
function renderTemplate(content, vars) {
|
|
86
|
+
const missing = [];
|
|
87
|
+
VAR_PATTERN.lastIndex = 0;
|
|
88
|
+
let match;
|
|
89
|
+
while ((match = VAR_PATTERN.exec(content)) !== null) {
|
|
90
|
+
const name = match[1];
|
|
91
|
+
if (!(name in vars))
|
|
92
|
+
missing.push(name);
|
|
93
|
+
}
|
|
94
|
+
if (missing.length > 0) {
|
|
95
|
+
throw new TemplateRenderError(`Missing required template variables: ${missing.join(", ")}`);
|
|
96
|
+
}
|
|
97
|
+
VAR_PATTERN.lastIndex = 0;
|
|
98
|
+
return content.replace(VAR_PATTERN, (_match, name) => vars[name] ?? "");
|
|
99
|
+
}
|
|
100
|
+
function renderTemplatePreview(content, vars) {
|
|
101
|
+
const unresolved = new Set;
|
|
102
|
+
VAR_PATTERN.lastIndex = 0;
|
|
103
|
+
const rendered = content.replace(VAR_PATTERN, (match, name) => {
|
|
104
|
+
if (name in vars)
|
|
105
|
+
return vars[name] ?? "";
|
|
106
|
+
unresolved.add(name);
|
|
107
|
+
return match;
|
|
108
|
+
});
|
|
109
|
+
return {
|
|
110
|
+
content: rendered,
|
|
111
|
+
unresolved: [...unresolved].sort()
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
function isTemplate(content) {
|
|
115
|
+
VAR_PATTERN.lastIndex = 0;
|
|
116
|
+
return VAR_PATTERN.test(content);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export { CONFIG_AGENTS, PROFILE_CONFIG_BINDING_SCHEMA, INSTRUCTION_ACTIVATION_MODES, INSTRUCTION_FALLBACKS, PROFILE_ASSET_BINDING_SCHEMA, ASSET_KINDS, ASSET_DESTINATION_STRATEGIES, ASSET_SCOPES, ASSET_UNINSTALL_POLICIES, ASSET_ROLLBACK_POLICIES, INSTRUCTIONS_DOMAIN_ARCHIVE_SCHEMA, ConfigNotFoundError, ProfileNotFoundError, ConfigApplyError, parseTemplateVars, extractTemplateVars, renderTemplate, renderTemplatePreview, isTemplate };
|
|
@@ -18,15 +18,15 @@ import {
|
|
|
18
18
|
resolveProfileVariables,
|
|
19
19
|
scanSecrets,
|
|
20
20
|
stampCursorGlobalAuthorityMarker
|
|
21
|
-
} from "./index-
|
|
21
|
+
} from "./index-7m4j8a33.js";
|
|
22
22
|
import {
|
|
23
23
|
ConfigApplyError,
|
|
24
24
|
parseTemplateVars
|
|
25
|
-
} from "./index-
|
|
25
|
+
} from "./index-n3fjspr0.js";
|
|
26
26
|
|
|
27
27
|
// src/lib/apply.ts
|
|
28
28
|
import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, realpathSync, writeFileSync } from "fs";
|
|
29
|
-
import { basename, dirname as dirname2, join as join2, resolve } from "path";
|
|
29
|
+
import { basename, dirname as dirname2, isAbsolute, join as join2, relative as relative2, resolve, sep as sep2 } from "path";
|
|
30
30
|
import { homedir } from "os";
|
|
31
31
|
|
|
32
32
|
// src/lib/session-render-ownership.ts
|
|
@@ -110,6 +110,17 @@ function expandPath(p) {
|
|
|
110
110
|
}
|
|
111
111
|
return resolve(p);
|
|
112
112
|
}
|
|
113
|
+
function compactPathForConfigHome(p) {
|
|
114
|
+
const absolute = resolve(p);
|
|
115
|
+
const configHome = resolve(getConfigHome());
|
|
116
|
+
const conventionalHome = resolve(process.env["HOME"] || homedir());
|
|
117
|
+
if (configHome !== conventionalHome)
|
|
118
|
+
return absolute;
|
|
119
|
+
const rel = relative2(configHome, absolute);
|
|
120
|
+
if (!rel || rel === ".." || rel.startsWith(`..${sep2}`) || isAbsolute(rel))
|
|
121
|
+
return absolute;
|
|
122
|
+
return `~/${rel}`;
|
|
123
|
+
}
|
|
113
124
|
function normalizeTargetPath(p) {
|
|
114
125
|
const expanded = expandPath(p);
|
|
115
126
|
try {
|
|
@@ -518,4 +529,4 @@ function sessionRendererOwnsCanonicalTarget(normalized, opts) {
|
|
|
518
529
|
return sessionRenderOwnsPath(normalized);
|
|
519
530
|
}
|
|
520
531
|
|
|
521
|
-
export { getConfigHome, expandPath, normalizeTargetPath, applyConfig, applyConfigs, applyConfigsWithReport, previewConfigs };
|
|
532
|
+
export { getConfigHome, expandPath, compactPathForConfigHome, normalizeTargetPath, applyConfig, applyConfigs, applyConfigsWithReport, previewConfigs };
|