Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions packages/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,27 @@ confidence quickstart # Launch the interactive setup wizard
| `confidence warehouse assignment-table create` | Create an assignment table for experiment analysis |
| `confidence warehouse crypto-key create` | Create a crypto key (Snowflake) |

### Data Entities

Read entities directly from the regional Metrics API using your current credentials or `--profile`.
These commands do not install MCP servers or launch onboarding.

```bash
confidence data entities list --page-size 100 --json
confidence data entities list --page-token '<nextPageToken>' --json
confidence data entities list --all --json
confidence data entities get --name entities/user_id --json
confidence data entities get --name entities/user_id --dry-run --json
```

- `list` fetches one page by default and returns `{ entities, nextPageToken, ... }` inside the JSON `data` envelope. Entity resources and unknown list-response fields retain all API fields. An empty or omitted server token becomes `""`.
- `--page-size` must be a positive integer no greater than 1000. `--page-token` is opaque and resumes a previous list response.
- `--all` collects all remaining pages, starting at `--page-token` if supplied. It returns an empty `nextPageToken` only when complete. Repeated cursors or more than 1000 pages fail without printing partial results. Unknown list-response fields are combined across pages; the latest value wins for repeated fields.
- `get` requires a qualified `--name entities/<id>` (not a bare ID or URL) and rejects responses naming a different entity.
- `--dry-run` validates inputs and previews the GET request without authentication or network requests. For `--all`, the preview describes the initial request; later cursors are only known during execution.

Only entity list/get are supported; these commands do not create, update, or delete entities.

### SDK

| Command | Description |
Expand Down
62 changes: 62 additions & 0 deletions packages/cli/__tests__/commands/data.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { execFileSync } from 'node:child_process';
import { fileURLToPath } from 'node:url';
import yargs from 'yargs';
import { prepareAuthTokens } from '@spotify-confidence/testing/auth';
import { dataCommand } from '@commands/index.js';

function run(args: string[]) {
let output = '';
const sut = yargs(args).scriptName('confidence').command(dataCommand).help().exitProcess(false);
return sut
.parseAsync(args, (_error: Error | undefined, _argv: unknown, text: string) => {
output = text;
})
.then(() => output);
}

describe('data command group', () => {
it('is registered in the real root help alongside existing commands', () => {
using _auth = prepareAuthTokens('none');
const sut = fileURLToPath(new URL('../../bin/cli.ts', import.meta.url));

const output = execFileSync(process.execPath, ['--import', 'tsx', sut, '--help'], {
encoding: 'utf8',
env: { ...process.env, CONFIDENCE_TELEMETRY: 'false' },
});

expect(output).toContain('confidence data');
expect(output).toContain('confidence warehouse');
expect(output).toContain('confidence flags');
});

it('shows help without authentication or placeholder API subcommands', async () => {
using _auth = prepareAuthTokens('none');
const sut = run;

const output = await sut(['data', '--help']);

expect(output).toContain('confidence data <command>');
expect(output).not.toMatch(/onboard|discover|proposal|workflow/iu);
});

it('advertises only list and get under entities without authentication', async () => {
using _auth = prepareAuthTokens('none');
const sut = run;

const output = await sut(['data', 'entities', '--help']);

expect(output).toContain('entities list');
expect(output).toContain('entities get');
expect(output).not.toMatch(/create|update|delete|onboard|workflow/iu);
});

it('shows guidance when invoked without a subcommand', async () => {
const sut = run;
expect(await sut(['data'])).toContain('confidence data --help');
});

it('rejects unimplemented subcommands', async () => {
const sut = run;
expect(await sut(['data', 'invented'])).toContain('Unknown argument: invented');
});
});
Loading
Loading