@golden-frijoles/cli 0.3.0 → 0.4.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.
@@ -181,6 +181,7 @@ exports.whoamiCommand = {
181
181
  return (0, exit_codes_1.exitForServerCode)(result.code);
182
182
  }
183
183
  const { account, credential, projects } = result.body;
184
+ const workspaces = result.body.workspaces ?? [];
184
185
  context.emit.ok({
185
186
  account,
186
187
  // The credential's id and LABEL. Never the token — `gf doctor`'s rule applies here too, and
@@ -190,9 +191,12 @@ exports.whoamiCommand = {
190
191
  tokenSource: context.auth.source,
191
192
  activeProject: context.auth.activeProject,
192
193
  projects,
194
+ workspaces,
193
195
  }, [
194
196
  `${account.email ?? account.userId} on ${context.api.baseUrl}`,
195
197
  `credential: ${credential.label} (from ${describeSource(context.auth.source)})`,
198
+ // The tenant (workspaces S2.3): one line per workspace, so a person in two sees both.
199
+ ...workspaces.map((workspace) => `workspace: ${workspace.name}`),
196
200
  `active project: ${context.auth.activeProject ?? 'none — run `gf projects use <slug>`'}`,
197
201
  '',
198
202
  (0, output_1.table)(['PROJECT', 'ROLE'], projects.map((project) => [
@@ -42,5 +42,22 @@ export type SyncPlan = {
42
42
  * Presentation only: whether the payload is VALID is the server's question, answered on `--yes`.
43
43
  */
44
44
  export declare function planSync(current: CurrentMetric[], proposed: SyncPayload): SyncPlan;
45
+ /** One reason `--yes` would be refused, as data an agent can branch on instead of parsing the sentence below. */
46
+ export type Blocker = {
47
+ kind: 'placeholders';
48
+ paths: string[];
49
+ } | {
50
+ kind: 'value-source';
51
+ keys: string[];
52
+ };
53
+ export type DryRunVerdict = {
54
+ sendable: boolean;
55
+ blockers: Blocker[];
56
+ };
57
+ /**
58
+ * Would `--yes` be accepted? Every blocker the CLI knows of, in the order the dry run's sentence checks them.
59
+ * `sendable: true` means nothing HERE refuses it; whether the payload is valid is still the server's question.
60
+ */
61
+ export declare function dryRunVerdict(plan: SyncPlan, unfilled: string[]): DryRunVerdict;
45
62
  export declare const northStarSetCommand: Command;
46
63
  export {};
@@ -12,6 +12,8 @@
12
12
  // sends nothing. A sync never replaces or deletes (think-skills C2): a new metric key is ADDED beside any existing
13
13
  // metric, and an input key that already exists MOVES to this metric. Both effects are named before anything is sent,
14
14
  // because neither can be undone by syncing again.
15
+ // Under `--json` it also says, as data, whether `--yes` would be accepted: `sendable`, and `blockers` saying why not
16
+ // (`dryRunVerdict`). The human sentence is rendered from that same verdict, so the two can't disagree.
15
17
  //
16
18
  // ── An unfilled template is refused here ──────────────────────────────────────────────────────────────────────────
17
19
  // The template's `<metric_key>` placeholders satisfy the schema (any non-empty string does), so the server would store
@@ -22,6 +24,7 @@ exports.northStarSetCommand = void 0;
22
24
  exports.readSyncBlock = readSyncBlock;
23
25
  exports.unfilledPaths = unfilledPaths;
24
26
  exports.planSync = planSync;
27
+ exports.dryRunVerdict = dryRunVerdict;
25
28
  const node_fs_1 = require("node:fs");
26
29
  const node_path_1 = require("node:path");
27
30
  const args_1 = require("../args");
@@ -139,15 +142,27 @@ function issueLines(issues) {
139
142
  }
140
143
  return out;
141
144
  }
142
- /** The dry run's last sentence. It never invites a `--yes` that is certain to be refused. */
143
- function nextStep(plan, unfilled) {
145
+ /**
146
+ * Would `--yes` be accepted? Every blocker the CLI knows of, in the order the dry run's sentence checks them.
147
+ * `sendable: true` means nothing HERE refuses it; whether the payload is valid is still the server's question.
148
+ */
149
+ function dryRunVerdict(plan, unfilled) {
150
+ const blockers = [];
144
151
  if (unfilled.length > 0)
145
- return 'Fill in the placeholders first: --yes refuses a file that still has them.';
152
+ blockers.push({ kind: 'placeholders', paths: unfilled });
146
153
  const refused = plan.inputs.filter((input) => input.change.startsWith('refused'));
147
- if (refused.length > 0) {
148
- return `--yes would be refused: an existing input's value source never changes (${refused.map((i) => i.key).join(', ')}). Use a new key, or keep its value source.`;
149
- }
150
- return 'Run again with --yes to send it.';
154
+ if (refused.length > 0)
155
+ blockers.push({ kind: 'value-source', keys: refused.map((input) => input.key) });
156
+ return { sendable: blockers.length === 0, blockers };
157
+ }
158
+ /** The dry run's last sentence, rendered from the verdict's first blocker. It never invites a refused `--yes`. */
159
+ function nextStep(verdict) {
160
+ const [first] = verdict.blockers;
161
+ if (!first)
162
+ return 'Run again with --yes to send it.';
163
+ if (first.kind === 'placeholders')
164
+ return 'Fill in the placeholders first: --yes refuses a file that still has them.';
165
+ return `--yes would be refused: an existing input's value source never changes (${first.keys.join(', ')}). Use a new key, or keep its value source.`;
151
166
  }
152
167
  async function readCurrent(context, project) {
153
168
  const response = await context.api.get('/api/v1/cli/north-star', { project });
@@ -209,7 +224,8 @@ exports.northStarSetCommand = {
209
224
  return current;
210
225
  const plan = planSync(current, payload);
211
226
  if (!send) {
212
- context.emit.ok({ dryRun: true, project, ...plan, unfilled }, `${describePlan(project, plan, unfilled)}\n\nDry run: nothing was sent. ${nextStep(plan, unfilled)}`);
227
+ const verdict = dryRunVerdict(plan, unfilled);
228
+ context.emit.ok({ dryRun: true, project, ...plan, unfilled, ...verdict }, `${describePlan(project, plan, unfilled)}\n\nDry run: nothing was sent. ${nextStep(verdict)}`);
213
229
  return exit_codes_1.EXIT.OK;
214
230
  }
215
231
  const response = await context.api.post('/api/v1/cli/north-star', { project, sync: payload });
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const VERSION = "0.3.0";
1
+ export declare const VERSION = "0.4.1";
package/dist/version.js CHANGED
@@ -10,4 +10,4 @@ exports.VERSION = void 0;
10
10
  //
11
11
  // It is a literal, and `version.test.ts` asserts it equals `package.json`'s — so the two cannot
12
12
  // drift, and the drift is caught by the unit gate rather than by someone reading `gf --version`.
13
- exports.VERSION = '0.3.0';
13
+ exports.VERSION = '0.4.1';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@golden-frijoles/cli",
3
3
  "private": false,
4
- "version": "0.3.0",
4
+ "version": "0.4.1",
5
5
  "description": "The Golden Frijoles CLI — create, roll out and kill feature flags from a terminal, or from an agent.",
6
6
  "bin": {
7
7
  "gf": "./dist/bin.js"