@w6w/cli 0.9.15 → 0.9.23

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.
Files changed (62) hide show
  1. package/README.md +29 -14
  2. package/dist/bin/w6w.js +4 -0
  3. package/dist/bin/w6w.js.map +1 -1
  4. package/dist/mod.d.ts +20 -2
  5. package/dist/mod.d.ts.map +1 -1
  6. package/dist/mod.js +25 -13
  7. package/dist/mod.js.map +1 -1
  8. package/dist/src/args.d.ts +8 -1
  9. package/dist/src/args.d.ts.map +1 -1
  10. package/dist/src/args.js +15 -3
  11. package/dist/src/args.js.map +1 -1
  12. package/dist/src/client.d.ts +51 -4
  13. package/dist/src/client.d.ts.map +1 -1
  14. package/dist/src/client.js +83 -30
  15. package/dist/src/client.js.map +1 -1
  16. package/dist/src/commands/agents-studio.d.ts +24 -0
  17. package/dist/src/commands/agents-studio.d.ts.map +1 -0
  18. package/dist/src/commands/agents-studio.js +431 -0
  19. package/dist/src/commands/agents-studio.js.map +1 -0
  20. package/dist/src/commands/assets.d.ts +47 -0
  21. package/dist/src/commands/assets.d.ts.map +1 -0
  22. package/dist/src/commands/assets.js +412 -0
  23. package/dist/src/commands/assets.js.map +1 -0
  24. package/dist/src/commands/auth.d.ts +24 -0
  25. package/dist/src/commands/auth.d.ts.map +1 -0
  26. package/dist/src/commands/auth.js +112 -0
  27. package/dist/src/commands/auth.js.map +1 -0
  28. package/dist/src/commands/config.d.ts +21 -0
  29. package/dist/src/commands/config.d.ts.map +1 -0
  30. package/dist/src/commands/config.js +73 -0
  31. package/dist/src/commands/config.js.map +1 -0
  32. package/dist/src/commands/connections.d.ts +1 -1
  33. package/dist/src/commands/connections.d.ts.map +1 -1
  34. package/dist/src/commands/connections.js +27 -2
  35. package/dist/src/commands/connections.js.map +1 -1
  36. package/dist/src/commands/index.d.ts +6 -0
  37. package/dist/src/commands/index.d.ts.map +1 -1
  38. package/dist/src/commands/index.js +18 -0
  39. package/dist/src/commands/index.js.map +1 -1
  40. package/dist/src/commands/ls.d.ts +21 -0
  41. package/dist/src/commands/ls.d.ts.map +1 -0
  42. package/dist/src/commands/ls.js +53 -0
  43. package/dist/src/commands/ls.js.map +1 -0
  44. package/dist/src/commands/models.d.ts +16 -0
  45. package/dist/src/commands/models.d.ts.map +1 -0
  46. package/dist/src/commands/models.js +126 -0
  47. package/dist/src/commands/models.js.map +1 -0
  48. package/dist/src/commands/vars.d.ts.map +1 -1
  49. package/dist/src/commands/vars.js +2 -2
  50. package/dist/src/commands/vars.js.map +1 -1
  51. package/dist/src/config-store.d.ts +86 -0
  52. package/dist/src/config-store.d.ts.map +1 -0
  53. package/dist/src/config-store.js +129 -0
  54. package/dist/src/config-store.js.map +1 -0
  55. package/dist/src/help.generated.d.ts.map +1 -1
  56. package/dist/src/help.generated.js +2723 -105
  57. package/dist/src/help.generated.js.map +1 -1
  58. package/dist/src/store-fs.d.ts +34 -0
  59. package/dist/src/store-fs.d.ts.map +1 -0
  60. package/dist/src/store-fs.js +151 -0
  61. package/dist/src/store-fs.js.map +1 -0
  62. package/package.json +2 -2
@@ -9,9 +9,16 @@
9
9
  * has a flag which outranks the environment variable.
10
10
  *
11
11
  * ```
12
- * CLI flag (--base-url / --token) > environment variable > nothing (an error)
12
+ * base URL CLI flag (--base-url) > W6W_BASE_URL > stored `baseUrl` > DEFAULT_BASE_URL
13
+ * token CLI flag (--token) > W6W_TOKEN > the stored token for the resolved base URL
13
14
  * ```
14
15
  *
16
+ * The stored tier is the per-user config `w6w auth login` writes (see
17
+ * `src/config-store.ts`). A stored token is **bound to the base URL it was saved
18
+ * for**: it is looked up by the canonical resolved base URL, exact match only, so
19
+ * pointing `--base-url` or `W6W_BASE_URL` at another host can never send it
20
+ * there. That is the trust boundary of this module.
21
+ *
15
22
  * The resolved values are passed to the SDK **explicitly**, and the SDK is never
16
23
  * left to read the environment on the CLI's behalf. That is a mechanism choice,
17
24
  * not a stylistic one: the CLI has to be able to say *which* source it was
@@ -23,7 +30,10 @@
23
30
  *
24
31
  * @module
25
32
  */
26
- import { ConfigError, W6WClient } from "@w6w/sdk";
33
+ import { ConfigError, joinBaseUrl, W6WClient } from "@w6w/sdk";
34
+ import { NO_CONFIG } from "./config-store.js";
35
+ /** The API every command targets unless told otherwise. Equals endpoints.json `defaultBaseUrl`. */
36
+ export const DEFAULT_BASE_URL = "https://api.w6w.io";
27
37
  /** Environment variable holding the server **origin**. Falls behind `--base-url`. */
28
38
  export const ENV_BASE_URL = "W6W_BASE_URL";
29
39
  /** Environment variable holding the bearer token. Falls behind `--token`. */
@@ -34,8 +44,8 @@ export const NO_ENV = () => undefined;
34
44
  * Read an environment variable, treating a blank value as **absent**.
35
45
  *
36
46
  * `W6W_BASE_URL=`, `W6W_BASE_URL=" "` and an unset `W6W_BASE_URL` are the same
37
- * thing: all three fall through the precedence chain to the next source, and
38
- * ultimately to a usage error naming both sources.
47
+ * thing: all three fall through the precedence chain to the next source (the
48
+ * stored base URL, then the default).
39
49
  *
40
50
  * The check is a trim-and-emptiness test and deliberately **not** a nullish
41
51
  * coalesce. `??` does not convert `""`, so a set-but-empty variable would
@@ -60,21 +70,6 @@ export function envValue(env, name) {
60
70
  return undefined;
61
71
  return value;
62
72
  }
63
- /**
64
- * Apply the precedence rule to one setting.
65
- *
66
- * A flag that was **given** wins outright, even when what it was given is empty:
67
- * that is a value the user typed, and quietly consulting the environment behind
68
- * an explicit `--token=` would be the CLI second-guessing them. (It still does
69
- * not produce a usable value — an empty flag reaches the same error — but it
70
- * gets there without a detour through the environment.) Only an **absent** flag
71
- * falls through.
72
- */
73
- function resolve(flag, env, name) {
74
- if (flag !== undefined)
75
- return flag;
76
- return envValue(env, name);
77
- }
78
73
  /**
79
74
  * A value the CLI cannot work with, phrased as a usage error.
80
75
  *
@@ -123,7 +118,7 @@ function requireAbsolute(baseUrl) {
123
118
  * the header builder and comes back as a bare `TypeError` from outside anyone's
124
119
  * error model: a stack trace, for a typo.
125
120
  */
126
- function isUnsendable(token) {
121
+ export function isUnsendable(token) {
127
122
  for (const character of token) {
128
123
  const code = character.codePointAt(0) ?? 0;
129
124
  if (code < 0x20 || code === 0x7f || code > 0xff)
@@ -138,6 +133,67 @@ function requireSendableToken(token) {
138
133
  throw configError("The w6w API token contains a character that cannot be sent in an HTTP header " +
139
134
  "(a control character, such as a newline).", "--token", ENV_TOKEN, "A token read out of a file usually carries a trailing newline — strip it.");
140
135
  }
136
+ /**
137
+ * The one resolver. `createClient` and every `auth` command use it, so what
138
+ * `auth status` reports is what a command will do.
139
+ *
140
+ * Base URL: flag (given, even empty) > env (blank = absent) > stored `baseUrl` >
141
+ * {@linkcode DEFAULT_BASE_URL}, validated, then canonicalised once. Token: flag >
142
+ * env > `stored.hosts[<canonical base URL>]` — exact key only.
143
+ *
144
+ * @throws {ConfigError} When the base URL is blank-by-flag, relative, or not http(s),
145
+ * or a resolved token cannot be sent in a header. A *missing* token is not an
146
+ * error here; `createClient` raises that.
147
+ */
148
+ export function resolveSettings(globals, env = NO_ENV, stored = NO_CONFIG) {
149
+ let raw;
150
+ let baseUrlSource;
151
+ if (globals.baseUrl !== undefined) {
152
+ raw = globals.baseUrl;
153
+ baseUrlSource = "flag";
154
+ }
155
+ else {
156
+ const fromEnv = envValue(env, ENV_BASE_URL);
157
+ if (fromEnv !== undefined) {
158
+ raw = fromEnv;
159
+ baseUrlSource = "env";
160
+ }
161
+ else if (stored.baseUrl.trim().length > 0) {
162
+ raw = stored.baseUrl;
163
+ baseUrlSource = "config";
164
+ }
165
+ else {
166
+ raw = DEFAULT_BASE_URL;
167
+ baseUrlSource = "default";
168
+ }
169
+ }
170
+ if (raw.trim().length === 0) {
171
+ throw configError("No w6w base URL is configured.", "--base-url", ENV_BASE_URL, "It holds the server's origin, like `https://api.example.com`; the API is served at its root, so no path is appended.");
172
+ }
173
+ // Validate for the CLI's own message, then canonicalise with the SDK's join —
174
+ // the single key used both to look a token up and to build the client.
175
+ const baseUrl = joinBaseUrl(requireAbsolute(raw.trim()));
176
+ let token;
177
+ let tokenSource;
178
+ if (globals.token !== undefined) {
179
+ token = globals.token;
180
+ tokenSource = "flag";
181
+ }
182
+ else {
183
+ const fromEnv = envValue(env, ENV_TOKEN);
184
+ if (fromEnv !== undefined) {
185
+ token = fromEnv;
186
+ tokenSource = "env";
187
+ }
188
+ else if (Object.hasOwn(stored.hosts, baseUrl)) {
189
+ token = stored.hosts[baseUrl].token;
190
+ tokenSource = "config";
191
+ }
192
+ }
193
+ if (token === undefined || token.trim().length === 0)
194
+ return { baseUrl, baseUrlSource };
195
+ return { baseUrl, baseUrlSource, token: requireSendableToken(token), tokenSource };
196
+ }
141
197
  /**
142
198
  * Build the API client for one invocation.
143
199
  *
@@ -147,25 +203,22 @@ function requireSendableToken(token) {
147
203
  *
148
204
  * @param globals - The parsed global flags.
149
205
  * @param env - The environment seam. Defaults to an empty environment.
150
- * @param options - Transport and default project.
206
+ * @param options - Transport, default project and the stored config.
151
207
  * @returns A configured client.
152
208
  * @throws {ConfigError} When the base URL or token is missing or unusable — a usage error.
153
209
  */
154
210
  export function createClient(globals, env = NO_ENV, options = {}) {
155
- const baseUrl = resolve(globals.baseUrl, env, ENV_BASE_URL);
156
- if (baseUrl === undefined || baseUrl.trim().length === 0) {
157
- throw configError("No w6w base URL is configured.", "--base-url", ENV_BASE_URL, "It holds the server's origin, like `https://api.example.com`; the API is served at its root, so no path is appended.");
158
- }
159
- const token = resolve(globals.token, env, ENV_TOKEN);
160
- if (token === undefined || token.trim().length === 0) {
161
- throw configError("No w6w API token is configured.", "--token", ENV_TOKEN, "Every w6w API command is authenticated.");
211
+ const settings = resolveSettings(globals, env, options.stored);
212
+ if (settings.token === undefined) {
213
+ throw configError(`No w6w API token is configured for ${settings.baseUrl}.`, "--token", ENV_TOKEN, "Or save one with `w6w auth login` (a saved token only applies to the base URL it was saved for). " +
214
+ "Every w6w API command is authenticated.");
162
215
  }
163
216
  // The join rule (origin in, base path appended, never doubled) belongs to the
164
217
  // SDK and is applied by the constructor. Nothing here re-derives it — read it
165
218
  // back off `client.config.baseUrl` if you need to know where a request went.
166
219
  return new W6WClient({
167
- baseUrl: requireAbsolute(baseUrl.trim()),
168
- token: requireSendableToken(token),
220
+ baseUrl: settings.baseUrl,
221
+ token: settings.token,
169
222
  project: options.project,
170
223
  fetch: options.fetch,
171
224
  });
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * `w6w skills|context|agents …` — the agent-authoring surface at the command line.
3
+ *
4
+ * Seventeen commands, **one SDK call each**. Skill upload is deliberately not
5
+ * here: it is `w6w assets upload --purpose skill`.
6
+ *
7
+ * Two write paths carry optimistic concurrency — `agents update` and
8
+ * `context entries-update`. Both send the body `revision` and, when given, the
9
+ * `--if-unmodified-since` precondition. A `409` is re-thrown as an `ApiError`
10
+ * with a message naming the **current revision** and what to do next; a `428`
11
+ * says the precondition is required. Both keep their status, so the exit code is
12
+ * the API-error code and a script can tell the write was refused. A uniform
13
+ * `404` needs no handling at all: `main()` prints the server's one-line message
14
+ * and exits, never a stack trace.
15
+ *
16
+ * Only flags the user typed reach the wire, so an omitted `--description` leaves
17
+ * the field alone and `--description ""` clears it.
18
+ *
19
+ * @module
20
+ */
21
+ import type { CommandRegistry } from "../../mod.ts";
22
+ /** Keys are the help tree's command paths (`naming.cli`). */
23
+ export declare const AGENT_STUDIO_COMMANDS: CommandRegistry;
24
+ //# sourceMappingURL=agents-studio.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agents-studio.d.ts","sourceRoot":"","sources":["../../../src/commands/agents-studio.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAkC,eAAe,EAAE,MAAM,cAAc,CAAC;AA+hBpF,6DAA6D;AAC7D,eAAO,MAAM,qBAAqB,EAAE,eAyBnC,CAAC"}
@@ -0,0 +1,431 @@
1
+ /**
2
+ * `w6w skills|context|agents …` — the agent-authoring surface at the command line.
3
+ *
4
+ * Seventeen commands, **one SDK call each**. Skill upload is deliberately not
5
+ * here: it is `w6w assets upload --purpose skill`.
6
+ *
7
+ * Two write paths carry optimistic concurrency — `agents update` and
8
+ * `context entries-update`. Both send the body `revision` and, when given, the
9
+ * `--if-unmodified-since` precondition. A `409` is re-thrown as an `ApiError`
10
+ * with a message naming the **current revision** and what to do next; a `428`
11
+ * says the precondition is required. Both keep their status, so the exit code is
12
+ * the API-error code and a script can tell the write was refused. A uniform
13
+ * `404` needs no handling at all: `main()` prints the server's one-line message
14
+ * and exits, never a stack trace.
15
+ *
16
+ * Only flags the user typed reach the wire, so an omitted `--description` leaves
17
+ * the field alone and `--description ""` clears it.
18
+ *
19
+ * @module
20
+ */
21
+ import { ApiError } from "@w6w/sdk";
22
+ import { argument, noExtraArguments, requiredFlag, table, textFlag, usageError } from "./shared.js";
23
+ /** A positive-integer flag, or `undefined` when absent. */
24
+ function count(context, name) {
25
+ const value = textFlag(context, name);
26
+ if (value === undefined)
27
+ return undefined;
28
+ if (!/^[0-9]+$/.test(value) || Number(value) < 1) {
29
+ throw usageError(context, `\`--${name}\` must be a positive integer.`);
30
+ }
31
+ return Number(value);
32
+ }
33
+ /** A non-negative integer flag that must be present (a revision may be `0`). */
34
+ function revision(context) {
35
+ const value = requiredFlag(context, "revision", "--revision <n>");
36
+ if (!/^[0-9]+$/.test(value)) {
37
+ throw usageError(context, "`--revision` must be a non-negative integer.");
38
+ }
39
+ return Number(value);
40
+ }
41
+ function includeArchived(context) {
42
+ return context.invocation.options.includeArchived === true ? { includeArchived: true } : {};
43
+ }
44
+ function tags(context) {
45
+ const value = textFlag(context, "tags");
46
+ if (value === undefined)
47
+ return undefined;
48
+ return value.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
49
+ }
50
+ /** A flag whose value is a JSON array of pins. */
51
+ function jsonList(context, name) {
52
+ const value = textFlag(context, name);
53
+ if (value === undefined)
54
+ return undefined;
55
+ let parsed;
56
+ try {
57
+ parsed = JSON.parse(value);
58
+ }
59
+ catch {
60
+ throw usageError(context, `\`--${name}\` must be valid JSON (an array).`);
61
+ }
62
+ if (!Array.isArray(parsed))
63
+ throw usageError(context, `\`--${name}\` must be a JSON array.`);
64
+ return parsed;
65
+ }
66
+ function visibility(context) {
67
+ const value = textFlag(context, "visibility");
68
+ if (value === undefined)
69
+ return undefined;
70
+ if (value !== "private" && value !== "project" && value !== "account") {
71
+ throw usageError(context, "`--visibility` must be private, project or account.");
72
+ }
73
+ return value;
74
+ }
75
+ const cell = (value) => value === null || value === undefined || value === "" ? "-" : String(value);
76
+ /**
77
+ * Run a precondition write, turning a 409 / 428 into an actionable message.
78
+ *
79
+ * The thrown error is still an `ApiError` with the original status, code and
80
+ * body, so the exit code and `--json` consumers are unchanged; only the sentence
81
+ * a human reads is replaced.
82
+ */
83
+ async function guarded(what, refetch, run) {
84
+ try {
85
+ return await run();
86
+ }
87
+ catch (err) {
88
+ if (err instanceof ApiError && err.status === 409) {
89
+ const current = err.raw?.error
90
+ ?.currentRevision;
91
+ const at = current === undefined ? "" : ` (current revision: ${current})`;
92
+ throw new ApiError(409, err.code, `Conflict: ${what} changed since you read it${at}. ` +
93
+ `Re-read it with \`${refetch}\` and retry with the new revision.`, err.raw);
94
+ }
95
+ if (err instanceof ApiError && err.status === 428) {
96
+ throw new ApiError(428, err.code, `Precondition required: ${what} can only be updated with a precondition. ` +
97
+ `Pass \`--if-unmodified-since <ts>\` (the updatedAt you read).`, err.raw);
98
+ }
99
+ throw err;
100
+ }
101
+ }
102
+ const precondition = (context) => ({
103
+ ifUnmodifiedSince: textFlag(context, "ifUnmodifiedSince"),
104
+ });
105
+ // ---------------------------------------------------------------- skills
106
+ const skillRow = (s) => [s.id, s.name, cell(s.activeVersionId), cell(s.archivedAt)];
107
+ const skillsList = async (context) => {
108
+ noExtraArguments(context, 0);
109
+ const rows = await context.client().skills.list({
110
+ ...includeArchived(context),
111
+ limit: count(context, "limit"),
112
+ });
113
+ context.out.emit(rows, (styles) => rows.length === 0
114
+ ? styles.dim("No skills.")
115
+ : table(["ID", "NAME", "ACTIVE VERSION", "ARCHIVED"], rows.map(skillRow), styles));
116
+ };
117
+ const skillsGet = async (context) => {
118
+ const id = argument(context, 0, "a skill id (see: `w6w skills list`)");
119
+ noExtraArguments(context, 1);
120
+ const skill = await context.client().skills.get(id);
121
+ context.out.emit(skill, (styles) => table(["ID", "NAME", "ACTIVE VERSION", "ARCHIVED"], [skillRow(skill)], styles));
122
+ };
123
+ const skillsVersions = async (context) => {
124
+ const id = argument(context, 0, "a skill id (see: `w6w skills list`)");
125
+ noExtraArguments(context, 1);
126
+ const rows = await context.client().skills.versions(id);
127
+ const row = (v) => {
128
+ const r = v;
129
+ return [cell(r.id), cell(r.version), cell(r.createdAt)];
130
+ };
131
+ context.out.emit(rows, (styles) => rows.length === 0
132
+ ? styles.dim("No versions.")
133
+ : table(["ID", "VERSION", "CREATED"], rows.map(row), styles));
134
+ };
135
+ const skillsArchive = async (context) => {
136
+ const id = argument(context, 0, "a skill id (see: `w6w skills list`)");
137
+ noExtraArguments(context, 1);
138
+ const skill = await context.client().skills.archive(id);
139
+ context.out.emit(skill, (styles) => `Archived ${styles.bold(skill.name)} ${styles.dim(`(${id})`)}`);
140
+ };
141
+ // --------------------------------------------------------------- context
142
+ const collectionRow = (c) => [
143
+ c.id,
144
+ c.name,
145
+ c.tags.join(",") || "-",
146
+ c.visibility,
147
+ cell(c.archivedAt),
148
+ ];
149
+ const COLLECTION_HEAD = ["ID", "NAME", "TAGS", "VISIBILITY", "ARCHIVED"];
150
+ const contextList = async (context) => {
151
+ noExtraArguments(context, 0);
152
+ const rows = await context.client().context.list({
153
+ ...includeArchived(context),
154
+ limit: count(context, "limit"),
155
+ });
156
+ context.out.emit(rows, (styles) => rows.length === 0
157
+ ? styles.dim("No context collections.")
158
+ : table(COLLECTION_HEAD, rows.map(collectionRow), styles));
159
+ };
160
+ const contextCreate = async (context) => {
161
+ const name = argument(context, 0, "a collection name");
162
+ noExtraArguments(context, 1);
163
+ const created = await context.client().context.create({
164
+ name,
165
+ description: textFlag(context, "description"),
166
+ tags: tags(context),
167
+ visibility: visibility(context),
168
+ });
169
+ context.out.emit(created, (styles) => `Created ${styles.bold(created.name)} ${styles.dim(`(${created.id})`)}`);
170
+ };
171
+ const contextGet = async (context) => {
172
+ const id = argument(context, 0, "a collection id (see: `w6w context list`)");
173
+ noExtraArguments(context, 1);
174
+ const found = await context.client().context.get(id);
175
+ context.out.emit(found, (styles) => table(COLLECTION_HEAD, [collectionRow(found)], styles));
176
+ };
177
+ /** A patch: only the typed flags are sent (collection edits are last-write-wins). */
178
+ const contextUpdate = async (context) => {
179
+ const id = argument(context, 0, "a collection id (see: `w6w context list`)");
180
+ noExtraArguments(context, 1);
181
+ const patch = {};
182
+ const name = textFlag(context, "name");
183
+ if (name !== undefined)
184
+ patch.name = name;
185
+ const description = textFlag(context, "description");
186
+ if (description !== undefined)
187
+ patch.description = description;
188
+ const tagList = tags(context);
189
+ if (tagList !== undefined)
190
+ patch.tags = tagList;
191
+ const updated = await context.client().context.update(id, patch);
192
+ context.out.emit(updated, (styles) => `Updated ${styles.bold(updated.name)} ${styles.dim(`(${id})`)}`);
193
+ };
194
+ const contextArchive = async (context) => {
195
+ const id = argument(context, 0, "a collection id (see: `w6w context list`)");
196
+ noExtraArguments(context, 1);
197
+ const archived = await context.client().context.archive(id);
198
+ context.out.emit(archived, (styles) => `Archived ${styles.bold(archived.name)} ${styles.dim(`(${id})`)}`);
199
+ };
200
+ const entryRow = (e) => [
201
+ e.id,
202
+ e.name,
203
+ e.mediaType,
204
+ cell(e.revision),
205
+ cell(e.archivedAt),
206
+ ];
207
+ const ENTRY_HEAD = ["ID", "NAME", "TYPE", "REVISION", "ARCHIVED"];
208
+ const entriesList = async (context) => {
209
+ const id = argument(context, 0, "a collection id (see: `w6w context list`)");
210
+ noExtraArguments(context, 1);
211
+ const rows = await context.client().context.entries.list(id, includeArchived(context));
212
+ context.out.emit(rows, (styles) => rows.length === 0 ? styles.dim("No entries.") : table(ENTRY_HEAD, rows.map(entryRow), styles));
213
+ };
214
+ const entriesCreate = async (context) => {
215
+ const id = argument(context, 0, "a collection id (see: `w6w context list`)");
216
+ const name = argument(context, 1, "an entry name");
217
+ noExtraArguments(context, 2);
218
+ const entry = await context.client().context.entries.create(id, {
219
+ name,
220
+ text: requiredFlag(context, "text", "--text <text>"),
221
+ });
222
+ context.out.emit(entry, (styles) => `Created ${styles.bold(entry.name)} ${styles.dim(`(${entry.id}, revision ${entry.revision})`)}`);
223
+ };
224
+ const entriesUpdate = async (context) => {
225
+ const id = argument(context, 0, "a collection id (see: `w6w context list`)");
226
+ const entryId = argument(context, 1, "an entry id (see: `w6w context entries-list`)");
227
+ noExtraArguments(context, 2);
228
+ const text = requiredFlag(context, "text", "--text <text>");
229
+ const rev = revision(context);
230
+ const entry = await guarded("the entry", `w6w context entries-list ${id}`, () => context.client().context.entries.update(id, entryId, { text, revision: rev }, precondition(context)));
231
+ context.out.emit(entry, (styles) => `Updated ${styles.bold(entry.name)} ${styles.dim(`(${entry.id}, revision ${entry.revision})`)}`);
232
+ };
233
+ // ------------------------------------------------------- context-entries
234
+ const topEntryRow = (e) => [
235
+ e.id,
236
+ e.name,
237
+ cell(e.mediaType),
238
+ cell(e.revision),
239
+ ];
240
+ const TOP_ENTRY_HEAD = ["ID", "NAME", "TYPE", "REVISION"];
241
+ const ceList = async (context) => {
242
+ noExtraArguments(context, 0);
243
+ const rows = await context.client().contextEntries.list({
244
+ ...includeArchived(context),
245
+ collectionId: textFlag(context, "collectionId"),
246
+ project: textFlag(context, "project"),
247
+ });
248
+ context.out.emit(rows, (styles) => rows.length === 0
249
+ ? styles.dim("No context entries.")
250
+ : table(TOP_ENTRY_HEAD, rows.map(topEntryRow), styles));
251
+ };
252
+ const ceCreate = async (context) => {
253
+ const name = argument(context, 0, "an entry name");
254
+ noExtraArguments(context, 1);
255
+ const ids = textFlag(context, "collectionId");
256
+ const collectionIds = ids === undefined
257
+ ? undefined
258
+ : ids.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
259
+ const entry = await context.client().contextEntries.create({
260
+ name,
261
+ text: requiredFlag(context, "text", "--text <text>"),
262
+ visibility: visibility(context),
263
+ ...(collectionIds ? { collectionIds } : {}),
264
+ });
265
+ context.out.emit(entry, (styles) => `Created ${styles.bold(entry.name)} ${styles.dim(`(${entry.id}, revision ${entry.revision})`)}`);
266
+ };
267
+ const ceGet = async (context) => {
268
+ const id = argument(context, 0, "an entry id (see: `w6w context-entries list`)");
269
+ noExtraArguments(context, 1);
270
+ const entry = await context.client().contextEntries.get(id);
271
+ context.out.emit(entry, (styles) => table(TOP_ENTRY_HEAD, [topEntryRow(entry)], styles));
272
+ };
273
+ const ceUpdate = async (context) => {
274
+ const id = argument(context, 0, "an entry id (see: `w6w context-entries list`)");
275
+ noExtraArguments(context, 1);
276
+ const text = requiredFlag(context, "text", "--text <text>");
277
+ const rev = revision(context);
278
+ const entry = await guarded("the entry", `w6w context-entries get ${id}`, () => context.client().contextEntries.update(id, { text, revision: rev }, precondition(context)));
279
+ context.out.emit(entry, (styles) => `Updated ${styles.bold(entry.name)} ${styles.dim(`(${entry.id}, revision ${entry.revision})`)}`);
280
+ };
281
+ const ceArchive = async (context) => {
282
+ const id = argument(context, 0, "an entry id (see: `w6w context-entries list`)");
283
+ noExtraArguments(context, 1);
284
+ const entry = await context.client().contextEntries.archive(id);
285
+ context.out.emit(entry, (styles) => `Archived ${styles.bold(entry.name)} ${styles.dim(`(${id})`)}`);
286
+ };
287
+ const ceAdd = async (context) => {
288
+ const id = argument(context, 0, "an entry id (see: `w6w context-entries list`)");
289
+ const collection = argument(context, 1, "a collection id (see: `w6w context list`)");
290
+ noExtraArguments(context, 2);
291
+ const entry = await context.client().contextEntries.addToCollection(id, collection);
292
+ context.out.emit(entry, (styles) => `Added ${styles.bold(entry.name)} to ${styles.dim(collection)}`);
293
+ };
294
+ const ceRemove = async (context) => {
295
+ const id = argument(context, 0, "an entry id (see: `w6w context-entries list`)");
296
+ const collection = argument(context, 1, "a collection id (see: `w6w context list`)");
297
+ noExtraArguments(context, 2);
298
+ const entry = await context.client().contextEntries.removeFromCollection(id, collection);
299
+ context.out.emit(entry, (styles) => `Removed ${styles.bold(entry.name)} from ${styles.dim(collection)}`);
300
+ };
301
+ // ---------------------------------------------------------------- agents
302
+ const agentRow = (a) => [
303
+ a.id,
304
+ cell(a.name),
305
+ cell(a.modelRouteId),
306
+ String(a.revision),
307
+ a.archived ? "yes" : "no",
308
+ "no",
309
+ ];
310
+ const AGENT_HEAD = ["ID", "NAME", "MODEL ROUTE", "REVISION", "ARCHIVED", "RUNNABLE"];
311
+ const agentsList = async (context) => {
312
+ noExtraArguments(context, 0);
313
+ const rows = await context.client().agents.list(includeArchived(context));
314
+ context.out.emit(rows, (styles) => rows.length === 0 ? styles.dim("No agents.") : table(AGENT_HEAD, rows.map(agentRow), styles));
315
+ };
316
+ /** The fields `agents create|update` share, only those typed. */
317
+ function agentFields(context) {
318
+ const fields = {};
319
+ const name = textFlag(context, "name");
320
+ if (name !== undefined)
321
+ fields.name = name;
322
+ const instructions = textFlag(context, "instructions");
323
+ if (instructions !== undefined)
324
+ fields.instructions = instructions;
325
+ const route = textFlag(context, "modelRouteId");
326
+ if (route !== undefined)
327
+ fields.modelRouteId = route;
328
+ const skills = jsonList(context, "skills");
329
+ if (skills !== undefined)
330
+ fields.skills = skills;
331
+ const pins = jsonList(context, "context");
332
+ if (pins !== undefined)
333
+ fields.context = pins;
334
+ const vis = visibility(context);
335
+ if (vis !== undefined)
336
+ fields.visibility = vis;
337
+ const project = textFlag(context, "project");
338
+ if (project !== undefined)
339
+ fields.project = project;
340
+ const modelOptions = modelOptionFlags(context);
341
+ if (modelOptions !== undefined)
342
+ fields.modelOptions = modelOptions;
343
+ return fields;
344
+ }
345
+ /** `--temperature`, `--top-p`, `--max-output-tokens` and the repeatable `--stop`. */
346
+ function modelOptionFlags(context) {
347
+ const options = {};
348
+ const number = (name, min, max, integer) => {
349
+ const raw = textFlag(context, name);
350
+ if (raw === undefined)
351
+ return undefined;
352
+ const value = Number(raw);
353
+ if (raw.trim() === "" || !Number.isFinite(value) || value < min || value > max ||
354
+ (integer && !Number.isInteger(value))) {
355
+ throw usageError(context, `\`--${name}\` must be ${integer ? "an integer" : "a number"} from ${min} to ${max}.`);
356
+ }
357
+ return value;
358
+ };
359
+ const temperature = number("temperature", 0, 2, false);
360
+ if (temperature !== undefined)
361
+ options.temperature = temperature;
362
+ const topP = number("topP", 0, 1, false);
363
+ if (topP !== undefined)
364
+ options.topP = topP;
365
+ const max = number("maxOutputTokens", 1, 1_000_000, true);
366
+ if (max !== undefined)
367
+ options.maxOutputTokens = max;
368
+ const stop = context.invocation.lists?.stop;
369
+ if (stop !== undefined)
370
+ options.stop = stop;
371
+ return Object.keys(options).length > 0 ? options : undefined;
372
+ }
373
+ const agentsCreate = async (context) => {
374
+ noExtraArguments(context, 0);
375
+ const agent = await context.client().agents.create(agentFields(context));
376
+ context.out.emit(agent, (styles) => `Created ${styles.bold(cell(agent.name))} ${styles.dim(`(${agent.id}, revision ${agent.revision})`)}`);
377
+ };
378
+ const agentsGet = async (context) => {
379
+ const id = argument(context, 0, "an agent id (see: `w6w agents list`)");
380
+ noExtraArguments(context, 1);
381
+ const agent = await context.client().agents.get(id);
382
+ context.out.emit(agent, (styles) => {
383
+ const issues = agent.validation.map((v) => ` ! ${JSON.stringify(v)}`);
384
+ return [
385
+ table(AGENT_HEAD, [agentRow(agent)], styles),
386
+ ...(agent.instructions.length > 0 ? ["", agent.instructions] : []),
387
+ ...(issues.length > 0 ? ["", "Validation:", ...issues] : []),
388
+ ].join("\n");
389
+ });
390
+ };
391
+ const agentsUpdate = async (context) => {
392
+ const id = argument(context, 0, "an agent id (see: `w6w agents list`)");
393
+ noExtraArguments(context, 1);
394
+ const patch = { ...agentFields(context), revision: revision(context) };
395
+ const agent = await guarded("the agent", `w6w agents get ${id}`, () => context.client().agents.update(id, patch, precondition(context)));
396
+ context.out.emit(agent, (styles) => `Updated ${styles.bold(cell(agent.name))} ${styles.dim(`(${id}, revision ${agent.revision})`)}`);
397
+ };
398
+ const agentsArchive = async (context) => {
399
+ const id = argument(context, 0, "an agent id (see: `w6w agents list`)");
400
+ noExtraArguments(context, 1);
401
+ const agent = await context.client().agents.archive(id);
402
+ context.out.emit(agent, (styles) => `Archived ${styles.bold(cell(agent.name))} ${styles.dim(`(${id})`)}`);
403
+ };
404
+ /** Keys are the help tree's command paths (`naming.cli`). */
405
+ export const AGENT_STUDIO_COMMANDS = {
406
+ "skills list": skillsList,
407
+ "skills get": skillsGet,
408
+ "skills versions": skillsVersions,
409
+ "skills archive": skillsArchive,
410
+ "context list": contextList,
411
+ "context create": contextCreate,
412
+ "context get": contextGet,
413
+ "context update": contextUpdate,
414
+ "context archive": contextArchive,
415
+ "context entries-list": entriesList,
416
+ "context entries-create": entriesCreate,
417
+ "context entries-update": entriesUpdate,
418
+ "context-entries list": ceList,
419
+ "context-entries create": ceCreate,
420
+ "context-entries get": ceGet,
421
+ "context-entries update": ceUpdate,
422
+ "context-entries archive": ceArchive,
423
+ "context-entries add-to-collection": ceAdd,
424
+ "context-entries remove-from-collection": ceRemove,
425
+ "agents list": agentsList,
426
+ "agents create": agentsCreate,
427
+ "agents get": agentsGet,
428
+ "agents update": agentsUpdate,
429
+ "agents archive": agentsArchive,
430
+ };
431
+ //# sourceMappingURL=agents-studio.js.map