@commercelayer/agent-cli 1.0.0-dev.2 → 1.0.0-dev.3
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 +1 -1
- package/dist/builtins/sandbox.js +3 -5
- package/dist/config.js +24 -7
- package/dist/engine.js +7 -6
- package/dist/secrets.js +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -50,7 +50,7 @@ Never from a flag or the environment. c11r exchanges the pair for a two hour tok
|
|
|
50
50
|
|
|
51
51
|
`organizations create` and `organizations connect <slug>` answer an organization token once: it is stored like a sandbox token. `connect --revoke-others` also ends every other token of that organization, and asks for confirmation. With a login and no organization token for the organization named, an organization noun stops with `no_credentials` and the next step `c11r organizations connect <slug>`. `members` and `roles` with an organization token and no login are sent with that token, and the API says what is needed: a claim for a sandbox, a login for a claimed organization. `organizations` with no login stops here with `login_required`.
|
|
52
52
|
|
|
53
|
-
`credentials create` and `credentials token` answer a secret once. c11r writes it to a file with mode 600 and prints the file, the format and a hint, never the value: by default `~/.config/c11r/secrets/<org>/<name>.env` (`<id>-token.env` for a token), or `--out <path>`, as `KEY=value` lines or with `--format json` one JSON object. The file is checked before the request is sent; one there already is replaced only with `--yes`. A file inside a git repository that git does not ignore gets the warning `secret_not_ignored`. With `--dry-run` nothing is written and `secret_file` says where it would go. Each file records the record it belongs to. A `delete` of a record whose noun answers secrets (`credentials`, `webhooks`) removes the files c11r wrote for it in `~/.config/c11r/secrets/<org>/` (a credential's secret and tokens, a webhook's shared secret), found by the id, name or code given, and lists them in `removed_files`; `sandbox destroy` removes the whole folder of that organization and names it in `forgotten.secrets`. A file written with `--out` is not tracked and stays: the warning `out_files_not_tracked` says so
|
|
53
|
+
`credentials create` and `credentials token` answer a secret once. c11r writes it to a file with mode 600 and prints the file, the format and a hint, never the value: by default `~/.config/c11r/secrets/<org>/<name>.env` (`<id>-token.env` for a token), or `--out <path>`, as `KEY=value` lines or with `--format json` one JSON object. The file is checked before the request is sent; one there already is replaced only with `--yes`. A file inside a git repository that git does not ignore gets the warning `secret_not_ignored`. With `--dry-run` nothing is written and `secret_file` says where it would go. Each file records the record it belongs to. A `delete` of a record whose noun answers secrets (`credentials`, `webhooks`) removes the files c11r wrote for it in `~/.config/c11r/secrets/<org>/` (a credential's secret and tokens, a webhook's shared secret), found by the id, name or code given, and lists them in `removed_files`; `sandbox destroy` removes the whole folder of that organization and names it in `forgotten.secrets`. A file written with `--out` is not tracked and stays: the warning `out_files_not_tracked` says so on the delete of the record whose secret went to `--out` on this machine, and on `sandbox destroy` of an organization that had one. Any other delete has no such warning. A token file carries `CL_BASE_ENDPOINT` beside the token. `sales-calls book` answers a cancel token once: it is kept in `credentials.json` and `sales-calls cancel <booking>` sends it.
|
|
54
54
|
|
|
55
55
|
## Global flags
|
|
56
56
|
|
package/dist/builtins/sandbox.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// reset moves both to the new organization; destroy forgets them. The token is printed never,
|
|
5
5
|
// not even by create: only its hint.
|
|
6
6
|
import crypto from 'node:crypto';
|
|
7
|
-
import { credentialsFile, defaultOrg,
|
|
7
|
+
import { credentialsFile, defaultOrg, forgetOutWritten, storedLogin, forgetOrg, LINK_FILE, readLink, removeLink, renameOrg, storedOrgs, storeOrg, writeLink, hintOf } from '../config.js';
|
|
8
8
|
import { CliError, fail } from '../errors.js';
|
|
9
9
|
import { apiUrl, envelope, request } from '../http.js';
|
|
10
10
|
import { parseSchema } from '../schema.js';
|
|
@@ -124,8 +124,7 @@ async function destroy(run) {
|
|
|
124
124
|
// here. The sandbox is gone either way, so this machine forgets it too.
|
|
125
125
|
if (!(e instanceof CliError && e.code === 'unauthorized') || run.globals.dryRun || !run.org.org)
|
|
126
126
|
throw e;
|
|
127
|
-
const out =
|
|
128
|
-
markOutWritten(run.org.org, false);
|
|
127
|
+
const out = forgetOutWritten(run.org.org);
|
|
129
128
|
forgetOrg(run.org.org);
|
|
130
129
|
const link = removeLink(run.org.org);
|
|
131
130
|
const secrets = removeOrgSecrets(run.org.org);
|
|
@@ -136,8 +135,7 @@ async function destroy(run) {
|
|
|
136
135
|
const org = r.data?.org ?? run.org.org;
|
|
137
136
|
if (!org)
|
|
138
137
|
return r;
|
|
139
|
-
const out =
|
|
140
|
-
markOutWritten(org, false);
|
|
138
|
+
const out = forgetOutWritten(org);
|
|
141
139
|
forgetOrg(org);
|
|
142
140
|
const link = removeLink(org);
|
|
143
141
|
const secrets = removeOrgSecrets(org);
|
package/dist/config.js
CHANGED
|
@@ -110,20 +110,37 @@ export function setDefaultOrg(org) {
|
|
|
110
110
|
delete c.default_org;
|
|
111
111
|
writeCredentials(c);
|
|
112
112
|
}
|
|
113
|
-
|
|
114
|
-
|
|
113
|
+
/** A record's secret went to an --out file: remembered so its delete can say that file stays. */
|
|
114
|
+
export function markOutWritten(org, record) {
|
|
115
|
+
const keys = record.keys.filter(Boolean);
|
|
116
|
+
if (!keys.length)
|
|
117
|
+
return;
|
|
118
|
+
const c = readCredentials();
|
|
119
|
+
const all = { ...(c.out_written ?? {}) };
|
|
120
|
+
const list = (all[org] ?? []).filter((r) => !(r.noun === record.noun && r.keys.some((k) => keys.includes(k))));
|
|
121
|
+
all[org] = [...list, { noun: record.noun, keys }];
|
|
122
|
+
c.out_written = all;
|
|
123
|
+
writeCredentials(c);
|
|
115
124
|
}
|
|
116
|
-
|
|
125
|
+
/**
|
|
126
|
+
* After a delete: whether that record had a secret written with --out, which is then forgotten.
|
|
127
|
+
* With no record named, the organization goes (sandbox destroy).
|
|
128
|
+
*/
|
|
129
|
+
export function forgetOutWritten(org, record) {
|
|
117
130
|
const c = readCredentials();
|
|
131
|
+
const list = c.out_written?.[org] ?? [];
|
|
132
|
+
const hit = (r) => !record || (r.noun === record.noun && r.keys.some((k) => record.keys.includes(k)));
|
|
133
|
+
if (!list.some(hit))
|
|
134
|
+
return false;
|
|
135
|
+
const rest = list.filter((r) => !hit(r));
|
|
118
136
|
const all = { ...(c.out_written ?? {}) };
|
|
119
|
-
if (
|
|
120
|
-
|
|
121
|
-
if (written)
|
|
122
|
-
all[org] = true;
|
|
137
|
+
if (rest.length)
|
|
138
|
+
all[org] = rest;
|
|
123
139
|
else
|
|
124
140
|
delete all[org];
|
|
125
141
|
c.out_written = all;
|
|
126
142
|
writeCredentials(c);
|
|
143
|
+
return true;
|
|
127
144
|
}
|
|
128
145
|
export function storedBooking(id) {
|
|
129
146
|
const b = readCredentials().bookings?.[id];
|
package/dist/engine.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// destructive verb, then the request. A plain noun needs no code here: its schema says
|
|
5
5
|
// everything. Every answer is the API's envelope, { data, state, warnings, next }.
|
|
6
6
|
import { parseCommand, parseFields, toFlag } from './argv.js';
|
|
7
|
-
import {
|
|
7
|
+
import { forgetOutWritten, raiseProblem, resolveOrg } from './config.js';
|
|
8
8
|
import { confirm, terminal } from './confirm.js';
|
|
9
9
|
import { CliError, closest, fail, fixWith } from './errors.js';
|
|
10
10
|
import { indexHelp, nounHelp, verbHelp } from './help.js';
|
|
@@ -118,9 +118,9 @@ export async function execute(argv, opts = {}) {
|
|
|
118
118
|
return filesGone(secretOf(r, run, secretPlan), run);
|
|
119
119
|
}
|
|
120
120
|
/**
|
|
121
|
-
* A delete
|
|
122
|
-
*
|
|
123
|
-
*
|
|
121
|
+
* A delete on a noun that answers secrets: the files c11r wrote for that record in the secrets
|
|
122
|
+
* folder go with it, listed in removed_files. out_files_not_tracked only when that record's secret
|
|
123
|
+
* was written with --out on this machine: that file stays where it was written.
|
|
124
124
|
*/
|
|
125
125
|
function filesGone(r, run) {
|
|
126
126
|
if (run.verb.name !== 'delete' || run.globals.dryRun || !run.org.org)
|
|
@@ -128,8 +128,9 @@ function filesGone(r, run) {
|
|
|
128
128
|
if (!Object.values(run.schema.verbs).some((v) => v.secret))
|
|
129
129
|
return r;
|
|
130
130
|
const data = (r.data && typeof r.data === 'object' ? r.data : {});
|
|
131
|
-
const
|
|
132
|
-
const
|
|
131
|
+
const keys = [run.parsed.id, data.id, data.name, data.code].filter((k) => typeof k === 'string' && k !== '');
|
|
132
|
+
const removed = removeRecordFiles(run.org.org, run.schema.noun, keys);
|
|
133
|
+
const warn = forgetOutWritten(run.org.org, { noun: run.schema.noun, keys });
|
|
133
134
|
return { ...r, data: { ...data, removed_files: removed }, warnings: [...r.warnings, ...(warn ? [OUT_NOT_TRACKED] : [])] };
|
|
134
135
|
}
|
|
135
136
|
/** A secret in the answer goes to its file; a dry run says where it would go. */
|
package/dist/secrets.js
CHANGED
|
@@ -97,9 +97,9 @@ export function writeSecret(r, plan, ctx) {
|
|
|
97
97
|
const created = ctx.verb === 'create';
|
|
98
98
|
fail('secret_not_written', `The API answered the ${secret.kind ?? 'secret'} of credential ${id} once, and c11r could not write it to ${file}: ${e.message}. It was not printed, and the API cannot show it again. ${created ? `c11r credentials token ${id} gives a working token now; for a new secret, create another credential and delete ${id}.` : `c11r credentials token ${id} gives another token.`}`, { path: 'out', next_step: { action: 'fix_request', command: `c11r credentials token ${id}` }, details: { credential_id: credentialId ?? null, file } });
|
|
99
99
|
}
|
|
100
|
-
// An --out file is not removed with its
|
|
100
|
+
// An --out file is not removed with its record: remember which record has one, for the warning.
|
|
101
101
|
if (plan.fixed && ctx.org)
|
|
102
|
-
markOutWritten(ctx.org,
|
|
102
|
+
markOutWritten(ctx.org, { noun: ctx.noun, keys: [record.id, record.name, record.code, ctx.id].filter((k) => typeof k === 'string' && k !== '') });
|
|
103
103
|
// The API says the secret is shown once: c11r kept it in the file, and printed none of it.
|
|
104
104
|
const warnings = r.warnings.filter((w) => w.code !== 'secret_shown_once' && w.code !== 'token_shown_once');
|
|
105
105
|
if (!ignoredByGit(file))
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@commercelayer/agent-cli",
|
|
3
|
-
"version": "1.0.0-dev.
|
|
3
|
+
"version": "1.0.0-dev.3",
|
|
4
4
|
"description": "c11r: the Commerce Layer CLI for coding agents. One grammar, c11r <noun> <verb>, from a sandbox to a running organization.",
|
|
5
5
|
"homepage": "https://commercelayer.ai",
|
|
6
6
|
"keywords": [
|