datavessel-cli 0.1.1 → 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 +40 -4
- package/dist/api.js +31 -4
- package/dist/api.js.map +1 -1
- package/dist/cli.js +8 -11
- package/dist/cli.js.map +1 -1
- package/dist/commands/init.js +83 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/setup.js +212 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/config.js +6 -1
- package/dist/config.js.map +1 -1
- package/dist/context.js +10 -4
- package/dist/context.js.map +1 -1
- package/dist/lock.js +68 -0
- package/dist/lock.js.map +1 -0
- package/dist/session.js +21 -0
- package/dist/session.js.map +1 -1
- package/dist/setup-profile.js +108 -0
- package/dist/setup-profile.js.map +1 -0
- package/dist/version.js +15 -0
- package/dist/version.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -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
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
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
|
-
|
|
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":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,eAAe,EAAqB,MAAM,aAAa,CAAC;AAErF,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;
|
|
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
|
-
|
|
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(
|
|
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,
|
|
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
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACxF,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,oFAAoF;AACpF,MAAM,CAAC,MAAM,gBAAgB,GAAG,2BAA2B,CAAC;AAE5D,0FAA0F;AAC1F,MAAM,CAAC,MAAM,eAAe,GAAG,2BAA2B,CAAC;AAiD3D,MAAM,UAAU,SAAS;IACvB,IAAI,OAAO,CAAC,GAAG,CAAC,qBAAqB;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC;IAChF,MAAM,IAAI,GACR,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC;QACnE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe;QAC7B,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;IACjC,OAAO,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,aAAa,CAAC,CAAC;AAC1D,MAAM,eAAe,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,kBAAkB,CAAC,CAAC;AACpE,MAAM,WAAW,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,cAAc,CAAC,CAAC;
|
|
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
|
-
|
|
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
|
|
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
|
package/dist/context.js.map
CHANGED
|
@@ -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,
|
|
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
|
package/dist/lock.js.map
ADDED
|
@@ -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
|
package/dist/session.js.map
CHANGED
|
@@ -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;
|
|
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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"}
|
package/dist/version.js
ADDED
|
@@ -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,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "datavessel-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
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",
|