@hasna/instructions 0.6.1 → 0.7.1
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 +141 -10
- package/dist/chunks/{apply-ynfn1av7.js → apply-c3sd4agz.js} +5 -3
- package/dist/chunks/{apply-sfzja1f3.js → apply-pnn7a3y7.js} +6 -3
- package/dist/chunks/database-wstmr56z.js +23 -0
- package/dist/chunks/{index-pkscjnj5.js → index-3djthcm6.js} +0 -1
- package/dist/chunks/index-5d7zdftc.js +186 -0
- package/dist/chunks/{index-1hpwskwd.js → index-6jncnnw7.js} +318 -329
- package/dist/chunks/index-8rb7ng2y.js +148 -0
- package/dist/chunks/{index-v7dkb384.js → index-aj66f6xr.js} +243 -100
- package/dist/chunks/index-fpeyzn3n.js +186 -0
- package/dist/chunks/{index-9p9gn7gh.js → index-jg8ptcwh.js} +5 -7
- package/dist/chunks/index-mvckkf15.js +363 -0
- package/dist/chunks/index-n3fjspr0.js +119 -0
- package/dist/chunks/{index-85n5wnd8.js → index-pdpg8a44.js} +5 -7
- package/dist/chunks/{index-e9epbsvs.js → index-r7nfef2g.js} +15 -4
- package/dist/chunks/{index-axhwg61p.js → index-ypcef3a2.js} +15 -4
- package/dist/chunks/legacy-store-migration-z2m5yzyk.js +322 -0
- package/dist/chunks/{local-a9nen65z.js → local-0a9gja58.js} +142 -2
- package/dist/chunks/{local-0d8qrc92.js → local-969ye538.js} +153 -188
- package/dist/chunks/s3-backup-hxe3zpfz.js +240 -0
- package/dist/chunks/s3-config-hhght91k.js +14 -0
- package/dist/chunks/s3-object-store-n0s82swt.js +14 -0
- package/dist/chunks/{sync-vy1yjvs6.js → sync-q5hvwq6e.js} +4 -4
- package/dist/chunks/{sync-m46fc257.js → sync-xtkbm5br.js} +5 -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 +1236 -256
- package/dist/data/config-store.d.ts +10 -1
- 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.js +1086 -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 +3 -18
- 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 +41 -30
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/sdk/index.d.ts +2 -0
- package/dist/sdk/index.d.ts.map +1 -1
- package/dist/sdk/index.js +229 -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 +58 -0
- package/dist/sdk/v1-client.d.ts.map +1 -0
- package/dist/sdk/v1.generated.d.ts +242 -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 +1261 -427
- package/dist/server/openapi.d.ts +1379 -93
- 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 +45 -2
- 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 +744 -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 +98 -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 +24 -13
- package/assets/skills/inbox/SKILL.md +0 -86
|
@@ -15,7 +15,14 @@ import {
|
|
|
15
15
|
isTemplate,
|
|
16
16
|
renderTemplate,
|
|
17
17
|
renderTemplatePreview
|
|
18
|
-
} from "./index-
|
|
18
|
+
} from "./index-n3fjspr0.js";
|
|
19
|
+
import {
|
|
20
|
+
INSTRUCTIONS_LOCAL_OPT_IN_ENV_KEYS,
|
|
21
|
+
clientTransportEnvKeys,
|
|
22
|
+
instructionsLocalModeNotice,
|
|
23
|
+
instructionsResolverInputs,
|
|
24
|
+
selectsInstructionsLocalStore
|
|
25
|
+
} from "./index-fpeyzn3n.js";
|
|
19
26
|
import {
|
|
20
27
|
__export,
|
|
21
28
|
__require
|
|
@@ -24,6 +31,7 @@ import {
|
|
|
24
31
|
// src/lib/compact-output.ts
|
|
25
32
|
var DEFAULT_LIST_LIMIT = 20;
|
|
26
33
|
var MAX_LIST_LIMIT = 100;
|
|
34
|
+
var MAX_LIST_CURSOR = 1e5;
|
|
27
35
|
function parseLimit(value, fallback = DEFAULT_LIST_LIMIT, max = MAX_LIST_LIMIT) {
|
|
28
36
|
const parsed = typeof value === "number" ? value : Number.parseInt(String(value ?? ""), 10);
|
|
29
37
|
if (!Number.isFinite(parsed) || parsed <= 0)
|
|
@@ -34,7 +42,7 @@ function parseCursor(value) {
|
|
|
34
42
|
const parsed = typeof value === "number" ? value : Number.parseInt(String(value ?? ""), 10);
|
|
35
43
|
if (!Number.isFinite(parsed) || parsed < 0)
|
|
36
44
|
return 0;
|
|
37
|
-
return Math.floor(parsed);
|
|
45
|
+
return Math.min(Math.floor(parsed), MAX_LIST_CURSOR);
|
|
38
46
|
}
|
|
39
47
|
function paginate(items, opts = {}) {
|
|
40
48
|
const limit = parseLimit(opts.limit, opts.defaultLimit ?? DEFAULT_LIST_LIMIT, opts.maxLimit ?? MAX_LIST_LIMIT);
|
|
@@ -110,9 +118,9 @@ import { createHash as createHash6 } from "crypto";
|
|
|
110
118
|
|
|
111
119
|
// src/lib/session-render.ts
|
|
112
120
|
import { createHash as createHash5 } from "crypto";
|
|
113
|
-
import { existsSync as
|
|
114
|
-
import { homedir as
|
|
115
|
-
import { basename as basename4, dirname as dirname4, extname as extname2, isAbsolute as isAbsolute3, join as
|
|
121
|
+
import { existsSync as existsSync4, readFileSync as readFileSync4, realpathSync as realpathSync2, statSync as statSync3 } from "fs";
|
|
122
|
+
import { homedir as homedir4 } from "os";
|
|
123
|
+
import { basename as basename4, dirname as dirname4, extname as extname2, isAbsolute as isAbsolute3, join as join5, parse as parse2, posix as posix2, relative as relative2, resolve as resolve6 } from "path";
|
|
116
124
|
|
|
117
125
|
// src/lib/codewith-shared-todos-storage-standard.ts
|
|
118
126
|
var CODEWITH_SHARED_TODOS_STORAGE_STANDARD_SLUG = "codewith-shared-todos-storage-standard";
|
|
@@ -8161,105 +8169,6 @@ function detectClaudeAuthorityConflicts(targetHome, ownedAuthorities = []) {
|
|
|
8161
8169
|
reason: knownLegacy ? "Claude target contains unmanaged legacy AGENTS.md with no-worktree directives; migrate or remove it through an owned authority path before applying." : "Claude target contains unmanaged AGENTS.md with unknown authority content; refusing to guess whether it conflicts with the managed Claude render."
|
|
8162
8170
|
}];
|
|
8163
8171
|
}
|
|
8164
|
-
// src/lib/raw-store-root.ts
|
|
8165
|
-
import { resolve as resolve7 } from "path";
|
|
8166
|
-
|
|
8167
|
-
// src/lib/app-home.ts
|
|
8168
|
-
import { existsSync as existsSync4 } from "fs";
|
|
8169
|
-
import { homedir as homedir4 } from "os";
|
|
8170
|
-
import { join as join5, resolve as resolve6 } from "path";
|
|
8171
|
-
import { homedir as pathsResolverHomedir2 } from "os";
|
|
8172
|
-
import { join as pathsResolverJoin2 } from "path";
|
|
8173
|
-
var PATHS_RESOLVER_KIND_ENV2 = {
|
|
8174
|
-
config: "HASNA_CONFIG_HOME",
|
|
8175
|
-
data: "HASNA_DATA_HOME",
|
|
8176
|
-
state: "HASNA_STATE_HOME",
|
|
8177
|
-
cache: "HASNA_CACHE_HOME"
|
|
8178
|
-
};
|
|
8179
|
-
var PATHS_RESOLVER_APP_SLUG_RE2 = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
8180
|
-
function pathsResolverAssertApp2(app) {
|
|
8181
|
-
if (typeof app !== "string" || app.length === 0) {
|
|
8182
|
-
throw new TypeError("paths: app must be a non-empty string");
|
|
8183
|
-
}
|
|
8184
|
-
if (!PATHS_RESOLVER_APP_SLUG_RE2.test(app)) {
|
|
8185
|
-
throw new TypeError(`paths: invalid app slug "${app}" \u2014 expected lowercase kebab-case ([a-z0-9]+(-[a-z0-9]+)*)`);
|
|
8186
|
-
}
|
|
8187
|
-
}
|
|
8188
|
-
function pathsResolverAssertKind2(kind) {
|
|
8189
|
-
if (!Object.keys(PATHS_RESOLVER_KIND_ENV2).includes(kind)) {
|
|
8190
|
-
throw new TypeError(`paths: invalid path kind "${kind}" \u2014 expected one of ${Object.keys(PATHS_RESOLVER_KIND_ENV2).join(", ")}`);
|
|
8191
|
-
}
|
|
8192
|
-
}
|
|
8193
|
-
function pathsResolverBaseDir2(kind, options) {
|
|
8194
|
-
pathsResolverAssertKind2(kind);
|
|
8195
|
-
const env = options.env ?? process.env;
|
|
8196
|
-
const override = env[PATHS_RESOLVER_KIND_ENV2[kind]];
|
|
8197
|
-
if (typeof override === "string" && override.length > 0)
|
|
8198
|
-
return override;
|
|
8199
|
-
const home = options.home ?? pathsResolverHomedir2();
|
|
8200
|
-
const platform = options.platform ?? process.platform;
|
|
8201
|
-
if (platform === "darwin") {
|
|
8202
|
-
switch (kind) {
|
|
8203
|
-
case "config":
|
|
8204
|
-
case "data":
|
|
8205
|
-
return pathsResolverJoin2(home, "Library", "Application Support", "Hasna");
|
|
8206
|
-
case "cache":
|
|
8207
|
-
return pathsResolverJoin2(home, "Library", "Caches", "Hasna");
|
|
8208
|
-
case "state":
|
|
8209
|
-
return pathsResolverJoin2(home, "Library", "Logs", "Hasna");
|
|
8210
|
-
}
|
|
8211
|
-
}
|
|
8212
|
-
switch (kind) {
|
|
8213
|
-
case "config":
|
|
8214
|
-
return pathsResolverJoin2(home, ".config", "hasna");
|
|
8215
|
-
case "data":
|
|
8216
|
-
return pathsResolverJoin2(home, ".local", "share", "hasna");
|
|
8217
|
-
case "state":
|
|
8218
|
-
return pathsResolverJoin2(home, ".local", "state", "hasna");
|
|
8219
|
-
case "cache":
|
|
8220
|
-
return pathsResolverJoin2(home, ".cache", "hasna");
|
|
8221
|
-
}
|
|
8222
|
-
}
|
|
8223
|
-
function pathsResolverResolve2(kind, options) {
|
|
8224
|
-
pathsResolverAssertApp2(options.app);
|
|
8225
|
-
const appSegment = options.internal === true ? pathsResolverJoin2("internal", options.app) : options.app;
|
|
8226
|
-
return pathsResolverJoin2(pathsResolverBaseDir2(kind, options), appSegment);
|
|
8227
|
-
}
|
|
8228
|
-
function configDir(options) {
|
|
8229
|
-
return pathsResolverResolve2("config", options);
|
|
8230
|
-
}
|
|
8231
|
-
var HASNA_CONFIGS_HOME_ENV = "HASNA_CONFIGS_HOME";
|
|
8232
|
-
function homeDir3(env = process.env) {
|
|
8233
|
-
return env["HOME"] || env["USERPROFILE"] || homedir4();
|
|
8234
|
-
}
|
|
8235
|
-
function legacyStoreHome(env = process.env) {
|
|
8236
|
-
return resolve6(join5(homeDir3(env), ".hasna", "instructions"));
|
|
8237
|
-
}
|
|
8238
|
-
function resolverStoreHome(env = process.env) {
|
|
8239
|
-
return configDir({ app: "configs", env, home: env.HOME || env.USERPROFILE || homedir4() });
|
|
8240
|
-
}
|
|
8241
|
-
function adoptResolverStoreHome(resolved, env = process.env) {
|
|
8242
|
-
const override = env.HASNA_CONFIG_HOME;
|
|
8243
|
-
if (typeof override === "string" && override.trim().length > 0)
|
|
8244
|
-
return true;
|
|
8245
|
-
return existsSync4(join5(resolved, "instructions.db"));
|
|
8246
|
-
}
|
|
8247
|
-
function exactStoreHome(env = process.env) {
|
|
8248
|
-
const v = env[HASNA_CONFIGS_HOME_ENV];
|
|
8249
|
-
return v && v.trim() ? v.trim() : undefined;
|
|
8250
|
-
}
|
|
8251
|
-
function getConfigsStoreHome(env = process.env) {
|
|
8252
|
-
const exact = exactStoreHome(env);
|
|
8253
|
-
if (exact)
|
|
8254
|
-
return resolve6(exact);
|
|
8255
|
-
const resolved = resolverStoreHome(env);
|
|
8256
|
-
return adoptResolverStoreHome(resolved, env) ? resolve6(resolved) : legacyStoreHome(env);
|
|
8257
|
-
}
|
|
8258
|
-
|
|
8259
|
-
// src/lib/raw-store-root.ts
|
|
8260
|
-
function getRawStoreRoot(env = process.env) {
|
|
8261
|
-
return resolve7(getConfigsStoreHome(env));
|
|
8262
|
-
}
|
|
8263
8172
|
|
|
8264
8173
|
// src/lib/session-render.ts
|
|
8265
8174
|
var ANTIGRAVITY_RULE_FILE_CHAR_LIMIT = 12000;
|
|
@@ -8542,13 +8451,13 @@ function yamlQuote2(value) {
|
|
|
8542
8451
|
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`;
|
|
8543
8452
|
}
|
|
8544
8453
|
function defaultTargetHome(tool, profile, sessionId) {
|
|
8545
|
-
const home = process.env["HOME"] ||
|
|
8546
|
-
return
|
|
8454
|
+
const home = process.env["HOME"] || homedir4();
|
|
8455
|
+
return join5(home, ".hasna", "accounts", "profiles", tool, slug(profile));
|
|
8547
8456
|
}
|
|
8548
8457
|
function joinTarget(targetHome, relativePath) {
|
|
8549
8458
|
const safeTargetHome = assertSafeTargetRoot(targetHome);
|
|
8550
8459
|
const safeRelativePath2 = assertSafeRelativePath(relativePath);
|
|
8551
|
-
return
|
|
8460
|
+
return join5(safeTargetHome, ...safeRelativePath2.split("/"));
|
|
8552
8461
|
}
|
|
8553
8462
|
function makeFile(targetHome, relativePath, role, content, sourceIds) {
|
|
8554
8463
|
const safeTargetHome = assertSafeTargetRoot(targetHome);
|
|
@@ -9118,7 +9027,7 @@ function buildOpenCodeFiles(targetHome, adapter, profile, sources, providerConfi
|
|
|
9118
9027
|
...sources.flatMap((source) => source.resolvedRules.map((rule) => rule.id))
|
|
9119
9028
|
]);
|
|
9120
9029
|
const existingConfigPath = joinTarget(targetHome, adapter.configFile);
|
|
9121
|
-
const selectedConfig =
|
|
9030
|
+
const selectedConfig = existsSync4(existingConfigPath) ? readOpenCodeConfig(readFileSync4(existingConfigPath, "utf8"), existingConfigPath) : providerConfig ? readOpenCodeConfig(providerConfig.content, providerConfig.sourceId) : {};
|
|
9122
9031
|
const preservedInstructions = normalizeOpenCodeInstructions(selectedConfig["instructions"]).filter((path) => !pathIsManagedOpenCodeInstruction(path, adapter.managedDir));
|
|
9123
9032
|
const config = {
|
|
9124
9033
|
...selectedConfig,
|
|
@@ -9321,7 +9230,7 @@ function adapterFor(input) {
|
|
|
9321
9230
|
return gatedNativeImports ? CODEWITH_NATIVE_ADAPTER : CODEWITH_FLATTENED_ADAPTER;
|
|
9322
9231
|
}
|
|
9323
9232
|
function getHomeDir() {
|
|
9324
|
-
return process.env["CONFIGS_HOME"] || process.env["HOME"] ||
|
|
9233
|
+
return process.env["CONFIGS_HOME"] || process.env["HOME"] || homedir4();
|
|
9325
9234
|
}
|
|
9326
9235
|
function cleanSessionPathInput(path) {
|
|
9327
9236
|
const trimmed = path.trim();
|
|
@@ -9336,16 +9245,16 @@ function resolveSessionPath(path) {
|
|
|
9336
9245
|
throw new Error("Session render path cannot be empty.");
|
|
9337
9246
|
const home = getHomeDir();
|
|
9338
9247
|
if (cleaned === "~")
|
|
9339
|
-
return
|
|
9248
|
+
return resolve6(home);
|
|
9340
9249
|
if (cleaned.startsWith("~/"))
|
|
9341
|
-
return
|
|
9250
|
+
return resolve6(home, cleaned.slice(2));
|
|
9342
9251
|
if (cleaned === "{{HOME}}" || cleaned === "${HOME}")
|
|
9343
|
-
return
|
|
9252
|
+
return resolve6(home);
|
|
9344
9253
|
if (cleaned.startsWith("{{HOME}}/"))
|
|
9345
|
-
return
|
|
9254
|
+
return resolve6(home, cleaned.slice("{{HOME}}/".length));
|
|
9346
9255
|
if (cleaned.startsWith("${HOME}/"))
|
|
9347
|
-
return
|
|
9348
|
-
return
|
|
9256
|
+
return resolve6(home, cleaned.slice("${HOME}/".length));
|
|
9257
|
+
return resolve6(cleaned);
|
|
9349
9258
|
}
|
|
9350
9259
|
function assertSafeRelativePath(relativePath) {
|
|
9351
9260
|
if (!relativePath.trim())
|
|
@@ -9361,7 +9270,7 @@ function assertSafeRelativePath(relativePath) {
|
|
|
9361
9270
|
function assertSafeTargetRoot(targetHome) {
|
|
9362
9271
|
if (!isAbsolute3(targetHome))
|
|
9363
9272
|
throw new Error(`Session render target must be an absolute path: ${targetHome}`);
|
|
9364
|
-
const normalized =
|
|
9273
|
+
const normalized = resolve6(targetHome);
|
|
9365
9274
|
if (normalized === parse2(normalized).root) {
|
|
9366
9275
|
throw new Error(`Session render target cannot be the filesystem root: ${targetHome}`);
|
|
9367
9276
|
}
|
|
@@ -9596,7 +9505,7 @@ function planSessionRender(input) {
|
|
|
9596
9505
|
sourceId: input.providerConfig.sourceId,
|
|
9597
9506
|
selectedPayloadSha256: sha2565(input.providerConfig.content),
|
|
9598
9507
|
renderedPayloadSha256: files.find((file) => file.relativePath === adapter.configFile)?.sha256 ?? sha2565(input.providerConfig.content),
|
|
9599
|
-
selected: !
|
|
9508
|
+
selected: !existsSync4(joinTarget(targetHome, adapter.configFile))
|
|
9600
9509
|
}
|
|
9601
9510
|
} : {},
|
|
9602
9511
|
...projectContext ? {
|
|
@@ -9879,7 +9788,7 @@ ${item.content.trimEnd()}`).join(`
|
|
|
9879
9788
|
}
|
|
9880
9789
|
function readIdentitySourcePath(sourcePath, baseDir, sourceId) {
|
|
9881
9790
|
const resolvedPath = resolveIdentitySourcePath(sourcePath.path, baseDir, sourceId);
|
|
9882
|
-
if (!
|
|
9791
|
+
if (!existsSync4(resolvedPath)) {
|
|
9883
9792
|
if (sourcePath.required) {
|
|
9884
9793
|
throw new Error(`Required identity instruction source path not found for ${sourceId}: ${sourcePath.path}`);
|
|
9885
9794
|
}
|
|
@@ -9902,8 +9811,8 @@ function resolveIdentitySourcePath(path, baseDir, sourceId) {
|
|
|
9902
9811
|
throw new Error(`Identity instruction source path cannot be empty for ${sourceId}.`);
|
|
9903
9812
|
if (cleaned.includes("\\"))
|
|
9904
9813
|
throw new Error(`Identity instruction source path must use POSIX separators for ${sourceId}: ${path}`);
|
|
9905
|
-
const resolvedPath = isAbsolute3(cleaned) ?
|
|
9906
|
-
if (!pathIsInside(resolvedPath,
|
|
9814
|
+
const resolvedPath = isAbsolute3(cleaned) ? resolve6(cleaned) : resolve6(baseDir, cleaned);
|
|
9815
|
+
if (!pathIsInside(resolvedPath, resolve6(baseDir))) {
|
|
9907
9816
|
throw new Error(`Identity instruction source path escapes export directory for ${sourceId}: ${path}`);
|
|
9908
9817
|
}
|
|
9909
9818
|
return resolvedPath;
|
|
@@ -10559,12 +10468,18 @@ function deepFreeze2(value) {
|
|
|
10559
10468
|
return Object.freeze(value);
|
|
10560
10469
|
}
|
|
10561
10470
|
|
|
10562
|
-
//
|
|
10471
|
+
// ../../node_modules/.bun/@hasna+contracts@1.0.2+e8014c875821e0be/node_modules/@hasna/contracts/dist/client/storage.js
|
|
10472
|
+
import { isIP } from "net";
|
|
10473
|
+
import { spawnSync } from "child_process";
|
|
10474
|
+
import { closeSync as closeSync2, fstatSync as fstatSync2, openSync as openSync2, readFileSync as readFileSync5 } from "fs";
|
|
10475
|
+
import { O_NOFOLLOW, O_NONBLOCK, O_RDONLY } from "constants";
|
|
10563
10476
|
import { createRequire } from "module";
|
|
10477
|
+
import { hostname as osHostname } from "os";
|
|
10478
|
+
import { isAbsolute as isAbsolute4, join as join6 } from "path";
|
|
10564
10479
|
function envToken(name) {
|
|
10565
10480
|
return name.toUpperCase().replace(/-/g, "_");
|
|
10566
10481
|
}
|
|
10567
|
-
function
|
|
10482
|
+
function clientTransportEnvKeys2(name) {
|
|
10568
10483
|
const envSegment = envToken(name);
|
|
10569
10484
|
return {
|
|
10570
10485
|
apiUrlKeys: [`HASNA_${envSegment}_API_URL`, `${envSegment}_API_URL`],
|
|
@@ -10578,46 +10493,6 @@ var CREDENTIAL_PROFILE_ENV_KEY = "HASNA_PROFILE";
|
|
|
10578
10493
|
function credentialPointerEnvKey(name) {
|
|
10579
10494
|
return `HASNA_${envToken(name)}_API_KEY_REF`;
|
|
10580
10495
|
}
|
|
10581
|
-
var MAX_CREDENTIAL_FILE_BYTES = 64 * 1024;
|
|
10582
|
-
var INSPECT_CUSTOM = Symbol.for("nodejs.util.inspect.custom");
|
|
10583
|
-
var CREDENTIAL_SEAL = Symbol.for("hasna:contracts:sealedCredential");
|
|
10584
|
-
var AMBIENT_ENVIRONMENT = Symbol.for("hasna:contracts:ambientClientEnvironment");
|
|
10585
|
-
var SECRETS_PACKAGE_SPECIFIER = "@hasna/" + "secrets";
|
|
10586
|
-
var requireSecretsSdk = createRequire(import.meta.url);
|
|
10587
|
-
var IDEMPOTENT_METHODS = new Set(["GET", "HEAD", "PUT", "DELETE", "OPTIONS"]);
|
|
10588
|
-
var AUTHORITY_OVERRIDE_HEADERS = new Set([
|
|
10589
|
-
"host",
|
|
10590
|
-
":authority",
|
|
10591
|
-
"forwarded",
|
|
10592
|
-
"x-forwarded-host",
|
|
10593
|
-
"x-original-host"
|
|
10594
|
-
]);
|
|
10595
|
-
|
|
10596
|
-
// ../contracts/dist/client/storage.js
|
|
10597
|
-
import { isIP } from "net";
|
|
10598
|
-
import { spawnSync } from "child_process";
|
|
10599
|
-
import { closeSync as closeSync2, fstatSync as fstatSync2, openSync as openSync2, readFileSync as readFileSync5 } from "fs";
|
|
10600
|
-
import { O_NOFOLLOW, O_NONBLOCK, O_RDONLY } from "constants";
|
|
10601
|
-
import { createRequire as createRequire2 } from "module";
|
|
10602
|
-
import { hostname as osHostname } from "os";
|
|
10603
|
-
import { isAbsolute as isAbsolute4, join as join7 } from "path";
|
|
10604
|
-
function envToken2(name) {
|
|
10605
|
-
return name.toUpperCase().replace(/-/g, "_");
|
|
10606
|
-
}
|
|
10607
|
-
function clientTransportEnvKeys2(name) {
|
|
10608
|
-
const envSegment = envToken2(name);
|
|
10609
|
-
return {
|
|
10610
|
-
apiUrlKeys: [`HASNA_${envSegment}_API_URL`, `${envSegment}_API_URL`],
|
|
10611
|
-
apiKeyKeys: [`HASNA_${envSegment}_API_KEY`, `${envSegment}_API_KEY`]
|
|
10612
|
-
};
|
|
10613
|
-
}
|
|
10614
|
-
function credentialOverrideEnvKey2(name) {
|
|
10615
|
-
return `HASNA_${envToken2(name)}_API_KEY_OVERRIDE`;
|
|
10616
|
-
}
|
|
10617
|
-
var CREDENTIAL_PROFILE_ENV_KEY2 = "HASNA_PROFILE";
|
|
10618
|
-
function credentialPointerEnvKey2(name) {
|
|
10619
|
-
return `HASNA_${envToken2(name)}_API_KEY_REF`;
|
|
10620
|
-
}
|
|
10621
10496
|
|
|
10622
10497
|
class CredentialResolutionError extends Error {
|
|
10623
10498
|
appName;
|
|
@@ -10648,12 +10523,12 @@ var KEYCHAIN_SECURITY_BIN = "/usr/bin/security";
|
|
|
10648
10523
|
var KEYCHAIN_SERVICE_PREFIX = "hasna.credentials";
|
|
10649
10524
|
var KEYCHAIN_ITEM_NOT_FOUND_STATUS = 44;
|
|
10650
10525
|
var KEYCHAIN_SPAWN_TIMEOUT_MS = 1e4;
|
|
10651
|
-
var
|
|
10526
|
+
var MAX_CREDENTIAL_FILE_BYTES = 64 * 1024;
|
|
10652
10527
|
var SAFE_APP_SLUG = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
|
|
10653
10528
|
var SAFE_PROFILE = /^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/;
|
|
10654
10529
|
var ILLEGAL_IN_HEADER_VALUE = /[^\t\x20-\x7e]/;
|
|
10655
10530
|
var VAULT_POINTER_SHAPE = /^[a-z0-9][a-z0-9-]*(?:\/[a-z0-9][a-z0-9-_.]*){2,}$/;
|
|
10656
|
-
function
|
|
10531
|
+
function homeDir3(env) {
|
|
10657
10532
|
const home = env.HOME?.trim();
|
|
10658
10533
|
return home ? home : null;
|
|
10659
10534
|
}
|
|
@@ -10665,15 +10540,15 @@ function hasnaHomeDir(env) {
|
|
|
10665
10540
|
const override = absoluteOverride(env, HASNA_HOME_ENV_KEY);
|
|
10666
10541
|
if (override)
|
|
10667
10542
|
return override;
|
|
10668
|
-
const home =
|
|
10669
|
-
return home ?
|
|
10543
|
+
const home = homeDir3(env);
|
|
10544
|
+
return home ? join6(home, HASNA_HOME_DIR) : null;
|
|
10670
10545
|
}
|
|
10671
10546
|
function appConfigDir(name, env) {
|
|
10672
10547
|
const configRoot = absoluteOverride(env, HASNA_CONFIG_HOME_ENV_KEY);
|
|
10673
10548
|
if (configRoot)
|
|
10674
|
-
return
|
|
10549
|
+
return join6(configRoot, name);
|
|
10675
10550
|
const root = hasnaHomeDir(env);
|
|
10676
|
-
return root ?
|
|
10551
|
+
return root ? join6(root, name, CONFIG_SUBDIR) : null;
|
|
10677
10552
|
}
|
|
10678
10553
|
function credentialDiskSourceList(name, env, profile = null) {
|
|
10679
10554
|
if (!SAFE_APP_SLUG.test(name))
|
|
@@ -10682,7 +10557,7 @@ function credentialDiskSourceList(name, env, profile = null) {
|
|
|
10682
10557
|
if (!directory)
|
|
10683
10558
|
return [];
|
|
10684
10559
|
const file = profile ? `${CREDENTIALS_FILE}-${profile}` : CREDENTIALS_FILE;
|
|
10685
|
-
return [{ path:
|
|
10560
|
+
return [{ path: join6(directory, file), tier: "disk" }];
|
|
10686
10561
|
}
|
|
10687
10562
|
function credentialDiskSources(name, env) {
|
|
10688
10563
|
return credentialDiskSourceList(name, env, null).map((s) => s.path);
|
|
@@ -10755,7 +10630,7 @@ function readAppConfigFile(path) {
|
|
|
10755
10630
|
const uid = process.getuid?.() ?? process.geteuid?.();
|
|
10756
10631
|
if (uid !== undefined && before.uid !== uid)
|
|
10757
10632
|
unsafe("the file is not owned by the current user");
|
|
10758
|
-
if (before.size >
|
|
10633
|
+
if (before.size > MAX_CREDENTIAL_FILE_BYTES)
|
|
10759
10634
|
unsafe("the file exceeds the size limit");
|
|
10760
10635
|
const bytes = readFileSync5(fd);
|
|
10761
10636
|
const after = fstatSync2(fd);
|
|
@@ -10810,14 +10685,14 @@ function appConfigDiskValue(name, env, keys) {
|
|
|
10810
10685
|
}
|
|
10811
10686
|
function assertUsableCredential(appName, source, value) {
|
|
10812
10687
|
if (VAULT_POINTER_SHAPE.test(value)) {
|
|
10813
|
-
throw new CredentialResolutionError(appName, `The credential from ${source} looks like a secrets-vault pointer (a path-shaped reference like ` + `'namespace/app/live/api_key'). A vault path is NEVER accepted as a literal API key. ` + `Use ${
|
|
10688
|
+
throw new CredentialResolutionError(appName, `The credential from ${source} looks like a secrets-vault pointer (a path-shaped reference like ` + `'namespace/app/live/api_key'). A vault path is NEVER accepted as a literal API key. ` + `Use ${credentialPointerEnvKey(appName)} to resolve the key through the vault, or provide the actual key value.`, [source]);
|
|
10814
10689
|
}
|
|
10815
10690
|
if (!ILLEGAL_IN_HEADER_VALUE.test(value))
|
|
10816
10691
|
return;
|
|
10817
10692
|
throw new CredentialResolutionError(appName, `The credential from ${source} contains characters that cannot be sent in an HTTP header ` + `(a control character or non-ASCII byte). A file written with CR-only line endings is the usual ` + `cause. Rewrite that credential file with one LF-terminated KEY=value line. ` + `The value is not shown here, and is deliberately never logged.`, [source]);
|
|
10818
10693
|
}
|
|
10819
|
-
var
|
|
10820
|
-
var
|
|
10694
|
+
var INSPECT_CUSTOM = Symbol.for("nodejs.util.inspect.custom");
|
|
10695
|
+
var CREDENTIAL_SEAL = Symbol.for("hasna:contracts:sealedCredential");
|
|
10821
10696
|
var CALLER_SUPPLIED_CREDENTIAL_PROVIDER_SOURCE = "caller-supplied CredentialProvider";
|
|
10822
10697
|
function sealCredential(fields) {
|
|
10823
10698
|
const { apiKey } = fields;
|
|
@@ -10843,13 +10718,13 @@ function sealCredential(fields) {
|
|
|
10843
10718
|
configurable: false
|
|
10844
10719
|
});
|
|
10845
10720
|
}
|
|
10846
|
-
Object.defineProperty(sealed,
|
|
10721
|
+
Object.defineProperty(sealed, INSPECT_CUSTOM, {
|
|
10847
10722
|
value: () => ({ ...visible, apiKey: "[redacted]" }),
|
|
10848
10723
|
enumerable: false,
|
|
10849
10724
|
writable: false,
|
|
10850
10725
|
configurable: false
|
|
10851
10726
|
});
|
|
10852
|
-
Object.defineProperty(sealed,
|
|
10727
|
+
Object.defineProperty(sealed, CREDENTIAL_SEAL, {
|
|
10853
10728
|
value: true,
|
|
10854
10729
|
enumerable: false,
|
|
10855
10730
|
writable: false,
|
|
@@ -10858,7 +10733,7 @@ function sealCredential(fields) {
|
|
|
10858
10733
|
return Object.freeze(sealed);
|
|
10859
10734
|
}
|
|
10860
10735
|
function isSealedCredential(credential) {
|
|
10861
|
-
return credential[
|
|
10736
|
+
return credential[CREDENTIAL_SEAL] === true;
|
|
10862
10737
|
}
|
|
10863
10738
|
function explicitCredential(appName, apiKey) {
|
|
10864
10739
|
const source = "explicit apiKey option";
|
|
@@ -10905,9 +10780,9 @@ function firstEnvValue(env, keys) {
|
|
|
10905
10780
|
}
|
|
10906
10781
|
return null;
|
|
10907
10782
|
}
|
|
10908
|
-
var
|
|
10783
|
+
var AMBIENT_ENVIRONMENT = Symbol.for("hasna:contracts:ambientClientEnvironment");
|
|
10909
10784
|
function isAmbientEnvironment(env) {
|
|
10910
|
-
return env === process.env || env[
|
|
10785
|
+
return env === process.env || env[AMBIENT_ENVIRONMENT] === true;
|
|
10911
10786
|
}
|
|
10912
10787
|
function defaultKeychainRunner(argv) {
|
|
10913
10788
|
const result = spawnSync(KEYCHAIN_SECURITY_BIN, [...argv], {
|
|
@@ -10980,9 +10855,9 @@ function snapshotClientEnvironment(name, env) {
|
|
|
10980
10855
|
for (const key of [
|
|
10981
10856
|
...keys.apiUrlKeys,
|
|
10982
10857
|
...keys.apiKeyKeys,
|
|
10983
|
-
|
|
10984
|
-
|
|
10985
|
-
|
|
10858
|
+
credentialOverrideEnvKey(name),
|
|
10859
|
+
credentialPointerEnvKey(name),
|
|
10860
|
+
CREDENTIAL_PROFILE_ENV_KEY,
|
|
10986
10861
|
"HOME",
|
|
10987
10862
|
HASNA_HOME_ENV_KEY,
|
|
10988
10863
|
HASNA_CONFIG_HOME_ENV_KEY,
|
|
@@ -11001,7 +10876,7 @@ function snapshotClientEnvironment(name, env) {
|
|
|
11001
10876
|
snapshot[key] = descriptor.value;
|
|
11002
10877
|
}
|
|
11003
10878
|
if (ambient) {
|
|
11004
|
-
Object.defineProperty(snapshot,
|
|
10879
|
+
Object.defineProperty(snapshot, AMBIENT_ENVIRONMENT, {
|
|
11005
10880
|
value: true,
|
|
11006
10881
|
enumerable: false,
|
|
11007
10882
|
writable: false,
|
|
@@ -11029,7 +10904,7 @@ function resolveCredential(name, env, options = {}) {
|
|
|
11029
10904
|
warning: null
|
|
11030
10905
|
});
|
|
11031
10906
|
}
|
|
11032
|
-
const overrideKeyName =
|
|
10907
|
+
const overrideKeyName = credentialOverrideEnvKey(name);
|
|
11033
10908
|
const overrideRaw = Object.prototype.hasOwnProperty.call(env, overrideKeyName) ? env[overrideKeyName] : undefined;
|
|
11034
10909
|
if (overrideRaw !== undefined) {
|
|
11035
10910
|
const override = overrideRaw.trim();
|
|
@@ -11046,7 +10921,7 @@ function resolveCredential(name, env, options = {}) {
|
|
|
11046
10921
|
warning: null
|
|
11047
10922
|
});
|
|
11048
10923
|
}
|
|
11049
|
-
const pointerKeyName =
|
|
10924
|
+
const pointerKeyName = credentialPointerEnvKey(name);
|
|
11050
10925
|
const pointerRaw = Object.prototype.hasOwnProperty.call(env, pointerKeyName) ? env[pointerKeyName] : undefined;
|
|
11051
10926
|
if (pointerRaw !== undefined) {
|
|
11052
10927
|
const pointer = pointerRaw.trim();
|
|
@@ -11069,13 +10944,13 @@ function resolveCredential(name, env, options = {}) {
|
|
|
11069
10944
|
if (options.profile !== undefined && !options.profile.trim()) {
|
|
11070
10945
|
throw new CredentialResolutionError(name, "The explicit profile argument is blank; an explicit identity selection never falls through.", ["explicit profile argument"]);
|
|
11071
10946
|
}
|
|
11072
|
-
const profileRaw = Object.prototype.hasOwnProperty.call(env,
|
|
10947
|
+
const profileRaw = Object.prototype.hasOwnProperty.call(env, CREDENTIAL_PROFILE_ENV_KEY) ? env[CREDENTIAL_PROFILE_ENV_KEY] : undefined;
|
|
11073
10948
|
if (profileRaw !== undefined && !profileRaw.trim()) {
|
|
11074
|
-
throw new CredentialResolutionError(name, `${
|
|
10949
|
+
throw new CredentialResolutionError(name, `${CREDENTIAL_PROFILE_ENV_KEY} is set but blank.`, [CREDENTIAL_PROFILE_ENV_KEY]);
|
|
11075
10950
|
}
|
|
11076
10951
|
const profile = options.profile?.trim() || profileRaw?.trim();
|
|
11077
10952
|
if (profile) {
|
|
11078
|
-
const profileSource = options.profile?.trim() ? "explicit profile argument" :
|
|
10953
|
+
const profileSource = options.profile?.trim() ? "explicit profile argument" : CREDENTIAL_PROFILE_ENV_KEY;
|
|
11079
10954
|
if (!SAFE_PROFILE.test(profile)) {
|
|
11080
10955
|
throw new CredentialResolutionError(name, `Profile name from ${profileSource} is not usable in a path. ` + `Use letters, digits, dot, dash, or underscore.`, [profileSource]);
|
|
11081
10956
|
}
|
|
@@ -11094,7 +10969,7 @@ function resolveCredential(name, env, options = {}) {
|
|
|
11094
10969
|
});
|
|
11095
10970
|
}
|
|
11096
10971
|
}
|
|
11097
|
-
throw new CredentialResolutionError(name, `Profile '${profile}' (from ${profileSource}) has no ${apiKeyKeys[0]} for '${name}'. ` + `Looked in: ${paths.join(", ") || "<no HOME in this environment>"}. ` + `A profile names WHICH identity to use, so it is never resolved around \u2014 ` + `create the profile's credential file or unset ${
|
|
10972
|
+
throw new CredentialResolutionError(name, `Profile '${profile}' (from ${profileSource}) has no ${apiKeyKeys[0]} for '${name}'. ` + `Looked in: ${paths.join(", ") || "<no HOME in this environment>"}. ` + `A profile names WHICH identity to use, so it is never resolved around \u2014 ` + `create the profile's credential file or unset ${CREDENTIAL_PROFILE_ENV_KEY}.`, paths);
|
|
11098
10973
|
}
|
|
11099
10974
|
const definedEnvEntries = apiKeyKeys.filter((key) => Object.prototype.hasOwnProperty.call(env, key) && env[key] !== undefined).map((key) => ({ key, value: String(env[key]).trim() }));
|
|
11100
10975
|
const blankEnv = definedEnvEntries.find((entry) => entry.value.length === 0);
|
|
@@ -11150,8 +11025,8 @@ function resolveCredential(name, env, options = {}) {
|
|
|
11150
11025
|
}
|
|
11151
11026
|
return null;
|
|
11152
11027
|
}
|
|
11153
|
-
var
|
|
11154
|
-
var
|
|
11028
|
+
var SECRETS_PACKAGE_SPECIFIER = "@hasna/" + "secrets";
|
|
11029
|
+
var requireSecretsSdk = createRequire(import.meta.url);
|
|
11155
11030
|
async function completePointerCredential(name, pointerResolution, env = process.env) {
|
|
11156
11031
|
const vaultKey = pointerResolution.pointerVaultKey;
|
|
11157
11032
|
const pointerEnvKey = pointerResolution.source;
|
|
@@ -11160,7 +11035,7 @@ async function completePointerCredential(name, pointerResolution, env = process.
|
|
|
11160
11035
|
}
|
|
11161
11036
|
let secretsSdk;
|
|
11162
11037
|
try {
|
|
11163
|
-
secretsSdk =
|
|
11038
|
+
secretsSdk = requireSecretsSdk(SECRETS_PACKAGE_SPECIFIER);
|
|
11164
11039
|
} catch {
|
|
11165
11040
|
throw new CredentialResolutionError(name, `${pointerEnvKey} names vault item '${vaultKey}', but the secrets SDK (@hasna/secrets) is not installed ` + `in this process. A vault pointer is TERMINAL: install @hasna/secrets to resolve it, or unset ${pointerEnvKey}.`, [pointerEnvKey]);
|
|
11166
11041
|
}
|
|
@@ -11457,8 +11332,8 @@ function authFailureGuidance(credential) {
|
|
|
11457
11332
|
return `${origin}, which was re-read from disk on this very call \u2014 so a stale shell is NOT the cause here. ` + `The stored credential is genuinely being rejected: rotate it, or re-run the fleet key distribution ` + `so this machine gets the current key.`;
|
|
11458
11333
|
}
|
|
11459
11334
|
var DEFAULT_RETRY_STATUSES = [408, 425, 429, 500, 502, 503, 504];
|
|
11460
|
-
var
|
|
11461
|
-
var
|
|
11335
|
+
var IDEMPOTENT_METHODS = new Set(["GET", "HEAD", "PUT", "DELETE", "OPTIONS"]);
|
|
11336
|
+
var AUTHORITY_OVERRIDE_HEADERS = new Set([
|
|
11462
11337
|
"host",
|
|
11463
11338
|
":authority",
|
|
11464
11339
|
"forwarded",
|
|
@@ -11468,7 +11343,7 @@ var AUTHORITY_OVERRIDE_HEADERS2 = new Set([
|
|
|
11468
11343
|
function assertNoAuthorityOverrideHeaders(headers, source) {
|
|
11469
11344
|
if (!headers)
|
|
11470
11345
|
return;
|
|
11471
|
-
const forbidden = Object.keys(headers).find((name) =>
|
|
11346
|
+
const forbidden = Object.keys(headers).find((name) => AUTHORITY_OVERRIDE_HEADERS.has(name.trim().toLowerCase()));
|
|
11472
11347
|
if (forbidden) {
|
|
11473
11348
|
throw new Error(`Authenticated ${source} headers must not set authority header '${forbidden}'.`);
|
|
11474
11349
|
}
|
|
@@ -11494,7 +11369,7 @@ function appendQuery(path, query) {
|
|
|
11494
11369
|
return path;
|
|
11495
11370
|
return `${path}${path.includes("?") ? "&" : "?"}${qs}`;
|
|
11496
11371
|
}
|
|
11497
|
-
var defaultSleep = (ms) => new Promise((
|
|
11372
|
+
var defaultSleep = (ms) => new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
11498
11373
|
function createHasnaHttpTransportInternal(options, requestBindingProvider) {
|
|
11499
11374
|
const fetchImpl = options.fetchImpl ?? ((input, init) => fetch(input, init));
|
|
11500
11375
|
const base = toV1BaseUrl(options.baseUrl);
|
|
@@ -11602,7 +11477,7 @@ function createHasnaHttpTransportInternal(options, requestBindingProvider) {
|
|
|
11602
11477
|
const upper = method.toUpperCase();
|
|
11603
11478
|
const rel = appendQuery(path.startsWith("/") ? path : `/${path}`, opts.query);
|
|
11604
11479
|
const retry = resolveRetry(opts.retry);
|
|
11605
|
-
const methodRetryable =
|
|
11480
|
+
const methodRetryable = IDEMPOTENT_METHODS.has(upper) || Boolean(opts.idempotencyKey);
|
|
11606
11481
|
const maxAttempts = retry && methodRetryable ? retry.retries + 1 : 1;
|
|
11607
11482
|
const binding = requestBindingProvider ? await requestBindingProvider() : {
|
|
11608
11483
|
baseUrl: base,
|
|
@@ -11779,56 +11654,6 @@ function resolveStorageClient(name, env = process.env, overrides) {
|
|
|
11779
11654
|
return { transport: "http", client: createHasnaStorageClient(name, wired.client) };
|
|
11780
11655
|
}
|
|
11781
11656
|
|
|
11782
|
-
// src/lib/local-opt-in.ts
|
|
11783
|
-
var INSTRUCTIONS_LOCAL_OPT_IN_ENV_KEYS = ["HASNA_INSTRUCTIONS_LOCAL"];
|
|
11784
|
-
function instructionsLocalModeNotice() {
|
|
11785
|
-
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.`;
|
|
11786
|
-
}
|
|
11787
|
-
function isInstructionsLocalOptIn(env = process.env) {
|
|
11788
|
-
return INSTRUCTIONS_LOCAL_OPT_IN_ENV_KEYS.some((key) => (env[key] ?? "").trim() === "1");
|
|
11789
|
-
}
|
|
11790
|
-
function instructionsAuthorityEnvKeys() {
|
|
11791
|
-
const keys = clientTransportEnvKeys("instructions");
|
|
11792
|
-
return [
|
|
11793
|
-
...keys.apiUrlKeys,
|
|
11794
|
-
...keys.apiKeyKeys,
|
|
11795
|
-
credentialOverrideEnvKey("instructions"),
|
|
11796
|
-
credentialPointerEnvKey("instructions"),
|
|
11797
|
-
CREDENTIAL_PROFILE_ENV_KEY
|
|
11798
|
-
];
|
|
11799
|
-
}
|
|
11800
|
-
function hasInstructionsEnvAuthorityIntent(env = process.env) {
|
|
11801
|
-
return instructionsAuthorityEnvKeys().some((key) => (env[key] ?? "").trim() !== "");
|
|
11802
|
-
}
|
|
11803
|
-
function selectsInstructionsLocalStore(env = process.env) {
|
|
11804
|
-
return !hasInstructionsEnvAuthorityIntent(env) && isInstructionsLocalOptIn(env);
|
|
11805
|
-
}
|
|
11806
|
-
function instructionsResolverEnv(env) {
|
|
11807
|
-
const blanks = instructionsAuthorityEnvKeys().filter((key) => (key in env) && (env[key] ?? "").trim() === "");
|
|
11808
|
-
if (blanks.length === 0)
|
|
11809
|
-
return env;
|
|
11810
|
-
const next = { ...env };
|
|
11811
|
-
for (const key of blanks)
|
|
11812
|
-
delete next[key];
|
|
11813
|
-
return next;
|
|
11814
|
-
}
|
|
11815
|
-
var CONTRACTS_AMBIENT_ENVIRONMENT = Symbol.for("hasna:contracts:ambientClientEnvironment");
|
|
11816
|
-
function isAmbientInstructionsEnv(env) {
|
|
11817
|
-
if (typeof process !== "undefined" && env === process.env)
|
|
11818
|
-
return true;
|
|
11819
|
-
return env[CONTRACTS_AMBIENT_ENVIRONMENT] === true;
|
|
11820
|
-
}
|
|
11821
|
-
function instructionsResolverInputs(env, credentials = {}) {
|
|
11822
|
-
const normalised = instructionsResolverEnv(env);
|
|
11823
|
-
if (normalised === env)
|
|
11824
|
-
return { env: normalised, credentials };
|
|
11825
|
-
const keychain = { ...credentials.keychain };
|
|
11826
|
-
if (keychain.enabled === undefined && keychain.run === undefined) {
|
|
11827
|
-
keychain.enabled = isAmbientInstructionsEnv(env);
|
|
11828
|
-
}
|
|
11829
|
-
return { env: normalised, credentials: { ...credentials, keychain } };
|
|
11830
|
-
}
|
|
11831
|
-
|
|
11832
11657
|
// src/lib/transport-resolver.ts
|
|
11833
11658
|
var INSTRUCTIONS_APP = "instructions";
|
|
11834
11659
|
var INSTRUCTIONS_LOCAL_OPT_IN_ENV = INSTRUCTIONS_LOCAL_OPT_IN_ENV_KEYS[0];
|
|
@@ -11871,11 +11696,11 @@ function announceLocalInstructionsMode(write = (line) => process.stderr.write(`$
|
|
|
11871
11696
|
}
|
|
11872
11697
|
|
|
11873
11698
|
// src/data/config-store.ts
|
|
11874
|
-
function parseBoundedPagePayload(value, label) {
|
|
11699
|
+
function parseBoundedPagePayload(value, label, expected) {
|
|
11875
11700
|
const page = value;
|
|
11876
11701
|
const consumed = Number(page?.cursor) + (page?.items?.length ?? 0);
|
|
11877
11702
|
const complete = Boolean(page && Number.isSafeInteger(page.total) && consumed >= Number(page.total));
|
|
11878
|
-
if (!page || !Array.isArray(page.items) || !Number.isSafeInteger(page.total) || Number(page.total) < 0 || !Number.isSafeInteger(page.limit) || Number(page.limit) < 1 || !Number.isSafeInteger(page.cursor) || Number(page.cursor) < 0 || page.items.length > Number(page.limit) || typeof page.has_more !== "boolean" || typeof page.complete !== "boolean" || page.truncated !== false || page.next_cursor !== null && !Number.isSafeInteger(page.next_cursor) || page.complete !== complete || page.has_more !== !complete || page.next_cursor !== (complete ? null : consumed)) {
|
|
11703
|
+
if (!page || !Array.isArray(page.items) || !Number.isSafeInteger(page.total) || Number(page.total) < 0 || !Number.isSafeInteger(page.limit) || Number(page.limit) < 1 || !Number.isSafeInteger(page.cursor) || Number(page.cursor) < 0 || page.items.length > Number(page.limit) || typeof page.has_more !== "boolean" || typeof page.complete !== "boolean" || page.truncated !== false || page.next_cursor !== null && !Number.isSafeInteger(page.next_cursor) || page.complete !== complete || page.has_more !== !complete || page.next_cursor !== (complete ? null : consumed) || expected !== undefined && Number(page.cursor) !== expected.cursor) {
|
|
11879
11704
|
throw new Error(`${label} returned an invalid or truncated bounded-read envelope`);
|
|
11880
11705
|
}
|
|
11881
11706
|
return {
|
|
@@ -11887,7 +11712,7 @@ function parseBoundedOrLegacyPage(value, legacyItems, options, label) {
|
|
|
11887
11712
|
if (value && typeof value === "object") {
|
|
11888
11713
|
const candidate = value;
|
|
11889
11714
|
if ("items" in candidate || "total" in candidate || "complete" in candidate || "truncated" in candidate || "next_cursor" in candidate) {
|
|
11890
|
-
return parseBoundedPagePayload(value, label);
|
|
11715
|
+
return parseBoundedPagePayload(value, label, normalizeBoundedReadOptions(options));
|
|
11891
11716
|
}
|
|
11892
11717
|
}
|
|
11893
11718
|
if (!Array.isArray(legacyItems)) {
|
|
@@ -11897,6 +11722,78 @@ function parseBoundedOrLegacyPage(value, legacyItems, options, label) {
|
|
|
11897
11722
|
const page = boundedReadPage(legacyItems.slice(normalized.cursor, normalized.cursor + normalized.limit), legacyItems.length, normalized);
|
|
11898
11723
|
return { ...page, source_bounded: false };
|
|
11899
11724
|
}
|
|
11725
|
+
function projectBoundedPage(page, project) {
|
|
11726
|
+
return {
|
|
11727
|
+
items: page.items.map(project),
|
|
11728
|
+
total: page.total,
|
|
11729
|
+
limit: page.limit,
|
|
11730
|
+
cursor: page.cursor,
|
|
11731
|
+
next_cursor: page.next_cursor,
|
|
11732
|
+
has_more: page.has_more,
|
|
11733
|
+
complete: page.complete,
|
|
11734
|
+
truncated: page.truncated,
|
|
11735
|
+
source_bounded: page.source_bounded
|
|
11736
|
+
};
|
|
11737
|
+
}
|
|
11738
|
+
|
|
11739
|
+
class CollectionChangedWhilePagingError extends Error {
|
|
11740
|
+
constructor(label, detail) {
|
|
11741
|
+
super(`${label} changed while paging: ${detail}`);
|
|
11742
|
+
this.name = "CollectionChangedWhilePagingError";
|
|
11743
|
+
}
|
|
11744
|
+
}
|
|
11745
|
+
var COLLECTION_READ_ATTEMPTS = 2;
|
|
11746
|
+
async function aggregateBoundedCollection(label, readPage, identity, options = {}) {
|
|
11747
|
+
let lastError = null;
|
|
11748
|
+
for (let attempt = 0;attempt < COLLECTION_READ_ATTEMPTS; attempt += 1) {
|
|
11749
|
+
try {
|
|
11750
|
+
const items = [];
|
|
11751
|
+
const seen = new Set;
|
|
11752
|
+
let expectedTotal = null;
|
|
11753
|
+
let cursor = 0;
|
|
11754
|
+
let previousIdentity = null;
|
|
11755
|
+
while (true) {
|
|
11756
|
+
const page = await readPage(cursor);
|
|
11757
|
+
if (page.cursor !== cursor) {
|
|
11758
|
+
throw new CollectionChangedWhilePagingError(label, `server returned cursor ${page.cursor} for requested cursor ${cursor}`);
|
|
11759
|
+
}
|
|
11760
|
+
if (expectedTotal === null)
|
|
11761
|
+
expectedTotal = page.total;
|
|
11762
|
+
else if (page.total !== expectedTotal) {
|
|
11763
|
+
throw new CollectionChangedWhilePagingError(label, `total changed from ${expectedTotal} to ${page.total}`);
|
|
11764
|
+
}
|
|
11765
|
+
for (const item of page.items) {
|
|
11766
|
+
const key = identity(item);
|
|
11767
|
+
if (!key)
|
|
11768
|
+
throw new CollectionChangedWhilePagingError(label, "an item had no stable identity");
|
|
11769
|
+
if (seen.has(key))
|
|
11770
|
+
throw new CollectionChangedWhilePagingError(label, `duplicate identity ${key}`);
|
|
11771
|
+
if (options.requireAscendingIdentity && page.source_bounded && previousIdentity !== null && key <= previousIdentity) {
|
|
11772
|
+
throw new CollectionChangedWhilePagingError(label, `identity order was not strictly increasing at ${key}`);
|
|
11773
|
+
}
|
|
11774
|
+
seen.add(key);
|
|
11775
|
+
previousIdentity = key;
|
|
11776
|
+
items.push(item);
|
|
11777
|
+
}
|
|
11778
|
+
if (page.complete) {
|
|
11779
|
+
if (items.length !== expectedTotal) {
|
|
11780
|
+
throw new CollectionChangedWhilePagingError(label, `received ${items.length} unique rows for total ${expectedTotal}`);
|
|
11781
|
+
}
|
|
11782
|
+
return items;
|
|
11783
|
+
}
|
|
11784
|
+
if (page.next_cursor === null || page.next_cursor <= cursor) {
|
|
11785
|
+
throw new CollectionChangedWhilePagingError(label, `cursor did not advance from ${cursor}`);
|
|
11786
|
+
}
|
|
11787
|
+
cursor = page.next_cursor;
|
|
11788
|
+
}
|
|
11789
|
+
} catch (error) {
|
|
11790
|
+
if (!(error instanceof CollectionChangedWhilePagingError))
|
|
11791
|
+
throw error;
|
|
11792
|
+
lastError = error;
|
|
11793
|
+
}
|
|
11794
|
+
}
|
|
11795
|
+
throw lastError ?? new CollectionChangedWhilePagingError(label, "read did not stabilize");
|
|
11796
|
+
}
|
|
11900
11797
|
var LOCAL_OPT_IN_ENV = INSTRUCTIONS_LOCAL_OPT_IN_ENV;
|
|
11901
11798
|
function isCloudAuthError(err) {
|
|
11902
11799
|
return typeof err === "object" && err !== null && err.name === "HasnaHttpError" && (err.status === 401 || err.status === 403);
|
|
@@ -11922,7 +11819,7 @@ function formatCliError(err, env = process.env) {
|
|
|
11922
11819
|
var localStoreModulePromise = null;
|
|
11923
11820
|
function localStoreModule() {
|
|
11924
11821
|
if (!localStoreModulePromise)
|
|
11925
|
-
localStoreModulePromise = import("./local-
|
|
11822
|
+
localStoreModulePromise = import("./local-969ye538.js");
|
|
11926
11823
|
return localStoreModulePromise;
|
|
11927
11824
|
}
|
|
11928
11825
|
|
|
@@ -11936,6 +11833,15 @@ class LocalConfigStore {
|
|
|
11936
11833
|
async listConfigs(filter) {
|
|
11937
11834
|
return (await localStoreModule()).listConfigs(filter, this.db);
|
|
11938
11835
|
}
|
|
11836
|
+
async listConfigsPage(filter = {}, options = {}) {
|
|
11837
|
+
return (await localStoreModule()).listConfigsPage(filter, options, this.db);
|
|
11838
|
+
}
|
|
11839
|
+
async listConfigIdentitiesPage(filter = {}, options = {}) {
|
|
11840
|
+
return (await localStoreModule()).listConfigIdentitiesPage(filter, options, this.db);
|
|
11841
|
+
}
|
|
11842
|
+
async listConfigSummariesPage(filter = {}, options = {}) {
|
|
11843
|
+
return (await localStoreModule()).listConfigSummariesPage(filter, options, this.db);
|
|
11844
|
+
}
|
|
11939
11845
|
async getConfig(idOrSlug) {
|
|
11940
11846
|
return (await localStoreModule()).getConfig(idOrSlug, this.db);
|
|
11941
11847
|
}
|
|
@@ -11970,15 +11876,7 @@ class LocalConfigStore {
|
|
|
11970
11876
|
return (await localStoreModule()).pruneSnapshots(configId, keep, this.db);
|
|
11971
11877
|
}
|
|
11972
11878
|
async listProfiles() {
|
|
11973
|
-
|
|
11974
|
-
let cursor = 0;
|
|
11975
|
-
while (true) {
|
|
11976
|
-
const page = await this.listProfilesPage({ limit: 100, cursor });
|
|
11977
|
-
profiles.push(...page.items);
|
|
11978
|
-
if (page.complete)
|
|
11979
|
-
return profiles;
|
|
11980
|
-
cursor = page.next_cursor;
|
|
11981
|
-
}
|
|
11879
|
+
return aggregateBoundedCollection("profile list", (cursor) => this.listProfilesPage({ limit: 100, cursor }), (profile) => profile.id);
|
|
11982
11880
|
}
|
|
11983
11881
|
async listProfilesPage(options = {}) {
|
|
11984
11882
|
return (await localStoreModule()).listProfilesPage(options, this.db);
|
|
@@ -11987,15 +11885,7 @@ class LocalConfigStore {
|
|
|
11987
11885
|
return (await localStoreModule()).getProfile(idOrSlug, this.db);
|
|
11988
11886
|
}
|
|
11989
11887
|
async getProfileConfigs(idOrSlug) {
|
|
11990
|
-
|
|
11991
|
-
let cursor = 0;
|
|
11992
|
-
while (true) {
|
|
11993
|
-
const page = await this.getProfileConfigsPage(idOrSlug, { limit: 100, cursor });
|
|
11994
|
-
configs.push(...page.items);
|
|
11995
|
-
if (page.complete)
|
|
11996
|
-
return configs;
|
|
11997
|
-
cursor = page.next_cursor;
|
|
11998
|
-
}
|
|
11888
|
+
return aggregateBoundedCollection("profile membership", (cursor) => this.getProfileConfigsPage(idOrSlug, { limit: 100, cursor }), (config) => config.id);
|
|
11999
11889
|
}
|
|
12000
11890
|
async getProfileConfigsPage(idOrSlug, options = {}) {
|
|
12001
11891
|
return (await localStoreModule()).getProfileConfigsPage(idOrSlug, options, this.db);
|
|
@@ -12055,6 +11945,43 @@ class LocalConfigStore {
|
|
|
12055
11945
|
(await localStoreModule()).resetLocalDatabase();
|
|
12056
11946
|
}
|
|
12057
11947
|
}
|
|
11948
|
+
function toConfigIdentity(value) {
|
|
11949
|
+
const record = value && typeof value === "object" ? value : {};
|
|
11950
|
+
return {
|
|
11951
|
+
id: String(record.id ?? ""),
|
|
11952
|
+
name: String(record.name ?? ""),
|
|
11953
|
+
slug: String(record.slug ?? ""),
|
|
11954
|
+
kind: String(record.kind ?? ""),
|
|
11955
|
+
category: String(record.category ?? ""),
|
|
11956
|
+
agent: String(record.agent ?? ""),
|
|
11957
|
+
format: String(record.format ?? ""),
|
|
11958
|
+
is_template: Boolean(record.is_template),
|
|
11959
|
+
version: Number(record.version ?? 0),
|
|
11960
|
+
created_at: String(record.created_at ?? ""),
|
|
11961
|
+
updated_at: String(record.updated_at ?? ""),
|
|
11962
|
+
synced_at: record.synced_at == null ? null : String(record.synced_at)
|
|
11963
|
+
};
|
|
11964
|
+
}
|
|
11965
|
+
function toConfigSummary(value) {
|
|
11966
|
+
const record = value && typeof value === "object" ? value : {};
|
|
11967
|
+
const outputs = Array.isArray(record.outputs) ? record.outputs : [];
|
|
11968
|
+
return {
|
|
11969
|
+
id: String(record.id ?? ""),
|
|
11970
|
+
slug: String(record.slug ?? ""),
|
|
11971
|
+
name: String(record.name ?? ""),
|
|
11972
|
+
category: String(record.category ?? ""),
|
|
11973
|
+
agent: String(record.agent ?? ""),
|
|
11974
|
+
kind: String(record.kind ?? ""),
|
|
11975
|
+
format: String(record.format ?? ""),
|
|
11976
|
+
target_path: record.target_path == null ? null : String(record.target_path),
|
|
11977
|
+
output_count: Number(record.output_count ?? outputs.length),
|
|
11978
|
+
version: Number(record.version ?? 0),
|
|
11979
|
+
is_template: Boolean(record.is_template),
|
|
11980
|
+
...record.updated_at !== undefined ? { updated_at: String(record.updated_at) } : {},
|
|
11981
|
+
...record.description !== undefined ? { description: record.description == null ? null : String(record.description) } : {},
|
|
11982
|
+
...Array.isArray(record.tags) ? { tags: record.tags.map(String) } : {}
|
|
11983
|
+
};
|
|
11984
|
+
}
|
|
12058
11985
|
|
|
12059
11986
|
class CloudConfigStore {
|
|
12060
11987
|
mode = "api";
|
|
@@ -12076,7 +12003,8 @@ class CloudConfigStore {
|
|
|
12076
12003
|
throw err;
|
|
12077
12004
|
}
|
|
12078
12005
|
}
|
|
12079
|
-
async
|
|
12006
|
+
async listConfigsPage(filter = {}, options = {}) {
|
|
12007
|
+
const normalized = normalizeBoundedReadOptions(options);
|
|
12080
12008
|
const params = new URLSearchParams;
|
|
12081
12009
|
if (filter.category)
|
|
12082
12010
|
params.set("category", filter.category);
|
|
@@ -12086,16 +12014,75 @@ class CloudConfigStore {
|
|
|
12086
12014
|
params.set("kind", filter.kind);
|
|
12087
12015
|
if (filter.search)
|
|
12088
12016
|
params.set("search", filter.search);
|
|
12089
|
-
const
|
|
12090
|
-
|
|
12091
|
-
|
|
12017
|
+
for (const tag of filter.tags ?? [])
|
|
12018
|
+
params.append("tag", tag);
|
|
12019
|
+
params.set("limit", String(normalized.limit));
|
|
12020
|
+
params.set("cursor", String(normalized.cursor));
|
|
12021
|
+
const { data } = await this.request("GET", `/configs?${params.toString()}`);
|
|
12022
|
+
return parseBoundedOrLegacyPage(data, data?.configs, normalized, "config list");
|
|
12023
|
+
}
|
|
12024
|
+
async listConfigIdentitiesPage(filter = {}, options = {}) {
|
|
12025
|
+
const normalized = normalizeBoundedReadOptions(options);
|
|
12026
|
+
const params = new URLSearchParams;
|
|
12027
|
+
if (filter.category)
|
|
12028
|
+
params.set("category", filter.category);
|
|
12029
|
+
if (filter.agent)
|
|
12030
|
+
params.set("agent", filter.agent);
|
|
12031
|
+
if (filter.kind)
|
|
12032
|
+
params.set("kind", filter.kind);
|
|
12033
|
+
if (filter.search)
|
|
12034
|
+
params.set("search", filter.search);
|
|
12035
|
+
for (const tag of filter.tags ?? [])
|
|
12036
|
+
params.append("tag", tag);
|
|
12037
|
+
params.set("view", "identity");
|
|
12038
|
+
params.set("limit", String(normalized.limit));
|
|
12039
|
+
params.set("cursor", String(normalized.cursor));
|
|
12040
|
+
const { data } = await this.request("GET", `/configs?${params.toString()}`);
|
|
12041
|
+
const page = parseBoundedOrLegacyPage(data, data?.configs, normalized, "config identity list");
|
|
12042
|
+
if (page.items.some((item) => {
|
|
12043
|
+
const record = item && typeof item === "object" ? item : {};
|
|
12044
|
+
return ["content", "target_path", "outputs", "description", "tags"].some((field) => Object.prototype.hasOwnProperty.call(record, field));
|
|
12045
|
+
})) {
|
|
12046
|
+
throw new Error("Instructions /v1 config identity projection is unavailable; deploy the identity endpoint before using compact lists");
|
|
12047
|
+
}
|
|
12048
|
+
return projectBoundedPage(page, toConfigIdentity);
|
|
12049
|
+
}
|
|
12050
|
+
async listConfigSummariesPage(filter = {}, options = {}) {
|
|
12051
|
+
const normalized = normalizeBoundedReadOptions(options);
|
|
12052
|
+
const params = new URLSearchParams;
|
|
12053
|
+
if (filter.category)
|
|
12054
|
+
params.set("category", filter.category);
|
|
12055
|
+
if (filter.agent)
|
|
12056
|
+
params.set("agent", filter.agent);
|
|
12057
|
+
if (filter.kind)
|
|
12058
|
+
params.set("kind", filter.kind);
|
|
12059
|
+
if (filter.search)
|
|
12060
|
+
params.set("search", filter.search);
|
|
12061
|
+
for (const tag of filter.tags ?? [])
|
|
12062
|
+
params.append("tag", tag);
|
|
12063
|
+
params.set("view", "summary");
|
|
12064
|
+
params.set("limit", String(normalized.limit));
|
|
12065
|
+
params.set("cursor", String(normalized.cursor));
|
|
12066
|
+
const { data } = await this.request("GET", `/configs?${params.toString()}`);
|
|
12067
|
+
const page = parseBoundedOrLegacyPage(data, data?.configs, normalized, "config summary list");
|
|
12068
|
+
if (page.items.some((item) => {
|
|
12069
|
+
const record = item && typeof item === "object" ? item : {};
|
|
12070
|
+
return Object.prototype.hasOwnProperty.call(record, "content") || Object.prototype.hasOwnProperty.call(record, "outputs");
|
|
12071
|
+
})) {
|
|
12072
|
+
throw new Error("Instructions /v1 config summary projection is unavailable; deploy the summary endpoint before using summary lists");
|
|
12073
|
+
}
|
|
12074
|
+
return projectBoundedPage(page, toConfigSummary);
|
|
12075
|
+
}
|
|
12076
|
+
async listConfigs(filter = {}) {
|
|
12077
|
+
const configs = await aggregateBoundedCollection("config list", (cursor) => this.listConfigsPage(filter, { limit: 100, cursor }), (config) => config.id, { requireAscendingIdentity: true });
|
|
12078
|
+
let filtered = configs;
|
|
12092
12079
|
if (filter.tags && filter.tags.length > 0) {
|
|
12093
|
-
|
|
12080
|
+
filtered = filtered.filter((config) => filter.tags.every((tag) => config.tags.includes(tag)));
|
|
12094
12081
|
}
|
|
12095
12082
|
if (filter.is_template !== undefined) {
|
|
12096
|
-
|
|
12083
|
+
filtered = filtered.filter((config) => config.is_template === filter.is_template);
|
|
12097
12084
|
}
|
|
12098
|
-
return
|
|
12085
|
+
return filtered;
|
|
12099
12086
|
}
|
|
12100
12087
|
async getConfig(idOrSlug) {
|
|
12101
12088
|
const { status, data } = await this.request("GET", `/configs/${encodeURIComponent(idOrSlug)}`, undefined, { allow404: true });
|
|
@@ -12126,8 +12113,11 @@ class CloudConfigStore {
|
|
|
12126
12113
|
return data ?? { total: 0 };
|
|
12127
12114
|
}
|
|
12128
12115
|
async listSnapshots(configId) {
|
|
12129
|
-
|
|
12130
|
-
|
|
12116
|
+
return aggregateBoundedCollection("snapshot list", async (cursor) => {
|
|
12117
|
+
const normalized = normalizeBoundedReadOptions({ limit: 100, cursor });
|
|
12118
|
+
const { data } = await this.request("GET", `/configs/${encodeURIComponent(configId)}/snapshots?limit=${normalized.limit}&cursor=${normalized.cursor}`);
|
|
12119
|
+
return parseBoundedOrLegacyPage(data, data?.snapshots, normalized, "snapshot list");
|
|
12120
|
+
}, (snapshot) => snapshot.id);
|
|
12131
12121
|
}
|
|
12132
12122
|
async getSnapshot(id) {
|
|
12133
12123
|
const { status, data } = await this.request("GET", `/snapshots/${encodeURIComponent(id)}`, undefined, { allow404: true });
|
|
@@ -12150,15 +12140,7 @@ class CloudConfigStore {
|
|
|
12150
12140
|
return data?.pruned ?? 0;
|
|
12151
12141
|
}
|
|
12152
12142
|
async listProfiles() {
|
|
12153
|
-
|
|
12154
|
-
let cursor = 0;
|
|
12155
|
-
while (true) {
|
|
12156
|
-
const page = await this.listProfilesPage({ limit: 100, cursor });
|
|
12157
|
-
profiles.push(...page.items);
|
|
12158
|
-
if (page.complete)
|
|
12159
|
-
return profiles;
|
|
12160
|
-
cursor = page.next_cursor;
|
|
12161
|
-
}
|
|
12143
|
+
return aggregateBoundedCollection("profile list", (cursor) => this.listProfilesPage({ limit: 100, cursor }), (profile) => profile.id);
|
|
12162
12144
|
}
|
|
12163
12145
|
async listProfilesPage(options = {}) {
|
|
12164
12146
|
const normalized = normalizeBoundedReadOptions(options);
|
|
@@ -12182,15 +12164,7 @@ class CloudConfigStore {
|
|
|
12182
12164
|
return profile;
|
|
12183
12165
|
}
|
|
12184
12166
|
async getProfileConfigs(idOrSlug) {
|
|
12185
|
-
|
|
12186
|
-
let cursor = 0;
|
|
12187
|
-
while (true) {
|
|
12188
|
-
const page = await this.getProfileConfigsPage(idOrSlug, { limit: 100, cursor });
|
|
12189
|
-
configs.push(...page.items);
|
|
12190
|
-
if (page.complete)
|
|
12191
|
-
return configs;
|
|
12192
|
-
cursor = page.next_cursor;
|
|
12193
|
-
}
|
|
12167
|
+
return aggregateBoundedCollection("profile membership", (cursor) => this.getProfileConfigsPage(idOrSlug, { limit: 100, cursor }), (config) => config.id);
|
|
12194
12168
|
}
|
|
12195
12169
|
async getProfileConfigsPage(idOrSlug, options = {}) {
|
|
12196
12170
|
const normalized = normalizeBoundedReadOptions(options);
|
|
@@ -12204,20 +12178,26 @@ class CloudConfigStore {
|
|
|
12204
12178
|
return parseBoundedOrLegacyPage(data.configs, data.profile.configs, normalized, "profile membership");
|
|
12205
12179
|
}
|
|
12206
12180
|
async getProfileConfigBindings(idOrSlug) {
|
|
12207
|
-
|
|
12208
|
-
|
|
12209
|
-
const
|
|
12210
|
-
const
|
|
12211
|
-
|
|
12212
|
-
|
|
12213
|
-
|
|
12214
|
-
|
|
12215
|
-
|
|
12216
|
-
|
|
12217
|
-
|
|
12218
|
-
|
|
12219
|
-
|
|
12220
|
-
|
|
12181
|
+
let routeMissing = false;
|
|
12182
|
+
const bindings = await aggregateBoundedCollection("profile config bindings", async (cursor) => {
|
|
12183
|
+
const normalized = normalizeBoundedReadOptions({ limit: 100, cursor });
|
|
12184
|
+
const { status, data } = await this.requestProfileRoute(idOrSlug, (profileId) => `/profiles/${encodeURIComponent(profileId)}/bindings?limit=${normalized.limit}&cursor=${normalized.cursor}`, (value) => Boolean(value && (Array.isArray(value.bindings) || Array.isArray(value.items))));
|
|
12185
|
+
if (status === 404) {
|
|
12186
|
+
routeMissing = true;
|
|
12187
|
+
return { ...boundedReadPage([], 0, normalized), source_bounded: false };
|
|
12188
|
+
}
|
|
12189
|
+
return parseBoundedOrLegacyPage(data, data?.bindings, normalized, "profile config bindings");
|
|
12190
|
+
}, (binding) => `${binding.profile_id}\x00${binding.config_id}`);
|
|
12191
|
+
if (!routeMissing)
|
|
12192
|
+
return bindings;
|
|
12193
|
+
const profile = await this.getProfile(idOrSlug);
|
|
12194
|
+
const configs = await this.getProfileConfigs(idOrSlug);
|
|
12195
|
+
return configs.map((config, sort_order) => ({
|
|
12196
|
+
profile_id: profile.id,
|
|
12197
|
+
config_id: config.id,
|
|
12198
|
+
sort_order,
|
|
12199
|
+
binding: legacyProfileConfigBinding()
|
|
12200
|
+
}));
|
|
12221
12201
|
}
|
|
12222
12202
|
async requestProfileRoute(idOrSlug, pathForId, isUsable) {
|
|
12223
12203
|
const attempted = new Set;
|
|
@@ -12275,14 +12255,20 @@ class CloudConfigStore {
|
|
|
12275
12255
|
await this.request("DELETE", `/profiles/${encodeURIComponent(profileIdOrSlug)}/configs/${encodeURIComponent(configId)}`, undefined, { allow404: true });
|
|
12276
12256
|
}
|
|
12277
12257
|
async getProfileAssetBindings(profileIdOrSlug) {
|
|
12278
|
-
|
|
12279
|
-
|
|
12280
|
-
|
|
12281
|
-
|
|
12282
|
-
|
|
12283
|
-
|
|
12284
|
-
|
|
12285
|
-
|
|
12258
|
+
let routeMissing = false;
|
|
12259
|
+
const assets = await aggregateBoundedCollection("profile asset bindings", async (cursor) => {
|
|
12260
|
+
const normalized = normalizeBoundedReadOptions({ limit: 100, cursor });
|
|
12261
|
+
const { status, data } = await this.requestProfileRoute(profileIdOrSlug, (profileId) => `/profiles/${encodeURIComponent(profileId)}/assets?limit=${normalized.limit}&cursor=${normalized.cursor}`, (value) => Boolean(value && (Array.isArray(value.assets) || Array.isArray(value.items))));
|
|
12262
|
+
if (status === 404) {
|
|
12263
|
+
routeMissing = true;
|
|
12264
|
+
return { ...boundedReadPage([], 0, normalized), source_bounded: false };
|
|
12265
|
+
}
|
|
12266
|
+
return parseBoundedOrLegacyPage(data, data?.assets, normalized, "profile asset bindings");
|
|
12267
|
+
}, (asset) => `${asset.profile_id}\x00${asset.binding.assetKey}`);
|
|
12268
|
+
if (!routeMissing)
|
|
12269
|
+
return assets;
|
|
12270
|
+
await this.getProfile(profileIdOrSlug);
|
|
12271
|
+
return [];
|
|
12286
12272
|
}
|
|
12287
12273
|
async addAssetToProfile(profileIdOrSlug, sourceConfigId, binding) {
|
|
12288
12274
|
const { data } = await this.request("POST", `/profiles/${encodeURIComponent(profileIdOrSlug)}/assets`, { source_config_id: sourceConfigId, binding }, { idempotent: true });
|
|
@@ -12352,8 +12338,11 @@ class CloudConfigStore {
|
|
|
12352
12338
|
await this.request("POST", "/machines/applied", { hostname });
|
|
12353
12339
|
}
|
|
12354
12340
|
async listMachines() {
|
|
12355
|
-
|
|
12356
|
-
|
|
12341
|
+
return aggregateBoundedCollection("machine list", async (cursor) => {
|
|
12342
|
+
const normalized = normalizeBoundedReadOptions({ limit: 100, cursor });
|
|
12343
|
+
const { data } = await this.request("GET", `/machines?limit=${normalized.limit}&cursor=${normalized.cursor}`);
|
|
12344
|
+
return parseBoundedOrLegacyPage(data, data?.machines, normalized, "machine list");
|
|
12345
|
+
}, (machine) => machine.id, { requireAscendingIdentity: true });
|
|
12357
12346
|
}
|
|
12358
12347
|
async sendFeedback(input) {
|
|
12359
12348
|
await this.request("POST", "/feedback", {
|
|
@@ -12603,9 +12592,9 @@ async function ensureGlobalAgentRulesStandardConfig(store = resolveConfigStore()
|
|
|
12603
12592
|
}
|
|
12604
12593
|
|
|
12605
12594
|
// src/lib/machine.ts
|
|
12606
|
-
import { arch as currentArch, homedir as
|
|
12607
|
-
import { existsSync as
|
|
12608
|
-
import { join as
|
|
12595
|
+
import { arch as currentArch, homedir as homedir5, hostname as currentHostname, type as currentOsType } from "os";
|
|
12596
|
+
import { existsSync as existsSync5 } from "fs";
|
|
12597
|
+
import { join as join7 } from "path";
|
|
12609
12598
|
var BREW_BUN_PATH = "/opt/homebrew/bin/bun";
|
|
12610
12599
|
function normalizeOsFamily(os) {
|
|
12611
12600
|
const value = (os ?? "").trim().toLowerCase();
|
|
@@ -12618,11 +12607,11 @@ function normalizeOsFamily(os) {
|
|
|
12618
12607
|
return value || "unknown";
|
|
12619
12608
|
}
|
|
12620
12609
|
function detectMachineContext(overrides = {}) {
|
|
12621
|
-
const
|
|
12610
|
+
const homeDir4 = overrides.home_dir ?? process.env["CONFIGS_HOME"] ?? process.env["HOME"] ?? homedir5();
|
|
12622
12611
|
const os = overrides.os ?? currentOsType();
|
|
12623
12612
|
const osFamily = normalizeOsFamily(os);
|
|
12624
|
-
const bunBinDir = overrides.bun_bin_dir ??
|
|
12625
|
-
const defaultBunPath = osFamily === "macos" &&
|
|
12613
|
+
const bunBinDir = overrides.bun_bin_dir ?? join7(homeDir4, ".bun", "bin");
|
|
12614
|
+
const defaultBunPath = osFamily === "macos" && existsSync5(BREW_BUN_PATH) ? BREW_BUN_PATH : join7(bunBinDir, "bun");
|
|
12626
12615
|
return {
|
|
12627
12616
|
id: "current-machine",
|
|
12628
12617
|
hostname: overrides.hostname ?? currentHostname(),
|
|
@@ -12631,11 +12620,11 @@ function detectMachineContext(overrides = {}) {
|
|
|
12631
12620
|
last_applied_at: null,
|
|
12632
12621
|
created_at: "",
|
|
12633
12622
|
os_family: osFamily,
|
|
12634
|
-
home_dir:
|
|
12635
|
-
workspace_root: overrides.workspace_root ??
|
|
12623
|
+
home_dir: homeDir4,
|
|
12624
|
+
workspace_root: overrides.workspace_root ?? join7(homeDir4, osFamily === "macos" ? "Workspace" : "workspace"),
|
|
12636
12625
|
bun_bin_dir: bunBinDir,
|
|
12637
12626
|
bun_path: overrides.bun_path ?? defaultBunPath,
|
|
12638
|
-
path_prefix: overrides.path_prefix ?? (osFamily === "macos" ? `${
|
|
12627
|
+
path_prefix: overrides.path_prefix ?? (osFamily === "macos" ? `${join7("/opt", "homebrew", "bin")}:${bunBinDir}` : bunBinDir)
|
|
12639
12628
|
};
|
|
12640
12629
|
}
|
|
12641
12630
|
function machineContextToVariables(machine) {
|
|
@@ -12699,4 +12688,4 @@ function renderMachineAwareContentPreview(content, variables) {
|
|
|
12699
12688
|
return isTemplate(content) ? renderTemplatePreview(content, variables) : { content, unresolved: [] };
|
|
12700
12689
|
}
|
|
12701
12690
|
|
|
12702
|
-
export { DEFAULT_LIST_LIMIT, parseLimit, paginate, truncateText, truncateMiddle, normalizeBoundedReadOptions, boundedReadPage, ensureGlobalAgentRulesStandardConfig, ensureCodewithSharedTodosStorageStandardConfig, redactFormatForTarget, redactContent, scanSecrets, isSecretVarName, SESSION_RENDER_MANAGED_MARKER, SESSION_RENDER_SCHEMA, SESSION_RENDER_MANIFEST_RELATIVE_PATH, SESSION_INSTRUCTION_LAYERS, getSessionRenderSnapshotDir, sessionRenderSnapshotWorkspaceRoot, PROJECT_CONTEXT_MAX_INPUT_BYTES, SESSION_MANAGED_INPUT_MAX_BYTES, ProjectContextError, parseProjectContextBundle, planProjectContext, observeProjectContextSessionGuard, withProjectContextSessionGuard, applyProjectContext, writeProjectContextCoordinatedFile, removeProjectContextCoordinatedFile, isRetiredOrUnsupportedConfigAgent, retiredOrUnsupportedAgentReason, applyTransform, normalizeProfileAssetBinding, observeCursorGlobalAuthorityAtPath, isCursorGlobalAuthorityPath, stampCursorGlobalAuthorityMarker, detectCursorAuthorityConflicts, detectClaudeAuthorityConflicts,
|
|
12691
|
+
export { DEFAULT_LIST_LIMIT, parseLimit, paginate, truncateText, truncateMiddle, normalizeBoundedReadOptions, boundedReadPage, ensureGlobalAgentRulesStandardConfig, ensureCodewithSharedTodosStorageStandardConfig, redactFormatForTarget, redactContent, scanSecrets, isSecretVarName, SESSION_RENDER_MANAGED_MARKER, SESSION_RENDER_SCHEMA, SESSION_RENDER_MANIFEST_RELATIVE_PATH, SESSION_INSTRUCTION_LAYERS, getSessionRenderSnapshotDir, sessionRenderSnapshotWorkspaceRoot, PROJECT_CONTEXT_MAX_INPUT_BYTES, SESSION_MANAGED_INPUT_MAX_BYTES, ProjectContextError, parseProjectContextBundle, planProjectContext, observeProjectContextSessionGuard, withProjectContextSessionGuard, applyProjectContext, writeProjectContextCoordinatedFile, removeProjectContextCoordinatedFile, isRetiredOrUnsupportedConfigAgent, retiredOrUnsupportedAgentReason, applyTransform, normalizeProfileAssetBinding, observeCursorGlobalAuthorityAtPath, isCursorGlobalAuthorityPath, stampCursorGlobalAuthorityMarker, detectCursorAuthorityConflicts, detectClaudeAuthorityConflicts, ANTIGRAVITY_RULE_FILE_CHAR_LIMIT, SESSION_RENDERER_OWNER_ID, SESSION_RENDER_TOOLS, SESSION_RENDER_OWNED_CONFIG_TARGETS, SESSION_RENDER_EXCLUSIVE_MANAGED_PATHS, normalizeSessionInstructionSourceId, resolveSessionPath, planSessionRender, sourceFromFilePath, sourceFromConfig, sourcesFromIdentityExport, legacyProfileConfigBinding, normalizeProfileConfigBinding, planProfileSessionRender, normalizeOsFamily, detectMachineContext, machineContextToVariables, resolveProfileVariables, templateizeMachineContent, renderMachineAwareContentPreview, formatCliError, CloudConfigStore, resolveConfigStore };
|