@hasna/instructions 0.7.0 → 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 +18 -4
- package/dist/chunks/{apply-7svah2qm.js → apply-c3sd4agz.js} +2 -2
- package/dist/chunks/{apply-jp13sa1e.js → apply-pnn7a3y7.js} +2 -2
- package/dist/chunks/{index-7m4j8a33.js → index-6jncnnw7.js} +117 -4
- package/dist/chunks/{index-4pfq42t5.js → index-aj66f6xr.js} +118 -27
- package/dist/chunks/{index-bzyxvwcd.js → index-jg8ptcwh.js} +2 -2
- package/dist/chunks/{index-arrrx0ed.js → index-mvckkf15.js} +39 -20
- package/dist/chunks/{index-1cnyjnd7.js → index-pdpg8a44.js} +2 -2
- package/dist/chunks/{index-z3ma4aqk.js → index-r7nfef2g.js} +1 -1
- package/dist/chunks/{index-fwbs6tma.js → index-ypcef3a2.js} +1 -1
- package/dist/chunks/{local-5wvv5xv3.js → local-0a9gja58.js} +141 -1
- package/dist/chunks/{local-zxa5dpf4.js → local-969ye538.js} +141 -1
- 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-q5hvwq6e.js} +3 -3
- package/dist/chunks/{sync-2075deve.js → sync-xtkbm5br.js} +3 -3
- package/dist/cli/index.js +269 -53
- package/dist/data/config-store.d.ts +10 -2
- 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 +282 -36
- package/dist/lib/compact-output.d.ts +2 -18
- package/dist/lib/compact-output.d.ts.map +1 -1
- package/dist/lib/export.d.ts.map +1 -1
- package/dist/lib/import.d.ts.map +1 -1
- package/dist/mcp/index.js +17 -17
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/sdk/index.js +27 -3
- package/dist/sdk/v1-client.d.ts +4 -3
- package/dist/sdk/v1-client.d.ts.map +1 -1
- package/dist/sdk/v1.generated.d.ts +32 -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 +93 -7
- package/dist/server/openapi.d.ts +117 -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 +33 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -52,9 +52,13 @@ existing row.
|
|
|
52
52
|
|
|
53
53
|
```bash
|
|
54
54
|
instructions --help
|
|
55
|
-
instructions list
|
|
56
|
-
instructions list --verbose
|
|
57
|
-
instructions list --json
|
|
55
|
+
instructions list # compact, paged summary
|
|
56
|
+
instructions list --verbose # expanded metadata, still paged
|
|
57
|
+
instructions list --json # legacy complete full-record array
|
|
58
|
+
instructions list --json --detail compact --limit 20 # bounded identity envelope
|
|
59
|
+
instructions list --json --detail compact --fields id,slug,name,version
|
|
60
|
+
instructions list --json --detail full --limit 20 # explicit bounded content read
|
|
61
|
+
instructions list --json --detail compact --all # explicit complete metadata read
|
|
58
62
|
instructions show <slug> # full metadata + content
|
|
59
63
|
instructions inspect <slug> # alias for show
|
|
60
64
|
instructions profile resolve
|
|
@@ -68,7 +72,9 @@ small. Human output is capped at 20 rows unless you pass `--limit`; use
|
|
|
68
72
|
`--cursor` to continue from the next page. Detail is explicit:
|
|
69
73
|
|
|
70
74
|
- `--verbose` expands list rows with descriptions, tags, and paths.
|
|
71
|
-
- `--json` preserves full
|
|
75
|
+
- Legacy `--json` with no modern detail flags preserves the complete full-record array for automation. Explicit `--limit`/`--cursor` now bound that legacy array.
|
|
76
|
+
- `--detail compact` returns a content-free `{ configs, _meta }` identity envelope through the already-deployed `/v1/configs?view=identity` projection. Add `--fields` (including immutable `id`), `--all`, or `--pretty` as needed.
|
|
77
|
+
- `--detail full` is the explicit content-bearing envelope; it is bounded unless `--all` is supplied.
|
|
72
78
|
- `show`/`inspect` and `snapshot show` print full config or snapshot content.
|
|
73
79
|
|
|
74
80
|
`instructions report --json` emits the stable `schema_version: 1` report
|
|
@@ -330,6 +336,14 @@ credentials may come from Bun's standard AWS chain (including an ECS task role);
|
|
|
330
336
|
explicit static credentials are optional and must be a complete pair. Status
|
|
331
337
|
never prints credential values or the bucket name.
|
|
332
338
|
|
|
339
|
+
The production deployment runs the immutable predeploy backup push and verify
|
|
340
|
+
as direct Bun commands in the exact candidate image. The GitHub runner alone
|
|
341
|
+
parses the push receipt, then supplies the recorded payload and manifest version
|
|
342
|
+
IDs to verification; it also checks the receipt digest and size, COMPLIANCE
|
|
343
|
+
Object Lock retention for both versions, and an exact versioned-payload
|
|
344
|
+
readback. Every backup gate completes before any ECR push, database migration,
|
|
345
|
+
or ECS update.
|
|
346
|
+
|
|
333
347
|
The public importable surface is available at `@hasna/instructions/storage`.
|
|
334
348
|
|
|
335
349
|
## Data Directory
|
|
@@ -8,8 +8,8 @@ import {
|
|
|
8
8
|
getConfigHome,
|
|
9
9
|
normalizeTargetPath,
|
|
10
10
|
previewConfigs
|
|
11
|
-
} from "./index-
|
|
12
|
-
import"./index-
|
|
11
|
+
} from "./index-ypcef3a2.js";
|
|
12
|
+
import"./index-aj66f6xr.js";
|
|
13
13
|
import"./index-35z65jsa.js";
|
|
14
14
|
import"./index-3djthcm6.js";
|
|
15
15
|
import"./index-nnwp92tk.js";
|
|
@@ -8,8 +8,8 @@ import {
|
|
|
8
8
|
getConfigHome,
|
|
9
9
|
normalizeTargetPath,
|
|
10
10
|
previewConfigs
|
|
11
|
-
} from "./index-
|
|
12
|
-
import"./index-
|
|
11
|
+
} from "./index-r7nfef2g.js";
|
|
12
|
+
import"./index-6jncnnw7.js";
|
|
13
13
|
import"./index-n3fjspr0.js";
|
|
14
14
|
import"./index-fpeyzn3n.js";
|
|
15
15
|
import"./index-bsan4c16.js";
|
|
@@ -11722,6 +11722,19 @@ function parseBoundedOrLegacyPage(value, legacyItems, options, label) {
|
|
|
11722
11722
|
const page = boundedReadPage(legacyItems.slice(normalized.cursor, normalized.cursor + normalized.limit), legacyItems.length, normalized);
|
|
11723
11723
|
return { ...page, source_bounded: false };
|
|
11724
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
|
+
}
|
|
11725
11738
|
|
|
11726
11739
|
class CollectionChangedWhilePagingError extends Error {
|
|
11727
11740
|
constructor(label, detail) {
|
|
@@ -11806,7 +11819,7 @@ function formatCliError(err, env = process.env) {
|
|
|
11806
11819
|
var localStoreModulePromise = null;
|
|
11807
11820
|
function localStoreModule() {
|
|
11808
11821
|
if (!localStoreModulePromise)
|
|
11809
|
-
localStoreModulePromise = import("./local-
|
|
11822
|
+
localStoreModulePromise = import("./local-969ye538.js");
|
|
11810
11823
|
return localStoreModulePromise;
|
|
11811
11824
|
}
|
|
11812
11825
|
|
|
@@ -11820,6 +11833,15 @@ class LocalConfigStore {
|
|
|
11820
11833
|
async listConfigs(filter) {
|
|
11821
11834
|
return (await localStoreModule()).listConfigs(filter, this.db);
|
|
11822
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
|
+
}
|
|
11823
11845
|
async getConfig(idOrSlug) {
|
|
11824
11846
|
return (await localStoreModule()).getConfig(idOrSlug, this.db);
|
|
11825
11847
|
}
|
|
@@ -11923,6 +11945,43 @@ class LocalConfigStore {
|
|
|
11923
11945
|
(await localStoreModule()).resetLocalDatabase();
|
|
11924
11946
|
}
|
|
11925
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
|
+
}
|
|
11926
11985
|
|
|
11927
11986
|
class CloudConfigStore {
|
|
11928
11987
|
mode = "api";
|
|
@@ -11944,7 +12003,7 @@ class CloudConfigStore {
|
|
|
11944
12003
|
throw err;
|
|
11945
12004
|
}
|
|
11946
12005
|
}
|
|
11947
|
-
async
|
|
12006
|
+
async listConfigsPage(filter = {}, options = {}) {
|
|
11948
12007
|
const normalized = normalizeBoundedReadOptions(options);
|
|
11949
12008
|
const params = new URLSearchParams;
|
|
11950
12009
|
if (filter.category)
|
|
@@ -11955,13 +12014,67 @@ class CloudConfigStore {
|
|
|
11955
12014
|
params.set("kind", filter.kind);
|
|
11956
12015
|
if (filter.search)
|
|
11957
12016
|
params.set("search", filter.search);
|
|
12017
|
+
for (const tag of filter.tags ?? [])
|
|
12018
|
+
params.append("tag", tag);
|
|
11958
12019
|
params.set("limit", String(normalized.limit));
|
|
11959
12020
|
params.set("cursor", String(normalized.cursor));
|
|
11960
12021
|
const { data } = await this.request("GET", `/configs?${params.toString()}`);
|
|
11961
12022
|
return parseBoundedOrLegacyPage(data, data?.configs, normalized, "config list");
|
|
11962
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
|
+
}
|
|
11963
12076
|
async listConfigs(filter = {}) {
|
|
11964
|
-
const configs = await aggregateBoundedCollection("config list", (cursor) => this.
|
|
12077
|
+
const configs = await aggregateBoundedCollection("config list", (cursor) => this.listConfigsPage(filter, { limit: 100, cursor }), (config) => config.id, { requireAscendingIdentity: true });
|
|
11965
12078
|
let filtered = configs;
|
|
11966
12079
|
if (filter.tags && filter.tags.length > 0) {
|
|
11967
12080
|
filtered = filtered.filter((config) => filter.tags.every((tag) => config.tags.includes(tag)));
|
|
@@ -12027,7 +12140,7 @@ class CloudConfigStore {
|
|
|
12027
12140
|
return data?.pruned ?? 0;
|
|
12028
12141
|
}
|
|
12029
12142
|
async listProfiles() {
|
|
12030
|
-
return aggregateBoundedCollection("profile list", (cursor) => this.listProfilesPage({ limit: 100, cursor }), (profile) => profile.id
|
|
12143
|
+
return aggregateBoundedCollection("profile list", (cursor) => this.listProfilesPage({ limit: 100, cursor }), (profile) => profile.id);
|
|
12031
12144
|
}
|
|
12032
12145
|
async listProfilesPage(options = {}) {
|
|
12033
12146
|
const normalized = normalizeBoundedReadOptions(options);
|
|
@@ -244,28 +244,6 @@ function truncateText(value, max = 80) {
|
|
|
244
244
|
return text.slice(0, max);
|
|
245
245
|
return `${text.slice(0, max - 3)}...`;
|
|
246
246
|
}
|
|
247
|
-
function summarizeConfig(config, opts = {}) {
|
|
248
|
-
const summary = {
|
|
249
|
-
id: config.id,
|
|
250
|
-
slug: config.slug,
|
|
251
|
-
name: config.name,
|
|
252
|
-
category: config.category,
|
|
253
|
-
agent: config.agent,
|
|
254
|
-
kind: config.kind,
|
|
255
|
-
format: config.format,
|
|
256
|
-
target_path: config.target_path,
|
|
257
|
-
output_count: config.outputs.length,
|
|
258
|
-
version: config.version,
|
|
259
|
-
is_template: config.is_template
|
|
260
|
-
};
|
|
261
|
-
if (opts.verbose) {
|
|
262
|
-
summary.updated_at = config.updated_at;
|
|
263
|
-
summary.description = config.description;
|
|
264
|
-
summary.tags = config.tags;
|
|
265
|
-
summary.outputs = config.outputs;
|
|
266
|
-
}
|
|
267
|
-
return summary;
|
|
268
|
-
}
|
|
269
247
|
function summarizeProfile(profile, opts = {}) {
|
|
270
248
|
const selectorCount = (profile.selectors.os?.length ?? 0) + (profile.selectors.arch?.length ?? 0) + (profile.selectors.hostnames?.length ?? 0);
|
|
271
249
|
const summary = {
|
|
@@ -2059,6 +2037,19 @@ function parseBoundedOrLegacyPage(value, legacyItems, options, label) {
|
|
|
2059
2037
|
const page = boundedReadPage(legacyItems.slice(normalized.cursor, normalized.cursor + normalized.limit), legacyItems.length, normalized);
|
|
2060
2038
|
return { ...page, source_bounded: false };
|
|
2061
2039
|
}
|
|
2040
|
+
function projectBoundedPage(page, project) {
|
|
2041
|
+
return {
|
|
2042
|
+
items: page.items.map(project),
|
|
2043
|
+
total: page.total,
|
|
2044
|
+
limit: page.limit,
|
|
2045
|
+
cursor: page.cursor,
|
|
2046
|
+
next_cursor: page.next_cursor,
|
|
2047
|
+
has_more: page.has_more,
|
|
2048
|
+
complete: page.complete,
|
|
2049
|
+
truncated: page.truncated,
|
|
2050
|
+
source_bounded: page.source_bounded
|
|
2051
|
+
};
|
|
2052
|
+
}
|
|
2062
2053
|
|
|
2063
2054
|
class CollectionChangedWhilePagingError extends Error {
|
|
2064
2055
|
constructor(label, detail) {
|
|
@@ -2124,7 +2115,7 @@ function isNotFoundHttpError2(err) {
|
|
|
2124
2115
|
var localStoreModulePromise = null;
|
|
2125
2116
|
function localStoreModule() {
|
|
2126
2117
|
if (!localStoreModulePromise)
|
|
2127
|
-
localStoreModulePromise = import("./local-
|
|
2118
|
+
localStoreModulePromise = import("./local-0a9gja58.js");
|
|
2128
2119
|
return localStoreModulePromise;
|
|
2129
2120
|
}
|
|
2130
2121
|
|
|
@@ -2138,6 +2129,15 @@ class LocalConfigStore {
|
|
|
2138
2129
|
async listConfigs(filter) {
|
|
2139
2130
|
return (await localStoreModule()).listConfigs(filter, this.db);
|
|
2140
2131
|
}
|
|
2132
|
+
async listConfigsPage(filter = {}, options = {}) {
|
|
2133
|
+
return (await localStoreModule()).listConfigsPage(filter, options, this.db);
|
|
2134
|
+
}
|
|
2135
|
+
async listConfigIdentitiesPage(filter = {}, options = {}) {
|
|
2136
|
+
return (await localStoreModule()).listConfigIdentitiesPage(filter, options, this.db);
|
|
2137
|
+
}
|
|
2138
|
+
async listConfigSummariesPage(filter = {}, options = {}) {
|
|
2139
|
+
return (await localStoreModule()).listConfigSummariesPage(filter, options, this.db);
|
|
2140
|
+
}
|
|
2141
2141
|
async getConfig(idOrSlug) {
|
|
2142
2142
|
return (await localStoreModule()).getConfig(idOrSlug, this.db);
|
|
2143
2143
|
}
|
|
@@ -2241,6 +2241,43 @@ class LocalConfigStore {
|
|
|
2241
2241
|
(await localStoreModule()).resetLocalDatabase();
|
|
2242
2242
|
}
|
|
2243
2243
|
}
|
|
2244
|
+
function toConfigIdentity(value) {
|
|
2245
|
+
const record = value && typeof value === "object" ? value : {};
|
|
2246
|
+
return {
|
|
2247
|
+
id: String(record.id ?? ""),
|
|
2248
|
+
name: String(record.name ?? ""),
|
|
2249
|
+
slug: String(record.slug ?? ""),
|
|
2250
|
+
kind: String(record.kind ?? ""),
|
|
2251
|
+
category: String(record.category ?? ""),
|
|
2252
|
+
agent: String(record.agent ?? ""),
|
|
2253
|
+
format: String(record.format ?? ""),
|
|
2254
|
+
is_template: Boolean(record.is_template),
|
|
2255
|
+
version: Number(record.version ?? 0),
|
|
2256
|
+
created_at: String(record.created_at ?? ""),
|
|
2257
|
+
updated_at: String(record.updated_at ?? ""),
|
|
2258
|
+
synced_at: record.synced_at == null ? null : String(record.synced_at)
|
|
2259
|
+
};
|
|
2260
|
+
}
|
|
2261
|
+
function toConfigSummary(value) {
|
|
2262
|
+
const record = value && typeof value === "object" ? value : {};
|
|
2263
|
+
const outputs = Array.isArray(record.outputs) ? record.outputs : [];
|
|
2264
|
+
return {
|
|
2265
|
+
id: String(record.id ?? ""),
|
|
2266
|
+
slug: String(record.slug ?? ""),
|
|
2267
|
+
name: String(record.name ?? ""),
|
|
2268
|
+
category: String(record.category ?? ""),
|
|
2269
|
+
agent: String(record.agent ?? ""),
|
|
2270
|
+
kind: String(record.kind ?? ""),
|
|
2271
|
+
format: String(record.format ?? ""),
|
|
2272
|
+
target_path: record.target_path == null ? null : String(record.target_path),
|
|
2273
|
+
output_count: Number(record.output_count ?? outputs.length),
|
|
2274
|
+
version: Number(record.version ?? 0),
|
|
2275
|
+
is_template: Boolean(record.is_template),
|
|
2276
|
+
...record.updated_at !== undefined ? { updated_at: String(record.updated_at) } : {},
|
|
2277
|
+
...record.description !== undefined ? { description: record.description == null ? null : String(record.description) } : {},
|
|
2278
|
+
...Array.isArray(record.tags) ? { tags: record.tags.map(String) } : {}
|
|
2279
|
+
};
|
|
2280
|
+
}
|
|
2244
2281
|
|
|
2245
2282
|
class CloudConfigStore {
|
|
2246
2283
|
mode = "api";
|
|
@@ -2262,7 +2299,7 @@ class CloudConfigStore {
|
|
|
2262
2299
|
throw err;
|
|
2263
2300
|
}
|
|
2264
2301
|
}
|
|
2265
|
-
async
|
|
2302
|
+
async listConfigsPage(filter = {}, options = {}) {
|
|
2266
2303
|
const normalized = normalizeBoundedReadOptions(options);
|
|
2267
2304
|
const params = new URLSearchParams;
|
|
2268
2305
|
if (filter.category)
|
|
@@ -2273,13 +2310,67 @@ class CloudConfigStore {
|
|
|
2273
2310
|
params.set("kind", filter.kind);
|
|
2274
2311
|
if (filter.search)
|
|
2275
2312
|
params.set("search", filter.search);
|
|
2313
|
+
for (const tag of filter.tags ?? [])
|
|
2314
|
+
params.append("tag", tag);
|
|
2276
2315
|
params.set("limit", String(normalized.limit));
|
|
2277
2316
|
params.set("cursor", String(normalized.cursor));
|
|
2278
2317
|
const { data } = await this.request("GET", `/configs?${params.toString()}`);
|
|
2279
2318
|
return parseBoundedOrLegacyPage(data, data?.configs, normalized, "config list");
|
|
2280
2319
|
}
|
|
2320
|
+
async listConfigIdentitiesPage(filter = {}, options = {}) {
|
|
2321
|
+
const normalized = normalizeBoundedReadOptions(options);
|
|
2322
|
+
const params = new URLSearchParams;
|
|
2323
|
+
if (filter.category)
|
|
2324
|
+
params.set("category", filter.category);
|
|
2325
|
+
if (filter.agent)
|
|
2326
|
+
params.set("agent", filter.agent);
|
|
2327
|
+
if (filter.kind)
|
|
2328
|
+
params.set("kind", filter.kind);
|
|
2329
|
+
if (filter.search)
|
|
2330
|
+
params.set("search", filter.search);
|
|
2331
|
+
for (const tag of filter.tags ?? [])
|
|
2332
|
+
params.append("tag", tag);
|
|
2333
|
+
params.set("view", "identity");
|
|
2334
|
+
params.set("limit", String(normalized.limit));
|
|
2335
|
+
params.set("cursor", String(normalized.cursor));
|
|
2336
|
+
const { data } = await this.request("GET", `/configs?${params.toString()}`);
|
|
2337
|
+
const page = parseBoundedOrLegacyPage(data, data?.configs, normalized, "config identity list");
|
|
2338
|
+
if (page.items.some((item) => {
|
|
2339
|
+
const record = item && typeof item === "object" ? item : {};
|
|
2340
|
+
return ["content", "target_path", "outputs", "description", "tags"].some((field) => Object.prototype.hasOwnProperty.call(record, field));
|
|
2341
|
+
})) {
|
|
2342
|
+
throw new Error("Instructions /v1 config identity projection is unavailable; deploy the identity endpoint before using compact lists");
|
|
2343
|
+
}
|
|
2344
|
+
return projectBoundedPage(page, toConfigIdentity);
|
|
2345
|
+
}
|
|
2346
|
+
async listConfigSummariesPage(filter = {}, options = {}) {
|
|
2347
|
+
const normalized = normalizeBoundedReadOptions(options);
|
|
2348
|
+
const params = new URLSearchParams;
|
|
2349
|
+
if (filter.category)
|
|
2350
|
+
params.set("category", filter.category);
|
|
2351
|
+
if (filter.agent)
|
|
2352
|
+
params.set("agent", filter.agent);
|
|
2353
|
+
if (filter.kind)
|
|
2354
|
+
params.set("kind", filter.kind);
|
|
2355
|
+
if (filter.search)
|
|
2356
|
+
params.set("search", filter.search);
|
|
2357
|
+
for (const tag of filter.tags ?? [])
|
|
2358
|
+
params.append("tag", tag);
|
|
2359
|
+
params.set("view", "summary");
|
|
2360
|
+
params.set("limit", String(normalized.limit));
|
|
2361
|
+
params.set("cursor", String(normalized.cursor));
|
|
2362
|
+
const { data } = await this.request("GET", `/configs?${params.toString()}`);
|
|
2363
|
+
const page = parseBoundedOrLegacyPage(data, data?.configs, normalized, "config summary list");
|
|
2364
|
+
if (page.items.some((item) => {
|
|
2365
|
+
const record = item && typeof item === "object" ? item : {};
|
|
2366
|
+
return Object.prototype.hasOwnProperty.call(record, "content") || Object.prototype.hasOwnProperty.call(record, "outputs");
|
|
2367
|
+
})) {
|
|
2368
|
+
throw new Error("Instructions /v1 config summary projection is unavailable; deploy the summary endpoint before using summary lists");
|
|
2369
|
+
}
|
|
2370
|
+
return projectBoundedPage(page, toConfigSummary);
|
|
2371
|
+
}
|
|
2281
2372
|
async listConfigs(filter = {}) {
|
|
2282
|
-
const configs = await aggregateBoundedCollection("config list", (cursor) => this.
|
|
2373
|
+
const configs = await aggregateBoundedCollection("config list", (cursor) => this.listConfigsPage(filter, { limit: 100, cursor }), (config) => config.id, { requireAscendingIdentity: true });
|
|
2283
2374
|
let filtered = configs;
|
|
2284
2375
|
if (filter.tags && filter.tags.length > 0) {
|
|
2285
2376
|
filtered = filtered.filter((config) => filter.tags.every((tag) => config.tags.includes(tag)));
|
|
@@ -2345,7 +2436,7 @@ class CloudConfigStore {
|
|
|
2345
2436
|
return data?.pruned ?? 0;
|
|
2346
2437
|
}
|
|
2347
2438
|
async listProfiles() {
|
|
2348
|
-
return aggregateBoundedCollection("profile list", (cursor) => this.listProfilesPage({ limit: 100, cursor }), (profile) => profile.id
|
|
2439
|
+
return aggregateBoundedCollection("profile list", (cursor) => this.listProfilesPage({ limit: 100, cursor }), (profile) => profile.id);
|
|
2349
2440
|
}
|
|
2350
2441
|
async listProfilesPage(options = {}) {
|
|
2351
2442
|
const normalized = normalizeBoundedReadOptions(options);
|
|
@@ -7297,4 +7388,4 @@ function renderMachineAwareContentPreview(content, variables) {
|
|
|
7297
7388
|
return isTemplate(content) ? renderTemplatePreview(content, variables) : { content, unresolved: [] };
|
|
7298
7389
|
}
|
|
7299
7390
|
|
|
7300
|
-
export { pagedPayload,
|
|
7391
|
+
export { pagedPayload, summarizeProfile, summarizeApplyResult, normalizeBoundedReadOptions, boundedReadPage, SESSION_RENDER_SCHEMA, SESSION_RENDER_MANIFEST_RELATIVE_PATH, isRetiredOrUnsupportedConfigAgent, retiredOrUnsupportedAgentReason, applyTransform, normalizeProfileAssetBinding, isCursorGlobalAuthorityPath, stampCursorGlobalAuthorityMarker, getReportedDbPath, getRawStoreRoot, ANTIGRAVITY_RULE_FILE_CHAR_LIMIT, SESSION_RENDERER_OWNER_ID, SESSION_RENDER_OWNED_CONFIG_TARGETS, SESSION_RENDER_EXCLUSIVE_MANAGED_PATHS, legacyProfileConfigBinding, normalizeProfileConfigBinding, hasInstructionsEnvAuthorityIntent, normalizeOsFamily, detectMachineContext, machineContextToVariables, resolveProfileVariables, templateizeMachineContent, renderMachineAwareContentPreview, resolveConfigStore };
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
expandPath,
|
|
6
6
|
getConfigHome,
|
|
7
7
|
normalizeTargetPath
|
|
8
|
-
} from "./index-
|
|
8
|
+
} from "./index-ypcef3a2.js";
|
|
9
9
|
import {
|
|
10
10
|
applyTransform,
|
|
11
11
|
detectMachineContext,
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
resolveConfigStore,
|
|
14
14
|
retiredOrUnsupportedAgentReason,
|
|
15
15
|
templateizeMachineContent
|
|
16
|
-
} from "./index-
|
|
16
|
+
} from "./index-aj66f6xr.js";
|
|
17
17
|
import {
|
|
18
18
|
isSecretVarName,
|
|
19
19
|
redactContent,
|
|
@@ -73,18 +73,20 @@ function createInstructionsS3ObjectStore(config, createClient = (options) => new
|
|
|
73
73
|
return {
|
|
74
74
|
async putIfAbsent(key, bytes, options) {
|
|
75
75
|
assertSafeInstructionsObjectKey(key);
|
|
76
|
+
let credentials;
|
|
77
|
+
try {
|
|
78
|
+
credentials = resolveRequestCredentials(config);
|
|
79
|
+
} catch {
|
|
80
|
+
throw new Error("Instructions S3 conditional object creation failed");
|
|
81
|
+
}
|
|
76
82
|
for (let attempt = 1;attempt <= CONDITIONAL_CREATE_ATTEMPTS; attempt += 1) {
|
|
77
83
|
let response;
|
|
78
84
|
const controller = new AbortController;
|
|
79
85
|
try {
|
|
80
|
-
const
|
|
81
|
-
response = await runWithDeadline(() => requestFetch(url, {
|
|
86
|
+
const signed = signConditionalCreateRequest(config, key, bytes, options.contentType, credentials, new Date);
|
|
87
|
+
response = await runWithDeadline(() => requestFetch(signed.url, {
|
|
82
88
|
method: "PUT",
|
|
83
|
-
headers:
|
|
84
|
-
"content-type": options.contentType,
|
|
85
|
-
"content-md5": createHash("md5").update(bytes).digest("base64"),
|
|
86
|
-
"if-none-match": "*"
|
|
87
|
-
},
|
|
89
|
+
headers: signed.headers,
|
|
88
90
|
body: Uint8Array.from(bytes),
|
|
89
91
|
redirect: "error",
|
|
90
92
|
signal: controller.signal
|
|
@@ -220,7 +222,7 @@ function resolveRequestCredentials(config) {
|
|
|
220
222
|
const secretAccessKey = process.env.AWS_SECRET_ACCESS_KEY?.trim();
|
|
221
223
|
const sessionToken = process.env.AWS_SESSION_TOKEN?.trim();
|
|
222
224
|
if (!accessKeyId || !secretAccessKey) {
|
|
223
|
-
throw new Error("Instructions S3
|
|
225
|
+
throw new Error("Instructions S3 signed requests require explicit or AWS environment credentials");
|
|
224
226
|
}
|
|
225
227
|
return { accessKeyId, secretAccessKey, ...sessionToken ? { sessionToken } : {} };
|
|
226
228
|
}
|
|
@@ -235,25 +237,43 @@ function signVersionedRequest(config, key, versionId, method, credentials, now)
|
|
|
235
237
|
"x-amz-date": amzDate,
|
|
236
238
|
...credentials.sessionToken ? { "x-amz-security-token": credentials.sessionToken } : {}
|
|
237
239
|
});
|
|
238
|
-
const signedHeaderNames = [
|
|
239
|
-
"host",
|
|
240
|
-
"x-amz-content-sha256",
|
|
241
|
-
"x-amz-date",
|
|
242
|
-
...credentials.sessionToken ? ["x-amz-security-token"] : []
|
|
243
|
-
].sort();
|
|
244
|
-
const canonicalHeaders = signedHeaderNames.map((name) => `${name}:${headers.get(name).trim()}
|
|
245
|
-
`).join("");
|
|
246
240
|
const canonicalQuery = `versionId=${awsEncode(versionId)}`;
|
|
241
|
+
authorizeRequest(method, url, canonicalQuery, headers, EMPTY_SHA256, credentials, config.region, shortDate, amzDate);
|
|
242
|
+
return { url: url.toString(), headers };
|
|
243
|
+
}
|
|
244
|
+
function signConditionalCreateRequest(config, key, bytes, contentType, credentials, now) {
|
|
245
|
+
const url = buildObjectUrl(config, key);
|
|
246
|
+
const amzDate = now.toISOString().replace(/[:-]|\.\d{3}/g, "");
|
|
247
|
+
const shortDate = amzDate.slice(0, 8);
|
|
248
|
+
const payloadHash = createHash("sha256").update(bytes).digest("hex");
|
|
249
|
+
const headers = new Headers({
|
|
250
|
+
"content-md5": createHash("md5").update(bytes).digest("base64"),
|
|
251
|
+
"content-type": contentType,
|
|
252
|
+
host: url.host,
|
|
253
|
+
"if-none-match": "*",
|
|
254
|
+
"x-amz-content-sha256": payloadHash,
|
|
255
|
+
"x-amz-date": amzDate,
|
|
256
|
+
...credentials.sessionToken ? { "x-amz-security-token": credentials.sessionToken } : {}
|
|
257
|
+
});
|
|
258
|
+
authorizeRequest("PUT", url, "", headers, payloadHash, credentials, config.region, shortDate, amzDate);
|
|
259
|
+
return { url: url.toString(), headers };
|
|
260
|
+
}
|
|
261
|
+
function authorizeRequest(method, url, canonicalQuery, headers, payloadHash, credentials, region, shortDate, amzDate) {
|
|
262
|
+
const signedHeaderNames = [];
|
|
263
|
+
headers.forEach((_value, name) => signedHeaderNames.push(name));
|
|
264
|
+
signedHeaderNames.sort();
|
|
265
|
+
const canonicalHeaders = signedHeaderNames.map((name) => `${name}:${headers.get(name).trim().replace(/\s+/g, " ")}
|
|
266
|
+
`).join("");
|
|
247
267
|
const canonicalRequest = [
|
|
248
268
|
method,
|
|
249
269
|
url.pathname,
|
|
250
270
|
canonicalQuery,
|
|
251
271
|
canonicalHeaders,
|
|
252
272
|
signedHeaderNames.join(";"),
|
|
253
|
-
|
|
273
|
+
payloadHash
|
|
254
274
|
].join(`
|
|
255
275
|
`);
|
|
256
|
-
const scope = `${shortDate}/${
|
|
276
|
+
const scope = `${shortDate}/${region}/s3/aws4_request`;
|
|
257
277
|
const stringToSign = [
|
|
258
278
|
"AWS4-HMAC-SHA256",
|
|
259
279
|
amzDate,
|
|
@@ -262,12 +282,11 @@ function signVersionedRequest(config, key, versionId, method, credentials, now)
|
|
|
262
282
|
].join(`
|
|
263
283
|
`);
|
|
264
284
|
const dateKey = hmac(`AWS4${credentials.secretAccessKey}`, shortDate);
|
|
265
|
-
const regionKey = hmac(dateKey,
|
|
285
|
+
const regionKey = hmac(dateKey, region);
|
|
266
286
|
const serviceKey = hmac(regionKey, "s3");
|
|
267
287
|
const signingKey = hmac(serviceKey, "aws4_request");
|
|
268
288
|
const signature = createHmac("sha256", signingKey).update(stringToSign).digest("hex");
|
|
269
289
|
headers.set("authorization", `AWS4-HMAC-SHA256 Credential=${credentials.accessKeyId}/${scope}, SignedHeaders=${signedHeaderNames.join(";")}, Signature=${signature}`);
|
|
270
|
-
return { url: url.toString(), headers };
|
|
271
290
|
}
|
|
272
291
|
function buildObjectUrl(config, key) {
|
|
273
292
|
const encodedKey = key.split("/").map(awsEncode).join("/");
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
expandPath,
|
|
6
6
|
getConfigHome,
|
|
7
7
|
normalizeTargetPath
|
|
8
|
-
} from "./index-
|
|
8
|
+
} from "./index-r7nfef2g.js";
|
|
9
9
|
import {
|
|
10
10
|
applyTransform,
|
|
11
11
|
detectMachineContext,
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
resolveConfigStore,
|
|
17
17
|
retiredOrUnsupportedAgentReason,
|
|
18
18
|
templateizeMachineContent
|
|
19
|
-
} from "./index-
|
|
19
|
+
} from "./index-6jncnnw7.js";
|
|
20
20
|
|
|
21
21
|
// src/lib/sync.ts
|
|
22
22
|
import { existsSync as existsSync2, readdirSync as readdirSync2, readFileSync as readFileSync2 } from "fs";
|