@aligndottech/cli 0.21.2 → 0.23.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 +72 -527
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +11 -7
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/telemetry.d.ts +8 -0
- package/dist/commands/telemetry.d.ts.map +1 -0
- package/dist/commands/telemetry.js +43 -0
- package/dist/commands/telemetry.js.map +1 -0
- package/dist/index.js +7 -3
- package/dist/index.js.map +1 -1
- package/dist/lib/config.d.ts +15 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +28 -0
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/distribution.d.ts +3 -0
- package/dist/lib/distribution.d.ts.map +1 -0
- package/dist/lib/distribution.js +4 -0
- package/dist/lib/distribution.js.map +1 -0
- package/dist/lib/local-db.d.ts.map +1 -1
- package/dist/lib/local-db.js +12 -10
- package/dist/lib/local-db.js.map +1 -1
- package/dist/lib/local-embeddings.d.ts +21 -0
- package/dist/lib/local-embeddings.d.ts.map +1 -1
- package/dist/lib/local-embeddings.js +34 -3
- package/dist/lib/local-embeddings.js.map +1 -1
- package/dist/lib/telemetry-consent.d.ts +23 -0
- package/dist/lib/telemetry-consent.d.ts.map +1 -0
- package/dist/lib/telemetry-consent.js +27 -0
- package/dist/lib/telemetry-consent.js.map +1 -0
- package/dist/lib/usage-telemetry.d.ts +32 -13
- package/dist/lib/usage-telemetry.d.ts.map +1 -1
- package/dist/lib/usage-telemetry.js +116 -51
- package/dist/lib/usage-telemetry.js.map +1 -1
- package/package.json +3 -10
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Narrow interface rather than the whole config store, so this module (and its tests) does not
|
|
3
|
+
* carry every unrelated accessor `createConfigStore()` exposes.
|
|
4
|
+
*/
|
|
5
|
+
export interface TelemetryConsentStore {
|
|
6
|
+
getTelemetryConsent(): 'granted' | 'declined' | undefined;
|
|
7
|
+
setTelemetryConsent(value: 'granted' | 'declined'): void;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* ALI-618 D3: the one-time local-mode consent prompt, shown from `runLocalSetup()`.
|
|
11
|
+
*
|
|
12
|
+
* Never asks twice - a decision already on disk (granted OR declined) is left alone. Never
|
|
13
|
+
* prompts without a TTY on both streams: a piped `setup --local` run hangs on a prompt it
|
|
14
|
+
* cannot answer, and a closed stdin crashes clack's raw-mode init AFTER the real setup work has
|
|
15
|
+
* already succeeded (the align-cli#118 lesson, `setup-local-non-tty.test.ts`). A non-interactive
|
|
16
|
+
* run leaves consent UNSET rather than implicitly declined - a scripted first run may be a CI
|
|
17
|
+
* smoke test, not a real user's choice, and it can still be asked on a later interactive run.
|
|
18
|
+
*
|
|
19
|
+
* Default is No: anything other than an explicit yes - the default answer, or Ctrl-C - leaves
|
|
20
|
+
* telemetry off (D3).
|
|
21
|
+
*/
|
|
22
|
+
export declare function maybeRequestTelemetryConsent(config: TelemetryConsentStore, interactive: boolean): Promise<void>;
|
|
23
|
+
//# sourceMappingURL=telemetry-consent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telemetry-consent.d.ts","sourceRoot":"","sources":["../../src/lib/telemetry-consent.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,mBAAmB,IAAI,SAAS,GAAG,UAAU,GAAG,SAAS,CAAC;IAC1D,mBAAmB,CAAC,KAAK,EAAE,SAAS,GAAG,UAAU,GAAG,IAAI,CAAC;CAC1D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,4BAA4B,CAChD,MAAM,EAAE,qBAAqB,EAC7B,WAAW,EAAE,OAAO,GACnB,OAAO,CAAC,IAAI,CAAC,CAYf"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import * as p from '@clack/prompts';
|
|
2
|
+
/**
|
|
3
|
+
* ALI-618 D3: the one-time local-mode consent prompt, shown from `runLocalSetup()`.
|
|
4
|
+
*
|
|
5
|
+
* Never asks twice - a decision already on disk (granted OR declined) is left alone. Never
|
|
6
|
+
* prompts without a TTY on both streams: a piped `setup --local` run hangs on a prompt it
|
|
7
|
+
* cannot answer, and a closed stdin crashes clack's raw-mode init AFTER the real setup work has
|
|
8
|
+
* already succeeded (the align-cli#118 lesson, `setup-local-non-tty.test.ts`). A non-interactive
|
|
9
|
+
* run leaves consent UNSET rather than implicitly declined - a scripted first run may be a CI
|
|
10
|
+
* smoke test, not a real user's choice, and it can still be asked on a later interactive run.
|
|
11
|
+
*
|
|
12
|
+
* Default is No: anything other than an explicit yes - the default answer, or Ctrl-C - leaves
|
|
13
|
+
* telemetry off (D3).
|
|
14
|
+
*/
|
|
15
|
+
export async function maybeRequestTelemetryConsent(config, interactive) {
|
|
16
|
+
if (config.getTelemetryConsent() !== undefined)
|
|
17
|
+
return;
|
|
18
|
+
if (!interactive)
|
|
19
|
+
return;
|
|
20
|
+
const answer = await p.confirm({
|
|
21
|
+
message: 'Help improve Align? Send an anonymous count of which commands you run - no code, no ' +
|
|
22
|
+
'decisions, no file names, ever. You can change this any time with `align telemetry off`.',
|
|
23
|
+
initialValue: false,
|
|
24
|
+
});
|
|
25
|
+
config.setTelemetryConsent(!p.isCancel(answer) && answer ? 'granted' : 'declined');
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=telemetry-consent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telemetry-consent.js","sourceRoot":"","sources":["../../src/lib/telemetry-consent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,gBAAgB,CAAC;AAWpC;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAChD,MAA6B,EAC7B,WAAoB;IAEpB,IAAI,MAAM,CAAC,mBAAmB,EAAE,KAAK,SAAS;QAAE,OAAO;IACvD,IAAI,CAAC,WAAW;QAAE,OAAO;IAEzB,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,OAAO,CAAC;QAC7B,OAAO,EACL,sFAAsF;YACtF,0FAA0F;QAC5F,YAAY,EAAE,KAAK;KACpB,CAAC,CAAC;IAEH,MAAM,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;AACrF,CAAC"}
|
|
@@ -1,16 +1,31 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type EnvironmentConfig, type TelemetryConsent } from './config.js';
|
|
2
2
|
/**
|
|
3
3
|
* ALI-403: emit one `cli.command` event per invocation so cloud CLI activation and weekly
|
|
4
4
|
* retention are countable.
|
|
5
5
|
*
|
|
6
|
-
* Cloud mode
|
|
7
|
-
* an event about a call already being made is not a new phone-home.
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
* Cloud mode is opt-out: a cloud user is already on an authenticated connection to our
|
|
7
|
+
* gateway, so an event about a call already being made is not a new phone-home. Local-embedded
|
|
8
|
+
* mode (ALI-618) is opt-in instead: `--local` users have no account and no tenant, so there is
|
|
9
|
+
* nothing to authenticate an event against, and nothing is sent until the user explicitly
|
|
10
|
+
* consents (see `config.ts`'s `getTelemetryConsent`, set by the one-time prompt in
|
|
11
|
+
* `commands/setup.ts`). Both modes send only a command name, never arguments or content.
|
|
10
12
|
*
|
|
11
|
-
*
|
|
13
|
+
* `ALIGN_TELEMETRY=0` (or `false` / `no` / `off`) is the single global off switch and wins in
|
|
14
|
+
* both modes, over a granted local consent included (ALI-618 D3b - one consent model, not two).
|
|
12
15
|
*/
|
|
13
16
|
export declare const TELEMETRY_TIMEOUT_MS = 2000;
|
|
17
|
+
export interface TelemetryStatus {
|
|
18
|
+
enabled: boolean;
|
|
19
|
+
reason: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* ALI-618 D3b: what `align telemetry status` prints. Takes the consent decision as a plain
|
|
23
|
+
* argument rather than reading `config.ts` itself, so the two consent MODELS stay visibly
|
|
24
|
+
* distinct in one function a reader can hold in their head - cloud's opt-out default and
|
|
25
|
+
* local's stored opt-in decision - with `ALIGN_TELEMETRY=0` as the one thing that overrides
|
|
26
|
+
* both, checked first.
|
|
27
|
+
*/
|
|
28
|
+
export declare function getTelemetryStatus(env: EnvironmentConfig, localConsent: TelemetryConsent | undefined): TelemetryStatus;
|
|
14
29
|
export declare function recordCommandUsage(env: EnvironmentConfig, command: string): Promise<void>;
|
|
15
30
|
/**
|
|
16
31
|
* The `--env` the user actually typed, including one Commander handed to a parent.
|
|
@@ -32,13 +47,17 @@ export declare function envFlagOf(cmd: {
|
|
|
32
47
|
* the one thing PR #77 said local mode does not do. Only the three-member `local` command
|
|
33
48
|
* group was excluded, and no local user types `align local ask`.
|
|
34
49
|
*
|
|
35
|
-
* `preferLocalEmbedded`
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
50
|
+
* `preferLocalEmbedded` IS now passed (ALI-618) - this paragraph used to say it was
|
|
51
|
+
* deliberately withheld, on the reasoning that the flag/ALIGN_ENV the user explicitly chose is
|
|
52
|
+
* what a CLOUD consent decision may rest on. That reasoning never covered local telemetry: the
|
|
53
|
+
* redirect only ever fires when the cloud env has no token, which is exactly the case
|
|
54
|
+
* recordCommandUsage's cloud branch already drops on its own (`if (!env.authToken || ...)
|
|
55
|
+
* return`) - so passing it here cannot cause an extra cloud send, only let a genuinely
|
|
56
|
+
* never-logged-in user's BARE command reach the local-embedded branch at all. Without it, that
|
|
57
|
+
* exact audience - "never met Tom" - resolved to the tokenless cloud default on every bare
|
|
58
|
+
* command and recordCommandUsage silently dropped it: neither cloud nor local ever counted
|
|
59
|
+
* them, which defeated the whole point of adding local telemetry. A fresh-context review
|
|
60
|
+
* caught this too. Fixed in `usage-telemetry-invocation-local-only.test.ts`.
|
|
42
61
|
*
|
|
43
62
|
* `setup` is suppressed once local-embedded is configured. The interactive "Local only" choice
|
|
44
63
|
* sets no flag, and the default env stays cloud on purpose, so the only evidence the session was
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usage-telemetry.d.ts","sourceRoot":"","sources":["../../src/lib/usage-telemetry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"usage-telemetry.d.ts","sourceRoot":"","sources":["../../src/lib/usage-telemetry.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,KAAK,iBAAiB,EAAE,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAGtG;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,oBAAoB,OAAQ,CAAC;AA6C1C,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,iBAAiB,EACtB,YAAY,EAAE,gBAAgB,GAAG,SAAS,GACzC,eAAe,CAcjB;AAED,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA8B/F;AAgCD;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE;IAAE,eAAe,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAAG,MAAM,GAAG,SAAS,CASjG;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC,CAMf"}
|
|
@@ -1,13 +1,18 @@
|
|
|
1
|
+
import { ALIGN_HOSTED_GATEWAY_URL } from './config.js';
|
|
2
|
+
import pkg from '../../package.json' with { type: 'json' };
|
|
1
3
|
/**
|
|
2
4
|
* ALI-403: emit one `cli.command` event per invocation so cloud CLI activation and weekly
|
|
3
5
|
* retention are countable.
|
|
4
6
|
*
|
|
5
|
-
* Cloud mode
|
|
6
|
-
* an event about a call already being made is not a new phone-home.
|
|
7
|
-
*
|
|
8
|
-
*
|
|
7
|
+
* Cloud mode is opt-out: a cloud user is already on an authenticated connection to our
|
|
8
|
+
* gateway, so an event about a call already being made is not a new phone-home. Local-embedded
|
|
9
|
+
* mode (ALI-618) is opt-in instead: `--local` users have no account and no tenant, so there is
|
|
10
|
+
* nothing to authenticate an event against, and nothing is sent until the user explicitly
|
|
11
|
+
* consents (see `config.ts`'s `getTelemetryConsent`, set by the one-time prompt in
|
|
12
|
+
* `commands/setup.ts`). Both modes send only a command name, never arguments or content.
|
|
9
13
|
*
|
|
10
|
-
*
|
|
14
|
+
* `ALIGN_TELEMETRY=0` (or `false` / `no` / `off`) is the single global off switch and wins in
|
|
15
|
+
* both modes, over a granted local consent included (ALI-618 D3b - one consent model, not two).
|
|
11
16
|
*/
|
|
12
17
|
export const TELEMETRY_TIMEOUT_MS = 2_000;
|
|
13
18
|
/**
|
|
@@ -24,24 +29,14 @@ function telemetryOptedOut() {
|
|
|
24
29
|
return false;
|
|
25
30
|
return !OPT_IN_VALUES.has(raw.trim().toLowerCase());
|
|
26
31
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
// The mode is the consent boundary (PR #77: cloud is opt-out, local is no-phone-home). It has
|
|
36
|
-
// to gate on its own because a token can be in scope without cloud consent: ALIGN_TOKEN
|
|
37
|
-
// exported into the shell, or a logged-in default env resolved by the caller.
|
|
38
|
-
if (env.mode === 'local-embedded')
|
|
39
|
-
return;
|
|
40
|
-
if (!env.authToken || !env.tenantId)
|
|
41
|
-
return;
|
|
42
|
-
// A blackholing proxy hangs rather than rejecting, so a bare await would freeze the CLI after
|
|
43
|
-
// its real work is done. The timer both aborts the request and wins the race, so we stop
|
|
44
|
-
// waiting even if the transport ignores the signal.
|
|
32
|
+
/**
|
|
33
|
+
* POST with a hard timeout, and never throw - telemetry must never fail or delay a command. A
|
|
34
|
+
* blackholing proxy hangs rather than rejecting, so a bare `fetch` would freeze the CLI after
|
|
35
|
+
* its real work is done. The timer both aborts the request and wins the race, so we stop
|
|
36
|
+
* waiting even if the transport ignores the signal. Shared by the cloud and local-embedded send
|
|
37
|
+
* paths below, which were two copies of this exact race before extraction (fresh-context review).
|
|
38
|
+
*/
|
|
39
|
+
async function postWithTimeout(url, init) {
|
|
45
40
|
const controller = new AbortController();
|
|
46
41
|
let giveUp = () => { };
|
|
47
42
|
const abandoned = new Promise((resolve) => {
|
|
@@ -52,33 +47,99 @@ export async function recordCommandUsage(env, command) {
|
|
|
52
47
|
giveUp();
|
|
53
48
|
}, TELEMETRY_TIMEOUT_MS);
|
|
54
49
|
try {
|
|
55
|
-
await Promise.race([
|
|
56
|
-
fetch(`${env.gatewayUrl}/telemetry/ingest`, {
|
|
57
|
-
method: 'POST',
|
|
58
|
-
signal: controller.signal,
|
|
59
|
-
headers: {
|
|
60
|
-
'Content-Type': 'application/json',
|
|
61
|
-
Authorization: `Bearer ${env.authToken}`,
|
|
62
|
-
'x-tenant-id': env.tenantId,
|
|
63
|
-
},
|
|
64
|
-
body: JSON.stringify({
|
|
65
|
-
eventName: 'cli.command',
|
|
66
|
-
category: 'engagement',
|
|
67
|
-
platform: 'cli',
|
|
68
|
-
properties: { command },
|
|
69
|
-
}),
|
|
70
|
-
}),
|
|
71
|
-
abandoned,
|
|
72
|
-
]);
|
|
50
|
+
await Promise.race([fetch(url, { ...init, signal: controller.signal }), abandoned]);
|
|
73
51
|
}
|
|
74
52
|
catch {
|
|
75
|
-
// Telemetry must never fail a command
|
|
76
|
-
//
|
|
53
|
+
// Telemetry must never fail a command - see "resolves when the gateway rejects" and
|
|
54
|
+
// "gives up rather than hanging" in usage-telemetry.test.ts / usage-telemetry-anonymous.test.ts.
|
|
77
55
|
}
|
|
78
56
|
finally {
|
|
79
57
|
clearTimeout(timer);
|
|
80
58
|
}
|
|
81
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* ALI-618 D3b: what `align telemetry status` prints. Takes the consent decision as a plain
|
|
62
|
+
* argument rather than reading `config.ts` itself, so the two consent MODELS stay visibly
|
|
63
|
+
* distinct in one function a reader can hold in their head - cloud's opt-out default and
|
|
64
|
+
* local's stored opt-in decision - with `ALIGN_TELEMETRY=0` as the one thing that overrides
|
|
65
|
+
* both, checked first.
|
|
66
|
+
*/
|
|
67
|
+
export function getTelemetryStatus(env, localConsent) {
|
|
68
|
+
if (telemetryOptedOut()) {
|
|
69
|
+
return { enabled: false, reason: 'off: ALIGN_TELEMETRY is set to an opt-out value' };
|
|
70
|
+
}
|
|
71
|
+
if (env.mode === 'local-embedded') {
|
|
72
|
+
if (localConsent === 'granted') {
|
|
73
|
+
return { enabled: true, reason: 'on: local mode, you opted in when asked' };
|
|
74
|
+
}
|
|
75
|
+
if (localConsent === 'declined') {
|
|
76
|
+
return { enabled: false, reason: 'off: local mode, you declined when asked' };
|
|
77
|
+
}
|
|
78
|
+
return { enabled: false, reason: 'off: local mode, you have not been asked yet' };
|
|
79
|
+
}
|
|
80
|
+
return { enabled: true, reason: 'on: cloud mode, opt-out default' };
|
|
81
|
+
}
|
|
82
|
+
export async function recordCommandUsage(env, command) {
|
|
83
|
+
if (telemetryOptedOut())
|
|
84
|
+
return;
|
|
85
|
+
// `align local ...` is the explicitly-offline path. Its caller may still hold a cloud token
|
|
86
|
+
// (the hook may resolve an env other than the one the command used), so the token check below
|
|
87
|
+
// is not enough on its own.
|
|
88
|
+
if (command === 'local' || command.startsWith('local '))
|
|
89
|
+
return;
|
|
90
|
+
// The mode is the consent boundary (PR #77: cloud is opt-out; ALI-618: local is opt-in via a
|
|
91
|
+
// stored consent decision, never a phone-home by default). It has to gate on its own because
|
|
92
|
+
// a token can be in scope without cloud consent: ALIGN_TOKEN exported into the shell, or a
|
|
93
|
+
// logged-in default env resolved by the caller.
|
|
94
|
+
if (env.mode === 'local-embedded') {
|
|
95
|
+
await recordAnonymousCommandUsage(command);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (!env.authToken || !env.tenantId)
|
|
99
|
+
return;
|
|
100
|
+
await postWithTimeout(`${env.gatewayUrl}/telemetry/ingest`, {
|
|
101
|
+
method: 'POST',
|
|
102
|
+
headers: {
|
|
103
|
+
'Content-Type': 'application/json',
|
|
104
|
+
Authorization: `Bearer ${env.authToken}`,
|
|
105
|
+
'x-tenant-id': env.tenantId,
|
|
106
|
+
},
|
|
107
|
+
body: JSON.stringify({
|
|
108
|
+
eventName: 'cli.command',
|
|
109
|
+
category: 'engagement',
|
|
110
|
+
platform: 'cli',
|
|
111
|
+
properties: { command },
|
|
112
|
+
}),
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* ALI-618: the local-embedded sibling of the cloud send above. No Authorization, no tenant -
|
|
117
|
+
* there is neither. Gated on a machine-local consent decision instead of a token, and the
|
|
118
|
+
* payload carries exactly three fields (install id, command name, CLI version) so there is
|
|
119
|
+
* nothing here for the gateway's strict schema to reject and nothing beyond what the consent
|
|
120
|
+
* prompt promises. See usage-telemetry-anonymous.test.ts.
|
|
121
|
+
*
|
|
122
|
+
* Targets `ALIGN_HOSTED_GATEWAY_URL`, never a `gatewayUrl` off the env - local-embedded mode
|
|
123
|
+
* makes no HTTP call for its own work (an embedded local DB client, see gateway-client.ts), so
|
|
124
|
+
* the `local` env's `gatewayUrl` is a vestigial `demo`-mode default nothing real listens on.
|
|
125
|
+
* A fresh-context review caught this: the original version sent every local ping to
|
|
126
|
+
* `http://localhost:8080`, silently discarded, for every user who had not separately stood up
|
|
127
|
+
* a local dev gateway.
|
|
128
|
+
*/
|
|
129
|
+
async function recordAnonymousCommandUsage(command) {
|
|
130
|
+
const { createConfigStore } = await import('./config.js');
|
|
131
|
+
const config = createConfigStore();
|
|
132
|
+
if (config.getTelemetryConsent() !== 'granted')
|
|
133
|
+
return;
|
|
134
|
+
const installId = config.getInstallId();
|
|
135
|
+
const topLevelCommand = command.split(' ')[0] ?? command;
|
|
136
|
+
const target = process.env['ALIGN_GATEWAY_URL'] || ALIGN_HOSTED_GATEWAY_URL;
|
|
137
|
+
await postWithTimeout(`${target}/telemetry/anonymous`, {
|
|
138
|
+
method: 'POST',
|
|
139
|
+
headers: { 'Content-Type': 'application/json' },
|
|
140
|
+
body: JSON.stringify({ installId, command: topLevelCommand, cliVersion: pkg.version }),
|
|
141
|
+
});
|
|
142
|
+
}
|
|
82
143
|
/**
|
|
83
144
|
* The `--env` the user actually typed, including one Commander handed to a parent.
|
|
84
145
|
*
|
|
@@ -108,13 +169,17 @@ export function envFlagOf(cmd) {
|
|
|
108
169
|
* the one thing PR #77 said local mode does not do. Only the three-member `local` command
|
|
109
170
|
* group was excluded, and no local user types `align local ask`.
|
|
110
171
|
*
|
|
111
|
-
* `preferLocalEmbedded`
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
172
|
+
* `preferLocalEmbedded` IS now passed (ALI-618) - this paragraph used to say it was
|
|
173
|
+
* deliberately withheld, on the reasoning that the flag/ALIGN_ENV the user explicitly chose is
|
|
174
|
+
* what a CLOUD consent decision may rest on. That reasoning never covered local telemetry: the
|
|
175
|
+
* redirect only ever fires when the cloud env has no token, which is exactly the case
|
|
176
|
+
* recordCommandUsage's cloud branch already drops on its own (`if (!env.authToken || ...)
|
|
177
|
+
* return`) - so passing it here cannot cause an extra cloud send, only let a genuinely
|
|
178
|
+
* never-logged-in user's BARE command reach the local-embedded branch at all. Without it, that
|
|
179
|
+
* exact audience - "never met Tom" - resolved to the tokenless cloud default on every bare
|
|
180
|
+
* command and recordCommandUsage silently dropped it: neither cloud nor local ever counted
|
|
181
|
+
* them, which defeated the whole point of adding local telemetry. A fresh-context review
|
|
182
|
+
* caught this too. Fixed in `usage-telemetry-invocation-local-only.test.ts`.
|
|
118
183
|
*
|
|
119
184
|
* `setup` is suppressed once local-embedded is configured. The interactive "Local only" choice
|
|
120
185
|
* sets no flag, and the default env stays cloud on purpose, so the only evidence the session was
|
|
@@ -128,6 +193,6 @@ export async function recordInvocationUsage(envFlag, command) {
|
|
|
128
193
|
const config = createConfigStore();
|
|
129
194
|
if (command === 'setup' && config.getEnvironment('local').mode === 'local-embedded')
|
|
130
195
|
return;
|
|
131
|
-
await recordCommandUsage(config.getEnvironment(resolveEnv(envFlag)), command);
|
|
196
|
+
await recordCommandUsage(config.getEnvironment(resolveEnv(envFlag, { preferLocalEmbedded: true })), command);
|
|
132
197
|
}
|
|
133
198
|
//# sourceMappingURL=usage-telemetry.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usage-telemetry.js","sourceRoot":"","sources":["../../src/lib/usage-telemetry.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"usage-telemetry.js","sourceRoot":"","sources":["../../src/lib/usage-telemetry.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aligndottech/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.23.0",
|
|
4
4
|
"mcpName": "io.github.aligndottech/cli",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Align CLI - capture decisions, check alignment, and manage connectors",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"build": "tsc -p tsconfig.json",
|
|
28
28
|
"prepublishOnly": "npm run build",
|
|
29
29
|
"dev": "tsx src/index.ts",
|
|
30
|
-
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
30
|
+
"typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.bun.json",
|
|
31
31
|
"lint": "eslint .",
|
|
32
32
|
"test": "vitest run",
|
|
33
33
|
"test:watch": "vitest",
|
|
@@ -37,7 +37,6 @@
|
|
|
37
37
|
"@aligndottech/connector-core": "^0.4.0",
|
|
38
38
|
"@clack/prompts": "^0.9.1",
|
|
39
39
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
40
|
-
"better-sqlite3": "^12.10.0",
|
|
41
40
|
"chalk": "^5.3.0",
|
|
42
41
|
"commander": "^12.1.0",
|
|
43
42
|
"conf": "^13.0.1",
|
|
@@ -49,7 +48,6 @@
|
|
|
49
48
|
},
|
|
50
49
|
"devDependencies": {
|
|
51
50
|
"@eslint/js": "^9.0.0",
|
|
52
|
-
"@types/better-sqlite3": "^7.6.13",
|
|
53
51
|
"@types/eventsource": "^1.1.15",
|
|
54
52
|
"@types/js-yaml": "^4.0.9",
|
|
55
53
|
"@types/node": "^22.0.0",
|
|
@@ -67,7 +65,7 @@
|
|
|
67
65
|
"@huggingface/transformers": "^4.2.0"
|
|
68
66
|
},
|
|
69
67
|
"engines": {
|
|
70
|
-
"node": ">=
|
|
68
|
+
"node": ">=22.16"
|
|
71
69
|
},
|
|
72
70
|
"publishConfig": {
|
|
73
71
|
"access": "public"
|
|
@@ -79,10 +77,5 @@
|
|
|
79
77
|
"repository": {
|
|
80
78
|
"type": "git",
|
|
81
79
|
"url": "https://github.com/aligndottech/align-cli"
|
|
82
|
-
},
|
|
83
|
-
"pnpm": {
|
|
84
|
-
"onlyBuiltDependencies": [
|
|
85
|
-
"better-sqlite3"
|
|
86
|
-
]
|
|
87
80
|
}
|
|
88
81
|
}
|