datavessel-cli 0.1.0 → 0.3.0

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # datavessel-cli
2
2
 
3
- Command-line interface for [datavessel](https://datavessel.io) — run 100+
3
+ Command-line interface for [datavessel](https://datavessel.io) — run 200+
4
4
  read/write analytics and commerce tools (GA4, Search Console, Google/Meta Ads,
5
5
  Shopify, WooCommerce, Shopware, …) from your terminal.
6
6
 
@@ -42,13 +42,21 @@ npm run dev -- tools list
42
42
  ## Quick start
43
43
 
44
44
  ```bash
45
+ datavessel setup # interactive wizard: sign in, connect, teach your agents
45
46
  datavessel login # sign in via your browser
47
+ datavessel init # verify, sync catalog, report what's ready
46
48
  datavessel tools list # browse the catalog
47
49
  datavessel tools show run_report # see a tool's parameters
48
50
  datavessel run run_report --property-id 123 --metrics sessions --metrics users
49
51
  datavessel --json run list_sites # machine-readable output
50
52
  ```
51
53
 
54
+ Headless (CI, agents): one command signs in and self-configures —
55
+
56
+ ```bash
57
+ datavessel init --api-key "$DATAVESSEL_API_KEY"
58
+ ```
59
+
52
60
  ## Authentication
53
61
 
54
62
  `datavessel login` opens your browser, signs you in with the normal datavessel
@@ -84,16 +92,44 @@ Credentials are stored per-profile under `~/.config/datavessel/credentials.json`
84
92
 
85
93
  ### Use with coding agents (Claude Code / Cursor)
86
94
 
87
- This repo ships [`SKILL.md`](./SKILL.md) a ready-made agent skill describing
88
- how to drive the CLI (discover tools, `--json` output, exit codes, auth). Drop
89
- it into `.claude/skills/datavessel/SKILL.md` for Claude Code, or reference it
90
- from a Cursor rule.
95
+ This repo is also an installable **Claude Code plugin**. It carries:
96
+
97
+ - [`skills/datavessel`](./skills/datavessel/SKILL.md) the shared base skill
98
+ describing how to drive the CLI (discover tools, `--json` output, exit
99
+ codes, auth);
100
+ - **team skills** — [`operator-team`](./skills/operator-team/SKILL.md),
101
+ [`marketing-team`](./skills/marketing-team/SKILL.md), and
102
+ [`builder-team`](./skills/builder-team/SKILL.md): each runs the matching
103
+ server-side team end to end (brief the lead, dispatch, wait, surface write
104
+ approvals, present the one report);
105
+ - an **agent hierarchy** in [`agents/`](./agents) — `dv-analytics` and
106
+ `dv-commerce-reader` run reads autonomously (and in parallel),
107
+ `dv-commerce-ops` executes store changes only with per-change human
108
+ approval, and `dv-verifier` independently confirms writes landed;
109
+ - [`/datavessel:setup`](./commands/setup.md) — one command that installs the
110
+ CLI, takes your key, runs `datavessel init`, and reports what's ready.
111
+
112
+ ```
113
+ /plugin marketplace add djr4/datavessel-cli
114
+ /plugin install datavessel@datavessel
115
+ /datavessel:setup
116
+ ```
117
+
118
+ Reads run free; writes ask first. The read agents are structurally limited to
119
+ `access: read` tools, so "autonomous" never means "can refund an order".
120
+
121
+ For Cursor (or manual setup), reference
122
+ [`skills/datavessel/SKILL.md`](./skills/datavessel/SKILL.md) from a rule or
123
+ copy it into `.claude/skills/datavessel/SKILL.md` (add the team skills the
124
+ same way if you use teams).
91
125
 
92
126
  ## Commands
93
127
 
94
128
  | Command | Description |
95
129
  | --- | --- |
96
130
  | `login` / `logout` / `whoami` | Manage and inspect authentication |
131
+ | `setup` | Interactive wizard: sign in, see exactly which sources to connect (with the URL), answer a few questions (GA4 property, Search Console site, store, Slack channel) — saved to team memory so agents and teams start with zero config |
132
+ | `init` | Sign in (optionally `--api-key`/`--token`), sync the catalog, and report providers, tier, and quota in one shot |
97
133
  | `tools list` | List tools (filter with `--provider`, `--access`, `--search`) |
98
134
  | `tools show <tool>` | Show a tool's description and parameters |
99
135
  | `run <tool> [--flags…]` | Execute a tool; flags come from its schema |
package/dist/api.js CHANGED
@@ -6,30 +6,55 @@
6
6
  * controllers (tools, providers/execute, auth, integrations, tiers).
7
7
  */
8
8
  import { CliError, ExitCode, mapBackendError } from './errors.js';
9
- import { needsRefresh, refreshOAuth } from './session.js';
9
+ import { needsRefresh, refreshOAuth, refreshOAuthLocked } from './session.js';
10
+ import { USER_AGENT } from './version.js';
10
11
  export class ApiClient {
11
12
  baseUrl;
12
13
  credential;
13
14
  timeoutMs;
14
15
  onRefresh;
16
+ refreshLock;
17
+ refreshing;
15
18
  constructor(opts) {
16
19
  this.baseUrl = opts.baseUrl.replace(/\/+$/, '');
17
20
  this.credential = opts.credential;
18
21
  this.timeoutMs = opts.timeoutMs ?? 60_000;
19
22
  this.onRefresh = opts.onRefresh;
23
+ this.refreshLock = opts.refreshLock;
24
+ }
25
+ /** Refresh once, persisting the rotation; serialized across processes. */
26
+ doRefresh(cred) {
27
+ if (this.refreshLock) {
28
+ const { lockDir, reload } = this.refreshLock;
29
+ return refreshOAuthLocked(cred, {
30
+ lockDir,
31
+ reload: () => {
32
+ const stored = reload();
33
+ return stored?.type === 'oauth' ? stored : undefined;
34
+ },
35
+ persist: (c) => this.onRefresh?.(c),
36
+ });
37
+ }
38
+ return refreshOAuth(cred).then((next) => {
39
+ this.onRefresh?.(next);
40
+ return next;
41
+ });
20
42
  }
21
43
  /**
22
44
  * Build auth headers, transparently refreshing an expired OAuth access token
23
- * first and persisting the rotated credential via `onRefresh`.
45
+ * first and persisting the rotated credential via `onRefresh`. Concurrent
46
+ * requests within this process share one in-flight refresh.
24
47
  */
25
48
  async authHeaders() {
26
49
  let cred = this.credential;
27
50
  if (!cred)
28
51
  return {};
29
52
  if (cred.type === 'oauth' && needsRefresh(cred)) {
30
- cred = await refreshOAuth(cred);
53
+ this.refreshing ??= this.doRefresh(cred).finally(() => {
54
+ this.refreshing = undefined;
55
+ });
56
+ cred = await this.refreshing;
31
57
  this.credential = cred;
32
- this.onRefresh?.(cred);
33
58
  }
34
59
  if (cred.type === 'api-key')
35
60
  return { 'X-API-Key': cred.token };
@@ -55,6 +80,8 @@ export class ApiClient {
55
80
  method,
56
81
  headers: {
57
82
  Accept: 'application/json',
83
+ // Identifies the CLI (vs MCP/web) in backend logs for channel attribution.
84
+ 'User-Agent': USER_AGENT,
58
85
  ...(opts.body !== undefined ? { 'Content-Type': 'application/json' } : {}),
59
86
  ...authHeaders,
60
87
  },
package/dist/api.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
package/dist/cli.js CHANGED
@@ -1,29 +1,22 @@
1
1
  /**
2
2
  * Assembles the commander program: global options + all subcommands.
3
3
  */
4
- import { readFileSync } from 'node:fs';
5
4
  import { Command } from 'commander';
6
5
  import { registerAuthCommands } from './commands/auth.js';
6
+ import { registerInitCommand } from './commands/init.js';
7
+ import { registerSetupCommand } from './commands/setup.js';
7
8
  import { registerToolsCommands } from './commands/tools.js';
8
9
  import { registerRunCommand } from './commands/run.js';
9
10
  import { registerAccountCommands } from './commands/account.js';
10
11
  import { registerConfigCommands } from './commands/config.js';
11
- function version() {
12
- try {
13
- const pkg = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
14
- return pkg.version ?? '0.0.0';
15
- }
16
- catch {
17
- return '0.0.0';
18
- }
19
- }
12
+ import { cliVersion } from './version.js';
20
13
  export function buildProgram() {
21
14
  const program = new Command();
22
15
  program
23
16
  .name('datavessel')
24
17
  .description('datavessel CLI — run 100+ analytics & commerce tools.\n' +
25
18
  'Commands and tool help are generated from the live backend catalog.')
26
- .version(version(), '-v, --version', 'Print the CLI version')
19
+ .version(cliVersion(), '-v, --version', 'Print the CLI version')
27
20
  .option('-p, --profile <name>', 'Configuration profile to use')
28
21
  .option('--base-url <url>', 'Override the backend API base URL')
29
22
  .option('--app-url <url>', 'Override the web app URL used for browser login')
@@ -35,11 +28,15 @@ export function buildProgram() {
35
28
  .enablePositionalOptions()
36
29
  .showHelpAfterError('(add --help for usage)');
37
30
  registerAuthCommands(program);
31
+ registerInitCommand(program);
32
+ registerSetupCommand(program);
38
33
  registerToolsCommands(program);
39
34
  registerRunCommand(program);
40
35
  registerAccountCommands(program);
41
36
  registerConfigCommands(program);
42
37
  program.addHelpText('after', '\nQuick start:\n' +
38
+ ' datavessel setup Interactive wizard: sign in, connect, teach your agents\n' +
39
+ ' datavessel init --api-key <key> Sign in headlessly and self-configure\n' +
43
40
  ' datavessel login Authenticate (paste a token)\n' +
44
41
  ' datavessel tools list Browse available tools\n' +
45
42
  ' datavessel tools show <tool> See a tool\'s parameters\n' +
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAE9D,SAAS,OAAO;IACd,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;QAC1F,OAAO,GAAG,CAAC,OAAO,IAAI,OAAO,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,CAAC;IACjB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAE9B,OAAO;SACJ,IAAI,CAAC,YAAY,CAAC;SAClB,WAAW,CACV,yDAAyD;QACvD,qEAAqE,CACxE;SACA,OAAO,CAAC,OAAO,EAAE,EAAE,eAAe,EAAE,uBAAuB,CAAC;SAC5D,MAAM,CAAC,sBAAsB,EAAE,8BAA8B,CAAC;SAC9D,MAAM,CAAC,kBAAkB,EAAE,mCAAmC,CAAC;SAC/D,MAAM,CAAC,iBAAiB,EAAE,iDAAiD,CAAC;SAC5E,MAAM,CAAC,eAAe,EAAE,+CAA+C,CAAC;SACxE,MAAM,CAAC,iBAAiB,EAAE,0CAA0C,CAAC;SACrE,MAAM,CAAC,QAAQ,EAAE,8BAA8B,EAAE,KAAK,CAAC;SACvD,MAAM,CAAC,WAAW,EAAE,6CAA6C,EAAE,KAAK,CAAC;QAC1E,+EAA+E;SAC9E,uBAAuB,EAAE;SACzB,kBAAkB,CAAC,wBAAwB,CAAC,CAAC;IAEhD,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC9B,qBAAqB,CAAC,OAAO,CAAC,CAAC;IAC/B,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC5B,uBAAuB,CAAC,OAAO,CAAC,CAAC;IACjC,sBAAsB,CAAC,OAAO,CAAC,CAAC;IAEhC,OAAO,CAAC,WAAW,CACjB,OAAO,EACP,kBAAkB;QAChB,mEAAmE;QACnE,6DAA6D;QAC7D,+DAA+D;QAC/D,qDAAqD;QACrD,8DAA8D;QAC9D,kBAAkB;QAClB,qEAAqE;QACrE,kCAAkC;QAClC,2CAA2C;QAC3C,yCAAyC,CAC5C,CAAC;IAEF,OAAO,OAAO,CAAC;AACjB,CAAC"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,MAAM,UAAU,YAAY;IAC1B,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAE9B,OAAO;SACJ,IAAI,CAAC,YAAY,CAAC;SAClB,WAAW,CACV,yDAAyD;QACvD,qEAAqE,CACxE;SACA,OAAO,CAAC,UAAU,EAAE,EAAE,eAAe,EAAE,uBAAuB,CAAC;SAC/D,MAAM,CAAC,sBAAsB,EAAE,8BAA8B,CAAC;SAC9D,MAAM,CAAC,kBAAkB,EAAE,mCAAmC,CAAC;SAC/D,MAAM,CAAC,iBAAiB,EAAE,iDAAiD,CAAC;SAC5E,MAAM,CAAC,eAAe,EAAE,+CAA+C,CAAC;SACxE,MAAM,CAAC,iBAAiB,EAAE,0CAA0C,CAAC;SACrE,MAAM,CAAC,QAAQ,EAAE,8BAA8B,EAAE,KAAK,CAAC;SACvD,MAAM,CAAC,WAAW,EAAE,6CAA6C,EAAE,KAAK,CAAC;QAC1E,+EAA+E;SAC9E,uBAAuB,EAAE;SACzB,kBAAkB,CAAC,wBAAwB,CAAC,CAAC;IAEhD,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC9B,mBAAmB,CAAC,OAAO,CAAC,CAAC;IAC7B,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC9B,qBAAqB,CAAC,OAAO,CAAC,CAAC;IAC/B,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC5B,uBAAuB,CAAC,OAAO,CAAC,CAAC;IACjC,sBAAsB,CAAC,OAAO,CAAC,CAAC;IAEhC,OAAO,CAAC,WAAW,CACjB,OAAO,EACP,kBAAkB;QAChB,8FAA8F;QAC9F,4EAA4E;QAC5E,mEAAmE;QACnE,6DAA6D;QAC7D,+DAA+D;QAC/D,qDAAqD;QACrD,8DAA8D;QAC9D,kBAAkB;QAClB,qEAAqE;QACrE,kCAAkC;QAClC,2CAA2C;QAC3C,yCAAyC,CAC5C,CAAC;IAEF,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * `datavessel init` — one-shot self-configuration.
3
+ *
4
+ * Point of the command: "add a key and it starts working". It optionally
5
+ * stores a supplied credential (so it doubles as a headless login), verifies
6
+ * it against the backend, force-syncs the tool catalog, and reports connected
7
+ * providers and quota — everything an agent or a human needs before the first
8
+ * real call, in one invocation with one machine-readable output.
9
+ */
10
+ import { buildContext, globalOpts } from '../context.js';
11
+ import { refreshCatalog } from '../catalog.js';
12
+ import { resolveProfileName, saveCredential } from '../config.js';
13
+ import { CliError, ExitCode } from '../errors.js';
14
+ import { printJson, success, info, warn, c } from '../output.js';
15
+ export function registerInitCommand(program) {
16
+ program
17
+ .command('init')
18
+ .description('Verify auth, sync the tool catalog, and report what is ready to use ' +
19
+ '(pass --api-key or --token to sign in first)')
20
+ .option('--api-key <key>', 'Store an API key for this profile, then configure')
21
+ .option('--token <jwt>', 'Store a Bearer token for this profile, then configure')
22
+ .action(async (opts, cmd) => {
23
+ const global = globalOpts(cmd);
24
+ const profile = resolveProfileName(global.profile);
25
+ // A supplied credential is stored up front so init works headlessly in
26
+ // CI and agent environments where the browser login flow is impossible.
27
+ if (opts.apiKey) {
28
+ saveCredential(profile, { type: 'api-key', token: String(opts.apiKey) });
29
+ }
30
+ else if (opts.token) {
31
+ saveCredential(profile, { type: 'bearer', token: String(opts.token) });
32
+ }
33
+ const ctx = buildContext(cmd);
34
+ if (!ctx.config.credential) {
35
+ throw new CliError('Not authenticated.', ExitCode.AUTH, 'Run `datavessel login` (browser), or `datavessel init --api-key <key>` for headless setup.');
36
+ }
37
+ const me = await ctx.client.me();
38
+ const tools = await refreshCatalog(ctx.client);
39
+ const { providers } = await ctx.client.connectedSources();
40
+ let usage;
41
+ try {
42
+ usage = await ctx.client.usage();
43
+ }
44
+ catch {
45
+ usage = undefined; // non-fatal: quota display is a nicety, not a gate
46
+ }
47
+ const readCount = tools.filter((t) => t.access === 'read').length;
48
+ const writeCount = tools.length - readCount;
49
+ if (ctx.global.json) {
50
+ printJson({
51
+ ok: true,
52
+ profile,
53
+ baseUrl: ctx.config.baseUrl,
54
+ user: { id: me.id, email: me.email, name: me.name },
55
+ catalog: { total: tools.length, read: readCount, write: writeCount },
56
+ providers,
57
+ usage: usage ?? null,
58
+ });
59
+ return;
60
+ }
61
+ success(`Signed in as ${c.bold(me.email)} (profile: ${profile})`);
62
+ success(`Catalog synced: ${tools.length} tools (${readCount} read / ${writeCount} write)`);
63
+ if (providers.length > 0) {
64
+ success(`Providers connected: ${providers.sort().join(', ')}`);
65
+ }
66
+ else {
67
+ warn('No providers connected yet.');
68
+ info(c.dim(' Connect GA4, Search Console, Shopify, … at https://app.datavessel.io/settings'));
69
+ }
70
+ if (usage) {
71
+ info(` Tier: ${usage.tier_name ?? usage.tier} — ${usage.remaining_tool_calls} tool calls remaining`);
72
+ }
73
+ info('');
74
+ info('Ready. Try:');
75
+ info(c.dim(' datavessel --json tools list --search "report"'));
76
+ info(c.dim(' datavessel --json run <tool> --help'));
77
+ info('');
78
+ info(`Using Claude Code? Install the plugin (skill + agent hierarchy):`);
79
+ info(c.dim(' /plugin marketplace add djr4/datavessel-cli'));
80
+ info(c.dim(' /plugin install datavessel@datavessel'));
81
+ });
82
+ }
83
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,212 @@
1
+ /**
2
+ * `datavessel setup` — interactive first-run wizard.
3
+ *
4
+ * The promise: run one command, answer a few questions, and every agent and
5
+ * team knows your stack. The wizard signs you in, tells you exactly which
6
+ * sources still need connecting (with the URL), discovers the rest by asking
7
+ * — which GA4 property, which Search Console site, which store — and persists
8
+ * the answers as a team-memory entry tagged for all three team leads, whose
9
+ * first phase is a recall of exactly those tags. After setup, a team run needs
10
+ * nothing but a goal.
11
+ *
12
+ * Headless environments should use `datavessel init` instead; this command
13
+ * requires a TTY and says so.
14
+ */
15
+ import { ApiClient } from '../api.js';
16
+ import { buildContext, globalOpts } from '../context.js';
17
+ import { refreshCatalog } from '../catalog.js';
18
+ import { resolveConfig, resolveProfileName, saveCredential } from '../config.js';
19
+ import { CliError, ExitCode } from '../errors.js';
20
+ import { loginViaBrowser } from '../oauth.js';
21
+ import { confirm, isInteractive, prompt, promptSecret } from '../prompt.js';
22
+ import { info, success, warn, c } from '../output.js';
23
+ import { parseChoice, parseGaProperties, parseGscSites, buildSetupMemoryContent, SETUP_MEMORY_TAGS, } from '../setup-profile.js';
24
+ /** Providers the wizard cares about, in the order we mention them. */
25
+ const CORE_PROVIDERS = [
26
+ 'google_analytics',
27
+ 'google_search_console',
28
+ 'shopify',
29
+ 'woocommerce',
30
+ 'shopware',
31
+ 'slack',
32
+ ];
33
+ const STORE_PROVIDERS = ['shopify', 'woocommerce', 'shopware'];
34
+ async function pickFromList(question, options) {
35
+ info('');
36
+ info(question);
37
+ options.forEach((opt, i) => info(` ${c.bold(String(i + 1))}. ${opt}`));
38
+ const answer = await prompt(c.dim(' Number (Enter to skip): '));
39
+ return parseChoice(answer, options.length);
40
+ }
41
+ export function registerSetupCommand(program) {
42
+ program
43
+ .command('setup')
44
+ .description('Interactive first-run wizard: sign in, connect sources, and teach your agents the stack by answering a few questions')
45
+ .action(async (_opts, cmd) => {
46
+ if (!isInteractive()) {
47
+ throw new CliError('`datavessel setup` is interactive and needs a terminal.', ExitCode.USAGE, 'For CI/headless environments use `datavessel init --api-key <key>`.');
48
+ }
49
+ const global = globalOpts(cmd);
50
+ const profile = resolveProfileName(global.profile);
51
+ const resolved = resolveConfig(global.profile);
52
+ const appUrl = global.appUrl || resolved.appUrl;
53
+ // ---- 1. Authenticate -------------------------------------------------
54
+ let ctx = buildContext(cmd);
55
+ let signedIn = false;
56
+ if (ctx.config.credential) {
57
+ try {
58
+ const me = await ctx.client.me();
59
+ success(`Signed in as ${c.bold(me.email)} (profile: ${profile})`);
60
+ signedIn = true;
61
+ }
62
+ catch {
63
+ warn('Stored credential no longer works — let’s sign in again.');
64
+ }
65
+ }
66
+ if (!signedIn) {
67
+ info('');
68
+ info('How would you like to sign in?');
69
+ info(` ${c.bold('1')}. Browser (recommended)`);
70
+ info(` ${c.bold('2')}. Paste an API key`);
71
+ const choice = parseChoice(await prompt(c.dim(' Number: ')), 2) ?? 0;
72
+ let credential;
73
+ if (choice === 1) {
74
+ const key = await promptSecret('API key: ');
75
+ if (!key)
76
+ throw new CliError('No API key entered.', ExitCode.AUTH);
77
+ credential = { type: 'api-key', token: key };
78
+ }
79
+ else {
80
+ credential = await loginViaBrowser({ appUrl, open: true });
81
+ }
82
+ const client = new ApiClient({ baseUrl: ctx.config.baseUrl, credential });
83
+ const me = await client.me();
84
+ saveCredential(profile, credential);
85
+ success(`Signed in as ${c.bold(me.email)} (profile: ${profile})`);
86
+ ctx = buildContext(cmd); // rebuild with the stored credential
87
+ }
88
+ // ---- 2. Sync the catalog --------------------------------------------
89
+ const tools = await refreshCatalog(ctx.client);
90
+ const toolNames = new Set(tools.map((t) => t.toolName));
91
+ success(`Catalog synced: ${tools.length} tools`);
92
+ // ---- 3. Connections: show what's live, link what's missing ----------
93
+ let providers = (await ctx.client.connectedSources()).providers;
94
+ const missing = () => CORE_PROVIDERS.filter((p) => !providers.includes(p));
95
+ if (providers.length > 0) {
96
+ success(`Connected: ${providers.slice().sort().join(', ')}`);
97
+ }
98
+ while (missing().length > 0) {
99
+ info('');
100
+ info(`Not connected yet: ${c.yellow(missing().join(', '))}`);
101
+ info(`Connect them here: ${c.cyan(`${appUrl}/settings`)}`);
102
+ info(c.dim('(Analytics + Search Console power reporting; your store platform powers operations; Slack receives team reports.)'));
103
+ const again = await confirm('Re-check connections now?', true);
104
+ if (!again)
105
+ break;
106
+ providers = (await ctx.client.connectedSources()).providers;
107
+ const stillMissing = missing();
108
+ if (stillMissing.length === 0)
109
+ success('All core sources connected.');
110
+ else
111
+ success(`Connected so far: ${providers.slice().sort().join(', ') || '(none)'}`);
112
+ }
113
+ // ---- 4. Discovery Q&A ------------------------------------------------
114
+ // Every step is optional and failure-tolerant: a discovery read that
115
+ // errors is skipped with a warning, never fatal.
116
+ const answers = {};
117
+ if (providers.includes('google_analytics') && toolNames.has('get_account_summaries')) {
118
+ try {
119
+ const data = await ctx.client.execute('get_account_summaries', {});
120
+ const props = parseGaProperties(data);
121
+ if (props.length === 1) {
122
+ answers.ga4PropertyId = props[0].id;
123
+ success(`GA4 property: ${props[0].label} (${props[0].id})`);
124
+ }
125
+ else if (props.length > 1) {
126
+ const idx = await pickFromList('Which GA4 property should agents report on by default?', props.map((p) => `${p.label} ${c.dim(`(${p.id})`)}`));
127
+ if (idx !== undefined)
128
+ answers.ga4PropertyId = props[idx - 1].id;
129
+ }
130
+ }
131
+ catch {
132
+ warn('Could not list GA4 properties — skipping (set it later by re-running setup).');
133
+ }
134
+ }
135
+ if (providers.includes('google_search_console') && toolNames.has('list_sites')) {
136
+ try {
137
+ const data = await ctx.client.execute('list_sites', {});
138
+ const sites = parseGscSites(data);
139
+ if (sites.length === 1) {
140
+ answers.gscSiteUrl = sites[0];
141
+ success(`Search Console site: ${sites[0]}`);
142
+ }
143
+ else if (sites.length > 1) {
144
+ const idx = await pickFromList('Which Search Console site should agents use by default?', sites);
145
+ if (idx !== undefined)
146
+ answers.gscSiteUrl = sites[idx - 1];
147
+ }
148
+ }
149
+ catch {
150
+ warn('Could not list Search Console sites — skipping.');
151
+ }
152
+ }
153
+ const connectedStores = STORE_PROVIDERS.filter((p) => providers.includes(p));
154
+ if (connectedStores.length === 1) {
155
+ answers.storePlatform = connectedStores[0];
156
+ }
157
+ else if (connectedStores.length > 1) {
158
+ const idx = await pickFromList('Multiple store platforms are connected. Which is the primary one?', connectedStores);
159
+ if (idx !== undefined)
160
+ answers.storePlatform = connectedStores[idx - 1];
161
+ }
162
+ if (answers.storePlatform) {
163
+ const url = (await prompt(`Store URL for ${answers.storePlatform} (Enter to skip): `)).trim();
164
+ if (url)
165
+ answers.storeUrl = url;
166
+ }
167
+ if (providers.includes('slack')) {
168
+ const channel = (await prompt('Slack channel for team reports [#ecommerce]: ')).trim();
169
+ answers.slackChannel = channel || '#ecommerce';
170
+ }
171
+ const notes = (await prompt('Anything agents should always know about your business? (Enter to skip): ')).trim();
172
+ if (notes)
173
+ answers.notes = notes;
174
+ // ---- 5. Persist as team memory --------------------------------------
175
+ // One entry carrying every team tag: leads recall `tags: ["team:<x>"]`
176
+ // and recall matches entries whose tags are a superset, so all three
177
+ // leads find this on their first PHASE 1 recall. Re-running setup
178
+ // updates the existing entry instead of stacking duplicates.
179
+ const content = buildSetupMemoryContent(answers);
180
+ try {
181
+ const existing = (await ctx.client.execute('datavessel_recall', {
182
+ tags: ['business-profile', 'setup'],
183
+ limit: 1,
184
+ }));
185
+ const entries = Array.isArray(existing) ? existing : (existing?.entries ?? []);
186
+ const existingId = entries[0]?.id;
187
+ if (existingId) {
188
+ await ctx.client.execute('datavessel_update_entry', { id: existingId, content });
189
+ success('Updated your saved setup profile (team memory).');
190
+ }
191
+ else {
192
+ await ctx.client.execute('datavessel_remember', {
193
+ content,
194
+ type: 'note',
195
+ tags: [...SETUP_MEMORY_TAGS],
196
+ });
197
+ success('Saved your setup profile to team memory.');
198
+ }
199
+ }
200
+ catch {
201
+ warn('Could not save the setup profile to team memory — agents will discover context themselves.');
202
+ }
203
+ // ---- 6. Done ---------------------------------------------------------
204
+ info('');
205
+ success(c.bold('Setup complete.'));
206
+ info('Your agent teams will recall this profile automatically. Try:');
207
+ info(c.dim(` • In the app: ${appUrl} → Agents → Teams → run the Operator with goal "auto"`));
208
+ info(c.dim(' • Here: datavessel --json tools list --search report'));
209
+ info(c.dim(' • Claude Code: /plugin install datavessel@datavessel → /datavessel:setup'));
210
+ });
211
+ }
212
+ //# sourceMappingURL=setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.js","sourceRoot":"","sources":["../../src/commands/setup.ts"],"names":[],"mappings":"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"}
package/dist/config.js CHANGED
@@ -30,6 +30,7 @@ export function configDir() {
30
30
  const configPath = () => join(configDir(), 'config.json');
31
31
  const credentialsPath = () => join(configDir(), 'credentials.json');
32
32
  const catalogPath = () => join(configDir(), 'catalog.json');
33
+ const refreshLockDir = () => join(configDir(), 'refresh.lock');
33
34
  export function ensureDir() {
34
35
  const dir = configDir();
35
36
  if (!existsSync(dir))
@@ -116,6 +117,10 @@ export function setDefaultProfile(profile) {
116
117
  cfg.defaultProfile = profile;
117
118
  writeConfig(cfg);
118
119
  }
120
+ /** Re-read a profile's credential from disk (fresh, not cached). */
121
+ export function getStoredCredential(profile) {
122
+ return readCredentials()[profile];
123
+ }
119
124
  export function saveCredential(profile, credential) {
120
125
  const creds = readCredentials();
121
126
  creds[profile] = credential;
@@ -134,5 +139,5 @@ export function listProfiles() {
134
139
  const fromCreds = Object.keys(readCredentials());
135
140
  return [...new Set(['default', ...fromConfig, ...fromCreds])].sort();
136
141
  }
137
- export const _paths = { configPath, credentialsPath, catalogPath };
142
+ export const _paths = { configPath, credentialsPath, catalogPath, refreshLockDir };
138
143
  //# sourceMappingURL=config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
package/dist/context.js CHANGED
@@ -3,7 +3,7 @@
3
3
  * program's global options, applying flag overrides on top of stored config.
4
4
  */
5
5
  import { ApiClient } from './api.js';
6
- import { resolveConfig, saveCredential } from './config.js';
6
+ import { _paths, getStoredCredential, resolveConfig, saveCredential, } from './config.js';
7
7
  /** Read the root program's global options regardless of nesting depth. */
8
8
  export function globalOpts(cmd) {
9
9
  let root = cmd;
@@ -29,11 +29,17 @@ export function buildContext(cmd) {
29
29
  }
30
30
  config.credential = credential;
31
31
  // Persist rotated OAuth tokens only when the credential came from disk (not
32
- // from an ephemeral --token / env override).
33
- const onRefresh = fromStore && credential?.type === 'oauth'
32
+ // from an ephemeral --token / env override). Disk-backed sessions also get
33
+ // the cross-process refresh lock so parallel dv invocations (agent fan-out)
34
+ // can't stampede the rotating refresh token.
35
+ const diskOAuth = fromStore && credential?.type === 'oauth';
36
+ const onRefresh = diskOAuth
34
37
  ? (c) => saveCredential(config.profile, c)
35
38
  : undefined;
36
- const client = new ApiClient({ baseUrl: config.baseUrl, credential, onRefresh });
39
+ const refreshLock = diskOAuth
40
+ ? { lockDir: _paths.refreshLockDir(), reload: () => getStoredCredential(config.profile) }
41
+ : undefined;
42
+ const client = new ApiClient({ baseUrl: config.baseUrl, credential, onRefresh, refreshLock });
37
43
  return { global, config, client };
38
44
  }
39
45
  //# sourceMappingURL=context.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,cAAc,EAAwC,MAAM,aAAa,CAAC;AAkBlG,0EAA0E;AAC1E,MAAM,UAAU,UAAU,CAAC,GAAY;IACrC,IAAI,IAAI,GAAY,GAAG,CAAC;IACxB,OAAO,IAAI,CAAC,MAAM;QAAE,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC;IACvC,OAAO,IAAI,CAAC,IAAI,EAAiB,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,GAAY;IACvC,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;IAC/B,MAAM,MAAM,GAAG,aAAa,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAE7C,yDAAyD;IACzD,IAAI,MAAM,CAAC,OAAO;QAAE,MAAM,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;IACpD,IAAI,UAAU,GAA2B,MAAM,CAAC,UAAU,CAAC;IAC3D,IAAI,SAAS,GAAG,IAAI,CAAC;IACrB,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,UAAU,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC;QACrD,SAAS,GAAG,KAAK,CAAC;IACpB,CAAC;SAAM,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QACzB,UAAU,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;QACvD,SAAS,GAAG,KAAK,CAAC;IACpB,CAAC;IACD,MAAM,CAAC,UAAU,GAAG,UAAU,CAAC;IAE/B,4EAA4E;IAC5E,6CAA6C;IAC7C,MAAM,SAAS,GACb,SAAS,IAAI,UAAU,EAAE,IAAI,KAAK,OAAO;QACvC,CAAC,CAAC,CAAC,CAAa,EAAE,EAAE,CAAC,cAAc,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;QACtD,CAAC,CAAC,SAAS,CAAC;IAEhB,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,CAAC;IACjF,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AACpC,CAAC"}
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EACL,MAAM,EACN,mBAAmB,EACnB,aAAa,EACb,cAAc,GAGf,MAAM,aAAa,CAAC;AAkBrB,0EAA0E;AAC1E,MAAM,UAAU,UAAU,CAAC,GAAY;IACrC,IAAI,IAAI,GAAY,GAAG,CAAC;IACxB,OAAO,IAAI,CAAC,MAAM;QAAE,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC;IACvC,OAAO,IAAI,CAAC,IAAI,EAAiB,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,GAAY;IACvC,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;IAC/B,MAAM,MAAM,GAAG,aAAa,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAE7C,yDAAyD;IACzD,IAAI,MAAM,CAAC,OAAO;QAAE,MAAM,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;IACpD,IAAI,UAAU,GAA2B,MAAM,CAAC,UAAU,CAAC;IAC3D,IAAI,SAAS,GAAG,IAAI,CAAC;IACrB,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,UAAU,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC;QACrD,SAAS,GAAG,KAAK,CAAC;IACpB,CAAC;SAAM,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QACzB,UAAU,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;QACvD,SAAS,GAAG,KAAK,CAAC;IACpB,CAAC;IACD,MAAM,CAAC,UAAU,GAAG,UAAU,CAAC;IAE/B,4EAA4E;IAC5E,2EAA2E;IAC3E,4EAA4E;IAC5E,6CAA6C;IAC7C,MAAM,SAAS,GAAG,SAAS,IAAI,UAAU,EAAE,IAAI,KAAK,OAAO,CAAC;IAC5D,MAAM,SAAS,GAAG,SAAS;QACzB,CAAC,CAAC,CAAC,CAAa,EAAE,EAAE,CAAC,cAAc,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;QACtD,CAAC,CAAC,SAAS,CAAC;IACd,MAAM,WAAW,GAAG,SAAS;QAC3B,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,cAAc,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,mBAAmB,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE;QACzF,CAAC,CAAC,SAAS,CAAC;IAEd,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,CAAC;IAC9F,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AACpC,CAAC"}
package/dist/lock.js ADDED
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Cross-process file lock for the credential store.
3
+ *
4
+ * Supabase rotates the refresh token on every refresh, so two `dv` processes
5
+ * refreshing concurrently race: the loser presents an already-consumed refresh
6
+ * token and the stored session is invalidated. Agent workflows fan `dv` calls
7
+ * out across parallel subagents, which makes that race likely — so refreshes
8
+ * are serialized through an exclusive on-disk lock. `mkdir` is atomic on every
9
+ * platform we support, which makes a directory the simplest portable lock.
10
+ * Locks abandoned by a crashed process are stolen once older than `staleMs`.
11
+ */
12
+ import { mkdirSync, rmdirSync, statSync } from 'node:fs';
13
+ import { setTimeout as sleep } from 'node:timers/promises';
14
+ function tryAcquire(lockDir) {
15
+ try {
16
+ mkdirSync(lockDir, { recursive: false });
17
+ return true;
18
+ }
19
+ catch {
20
+ return false;
21
+ }
22
+ }
23
+ function stealIfStale(lockDir, staleMs) {
24
+ try {
25
+ const age = Date.now() - statSync(lockDir).mtimeMs;
26
+ if (age > staleMs)
27
+ rmdirSync(lockDir);
28
+ }
29
+ catch {
30
+ // Raced with the holder releasing it — the next acquire attempt decides.
31
+ }
32
+ }
33
+ function release(lockDir) {
34
+ try {
35
+ rmdirSync(lockDir);
36
+ }
37
+ catch {
38
+ // Already gone (stolen as stale); nothing to release.
39
+ }
40
+ }
41
+ /**
42
+ * Run `fn` while holding an exclusive lock at `lockDir`.
43
+ *
44
+ * If the lock cannot be acquired within `timeoutMs`, `fn` runs anyway: a
45
+ * wedged lock must never brick the CLI, and the unlocked path merely degrades
46
+ * to the pre-lock behaviour.
47
+ */
48
+ export async function withFileLock(lockDir, fn, opts = {}) {
49
+ const staleMs = opts.staleMs ?? 30_000;
50
+ const timeoutMs = opts.timeoutMs ?? 20_000;
51
+ const pollMs = opts.pollMs ?? 100;
52
+ const deadline = Date.now() + timeoutMs;
53
+ let acquired = tryAcquire(lockDir);
54
+ while (!acquired && Date.now() < deadline) {
55
+ stealIfStale(lockDir, staleMs);
56
+ acquired = tryAcquire(lockDir);
57
+ if (!acquired)
58
+ await sleep(pollMs);
59
+ }
60
+ try {
61
+ return await fn();
62
+ }
63
+ finally {
64
+ if (acquired)
65
+ release(lockDir);
66
+ }
67
+ }
68
+ //# sourceMappingURL=lock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lock.js","sourceRoot":"","sources":["../src/lock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACzD,OAAO,EAAE,UAAU,IAAI,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAW3D,SAAS,UAAU,CAAC,OAAe;IACjC,IAAI,CAAC;QACH,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;QACzC,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,YAAY,CAAC,OAAe,EAAE,OAAe;IACpD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC;QACnD,IAAI,GAAG,GAAG,OAAO;YAAE,SAAS,CAAC,OAAO,CAAC,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,yEAAyE;IAC3E,CAAC;AACH,CAAC;AAED,SAAS,OAAO,CAAC,OAAe;IAC9B,IAAI,CAAC;QACH,SAAS,CAAC,OAAO,CAAC,CAAC;IACrB,CAAC;IAAC,MAAM,CAAC;QACP,sDAAsD;IACxD,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,OAAe,EACf,EAAoB,EACpB,OAAwB,EAAE;IAE1B,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,MAAM,CAAC;IACvC,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,MAAM,CAAC;IAC3C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,GAAG,CAAC;IAElC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;IACxC,IAAI,QAAQ,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;IACnC,OAAO,CAAC,QAAQ,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;QAC1C,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC/B,QAAQ,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;QAC/B,IAAI,CAAC,QAAQ;YAAE,MAAM,KAAK,CAAC,MAAM,CAAC,CAAC;IACrC,CAAC;IAED,IAAI,CAAC;QACH,OAAO,MAAM,EAAE,EAAE,CAAC;IACpB,CAAC;YAAS,CAAC;QACT,IAAI,QAAQ;YAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IACjC,CAAC;AACH,CAAC"}
package/dist/session.js CHANGED
@@ -7,6 +7,7 @@
7
7
  * during login (both are public values) so no secrets are baked into the CLI.
8
8
  */
9
9
  import { CliError, ExitCode } from './errors.js';
10
+ import { withFileLock } from './lock.js';
10
11
  /** True when the access token is expired or within `skewSec` of expiring. */
11
12
  export function needsRefresh(cred, skewSec = 60) {
12
13
  return Date.now() / 1000 >= cred.expiresAt - skewSec;
@@ -49,4 +50,24 @@ export async function refreshOAuth(cred) {
49
50
  expiresAt,
50
51
  };
51
52
  }
53
+ /**
54
+ * Refresh with cross-process single-flight semantics.
55
+ *
56
+ * Because Supabase rotates the refresh token, concurrent refreshes from
57
+ * parallel `dv` processes invalidate each other. Under the lock we re-read the
58
+ * stored credential first: if a sibling process already refreshed, its rotated
59
+ * session is simply adopted and no network call is made. Only the process that
60
+ * finds the stored token still stale actually refreshes, and it persists the
61
+ * rotation before releasing the lock so every waiter sees it.
62
+ */
63
+ export async function refreshOAuthLocked(cred, opts) {
64
+ return withFileLock(opts.lockDir, async () => {
65
+ const stored = opts.reload() ?? cred;
66
+ if (!needsRefresh(stored))
67
+ return stored;
68
+ const next = await refreshOAuth(stored);
69
+ opts.persist(next);
70
+ return next;
71
+ });
72
+ }
52
73
  //# sourceMappingURL=session.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAGjD,6EAA6E;AAC7E,MAAM,UAAU,YAAY,CAAC,IAAqB,EAAE,OAAO,GAAG,EAAE;IAC9D,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,IAAI,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC;AACvD,CAAC;AASD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAqB;IACtD,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,yCAAyC,CAAC;IAC7F,IAAI,GAAa,CAAC;IAClB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YACrB,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,MAAM,EAAE,IAAI,CAAC,OAAO;gBACpB,aAAa,EAAE,UAAU,IAAI,CAAC,OAAO,EAAE;gBACvC,cAAc,EAAE,kBAAkB;aACnC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,aAAa,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC;SAC3D,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,MAAM,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAChE,MAAM,IAAI,QAAQ,CAAC,2DAA2D,MAAM,EAAE,CAAC,CAAC;IAC1F,CAAC;IAED,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,QAAQ,CAChB,sDAAsD,EACtD,QAAQ,CAAC,IAAI,EACb,0CAA0C,CAC3C,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAwB,CAAC;IACvD,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;QACvB,MAAM,IAAI,QAAQ,CAAC,kDAAkD,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxF,CAAC;IACD,MAAM,SAAS,GACb,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,CAAC;IAC/E,OAAO;QACL,GAAG,IAAI;QACP,WAAW,EAAE,IAAI,CAAC,YAAY;QAC9B,YAAY,EAAE,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,YAAY;QACrD,SAAS;KACV,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEzC,6EAA6E;AAC7E,MAAM,UAAU,YAAY,CAAC,IAAqB,EAAE,OAAO,GAAG,EAAE;IAC9D,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,IAAI,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC;AACvD,CAAC;AASD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAqB;IACtD,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,yCAAyC,CAAC;IAC7F,IAAI,GAAa,CAAC;IAClB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YACrB,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,MAAM,EAAE,IAAI,CAAC,OAAO;gBACpB,aAAa,EAAE,UAAU,IAAI,CAAC,OAAO,EAAE;gBACvC,cAAc,EAAE,kBAAkB;aACnC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,aAAa,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC;SAC3D,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,MAAM,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAChE,MAAM,IAAI,QAAQ,CAAC,2DAA2D,MAAM,EAAE,CAAC,CAAC;IAC1F,CAAC;IAED,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,QAAQ,CAChB,sDAAsD,EACtD,QAAQ,CAAC,IAAI,EACb,0CAA0C,CAC3C,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAwB,CAAC;IACvD,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;QACvB,MAAM,IAAI,QAAQ,CAAC,kDAAkD,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxF,CAAC;IACD,MAAM,SAAS,GACb,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,CAAC;IAC/E,OAAO;QACL,GAAG,IAAI;QACP,WAAW,EAAE,IAAI,CAAC,YAAY;QAC9B,YAAY,EAAE,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,YAAY;QACrD,SAAS;KACV,CAAC;AACJ,CAAC;AAWD;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,IAAqB,EACrB,IAA0B;IAE1B,OAAO,YAAY,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,IAAI,EAAE;QAC3C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,IAAI,IAAI,CAAC;QACrC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC;YAAE,OAAO,MAAM,CAAC;QACzC,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,MAAM,CAAC,CAAC;QACxC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACnB,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Pure helpers for `datavessel setup`: response parsing and the memory entry
3
+ * the wizard persists. Kept free of I/O so they're unit-testable.
4
+ */
5
+ /**
6
+ * Tags on the saved setup profile. Team leads recall `tags: ["team:<x>"]`,
7
+ * and recall matches entries whose tag array CONTAINS the requested tags
8
+ * (`tags @> filter` server-side) — so one entry carrying every team tag is
9
+ * found by all three leads' first-phase recall.
10
+ */
11
+ export const SETUP_MEMORY_TAGS = [
12
+ 'business-profile',
13
+ 'setup',
14
+ 'team:operator',
15
+ 'team:marketing',
16
+ 'team:builder',
17
+ ];
18
+ /** "3" → 3 when within [1, count]; anything else (incl. empty) → undefined. */
19
+ export function parseChoice(answer, count) {
20
+ const n = Number.parseInt(answer.trim(), 10);
21
+ if (!Number.isInteger(n) || n < 1 || n > count)
22
+ return undefined;
23
+ return n;
24
+ }
25
+ /**
26
+ * Parse `get_account_summaries` output into pickable GA4 properties. The GA
27
+ * Admin API shape is accountSummaries[].propertySummaries[].property
28
+ * ("properties/123"); the backend may return it under `account_summaries` or
29
+ * as a bare array, so both are handled and anything unrecognized yields [].
30
+ */
31
+ export function parseGaProperties(data) {
32
+ const root = data;
33
+ const summaries = Array.isArray(root)
34
+ ? root
35
+ : (root?.account_summaries ?? root?.accountSummaries);
36
+ if (!Array.isArray(summaries))
37
+ return [];
38
+ const options = [];
39
+ for (const account of summaries) {
40
+ if (!account || typeof account !== 'object')
41
+ continue;
42
+ const acc = account;
43
+ const accountName = acc.displayName ?? acc.display_name ?? 'Unnamed account';
44
+ const props = acc.propertySummaries ?? acc.property_summaries;
45
+ if (!Array.isArray(props))
46
+ continue;
47
+ for (const p of props) {
48
+ if (!p?.property)
49
+ continue;
50
+ const id = p.property.replace(/^properties\//, '');
51
+ options.push({
52
+ id,
53
+ label: `${p.displayName ?? p.display_name ?? id} — ${accountName}`,
54
+ });
55
+ }
56
+ }
57
+ return options;
58
+ }
59
+ /**
60
+ * Parse `list_sites` output into site URLs. Search Console returns
61
+ * siteEntry[].siteUrl; tolerate bare arrays of strings/objects too.
62
+ */
63
+ export function parseGscSites(data) {
64
+ const root = data;
65
+ const entries = Array.isArray(root)
66
+ ? root
67
+ : (root?.siteEntry ?? root?.sites);
68
+ if (!Array.isArray(entries))
69
+ return [];
70
+ const sites = [];
71
+ for (const entry of entries) {
72
+ if (typeof entry === 'string')
73
+ sites.push(entry);
74
+ else if (entry && typeof entry === 'object') {
75
+ const e = entry;
76
+ const url = e.siteUrl ?? e.site_url ?? e.url;
77
+ if (url)
78
+ sites.push(url);
79
+ }
80
+ }
81
+ return sites;
82
+ }
83
+ /**
84
+ * The memory entry content. Team leads read this verbatim during recall, so
85
+ * it names each fact the way the lead templates and member input schemas do
86
+ * (property_id, site_url, shop URL, Slack channel).
87
+ */
88
+ export function buildSetupMemoryContent(answers) {
89
+ const parts = [
90
+ 'Business setup profile (saved by `datavessel setup`; use these as member inputs and defaults):',
91
+ ];
92
+ if (answers.storePlatform)
93
+ parts.push(`- Store platform: ${answers.storePlatform}`);
94
+ if (answers.storeUrl)
95
+ parts.push(`- Store URL (shop_url): ${answers.storeUrl}`);
96
+ if (answers.ga4PropertyId)
97
+ parts.push(`- GA4 property_id: ${answers.ga4PropertyId}`);
98
+ if (answers.gscSiteUrl)
99
+ parts.push(`- Search Console site_url: ${answers.gscSiteUrl}`);
100
+ if (answers.slackChannel)
101
+ parts.push(`- Slack report channel: ${answers.slackChannel}`);
102
+ if (answers.notes)
103
+ parts.push(`- Notes from the owner: ${answers.notes}`);
104
+ if (parts.length === 1)
105
+ parts.push('- (nothing configured yet — discover context at runtime)');
106
+ return parts.join('\n');
107
+ }
108
+ //# sourceMappingURL=setup-profile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup-profile.js","sourceRoot":"","sources":["../src/setup-profile.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * CLI version, read from package.json, and the User-Agent derived from it.
3
+ */
4
+ import { readFileSync } from 'node:fs';
5
+ export function cliVersion() {
6
+ try {
7
+ const pkg = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
8
+ return pkg.version ?? '0.0.0';
9
+ }
10
+ catch {
11
+ return '0.0.0';
12
+ }
13
+ }
14
+ export const USER_AGENT = `datavessel-cli/${cliVersion()}`;
15
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,MAAM,UAAU,UAAU;IACxB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;QAC1F,OAAO,GAAG,CAAC,OAAO,IAAI,OAAO,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,CAAC;IACjB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,kBAAkB,UAAU,EAAE,EAAE,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "datavessel-cli",
3
- "version": "0.1.0",
4
- "description": "Command-line interface for datavessel: 100+ read/write tools (GA4, Search Console, Google/Meta Ads, Shopify, WooCommerce, Shopware). Commands and help are generated dynamically from the backend tool catalog.",
3
+ "version": "0.3.0",
4
+ "description": "Command-line interface for datavessel: 200+ read/write tools (GA4, Search Console, Google/Meta Ads, Shopify, WooCommerce, Shopware). Commands and help are generated dynamically from the backend tool catalog.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
7
7
  "author": "datavessel",