@aligndottech/cli 0.50.0 → 0.51.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 +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +6 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/config.d.ts +8 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +33 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/connect-agents.d.ts.map +1 -1
- package/dist/commands/connect-agents.js +3 -1
- package/dist/commands/connect-agents.js.map +1 -1
- package/dist/commands/env.d.ts.map +1 -1
- package/dist/commands/env.js +11 -0
- package/dist/commands/env.js.map +1 -1
- package/dist/commands/invite.d.ts +8 -18
- package/dist/commands/invite.d.ts.map +1 -1
- package/dist/commands/invite.js +23 -46
- package/dist/commands/invite.js.map +1 -1
- package/dist/commands/join.d.ts +5 -0
- package/dist/commands/join.d.ts.map +1 -0
- package/dist/commands/join.js +49 -0
- package/dist/commands/join.js.map +1 -0
- package/dist/commands/local-relink.d.ts +35 -0
- package/dist/commands/local-relink.d.ts.map +1 -0
- package/dist/commands/local-relink.js +72 -0
- package/dist/commands/local-relink.js.map +1 -0
- package/dist/commands/local.d.ts.map +1 -1
- package/dist/commands/local.js +37 -0
- package/dist/commands/local.js.map +1 -1
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +21 -2
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/mcp.d.ts +8 -0
- package/dist/commands/mcp.d.ts.map +1 -1
- package/dist/commands/mcp.js +12 -5
- package/dist/commands/mcp.js.map +1 -1
- package/dist/commands/registry.d.ts.map +1 -1
- package/dist/commands/registry.js +4 -0
- package/dist/commands/registry.js.map +1 -1
- package/dist/commands/share.d.ts.map +1 -1
- package/dist/commands/share.js +81 -12
- package/dist/commands/share.js.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +10 -0
- package/dist/commands/status.js.map +1 -1
- package/dist/detector/detector-version.d.ts +16 -0
- package/dist/detector/detector-version.d.ts.map +1 -0
- package/dist/detector/detector-version.js +36 -0
- package/dist/detector/detector-version.js.map +1 -0
- package/dist/detector/relationship-contract.d.ts +30 -0
- package/dist/detector/relationship-contract.d.ts.map +1 -0
- package/dist/detector/relationship-contract.js +120 -0
- package/dist/detector/relationship-contract.js.map +1 -0
- package/dist/detector/relationship-contract.v1.json +53 -0
- package/dist/detector/relationship-prompt.d.ts +20 -0
- package/dist/detector/relationship-prompt.d.ts.map +1 -0
- package/dist/detector/relationship-prompt.js +55 -0
- package/dist/detector/relationship-prompt.js.map +1 -0
- package/dist/detector/relationship-prompt.v1.json +13 -0
- package/dist/detector/resolve-pair.d.ts +39 -0
- package/dist/detector/resolve-pair.d.ts.map +1 -0
- package/dist/detector/resolve-pair.js +345 -0
- package/dist/detector/resolve-pair.js.map +1 -0
- package/dist/detector/similar-item.d.ts +20 -0
- package/dist/detector/similar-item.d.ts.map +1 -0
- package/dist/detector/similar-item.js +16 -0
- package/dist/detector/similar-item.js.map +1 -0
- package/dist/index.js +29 -11
- package/dist/index.js.map +1 -1
- package/dist/lib/advisory-dedup.d.ts.map +1 -1
- package/dist/lib/advisory-dedup.js +16 -8
- package/dist/lib/advisory-dedup.js.map +1 -1
- package/dist/lib/advisory-verdict.d.ts +19 -0
- package/dist/lib/advisory-verdict.d.ts.map +1 -1
- package/dist/lib/advisory-verdict.js +6 -3
- package/dist/lib/advisory-verdict.js.map +1 -1
- package/dist/lib/backup-exclusion.d.ts +10 -0
- package/dist/lib/backup-exclusion.d.ts.map +1 -0
- package/dist/lib/backup-exclusion.js +58 -0
- package/dist/lib/backup-exclusion.js.map +1 -0
- package/dist/lib/cli-oauth.d.ts +2 -0
- package/dist/lib/cli-oauth.d.ts.map +1 -1
- package/dist/lib/cli-oauth.js +61 -10
- package/dist/lib/cli-oauth.js.map +1 -1
- package/dist/lib/config.d.ts +41 -1
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +106 -1
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/curation/guardrail.d.ts.map +1 -1
- package/dist/lib/curation/guardrail.js +2 -0
- package/dist/lib/curation/guardrail.js.map +1 -1
- package/dist/lib/curation/judgements-db.d.ts +1 -0
- package/dist/lib/curation/judgements-db.d.ts.map +1 -1
- package/dist/lib/curation/judgements-db.js +9 -3
- package/dist/lib/curation/judgements-db.js.map +1 -1
- package/dist/lib/curation/mark.js +4 -2
- package/dist/lib/curation/mark.js.map +1 -1
- package/dist/lib/destination-name.d.ts +24 -0
- package/dist/lib/destination-name.d.ts.map +1 -0
- package/dist/lib/destination-name.js +39 -0
- package/dist/lib/destination-name.js.map +1 -0
- package/dist/lib/destination-summary.d.ts +6 -0
- package/dist/lib/destination-summary.d.ts.map +1 -0
- package/dist/lib/destination-summary.js +27 -0
- package/dist/lib/destination-summary.js.map +1 -0
- package/dist/lib/destination-trust.d.ts +54 -0
- package/dist/lib/destination-trust.d.ts.map +1 -0
- package/dist/lib/destination-trust.js +107 -0
- package/dist/lib/destination-trust.js.map +1 -0
- package/dist/lib/env-resolver.d.ts.map +1 -1
- package/dist/lib/env-resolver.js +3 -0
- package/dist/lib/env-resolver.js.map +1 -1
- package/dist/lib/fatal.d.ts +11 -0
- package/dist/lib/fatal.d.ts.map +1 -0
- package/dist/lib/fatal.js +22 -0
- package/dist/lib/fatal.js.map +1 -0
- package/dist/lib/gateway-client.d.ts +8 -16
- package/dist/lib/gateway-client.d.ts.map +1 -1
- package/dist/lib/gateway-client.js +30 -20
- package/dist/lib/gateway-client.js.map +1 -1
- package/dist/lib/invite-prompt.d.ts +4 -4
- package/dist/lib/invite-prompt.d.ts.map +1 -1
- package/dist/lib/invite-prompt.js +4 -4
- package/dist/lib/invite-prompt.js.map +1 -1
- package/dist/lib/invite-settings.d.ts +18 -0
- package/dist/lib/invite-settings.d.ts.map +1 -0
- package/dist/lib/invite-settings.js +29 -0
- package/dist/lib/invite-settings.js.map +1 -0
- package/dist/lib/join-flow.d.ts +60 -0
- package/dist/lib/join-flow.d.ts.map +1 -0
- package/dist/lib/join-flow.js +282 -0
- package/dist/lib/join-flow.js.map +1 -0
- package/dist/lib/launch/mcp-child-env.d.ts.map +1 -1
- package/dist/lib/launch/mcp-child-env.js +5 -2
- package/dist/lib/launch/mcp-child-env.js.map +1 -1
- package/dist/lib/lead-prompt.d.ts +106 -0
- package/dist/lib/lead-prompt.d.ts.map +1 -0
- package/dist/lib/lead-prompt.js +175 -0
- package/dist/lib/lead-prompt.js.map +1 -0
- package/dist/lib/local-candidate-classify.d.ts +26 -0
- package/dist/lib/local-candidate-classify.d.ts.map +1 -0
- package/dist/lib/local-candidate-classify.js +53 -0
- package/dist/lib/local-candidate-classify.js.map +1 -0
- package/dist/lib/local-db-migrate.d.ts +1 -1
- package/dist/lib/local-db-migrate.d.ts.map +1 -1
- package/dist/lib/local-db-migrate.js +45 -1
- package/dist/lib/local-db-migrate.js.map +1 -1
- package/dist/lib/local-db-v12.d.ts +17 -0
- package/dist/lib/local-db-v12.d.ts.map +1 -0
- package/dist/lib/local-db-v12.js +8 -0
- package/dist/lib/local-db-v12.js.map +1 -0
- package/dist/lib/local-db.d.ts +13 -13
- package/dist/lib/local-db.d.ts.map +1 -1
- package/dist/lib/local-db.js +41 -6
- package/dist/lib/local-db.js.map +1 -1
- package/dist/lib/local-gateway-client.d.ts +1 -0
- package/dist/lib/local-gateway-client.d.ts.map +1 -1
- package/dist/lib/local-gateway-client.js +31 -20
- package/dist/lib/local-gateway-client.js.map +1 -1
- package/dist/lib/local-ingest.d.ts +2 -0
- package/dist/lib/local-ingest.d.ts.map +1 -1
- package/dist/lib/local-ingest.js.map +1 -1
- package/dist/lib/local-link-pass.d.ts.map +1 -1
- package/dist/lib/local-link-pass.js +25 -29
- package/dist/lib/local-link-pass.js.map +1 -1
- package/dist/lib/local-llm.d.ts +1 -1
- package/dist/lib/local-llm.d.ts.map +1 -1
- package/dist/lib/local-llm.js +3 -2
- package/dist/lib/local-llm.js.map +1 -1
- package/dist/lib/local-mode.d.ts +5 -1
- package/dist/lib/local-mode.d.ts.map +1 -1
- package/dist/lib/local-mode.js +11 -6
- package/dist/lib/local-mode.js.map +1 -1
- package/dist/lib/local-relationship-classifier.d.ts +4 -0
- package/dist/lib/local-relationship-classifier.d.ts.map +1 -1
- package/dist/lib/local-relationship-classifier.js +9 -4
- package/dist/lib/local-relationship-classifier.js.map +1 -1
- package/dist/lib/local-relink.d.ts +59 -0
- package/dist/lib/local-relink.d.ts.map +1 -0
- package/dist/lib/local-relink.js +171 -0
- package/dist/lib/local-relink.js.map +1 -0
- package/dist/lib/local-set-classifier.d.ts +36 -0
- package/dist/lib/local-set-classifier.d.ts.map +1 -0
- package/dist/lib/local-set-classifier.js +81 -0
- package/dist/lib/local-set-classifier.js.map +1 -0
- package/dist/lib/local-snapshot-loader.d.ts +29 -0
- package/dist/lib/local-snapshot-loader.d.ts.map +1 -0
- package/dist/lib/local-snapshot-loader.js +108 -0
- package/dist/lib/local-snapshot-loader.js.map +1 -0
- package/dist/lib/login-flow.d.ts +15 -0
- package/dist/lib/login-flow.d.ts.map +1 -1
- package/dist/lib/login-flow.js +80 -4
- package/dist/lib/login-flow.js.map +1 -1
- package/dist/lib/mcp/share-status-tool.d.ts +13 -0
- package/dist/lib/mcp/share-status-tool.d.ts.map +1 -0
- package/dist/lib/mcp/share-status-tool.js +116 -0
- package/dist/lib/mcp/share-status-tool.js.map +1 -0
- package/dist/lib/mcp/share-tool.d.ts +18 -14
- package/dist/lib/mcp/share-tool.d.ts.map +1 -1
- package/dist/lib/mcp/share-tool.js +127 -21
- package/dist/lib/mcp/share-tool.js.map +1 -1
- package/dist/lib/model-cache.d.ts +10 -0
- package/dist/lib/model-cache.d.ts.map +1 -0
- package/dist/lib/model-cache.js +35 -0
- package/dist/lib/model-cache.js.map +1 -0
- package/dist/lib/next-step.d.ts.map +1 -1
- package/dist/lib/next-step.js +2 -1
- package/dist/lib/next-step.js.map +1 -1
- package/dist/lib/private-files.d.ts +33 -0
- package/dist/lib/private-files.d.ts.map +1 -0
- package/dist/lib/private-files.js +96 -0
- package/dist/lib/private-files.js.map +1 -0
- package/dist/lib/redaction-notice.d.ts +7 -0
- package/dist/lib/redaction-notice.d.ts.map +1 -0
- package/dist/lib/redaction-notice.js +32 -0
- package/dist/lib/redaction-notice.js.map +1 -0
- package/dist/lib/relink-estimate.d.ts +16 -0
- package/dist/lib/relink-estimate.d.ts.map +1 -0
- package/dist/lib/relink-estimate.js +30 -0
- package/dist/lib/relink-estimate.js.map +1 -0
- package/dist/lib/resolve-env.d.ts +15 -1
- package/dist/lib/resolve-env.d.ts.map +1 -1
- package/dist/lib/resolve-env.js +27 -7
- package/dist/lib/resolve-env.js.map +1 -1
- package/dist/lib/scope-defaults.d.ts.map +1 -1
- package/dist/lib/scope-defaults.js +2 -0
- package/dist/lib/scope-defaults.js.map +1 -1
- package/dist/lib/scope-real.d.ts +57 -0
- package/dist/lib/scope-real.d.ts.map +1 -1
- package/dist/lib/setup-route.d.ts +4 -2
- package/dist/lib/setup-route.d.ts.map +1 -1
- package/dist/lib/setup-route.js +12 -6
- package/dist/lib/setup-route.js.map +1 -1
- package/dist/lib/share/approval.d.ts +71 -0
- package/dist/lib/share/approval.d.ts.map +1 -0
- package/dist/lib/share/approval.js +139 -0
- package/dist/lib/share/approval.js.map +1 -0
- package/dist/lib/share/approve-link.d.ts +31 -0
- package/dist/lib/share/approve-link.d.ts.map +1 -0
- package/dist/lib/share/approve-link.js +46 -0
- package/dist/lib/share/approve-link.js.map +1 -0
- package/dist/lib/share/browser-flow.d.ts +85 -0
- package/dist/lib/share/browser-flow.d.ts.map +1 -0
- package/dist/lib/share/browser-flow.js +168 -0
- package/dist/lib/share/browser-flow.js.map +1 -0
- package/dist/lib/share/command.d.ts +34 -1
- package/dist/lib/share/command.d.ts.map +1 -1
- package/dist/lib/share/command.js +153 -11
- package/dist/lib/share/command.js.map +1 -1
- package/dist/lib/share/delivery-options.d.ts +15 -0
- package/dist/lib/share/delivery-options.d.ts.map +1 -0
- package/dist/lib/share/delivery-options.js +16 -0
- package/dist/lib/share/delivery-options.js.map +1 -0
- package/dist/lib/share/delivery.d.ts +83 -0
- package/dist/lib/share/delivery.d.ts.map +1 -0
- package/dist/lib/share/delivery.js +134 -0
- package/dist/lib/share/delivery.js.map +1 -0
- package/dist/lib/share/envelope.d.ts +61 -0
- package/dist/lib/share/envelope.d.ts.map +1 -0
- package/dist/lib/share/envelope.js +99 -0
- package/dist/lib/share/envelope.js.map +1 -0
- package/dist/lib/share/ledger.d.ts.map +1 -1
- package/dist/lib/share/ledger.js +3 -1
- package/dist/lib/share/ledger.js.map +1 -1
- package/dist/lib/share/payload.d.ts +9 -0
- package/dist/lib/share/payload.d.ts.map +1 -1
- package/dist/lib/share/payload.js +9 -0
- package/dist/lib/share/payload.js.map +1 -1
- package/dist/lib/share/pending.d.ts +47 -1
- package/dist/lib/share/pending.d.ts.map +1 -1
- package/dist/lib/share/pending.js +139 -13
- package/dist/lib/share/pending.js.map +1 -1
- package/dist/lib/share/preview.d.ts +5 -1
- package/dist/lib/share/preview.d.ts.map +1 -1
- package/dist/lib/share/preview.js +3 -1
- package/dist/lib/share/preview.js.map +1 -1
- package/dist/lib/share/qr.d.ts +13 -0
- package/dist/lib/share/qr.d.ts.map +1 -0
- package/dist/lib/share/qr.js +77 -0
- package/dist/lib/share/qr.js.map +1 -0
- package/dist/lib/share/requests-client.d.ts +63 -0
- package/dist/lib/share/requests-client.d.ts.map +1 -0
- package/dist/lib/share/requests-client.js +69 -0
- package/dist/lib/share/requests-client.js.map +1 -0
- package/dist/lib/share/run.d.ts +20 -1
- package/dist/lib/share/run.d.ts.map +1 -1
- package/dist/lib/share/run.js +27 -10
- package/dist/lib/share/run.js.map +1 -1
- package/dist/lib/share/secret-scan.d.ts +5 -0
- package/dist/lib/share/secret-scan.d.ts.map +1 -1
- package/dist/lib/share/secret-scan.js +43 -2
- package/dist/lib/share/secret-scan.js.map +1 -1
- package/dist/lib/share/target.d.ts +38 -0
- package/dist/lib/share/target.d.ts.map +1 -0
- package/dist/lib/share/target.js +80 -0
- package/dist/lib/share/target.js.map +1 -0
- package/dist/lib/share/tty.d.ts +8 -0
- package/dist/lib/share/tty.d.ts.map +1 -1
- package/dist/lib/share/tty.js +45 -0
- package/dist/lib/share/tty.js.map +1 -1
- package/dist/lib/source-sync-state.d.ts.map +1 -1
- package/dist/lib/source-sync-state.js +2 -0
- package/dist/lib/source-sync-state.js.map +1 -1
- package/dist/lib/sync/blocked.d.ts.map +1 -1
- package/dist/lib/sync/blocked.js +2 -1
- package/dist/lib/sync/blocked.js.map +1 -1
- package/dist/lib/sync/classify.d.ts.map +1 -1
- package/dist/lib/sync/classify.js +2 -0
- package/dist/lib/sync/classify.js.map +1 -1
- package/dist/lib/sync/real-env.d.ts +57 -0
- package/dist/lib/sync/real-env.d.ts.map +1 -1
- package/dist/lib/sync/sync-state.d.ts.map +1 -1
- package/dist/lib/sync/sync-state.js +3 -1
- package/dist/lib/sync/sync-state.js.map +1 -1
- package/dist/lib/usage-telemetry.d.ts +2 -2
- package/dist/lib/usage-telemetry.d.ts.map +1 -1
- package/dist/lib/usage-telemetry.js +21 -3
- package/dist/lib/usage-telemetry.js.map +1 -1
- package/package.json +4 -2
- package/dist/lib/personal-email-domains.d.ts +0 -8
- package/dist/lib/personal-email-domains.d.ts.map +0 -1
- package/dist/lib/personal-email-domains.js +0 -39
- package/dist/lib/personal-email-domains.js.map +0 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { lstatSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { tmpdir } from 'node:os';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
+
import { tightenFile } from './private-files.js';
|
|
4
5
|
import { createHash, randomUUID } from 'node:crypto';
|
|
5
6
|
/**
|
|
6
7
|
* ALI-570: the store that carries an adjudication verdict from the background adjudicator
|
|
@@ -65,7 +66,8 @@ export function contentHashOf(text) {
|
|
|
65
66
|
* each user a private %LOCALAPPDATA%\Temp - which is also why the uid falls back to a
|
|
66
67
|
* constant there rather than trying to synthesise one.
|
|
67
68
|
*/
|
|
68
|
-
|
|
69
|
+
/** `<tmp>/align-<uid>`: created 0700, refused when it is a link or not ours. Also holds the advisory dedup markers. */
|
|
70
|
+
export function privateTmpDir() {
|
|
69
71
|
try {
|
|
70
72
|
const uid = typeof process.getuid === 'function' ? String(process.getuid()) : 'win';
|
|
71
73
|
const dir = path.join(tmpdir(), `align-${uid}`);
|
|
@@ -77,6 +79,7 @@ function storeDir() {
|
|
|
77
79
|
return null;
|
|
78
80
|
if (typeof process.getuid === 'function' && st.uid !== process.getuid())
|
|
79
81
|
return null;
|
|
82
|
+
tightenFile(dir); // ours, but an older version may have left it wider: owner-only now
|
|
80
83
|
return dir;
|
|
81
84
|
}
|
|
82
85
|
catch {
|
|
@@ -89,7 +92,7 @@ function storeDir() {
|
|
|
89
92
|
* the change hash - the key has to be as specific as the thing it identifies.
|
|
90
93
|
*/
|
|
91
94
|
function storePath(cwd, envName) {
|
|
92
|
-
const dir =
|
|
95
|
+
const dir = privateTmpDir();
|
|
93
96
|
if (!dir)
|
|
94
97
|
return null;
|
|
95
98
|
const hash = createHash('sha1').update(`${cwd}\0${envName}`).digest('hex').slice(0, 16);
|
|
@@ -97,7 +100,7 @@ function storePath(cwd, envName) {
|
|
|
97
100
|
}
|
|
98
101
|
/** Where the adjudication payload for one change is handed to the detached child. */
|
|
99
102
|
export function adjudicationPayloadPath(contentHash) {
|
|
100
|
-
const dir =
|
|
103
|
+
const dir = privateTmpDir();
|
|
101
104
|
if (!dir)
|
|
102
105
|
return null;
|
|
103
106
|
return path.join(dir, `adjudicate-${contentHash.slice(0, 12)}-${randomUUID()}.json`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"advisory-verdict.js","sourceRoot":"","sources":["../../src/lib/advisory-verdict.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACpG,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAErD;;;;;;;;;;;;;;;;GAgBG;AAEH,6EAA6E;AAC7E,MAAM,CAAC,MAAM,cAAc,GAAG,EAAE,GAAG,MAAM,CAAC;AAC1C;;;;;GAKG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,GAAG,MAAM,CAAC;AACzC,8FAA8F;AAC9F,MAAM,CAAC,MAAM,mBAAmB,GAAG,EAAE,CAAC;AACtC;;;;GAIG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,CAAC;AAE9C,oEAAoE;AACpE,MAAM,cAAc,GAAG,GAAG,CAAC;AAE3B;;;;GAIG;AACH,MAAM,YAAY,GAAG,CAAC,CAAC;AAqCvB,MAAM,KAAK,GAAU,EAAE,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;AAEnD,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACvD,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,
|
|
1
|
+
{"version":3,"file":"advisory-verdict.js","sourceRoot":"","sources":["../../src/lib/advisory-verdict.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const CACHEDIR_TAG_SIGNATURE = "Signature: 8a477f597d28d172789f06886806bc55";
|
|
2
|
+
export interface BackupDeps {
|
|
3
|
+
platform: string;
|
|
4
|
+
hasTmutil: () => boolean;
|
|
5
|
+
run: (cmd: string, args: string[]) => void;
|
|
6
|
+
writeFile?: (p: string, data: string) => void;
|
|
7
|
+
}
|
|
8
|
+
/** Exclude the directory holding `dbPath` from backups, once. A no-op until the graph exists. */
|
|
9
|
+
export declare function excludeGraphFromBackups(dbPath: string, deps?: BackupDeps): void;
|
|
10
|
+
//# sourceMappingURL=backup-exclusion.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backup-exclusion.d.ts","sourceRoot":"","sources":["../../src/lib/backup-exclusion.ts"],"names":[],"mappings":"AAwBA,eAAO,MAAM,sBAAsB,gDAAgD,CAAC;AAGpF,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,OAAO,CAAC;IACzB,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC3C,SAAS,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/C;AAQD,iGAAiG;AACjG,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,GAAE,UAAwB,GAAG,IAAI,CAgB5F"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keep the local graph out of backups and sync, best effort.
|
|
3
|
+
*
|
|
4
|
+
* The graph holds decision text from every connector a person imported, and it is not encrypted
|
|
5
|
+
* (by design, see docs/local-mode.md). A Time Machine disk or a backup service is a second copy of
|
|
6
|
+
* it, in a place the person may not think of as theirs to protect. So, once, the directory that
|
|
7
|
+
* holds it is:
|
|
8
|
+
* - excluded from Time Machine on macOS (`tmutil addexclusion`, a sticky exclusion that follows
|
|
9
|
+
* the folder, run only when /usr/bin/tmutil exists), and
|
|
10
|
+
* - tagged with CACHEDIR.TAG (https://bford.info/cachedir/), which borg, restic, tar and other
|
|
11
|
+
* backup tools skip when asked to exclude caches.
|
|
12
|
+
*
|
|
13
|
+
* There is no marker-FILE convention for iCloud or Dropbox: iCloud skips items whose NAME ends in
|
|
14
|
+
* `.nosync`, which would mean renaming the user's config directory. Neither syncs the config
|
|
15
|
+
* directory by default, so nothing is written for them. Undo: `tmutil removeexclusion <dir>` and
|
|
16
|
+
* delete the tag (docs/local-mode.md); a separate `.backup-exclusion-done` marker
|
|
17
|
+
* keeps that undo from being reversed.
|
|
18
|
+
*
|
|
19
|
+
* Never fatal: every step is wrapped, and nothing here can stop a command from running.
|
|
20
|
+
*/
|
|
21
|
+
import { spawnSync } from 'node:child_process';
|
|
22
|
+
import fs from 'node:fs';
|
|
23
|
+
import path from 'node:path';
|
|
24
|
+
export const CACHEDIR_TAG_SIGNATURE = 'Signature: 8a477f597d28d172789f06886806bc55';
|
|
25
|
+
const TMUTIL = '/usr/bin/tmutil';
|
|
26
|
+
const defaultDeps = {
|
|
27
|
+
platform: process.platform,
|
|
28
|
+
hasTmutil: () => fs.existsSync(TMUTIL),
|
|
29
|
+
run: (cmd, args) => { spawnSync(cmd, args, { stdio: 'ignore', timeout: 5000 }); },
|
|
30
|
+
};
|
|
31
|
+
/** Exclude the directory holding `dbPath` from backups, once. A no-op until the graph exists. */
|
|
32
|
+
export function excludeGraphFromBackups(dbPath, deps = defaultDeps) {
|
|
33
|
+
try {
|
|
34
|
+
if (!fs.existsSync(dbPath))
|
|
35
|
+
return;
|
|
36
|
+
const dir = path.dirname(dbPath);
|
|
37
|
+
const tag = path.join(dir, 'CACHEDIR.TAG');
|
|
38
|
+
// Its own "already done" marker, not the tag: a person who deletes the tag to back the graph up again
|
|
39
|
+
// (the documented undo) must not have it, or the Time Machine exclusion, put back by the next command.
|
|
40
|
+
const done = path.join(dir, '.backup-exclusion-done');
|
|
41
|
+
if (fs.existsSync(done) || fs.existsSync(tag))
|
|
42
|
+
return;
|
|
43
|
+
try {
|
|
44
|
+
fs.writeFileSync(done, '', { mode: 0o600 });
|
|
45
|
+
}
|
|
46
|
+
catch { /* best effort */ }
|
|
47
|
+
if (deps.platform === 'darwin' && deps.hasTmutil()) {
|
|
48
|
+
try {
|
|
49
|
+
deps.run(TMUTIL, ['addexclusion', dir]);
|
|
50
|
+
}
|
|
51
|
+
catch { /* best effort */ }
|
|
52
|
+
}
|
|
53
|
+
const body = `${CACHEDIR_TAG_SIGNATURE}\n# This file marks the Align CLI local decision graph so backup tools can skip it.\n# See https://bford.info/cachedir/ and docs/local-mode.md in align-cli.\n`;
|
|
54
|
+
(deps.writeFile ?? ((p, d) => fs.writeFileSync(p, d, { mode: 0o600 })))(tag, body);
|
|
55
|
+
}
|
|
56
|
+
catch { /* best effort: never stop a command */ }
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=backup-exclusion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backup-exclusion.js","sourceRoot":"","sources":["../../src/lib/backup-exclusion.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,MAAM,CAAC,MAAM,sBAAsB,GAAG,6CAA6C,CAAC;AACpF,MAAM,MAAM,GAAG,iBAAiB,CAAC;AASjC,MAAM,WAAW,GAAe;IAC9B,QAAQ,EAAE,OAAO,CAAC,QAAQ;IAC1B,SAAS,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC;IACtC,GAAG,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,GAAG,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;CAClF,CAAC;AAEF,iGAAiG;AACjG,MAAM,UAAU,uBAAuB,CAAC,MAAc,EAAE,OAAmB,WAAW;IACpF,IAAI,CAAC;QACH,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC;YAAE,OAAO;QACnC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACjC,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;QAC3C,sGAAsG;QACtG,uGAAuG;QACvG,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,wBAAwB,CAAC,CAAC;QACtD,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,OAAO;QACtD,IAAI,CAAC;YAAC,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC;QAChF,IAAI,IAAI,CAAC,QAAQ,KAAK,QAAQ,IAAI,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC;YACnD,IAAI,CAAC;gBAAC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC;QAC9E,CAAC;QACD,MAAM,IAAI,GAAG,GAAG,sBAAsB,gKAAgK,CAAC;QACvM,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACrF,CAAC;IAAC,MAAM,CAAC,CAAC,uCAAuC,CAAC,CAAC;AACrD,CAAC"}
|
package/dist/lib/cli-oauth.d.ts
CHANGED
|
@@ -6,6 +6,8 @@ export declare function waitForCallback(opts: {
|
|
|
6
6
|
ports: number[];
|
|
7
7
|
timeoutMs: number;
|
|
8
8
|
onBound?: (port: number, nonce: string) => void | Promise<void>;
|
|
9
|
+
/** Stops the wait: the listeners close and the promise rejects. */
|
|
10
|
+
signal?: AbortSignal;
|
|
9
11
|
}): Promise<CallbackResult>;
|
|
10
12
|
export declare const CLI_CALLBACK_PORTS: number[];
|
|
11
13
|
//# sourceMappingURL=cli-oauth.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-oauth.d.ts","sourceRoot":"","sources":["../../src/lib/cli-oauth.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,IAAI,EAAE,MAAM,CAAC;CACd;
|
|
1
|
+
{"version":3,"file":"cli-oauth.d.ts","sourceRoot":"","sources":["../../src/lib/cli-oauth.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,IAAI,EAAE,MAAM,CAAC;CACd;AAKD,wBAAgB,eAAe,CAAC,IAAI,EAAE;IACpC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,mEAAmE;IACnE,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,GAAG,OAAO,CAAC,cAAc,CAAC,CA0G1B;AAED,eAAO,MAAM,kBAAkB,UAAiC,CAAC"}
|
package/dist/lib/cli-oauth.js
CHANGED
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
import http from 'node:http';
|
|
2
2
|
import { randomBytes } from 'node:crypto';
|
|
3
|
+
/** The page posts a token and a nonce: well under this. Anything larger is not it. */
|
|
4
|
+
const MAX_BODY_BYTES = 8 * 1024;
|
|
3
5
|
export function waitForCallback(opts) {
|
|
4
6
|
return new Promise((resolve, reject) => {
|
|
5
|
-
let
|
|
7
|
+
let servers = [];
|
|
8
|
+
const closeAll = () => { for (const x of servers)
|
|
9
|
+
x.close(); };
|
|
6
10
|
const nonce = randomBytes(16).toString('hex');
|
|
11
|
+
opts.signal?.addEventListener('abort', () => {
|
|
12
|
+
clearTimeout(timer);
|
|
13
|
+
closeAll();
|
|
14
|
+
reject(new Error('cancelled'));
|
|
15
|
+
}, { once: true });
|
|
7
16
|
const timer = setTimeout(() => {
|
|
8
|
-
|
|
17
|
+
closeAll();
|
|
9
18
|
reject(new Error('CLI OAuth timed out waiting for browser callback'));
|
|
10
19
|
}, opts.timeoutMs);
|
|
11
20
|
function tryPort(remaining) {
|
|
@@ -15,7 +24,7 @@ export function waitForCallback(opts) {
|
|
|
15
24
|
return;
|
|
16
25
|
}
|
|
17
26
|
const [port, ...rest] = remaining;
|
|
18
|
-
const
|
|
27
|
+
const onRequest = (req, res) => {
|
|
19
28
|
const origin = req.headers['origin'];
|
|
20
29
|
if (origin)
|
|
21
30
|
res.setHeader('Access-Control-Allow-Origin', origin);
|
|
@@ -31,16 +40,34 @@ export function waitForCallback(opts) {
|
|
|
31
40
|
res.writeHead(405).end();
|
|
32
41
|
return;
|
|
33
42
|
}
|
|
34
|
-
|
|
35
|
-
|
|
43
|
+
// Any web page can POST here (a no-cors request needs no permission), so what arrives is read under a bound and a
|
|
44
|
+
// stray request is answered and ignored. Only the right nonce ends the wait.
|
|
45
|
+
const chunks = [];
|
|
46
|
+
let size = 0;
|
|
47
|
+
let tooBig = false;
|
|
48
|
+
req.on('data', (chunk) => {
|
|
49
|
+
if (tooBig)
|
|
50
|
+
return;
|
|
51
|
+
size += chunk.length;
|
|
52
|
+
if (size > MAX_BODY_BYTES) {
|
|
53
|
+
tooBig = true;
|
|
54
|
+
res.writeHead(413, { Connection: 'close' }).end(() => req.destroy());
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
chunks.push(chunk);
|
|
58
|
+
});
|
|
36
59
|
req.on('end', () => {
|
|
60
|
+
if (tooBig)
|
|
61
|
+
return;
|
|
37
62
|
let parsed;
|
|
38
63
|
try {
|
|
39
|
-
|
|
64
|
+
const v = JSON.parse(Buffer.concat(chunks).toString('utf8'));
|
|
65
|
+
if (typeof v !== 'object' || v === null || Array.isArray(v))
|
|
66
|
+
throw new Error('not an object');
|
|
67
|
+
parsed = v;
|
|
40
68
|
}
|
|
41
69
|
catch {
|
|
42
70
|
res.writeHead(400).end();
|
|
43
|
-
reject(new Error('Invalid JSON received in CLI OAuth callback'));
|
|
44
71
|
return;
|
|
45
72
|
}
|
|
46
73
|
if (parsed['cli_nonce'] !== nonce) {
|
|
@@ -50,10 +77,11 @@ export function waitForCallback(opts) {
|
|
|
50
77
|
const { cli_nonce: _, ...payload } = parsed;
|
|
51
78
|
res.writeHead(200, { 'Content-Type': 'application/json' }).end('{"ok":true}');
|
|
52
79
|
clearTimeout(timer);
|
|
53
|
-
|
|
80
|
+
closeAll();
|
|
54
81
|
resolve({ data: payload, port });
|
|
55
82
|
});
|
|
56
|
-
}
|
|
83
|
+
};
|
|
84
|
+
const s = http.createServer(onRequest);
|
|
57
85
|
s.on('error', (err) => {
|
|
58
86
|
if (err.code === 'EADDRINUSE') {
|
|
59
87
|
tryPort(rest);
|
|
@@ -62,7 +90,30 @@ export function waitForCallback(opts) {
|
|
|
62
90
|
clearTimeout(timer);
|
|
63
91
|
reject(err);
|
|
64
92
|
});
|
|
65
|
-
|
|
93
|
+
// 127.0.0.1, not every interface: this socket accepts a credential, and on 0.0.0.0 anyone on the LAN can dial it (ALI-1504).
|
|
94
|
+
s.listen(port, '127.0.0.1', () => {
|
|
95
|
+
// The web page posts to http://localhost, which a browser may resolve to ::1. Answer there too, or the token goes to
|
|
96
|
+
// whatever else holds ::1 on this port. A port whose ::1 side is taken is skipped whole: never half of a pair.
|
|
97
|
+
const s6 = http.createServer(onRequest);
|
|
98
|
+
s6.once('error', (err) => {
|
|
99
|
+
if (err.code === 'EADDRINUSE') {
|
|
100
|
+
s.close();
|
|
101
|
+
tryPort(rest);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
// No IPv6 loopback on this machine (a container, a disabled stack): IPv4 alone is all there is to answer on.
|
|
105
|
+
servers = [s];
|
|
106
|
+
if (opts.signal?.aborted) {
|
|
107
|
+
closeAll();
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
void opts.onBound?.(port, nonce);
|
|
111
|
+
});
|
|
112
|
+
s6.listen(port, '::1', () => { servers = [s, s6]; if (opts.signal?.aborted) {
|
|
113
|
+
closeAll();
|
|
114
|
+
return;
|
|
115
|
+
} void opts.onBound?.(port, nonce); });
|
|
116
|
+
});
|
|
66
117
|
}
|
|
67
118
|
tryPort(opts.ports);
|
|
68
119
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-oauth.js","sourceRoot":"","sources":["../../src/lib/cli-oauth.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAO1C,MAAM,UAAU,eAAe,CAAC,
|
|
1
|
+
{"version":3,"file":"cli-oauth.js","sourceRoot":"","sources":["../../src/lib/cli-oauth.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/config.d.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { type WrittenConfig } from './safe-config-write.js';
|
|
2
2
|
import { type StoredProviderId } from './llm-providers.js';
|
|
3
3
|
import type { StoredScope } from './scope-values.js';
|
|
4
|
-
|
|
4
|
+
import { type TeamDestinationName } from './destination-name.js';
|
|
5
|
+
export type BuiltinEnv = 'local' | 'preview' | 'prod';
|
|
6
|
+
/** A builtin, or the name of a team destination saved by `align join`. */
|
|
7
|
+
export type EnvName = BuiltinEnv | TeamDestinationName;
|
|
5
8
|
export interface EnvironmentConfig {
|
|
6
9
|
gatewayUrl: string;
|
|
7
10
|
authToken: string | null;
|
|
@@ -9,6 +12,13 @@ export interface EnvironmentConfig {
|
|
|
9
12
|
ngrokUrl?: string;
|
|
10
13
|
mode: 'demo' | 'auth' | 'local-embedded';
|
|
11
14
|
localDbPath?: string;
|
|
15
|
+
/** 'team' for a destination saved by `align join`; absent for the three builtins. */
|
|
16
|
+
kind?: 'builtin' | 'team';
|
|
17
|
+
/** Team destinations: the web app the gateway named at join time (never guessed from the gateway URL). */
|
|
18
|
+
appUrl?: string;
|
|
19
|
+
/** Team destinations: the org name the SERVER claimed. Display only, never an identity. */
|
|
20
|
+
orgNameClaimed?: string;
|
|
21
|
+
joinedAt?: string;
|
|
12
22
|
}
|
|
13
23
|
/** The gateway URL an environment uses when nothing overrides it (ALIGN_GATEWAY_URL, a saved value). */
|
|
14
24
|
export declare function defaultGatewayUrlFor(env: string): string;
|
|
@@ -77,11 +87,34 @@ export declare function savedLlmConfig(config: {
|
|
|
77
87
|
provider?: string;
|
|
78
88
|
model?: string;
|
|
79
89
|
};
|
|
90
|
+
export type LeadPromptOutcome = 'declined' | 'submitted' | 'skipped';
|
|
91
|
+
export interface LeadState {
|
|
92
|
+
shownAt?: string;
|
|
93
|
+
version?: string;
|
|
94
|
+
outcome?: LeadPromptOutcome;
|
|
95
|
+
submittedAt?: string;
|
|
96
|
+
}
|
|
80
97
|
export declare function createConfigStore(): {
|
|
81
98
|
getEnvironment(env: EnvName): EnvironmentConfig;
|
|
99
|
+
/** One write: a crash cannot leave a token saved without the gateway it belongs to. */
|
|
100
|
+
saveTeamDestination(name: string, d: {
|
|
101
|
+
gatewayUrl: string;
|
|
102
|
+
appUrl: string;
|
|
103
|
+
authToken: string;
|
|
104
|
+
tenantId: string | null;
|
|
105
|
+
orgNameClaimed?: string;
|
|
106
|
+
}, now?: Date): void;
|
|
107
|
+
/** Logout for a team destination: the entry stays so `align login --env <name>` can renew it. */
|
|
108
|
+
clearTeamToken(name: string): void;
|
|
109
|
+
getShareDestination(): string | null;
|
|
110
|
+
setShareDestination(name: string): void;
|
|
111
|
+
clearShareDestination(): void;
|
|
82
112
|
setAuthToken(env: EnvName, token: string): void;
|
|
83
113
|
setTenantId(env: EnvName, tenantId: string): void;
|
|
84
114
|
setNgrokUrl(url: string): void;
|
|
115
|
+
/** True only for a destination `align join` saved. A builtin name is never one. */
|
|
116
|
+
hasTeamDestination(name: string): boolean;
|
|
117
|
+
listTeamDestinationNames(): string[];
|
|
85
118
|
setDefaultEnv(env: EnvName): void;
|
|
86
119
|
getDefaultEnv(): EnvName;
|
|
87
120
|
getConnectorToken(env: EnvName, connectorKey: string): string | null;
|
|
@@ -123,6 +156,9 @@ export declare function createConfigStore(): {
|
|
|
123
156
|
setAgent(agent: string): void;
|
|
124
157
|
isLaunchOff(): boolean;
|
|
125
158
|
setLaunchOff(off: boolean): void;
|
|
159
|
+
/** The saved detector choice, or undefined when none is saved (the default then applies). */
|
|
160
|
+
getDetector(): string | undefined;
|
|
161
|
+
setDetector(detector: string): void;
|
|
126
162
|
clearAgent(): void;
|
|
127
163
|
isBackgroundSyncOff(): boolean;
|
|
128
164
|
setBackgroundSyncOff(off: boolean): void;
|
|
@@ -147,6 +183,10 @@ export declare function createConfigStore(): {
|
|
|
147
183
|
} | undefined;
|
|
148
184
|
getTelemetryNoticeShownAt(): string | undefined;
|
|
149
185
|
markTelemetryNoticeShown(): void;
|
|
186
|
+
getLeadState(): LeadState;
|
|
187
|
+
markLeadPromptShown(version: string, now?: Date): void;
|
|
188
|
+
setLeadOutcome(outcome: LeadPromptOutcome, now?: Date): void;
|
|
189
|
+
clearLeadPromptShown(): void;
|
|
150
190
|
getProviderKey(provider: GuidedProviderKey): string | null;
|
|
151
191
|
setProviderKey(provider: GuidedProviderKey, key: string): void;
|
|
152
192
|
clearProviderKey(provider: GuidedProviderKey): void;
|
package/dist/lib/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAIA,OAAO,EAAsB,KAAK,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAChF,OAAO,EAAsB,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC/E,OAAO,KAAK,EAAe,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAElE,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/config.js
CHANGED
|
@@ -4,6 +4,9 @@ import fs from 'node:fs';
|
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { mergeWrittenConfig } from './safe-config-write.js';
|
|
6
6
|
import { STORABLE_PROVIDERS } from './llm-providers.js';
|
|
7
|
+
import { asDestinationName, validateDestinationName } from './destination-name.js';
|
|
8
|
+
import { assertTransport } from './destination-trust.js';
|
|
9
|
+
import { ensurePrivateDir, tightenFile } from './private-files.js';
|
|
7
10
|
const DEFAULTS = {
|
|
8
11
|
local: { gatewayUrl: 'http://localhost:8080', authToken: null, tenantId: null, mode: 'demo' },
|
|
9
12
|
preview: { gatewayUrl: 'https://api.preview.align.tech', authToken: null, tenantId: null, mode: 'auth' },
|
|
@@ -51,8 +54,10 @@ export function migrateConfigDirectory(oldDir, newDir) {
|
|
|
51
54
|
const newFile = path.join(newDir, 'config.json');
|
|
52
55
|
if (fs.existsSync(newFile) || !fs.existsSync(oldFile))
|
|
53
56
|
return;
|
|
54
|
-
|
|
57
|
+
// copyFileSync carries the old file's mode across, so the copy is tightened (it holds tokens).
|
|
58
|
+
ensurePrivateDir(newDir);
|
|
55
59
|
fs.copyFileSync(oldFile, newFile);
|
|
60
|
+
tightenFile(newFile);
|
|
56
61
|
}
|
|
57
62
|
/**
|
|
58
63
|
* Saved provider keys and the saved preference, as data for local-llm's setSavedLlmSource.
|
|
@@ -84,14 +89,38 @@ export function createConfigStore() {
|
|
|
84
89
|
// rather than ordinary config. 0600 is also what the setup copy promises the user.
|
|
85
90
|
configFileMode: 0o600,
|
|
86
91
|
});
|
|
92
|
+
// configFileMode applies when conf WRITES the file, and conf creates the directory 0755. Re-check
|
|
93
|
+
// both on every open, so a file an older version wrote 0644 is tightened before anything reads it.
|
|
94
|
+
// `path` is absent only on a test double of conf.
|
|
95
|
+
if (typeof store.path === 'string') {
|
|
96
|
+
ensurePrivateDir(path.dirname(store.path));
|
|
97
|
+
tightenFile(store.path);
|
|
98
|
+
}
|
|
87
99
|
const getEnvs = () => store.get('environments');
|
|
88
100
|
const getTokens = () => store.get('connectorTokens');
|
|
101
|
+
// A team destination is a saved entry of kind team under a VALID name. The name check is what keeps a hand-edited key
|
|
102
|
+
// such as `a;b` from ever reaching a command line this CLI prints (envFlag) or a `--env` an agent config stores.
|
|
103
|
+
const isTeam = (name) => Object.hasOwn(getEnvs(), name) && getEnvs()[name]?.kind === 'team' && validateDestinationName(name) === null;
|
|
89
104
|
// Extra fields (an Atlassian email, a GitLab domain) live beside the token under a `field:`
|
|
90
105
|
// segment. The OAuth path already writes `<env>:<key>:cloudId` and `:siteBase` in this same
|
|
91
106
|
// map, and the segment is what stops a connector field of either name colliding with them.
|
|
92
107
|
const fieldPrefix = (env, connectorKey) => `${env}:${connectorKey}:field:`;
|
|
93
108
|
return {
|
|
94
109
|
getEnvironment(env) {
|
|
110
|
+
// A team destination is exactly what `align join` stored. No builtin defaults, and none of
|
|
111
|
+
// the ALIGN_* overrides below: those exist for CI and self-hosts of the builtins, and on a
|
|
112
|
+
// named destination they would let the shell redirect a saved token to another server (S4, S5).
|
|
113
|
+
if (!Object.hasOwn(DEFAULTS, env)) {
|
|
114
|
+
const saved = isTeam(env) ? getEnvs()[env] : undefined;
|
|
115
|
+
if (saved === undefined)
|
|
116
|
+
throw new Error(`Unknown environment "${String(env).slice(0, 40)}"`);
|
|
117
|
+
// The file is a person's to edit: the transport rule is re-checked on READ, so a hand-written plain-http gateway is unusable, not trusted.
|
|
118
|
+
if (saved.gatewayUrl)
|
|
119
|
+
assertTransport(saved.gatewayUrl);
|
|
120
|
+
if (saved.appUrl)
|
|
121
|
+
assertTransport(saved.appUrl);
|
|
122
|
+
return { authToken: null, tenantId: null, mode: 'auth', ...saved };
|
|
123
|
+
}
|
|
95
124
|
const base = { ...DEFAULTS[env], ...(getEnvs()[env] ?? {}) };
|
|
96
125
|
// Env var overrides - useful for CI and self-hosted deployments
|
|
97
126
|
if (!base.authToken && process.env['ALIGN_TOKEN']) {
|
|
@@ -105,6 +134,41 @@ export function createConfigStore() {
|
|
|
105
134
|
}
|
|
106
135
|
return base;
|
|
107
136
|
},
|
|
137
|
+
/** One write: a crash cannot leave a token saved without the gateway it belongs to. */
|
|
138
|
+
saveTeamDestination(name, d, now = new Date()) {
|
|
139
|
+
const valid = asDestinationName(name);
|
|
140
|
+
if (!d.authToken)
|
|
141
|
+
throw new Error('saveTeamDestination: needs a non-empty token');
|
|
142
|
+
const entry = {
|
|
143
|
+
kind: 'team',
|
|
144
|
+
mode: 'auth',
|
|
145
|
+
gatewayUrl: assertTransport(d.gatewayUrl),
|
|
146
|
+
appUrl: assertTransport(d.appUrl),
|
|
147
|
+
authToken: d.authToken,
|
|
148
|
+
tenantId: d.tenantId,
|
|
149
|
+
joinedAt: now.toISOString(),
|
|
150
|
+
...(d.orgNameClaimed === undefined ? {} : { orgNameClaimed: d.orgNameClaimed }),
|
|
151
|
+
};
|
|
152
|
+
store.set('environments', { ...getEnvs(), [valid]: entry });
|
|
153
|
+
},
|
|
154
|
+
/** Logout for a team destination: the entry stays so `align login --env <name>` can renew it. */
|
|
155
|
+
clearTeamToken(name) {
|
|
156
|
+
const envs = getEnvs();
|
|
157
|
+
if (!isTeam(name))
|
|
158
|
+
return;
|
|
159
|
+
store.set('environments', { ...envs, [name]: { ...envs[name], authToken: null } });
|
|
160
|
+
},
|
|
161
|
+
getShareDestination() {
|
|
162
|
+
const n = store.get('shareDestination');
|
|
163
|
+
return typeof n === 'string' && isTeam(n) ? n : null;
|
|
164
|
+
},
|
|
165
|
+
setShareDestination(name) {
|
|
166
|
+
if (!isTeam(name)) {
|
|
167
|
+
throw new Error(`"${name.slice(0, 40)}" is not a saved team destination`);
|
|
168
|
+
}
|
|
169
|
+
store.set('shareDestination', name);
|
|
170
|
+
},
|
|
171
|
+
clearShareDestination() { store.delete('shareDestination'); },
|
|
108
172
|
setAuthToken(env, token) {
|
|
109
173
|
const envs = getEnvs();
|
|
110
174
|
store.set('environments', { ...envs, [env]: { ...(envs[env] ?? {}), authToken: token } });
|
|
@@ -117,6 +181,13 @@ export function createConfigStore() {
|
|
|
117
181
|
const envs = getEnvs();
|
|
118
182
|
store.set('environments', { ...envs, local: { ...(envs['local'] ?? {}), ngrokUrl: url } });
|
|
119
183
|
},
|
|
184
|
+
/** True only for a destination `align join` saved. A builtin name is never one. */
|
|
185
|
+
hasTeamDestination(name) {
|
|
186
|
+
return isTeam(name);
|
|
187
|
+
},
|
|
188
|
+
listTeamDestinationNames() {
|
|
189
|
+
return Object.keys(getEnvs()).filter(isTeam).sort();
|
|
190
|
+
},
|
|
120
191
|
setDefaultEnv(env) { store.set('defaultEnv', env); },
|
|
121
192
|
getDefaultEnv() { return store.get('defaultEnv'); },
|
|
122
193
|
getConnectorToken(env, connectorKey) {
|
|
@@ -268,6 +339,8 @@ export function createConfigStore() {
|
|
|
268
339
|
const envs = getEnvs();
|
|
269
340
|
const { [env]: _, ...rest } = envs;
|
|
270
341
|
store.set('environments', rest);
|
|
342
|
+
if (store.get('shareDestination') === env)
|
|
343
|
+
store.delete('shareDestination');
|
|
271
344
|
},
|
|
272
345
|
// ALI-618: global to the machine's install, not per-environment - unlike authToken/tenantId,
|
|
273
346
|
// an anonymous local-mode user has no account for either to belong to. Generated once and
|
|
@@ -301,6 +374,13 @@ export function createConfigStore() {
|
|
|
301
374
|
else
|
|
302
375
|
store.delete('launchOff');
|
|
303
376
|
},
|
|
377
|
+
/** The saved detector choice, or undefined when none is saved (the default then applies). */
|
|
378
|
+
getDetector() {
|
|
379
|
+
return store.get('detector');
|
|
380
|
+
},
|
|
381
|
+
setDetector(detector) {
|
|
382
|
+
store.set('detector', detector);
|
|
383
|
+
},
|
|
304
384
|
clearAgent() {
|
|
305
385
|
store.delete('agent');
|
|
306
386
|
},
|
|
@@ -399,6 +479,31 @@ export function createConfigStore() {
|
|
|
399
479
|
if (!store.get('telemetryNoticeShownAt'))
|
|
400
480
|
store.set('telemetryNoticeShownAt', new Date().toISOString());
|
|
401
481
|
},
|
|
482
|
+
// The optional work-email prompt at the share moment (lib/lead-prompt.ts). NOT telemetry, so its
|
|
483
|
+
// state is its own keys. Only timestamps and an outcome word live here, never the address.
|
|
484
|
+
getLeadState() {
|
|
485
|
+
return {
|
|
486
|
+
shownAt: store.get('leadPromptShownAt'),
|
|
487
|
+
version: store.get('leadPromptVersion'),
|
|
488
|
+
outcome: store.get('leadPromptOutcome'),
|
|
489
|
+
submittedAt: store.get('leadEmailSubmittedAt'),
|
|
490
|
+
};
|
|
491
|
+
},
|
|
492
|
+
markLeadPromptShown(version, now = new Date()) {
|
|
493
|
+
store.set('leadPromptShownAt', now.toISOString());
|
|
494
|
+
store.set('leadPromptVersion', version);
|
|
495
|
+
store.set('leadPromptOutcome', 'skipped');
|
|
496
|
+
},
|
|
497
|
+
setLeadOutcome(outcome, now = new Date()) {
|
|
498
|
+
store.set('leadPromptOutcome', outcome);
|
|
499
|
+
if (outcome === 'submitted')
|
|
500
|
+
store.set('leadEmailSubmittedAt', now.toISOString());
|
|
501
|
+
},
|
|
502
|
+
clearLeadPromptShown() {
|
|
503
|
+
store.delete('leadPromptShownAt');
|
|
504
|
+
store.delete('leadPromptVersion');
|
|
505
|
+
store.delete('leadPromptOutcome');
|
|
506
|
+
},
|
|
402
507
|
// ALI-1284: the key `align setup`'s guided free-tier path collected, persisted the same
|
|
403
508
|
// way a local connector's read-only token already is (saveConnectorFields above) - one
|
|
404
509
|
// paste, reused on every later invocation. savedLlmConfig hands it to local-llm as data;
|