@veilio-inc/cli 0.2.0 → 0.3.1

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  # Veilio Community License
2
2
 
3
- _Version 1.0 · Effective 2026-08-08_
3
+ _Version 1.1 · Effective 2026-09-25_
4
4
 
5
5
  **Copyright © 2026 Veilio**
6
6
 
@@ -10,7 +10,8 @@ _Version 1.0 · Effective 2026-08-08_
10
10
  > The one thing you may not do without written permission is sell Veilio itself:
11
11
  > reselling it, white-labeling it, or running it as a hosted service for other
12
12
  > people. Contributions are welcome. For a commercial or redistribution license,
13
- > email `hello@veilio.dev`.
13
+ > email `hello@veilio.dev`. Veilio is not licensed for use in or from Russia or
14
+ > Belarus, or by sanctioned persons (Section 5A).
14
15
 
15
16
  ---
16
17
 
@@ -48,11 +49,17 @@ For the purposes of this License:
48
49
 
49
50
  **"Competing Product"** means a commercially offered product or service whose primary purpose and core functionality substantially overlap with the Software or Cloud Edition.
50
51
 
52
+ **"Applicable Sanctions"** means any economic, financial, trade or other restrictive measures applicable to Veilio or the relevant transaction under the laws of the European Union or the Republic of Poland, including applicable asset-freezing and prohibition-on-making-available measures, and any other sanctions or trade restrictions that are legally binding on Veilio.
53
+
54
+ **"Restricted Person"** means any natural or legal person, entity or body that: (a) is designated or otherwise subject to restrictive measures under Applicable Sanctions, (b) is directly or indirectly owned or controlled by such a person, entity or body, (c) acts on behalf of or at the direction of such a person, entity or body; or (d) is otherwise a person to whom Veilio is prohibited under Applicable Sanctions from providing the Software, funds or economic resources.
55
+
56
+ **"Restricted Territory"** means the Russian Federation and the Republic of Belarus.
57
+
51
58
  ---
52
59
 
53
60
  ## 3. Permissions
54
61
 
55
- Subject to the restrictions in this License, you are granted a worldwide, royalty-free, non-exclusive license to:
62
+ Subject to the restrictions in this License, including Section 5A, you are granted a worldwide, royalty-free, non-exclusive license to:
56
63
 
57
64
  * use the Software for personal purposes;
58
65
  * use the Software for internal commercial purposes;
@@ -114,6 +121,24 @@ Requests for written permission may be sent to `hello@veilio.dev`.
114
121
 
115
122
  ---
116
123
 
124
+ ## 5A. Restricted Territories and Sanctions
125
+
126
+ **5A.1.** No license or other right to the Software is granted to:
127
+
128
+ * persons or entities incorporated, registered, established or headquartered in a Restricted Territory;
129
+ * natural persons whose principal place of business or ordinary residence is in a Restricted Territory; or
130
+ * Restricted Persons.
131
+
132
+ **5A.2.** You must not access or use the Software from a Restricted Territory, make the Software available to any person located in a Restricted Territory, or use the Software directly or indirectly for the benefit of a Restricted Person or a person or entity incorporated, registered, established or headquartered in a Restricted Territory.
133
+
134
+ **5A.3.** By using the Software, you represent and warrant, both when you first use it and throughout your use of it, that you are not a Restricted Person and do not fall within any of the territorial restrictions set out in this Section.
135
+
136
+ **5A.4.** You must not use an intermediary, affiliate, nominee, proxy, VPN or other arrangement for the purpose of circumventing the restrictions set out in this Section or Applicable Sanctions.
137
+
138
+ **5A.5.** Any breach of this Section is a material violation of this License and terminates your rights under it (Section 14). Veilio does not grant written permission for exceptions to this Section.
139
+
140
+ ---
141
+
117
142
  ## 6. Cloud Edition
118
143
 
119
144
  The Cloud Edition is the official commercial hosted offering of the project.
@@ -218,7 +243,7 @@ TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL THE AUTHORS
218
243
 
219
244
  ## 14. Termination
220
245
 
221
- Your rights under this License terminate automatically if you materially violate its terms.
246
+ Your rights under this License terminate automatically if you materially violate its terms. Any breach of Section 5A is a material violation.
222
247
 
223
248
  Upon termination, you must cease the activities that are prohibited by this License.
224
249
 
@@ -244,5 +269,5 @@ Each version will be identified by a version number. Unless explicitly stated ot
244
269
 
245
270
  **Project:** Veilio
246
271
  **Copyright:** © 2026 Veilio
247
- **License:** Veilio Community License, Version 1.0
272
+ **License:** Veilio Community License, Version 1.1
248
273
  **Contact:** `hello@veilio.dev`
package/README.md CHANGED
@@ -8,6 +8,8 @@ pbpaste | veilio restore # bring the answer back
8
8
  git diff --cached | veilio scan # refuse to commit a live key
9
9
  ```
10
10
 
11
+ Full guide - terminal, Cloud sign-in, and connecting AI assistants (Claude Code, Claude Desktop, Xcode, Cursor, VS Code): [docs/USING-THE-CLI-AND-MCP.md](../../docs/USING-THE-CLI-AND-MCP.md).
12
+
11
13
  ## Install
12
14
 
13
15
  ```bash
@@ -32,17 +34,15 @@ behavior; it only unlocks the four commands below that name Cloud explicitly.
32
34
 
33
35
  ## Cloud sync (Individual plan and above)
34
36
 
35
- > **None of this is in `0.1.0`, which is what npm currently has.** These
36
- > commands are merged here and ship with the next release; until then they run
37
- > from a clone — `npm run build:packages`, then
38
- > `node packages/cli/dist/index.js --help`.
39
-
40
37
  ```bash
41
- veilio login # prompts for email/password; --instance for self-hosted
38
+ veilio login # email, password, and the authentication code if 2FA is on
42
39
  veilio whoami # who you're signed in as, no request made
43
40
  veilio maps list # ids, scope and symbol counts for everything in Cloud
44
41
  veilio maps pull <id> # decrypt locally, write second — never a partial write
45
42
  veilio maps push <name> # upload the local map under a new Cloud name
43
+ veilio team unlock # open the team key with your vault passphrase (kept 7 days)
44
+ veilio team lock # remove the unlocked team key from this machine
45
+ veilio rules pull # fetch your custom rules; scrub then applies them offline
46
46
  veilio logout # revokes server-side, then removes the local credential
47
47
  ```
48
48
 
@@ -53,10 +53,16 @@ accepted the sign-in. `0600` is the floor, not the final answer — the OS
53
53
  keychain is a stronger option and a planned follow-up. A personal map is
54
54
  zero-knowledge: pulling or pushing one prompts for the vault passphrase and
55
55
  derives the key here, on your machine — the passphrase and the key never
56
- leave it. A team map arrives already open, because the server can read those
57
- (stated in the privacy policy) and there is nothing local left to decrypt.
56
+ leave it. A team map is sealed under the team key, which the server cannot
57
+ read either; `veilio team unlock` opens it here with your vault passphrase.
58
+
59
+ Custom rules (whitelist and replace, set in the web app) are applied by
60
+ `scrub` from a local copy that `veilio rules pull` writes to
61
+ `~/.veilio/rules.json` (`0600`). `scrub` never fetches them itself - it stays
62
+ offline - and says on every run how many rules it applied and how old the copy
63
+ is. Pull again after the rules change; `logout` removes the copy.
58
64
 
59
- Every one of these six is a client of `GET /api/maps`, `GET /api/maps/:id` and
65
+ The map commands are clients of `GET /api/maps`, `GET /api/maps/:id` and
60
66
  `POST /api/maps` — the exact same routes the browser uses, behind the exact
61
67
  same entitlement check. There is no CLI-shaped API and nothing here can reach
62
68
  a plan feature the web app couldn't.
@@ -113,13 +119,14 @@ Redacted credentials are **not** in the map. `restore` cannot bring them back, b
113
119
  sarif: veilio.sarif # optional: upload to code scanning
114
120
  ```
115
121
 
116
- **This example does not work yet, and needs two things that do not exist.** The
117
- `@v0.1.0` ref is a git tag on this repository — the only tags here are
118
- `engine-v*`, cut by semantic-release for the engine — and the Action's own script
119
- runs `npx --yes @veilio-inc/cli@<version>`, which needs the package on npm.
120
- Publishing supplies the second; the first is a tag someone has to cut, and note
121
- that `v*.*.*` is also what triggers the Community Edition release workflow, so
122
- the two are not independent.
122
+ **This example does not work yet, and needs a tag that does not exist.** The
123
+ `@v0.1.0` ref is a git tag on this repository, and the tags here are `engine-v*`
124
+ (cut by semantic-release for the engine) and `@veilio-inc/cli@*` /
125
+ `@veilio-inc/mcp@*` (cut by Changesets when the tools release) — neither shape
126
+ matches. The Action's own script runs `npx --yes @veilio-inc/cli@<version>`,
127
+ which is satisfied now that the CLI is published; what is left is a `v*.*.*` tag
128
+ someone has to cut, and note that `v*.*.*` is also what triggers the Community
129
+ Edition release workflow, so the two are not independent.
123
130
 
124
131
  Scans the **pull-request diff** by default, not the whole tree. A repo adopting
125
132
  this mid-life almost always has a historical finding somewhere; blocking every PR
package/dist/args.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { type LanguageOption } from '@veilio-inc/engine';
2
2
  import type { SecretPolicy } from '@veilio-inc/engine';
3
- export type Command = 'scrub' | 'restore' | 'scan' | 'map' | 'login' | 'logout' | 'whoami' | 'maps' | 'help' | 'version';
3
+ export type Command = 'scrub' | 'restore' | 'scan' | 'map' | 'login' | 'logout' | 'whoami' | 'maps' | 'team' | 'rules' | 'help' | 'version';
4
4
  export interface ParsedArgs {
5
5
  command: Command;
6
6
  /** Positional file paths. Empty means read stdin (or, for `scan`, error). */
@@ -32,6 +32,16 @@ export interface ParsedArgs {
32
32
  * visibly separate from the offline one.
33
33
  */
34
34
  mapsAction: 'list' | 'pull' | 'push' | null;
35
+ /**
36
+ * `team unlock` / `team lock`.
37
+ *
38
+ * A subcommand for the same reason `maps` is one: `veilio unlock` alone would
39
+ * not say what it unlocks, and what it unlocks is specifically the team's
40
+ * keys rather than the account or the local store.
41
+ */
42
+ teamAction: 'unlock' | 'lock' | null;
43
+ /** `rules pull`. */
44
+ rulesAction: 'pull' | null;
35
45
  /**
36
46
  * Base URL of the Veilio instance to sign in to. Null means the public Cloud.
37
47
  *
@@ -1 +1 @@
1
- {"version":3,"file":"args.d.ts","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"AAIA,OAAO,EAA4B,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAClF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEtD,MAAM,MAAM,OAAO,GACjB,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;AAEpG,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAA;IAChB,6EAA6E;IAC7E,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,QAAQ,EAAE,cAAc,CAAA;IACxB,OAAO,EAAE,YAAY,CAAA;IACrB,qEAAqE;IACrE,QAAQ,EAAE,OAAO,CAAA;IACjB,uCAAuC;IACvC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,sCAAsC;IACtC,IAAI,EAAE,OAAO,CAAA;IACb,qDAAqD;IACrD,KAAK,EAAE,OAAO,CAAA;IACd,qCAAqC;IACrC,KAAK,EAAE,OAAO,CAAA;IACd,6DAA6D;IAC7D,MAAM,EAAE,OAAO,CAAA;IACf,wCAAwC;IACxC,QAAQ,EAAE,OAAO,CAAA;IACjB,iEAAiE;IACjE,KAAK,EAAE,OAAO,CAAA;IACd;;;;;;;OAOG;IACH,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IAE3C;;;;;;OAMG;IACH,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CACxB;AAED,qBAAa,UAAW,SAAQ,KAAK;CAAG;AAexC;;;;;GAKG;AACH,eAAO,MAAM,cAAc,cAA0D,CAAA;AAWrF,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,UAAU,CAkI7D"}
1
+ {"version":3,"file":"args.d.ts","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"AAIA,OAAO,EAA4B,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAClF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEtD,MAAM,MAAM,OAAO,GACf,OAAO,GACP,SAAS,GACT,MAAM,GACN,KAAK,GACL,OAAO,GACP,QAAQ,GACR,QAAQ,GACR,MAAM,GACN,MAAM,GACN,OAAO,GACP,MAAM,GACN,SAAS,CAAA;AAEb,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAA;IAChB,6EAA6E;IAC7E,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,QAAQ,EAAE,cAAc,CAAA;IACxB,OAAO,EAAE,YAAY,CAAA;IACrB,qEAAqE;IACrE,QAAQ,EAAE,OAAO,CAAA;IACjB,uCAAuC;IACvC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,sCAAsC;IACtC,IAAI,EAAE,OAAO,CAAA;IACb,qDAAqD;IACrD,KAAK,EAAE,OAAO,CAAA;IACd,qCAAqC;IACrC,KAAK,EAAE,OAAO,CAAA;IACd,6DAA6D;IAC7D,MAAM,EAAE,OAAO,CAAA;IACf,wCAAwC;IACxC,QAAQ,EAAE,OAAO,CAAA;IACjB,iEAAiE;IACjE,KAAK,EAAE,OAAO,CAAA;IACd;;;;;;;OAOG;IACH,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IAE3C;;;;;;OAMG;IACH,UAAU,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,CAAA;IACpC,oBAAoB;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAE1B;;;;;;OAMG;IACH,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CACxB;AAED,qBAAa,UAAW,SAAQ,KAAK;CAAG;AAiBxC;;;;;GAKG;AACH,eAAO,MAAM,cAAc,cAOzB,CAAA;AAWF,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,UAAU,CA0J7D"}
package/dist/args.js CHANGED
@@ -13,6 +13,8 @@ const COMMANDS = new Set([
13
13
  'logout',
14
14
  'whoami',
15
15
  'maps',
16
+ 'team',
17
+ 'rules',
16
18
  'help',
17
19
  'version',
18
20
  ]);
@@ -22,7 +24,14 @@ const COMMANDS = new Set([
22
24
  * command without deciding which side of the line it falls on is a compile
23
25
  * error rather than an accident.
24
26
  */
25
- export const CLOUD_COMMANDS = new Set(['login', 'logout', 'whoami', 'maps']);
27
+ export const CLOUD_COMMANDS = new Set([
28
+ 'login',
29
+ 'logout',
30
+ 'whoami',
31
+ 'maps',
32
+ 'team',
33
+ 'rules',
34
+ ]);
26
35
  const SECRET_POLICIES = new Set(['redact', 'warn', 'off']);
27
36
  const LANGUAGE_VALUES = new Set([...LANGUAGES, 'auto']);
28
37
  function requireValue(flag, value) {
@@ -47,6 +56,8 @@ export function parseArgs(argv) {
47
56
  force: false,
48
57
  instance: null,
49
58
  mapsAction: null,
59
+ teamAction: null,
60
+ rulesAction: null,
50
61
  };
51
62
  if (argv.length === 0)
52
63
  return parsed;
@@ -70,6 +81,26 @@ export function parseArgs(argv) {
70
81
  i = 2;
71
82
  }
72
83
  }
84
+ if (parsed.command === 'team') {
85
+ const verb = argv[1];
86
+ if (verb !== undefined && !verb.startsWith('-')) {
87
+ if (verb !== 'unlock' && verb !== 'lock') {
88
+ throw new UsageError(`unknown team action "${verb}" — expected unlock or lock`);
89
+ }
90
+ parsed.teamAction = verb;
91
+ i = 2;
92
+ }
93
+ }
94
+ if (parsed.command === 'rules') {
95
+ const verb = argv[1];
96
+ if (verb !== undefined && !verb.startsWith('-')) {
97
+ if (verb !== 'pull') {
98
+ throw new UsageError(`unknown rules action "${verb}" — expected pull`);
99
+ }
100
+ parsed.rulesAction = verb;
101
+ i = 2;
102
+ }
103
+ }
73
104
  }
74
105
  for (; i < argv.length; i++) {
75
106
  const arg = argv[i];
package/dist/args.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"args.js","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"args.js","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { type TeamLayer } from '@veilio-inc/engine';
1
2
  import { type Io } from './commands.js';
2
3
  /**
3
4
  * Sign in, and store the credential only if the account can actually use it.
@@ -67,4 +68,33 @@ export declare function runMapsPull(id: string | null, mapPath: string, io: Io,
67
68
  }): Promise<number>;
68
69
  /** Upload the local map. Same endpoint, same quotas, same validation. */
69
70
  export declare function runMapsPush(name: string | null, mapPath: string, io: Io): Promise<number>;
71
+ /**
72
+ * Fetch the account's custom rules so `veilio scrub` can apply them offline.
73
+ *
74
+ * Merged here, in the web app's order, so every later scrub applies exactly
75
+ * what the browser would. A plan without custom rules REMOVES any cache left
76
+ * from before: rules the account can no longer use must not go on shaping
77
+ * its output. Any other failure keeps the cache and says so.
78
+ */
79
+ export declare function runRulesPull(io: Io): Promise<number>;
80
+ /**
81
+ * Unlock this team's keys for processes that cannot ask for a passphrase.
82
+ *
83
+ * The MCP server starts inside a coding agent with no terminal attached, so the
84
+ * keys it needs have to be put on disk by a run like this one, where a person
85
+ * is present to type the passphrase. See `team-unlock.ts` for what is stored
86
+ * and why it is the team key rather than the vault key.
87
+ */
88
+ export declare function runTeamUnlock(io: Io, days?: number): Promise<number>;
89
+ /** Remove the unlocked team keys. */
90
+ export declare function runTeamLock(io: Io): number;
91
+ /**
92
+ * The team's maps for `veilio restore` (spec 028), handed to the local command
93
+ * as a callback so that command stays unlinked from the network. Signed out:
94
+ * no request, no layer - a local restore, as before.
95
+ */
96
+ export declare function teamLayerFor(home: string | undefined, missing: readonly string[]): Promise<{
97
+ team: TeamLayer | null;
98
+ note: string | null;
99
+ }>;
70
100
  //# sourceMappingURL=cloud-commands.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cloud-commands.d.ts","sourceRoot":"","sources":["../src/cloud-commands.ts"],"names":[],"mappings":"AA+BA,OAAO,EAAuB,KAAK,EAAE,EAAE,MAAM,eAAe,CAAA;AAW5D;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA+C/E;AAED;;;;;;;;GAQG;AACH,wBAAsB,SAAS,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAgDvD;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,EAAE,GAAG,MAAM,CAQxC;AAyDD;;;;;;GAMG;AACH,wBAAsB,WAAW,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAqBzD;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,WAAW,CAC/B,EAAE,EAAE,MAAM,GAAG,IAAI,EACjB,OAAO,EAAE,MAAM,EACf,EAAE,EAAE,EAAE,EACN,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAChC,OAAO,CAAC,MAAM,CAAC,CAgGjB;AAED,yEAAyE;AACzE,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAgE/F"}
1
+ {"version":3,"file":"cloud-commands.d.ts","sourceRoot":"","sources":["../src/cloud-commands.ts"],"names":[],"mappings":"AAuBA,OAAO,EAeL,KAAK,SAAS,EACf,MAAM,oBAAoB,CAAA;AAa3B,OAAO,EAAuB,KAAK,EAAE,EAAE,MAAM,eAAe,CAAA;AAc5D;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA2E/E;AAED;;;;;;;;GAQG;AACH,wBAAsB,SAAS,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAgFvD;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,EAAE,GAAG,MAAM,CAQxC;AAyDD;;;;;;GAMG;AACH,wBAAsB,WAAW,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAqBzD;AA+CD;;;;;;;;;;;GAWG;AACH,wBAAsB,WAAW,CAC/B,EAAE,EAAE,MAAM,GAAG,IAAI,EACjB,OAAO,EAAE,MAAM,EACf,EAAE,EAAE,EAAE,EACN,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAChC,OAAO,CAAC,MAAM,CAAC,CA+GjB;AAED,yEAAyE;AACzE,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAgE/F;AAcD;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAqC1D;AAID;;;;;;;GAOG;AACH,wBAAsB,aAAa,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAmH1E;AAED,qCAAqC;AACrC,wBAAgB,WAAW,CAAC,EAAE,EAAE,EAAE,GAAG,MAAM,CAgB1C;AAID;;;;GAIG;AACH,wBAAsB,YAAY,CAChC,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,OAAO,EAAE,SAAS,MAAM,EAAE,GACzB,OAAO,CAAC;IAAE,IAAI,EAAE,SAAS,GAAG,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CAO1D"}
@@ -6,10 +6,13 @@
6
6
  // with no account touches nothing (FR-002). Putting these here is what keeps
7
7
  // that walk meaningful instead of something to be deleted the moment it becomes
8
8
  // inconvenient.
9
- import { CloudError, createMap, getMap, getVault, listMaps, request, } from './cloud.js';
10
- import { checkVaultVerifier, decryptMapFromVault, deriveVaultKey, encryptMapForVault, fromBase64, parseVaultEnvelope, } from '@veilio-inc/engine';
9
+ import { CloudError, createMap, getMap, getVault, getUserKeys, getTeamKeyWraps, listMaps, listRules, request, } from './cloud.js';
10
+ import { checkVaultVerifier, decryptMapFromVault, deriveVaultKey, unwrapPrivateKey, unwrapTeamKey, exportTeamKey, encryptMapForVault, fromBase64, parseVaultEnvelope, importTeamKey, decryptTeamMapWithAny, } from '@veilio-inc/engine';
11
11
  import { loadMap, loadRemote, saveMap } from './store.js';
12
+ import { resolveTeamNamespace, teamLayerNote } from './team-namespace.js';
13
+ import { readTeamUnlock, removeTeamUnlock, writeTeamUnlock, teamUnlockPath, expiryFrom, } from './team-unlock.js';
12
14
  import { readCredential, removeCredential, writeCredential } from './credential.js';
15
+ import { mergeRules, removeRules, rulesPath, writeRules } from './rules.js';
13
16
  import { EXIT_ERROR, EXIT_OK } from './commands.js';
14
17
  import { DEFAULT_INSTANCE } from './cloud.js';
15
18
  /** The endpoint a sign-in is checked against. See `runLogin`. */
@@ -61,6 +64,32 @@ export async function runLogin(instance, io) {
61
64
  catch (err) {
62
65
  return reportLoginFailure(err, io);
63
66
  }
67
+ // A second factor. The token that came back is a challenge, not a session:
68
+ // storing it made every later command fail, and the failure read as a wrong
69
+ // password (found on staging, 2026-09-26). Ask for the code and complete the
70
+ // sign-in the way the web app does.
71
+ if (session.secondFactorRequired === true) {
72
+ const code = (await requirePrompt(io, 'Authentication code (or a recovery code): ')).trim();
73
+ if (code === '') {
74
+ io.stderr('veilio: no authentication code given\n');
75
+ return EXIT_ERROR;
76
+ }
77
+ try {
78
+ session = await request('/api/auth/2fa/verify', {
79
+ credential: { token: session.token, account, instance: base },
80
+ method: 'POST',
81
+ body: { code },
82
+ });
83
+ }
84
+ catch (err) {
85
+ if (err instanceof CloudError && err.kind === 'unauthenticated') {
86
+ io.stderr('veilio: that authentication code was not accepted, or it expired. ' +
87
+ 'Run `veilio login` again with a fresh code.\n');
88
+ return EXIT_ERROR;
89
+ }
90
+ return reportLoginFailure(err, io);
91
+ }
92
+ }
64
93
  if (typeof session.token !== 'string' || session.token === '') {
65
94
  // A 200 with no token is not a sign-in. Writing an empty credential here
66
95
  // would produce a "signed in" state that fails on every use.
@@ -104,7 +133,14 @@ export async function runLogout(io) {
104
133
  if (err instanceof CloudError && err.kind === 'unauthenticated') {
105
134
  // Already revoked, or expired. The server-side state is what logout
106
135
  // wanted, so finishing the job locally is correct rather than an error.
136
+ //
137
+ // "Locally" has to include the team keys. They outlive the session that
138
+ // fetched them — a revoked token stops working, an unlocked team key goes
139
+ // on opening the team's maps — so leaving them here would be the one
140
+ // branch where signing out quietly kept the more dangerous half.
107
141
  try {
142
+ removeTeamUnlock(io.home);
143
+ removeRules(io.home);
108
144
  removeCredential(io.home);
109
145
  }
110
146
  catch (removeErr) {
@@ -121,6 +157,28 @@ export async function runLogout(io) {
121
157
  'To end the session now, sign out from the web app.\n');
122
158
  return EXIT_ERROR;
123
159
  }
160
+ // Before the credential, because this is key material rather than a token
161
+ // the server has already revoked. Signing out while the team's keys stay
162
+ // readable on disk is exactly the gap between what a person believes they
163
+ // gave up and what is still there.
164
+ try {
165
+ removeTeamUnlock(io.home);
166
+ }
167
+ catch (err) {
168
+ io.stderr(`veilio: the session was revoked, but the unlocked team keys could not be removed ` +
169
+ `(${err instanceof Error ? err.message : String(err)}). Delete ${teamUnlockPath(io.home)} by hand.\n`);
170
+ return EXIT_ERROR;
171
+ }
172
+ // The rules are the account's too, and a whitelist among them keeps names
173
+ // readable: they go with the session rather than outliving it.
174
+ try {
175
+ removeRules(io.home);
176
+ }
177
+ catch (err) {
178
+ io.stderr(`veilio: the session was revoked, but the cached custom rules could not be removed ` +
179
+ `(${err instanceof Error ? err.message : String(err)}). Delete ${rulesPath(io.home)} by hand.\n`);
180
+ return EXIT_ERROR;
181
+ }
124
182
  try {
125
183
  removeCredential(io.home);
126
184
  }
@@ -229,6 +287,41 @@ export async function runMapsList(io) {
229
287
  }
230
288
  return EXIT_OK;
231
289
  }
290
+ /**
291
+ * Open a team map with the team keys `veilio team unlock` stored.
292
+ *
293
+ * The same keys the MCP server reads, for the same reason: this machine may
294
+ * have nobody present to type a vault passphrase, and the team key - not the
295
+ * vault key - is what a team map is sealed under. Reports and returns null
296
+ * when it cannot, so the caller writes nothing.
297
+ */
298
+ async function openTeamEnvelope(credential, mapData, io) {
299
+ const unlock = readTeamUnlock({ instance: credential.instance, account: credential.account }, io.home);
300
+ if (!unlock || unlock.keys.length === 0) {
301
+ io.stderr('veilio: that is a team map, and no team key is unlocked on this machine. ' +
302
+ 'Run `veilio team unlock` first. Nothing was written.\n');
303
+ return null;
304
+ }
305
+ const keys = [];
306
+ for (const stored of unlock.keys) {
307
+ try {
308
+ keys.push({ version: stored.version, key: await importTeamKey(stored.key) });
309
+ }
310
+ catch {
311
+ // A damaged entry; the others may still open the map.
312
+ continue;
313
+ }
314
+ }
315
+ try {
316
+ return await decryptTeamMapWithAny(keys, JSON.parse(mapData));
317
+ }
318
+ catch (err) {
319
+ io.stderr(`veilio: that team map could not be opened with the unlocked team keys — ` +
320
+ `${err instanceof Error ? err.message : String(err)}. ` +
321
+ 'If the team key was rotated since, run `veilio team unlock` again. Nothing was written.\n');
322
+ return null;
323
+ }
324
+ }
232
325
  /**
233
326
  * Pull a map into the local store: decrypt FIRST, write second.
234
327
  *
@@ -256,11 +349,27 @@ export async function runMapsPull(id, mapPath, io, options = {}) {
256
349
  catch (err) {
257
350
  return reportCloudFailure(err, io);
258
351
  }
259
- // A team map arrives already open — the server can read those, and says so in
260
- // the privacy policy. Only a client envelope is ours to decrypt.
261
- let map;
352
+ // Every map is an envelope the server cannot open: a personal map under the
353
+ // vault key, a team map under the team key. Which one is written on the
354
+ // envelope itself.
262
355
  if (typeof remote.map_data !== 'string') {
263
- map = remote.map_data;
356
+ io.stderr('veilio: that map is not an encrypted envelope, so it was not written.\n');
357
+ return EXIT_ERROR;
358
+ }
359
+ let envelope;
360
+ try {
361
+ envelope = JSON.parse(remote.map_data);
362
+ }
363
+ catch {
364
+ io.stderr('veilio: that map is not an encrypted envelope, so it was not written.\n');
365
+ return EXIT_ERROR;
366
+ }
367
+ let map;
368
+ if (envelope.alg === 'AES-256-GCM-TEAM') {
369
+ const opened = await openTeamEnvelope(credential, remote.map_data, io);
370
+ if (!opened)
371
+ return EXIT_ERROR;
372
+ map = opened;
264
373
  }
265
374
  else {
266
375
  let vault;
@@ -391,4 +500,173 @@ function notSignedIn(io) {
391
500
  function reportCloudFailure(err, io) {
392
501
  return reportLoginFailure(err, io);
393
502
  }
503
+ // ─── rules: pull ──────────────────────────────────────────────────────────────
504
+ /**
505
+ * Fetch the account's custom rules so `veilio scrub` can apply them offline.
506
+ *
507
+ * Merged here, in the web app's order, so every later scrub applies exactly
508
+ * what the browser would. A plan without custom rules REMOVES any cache left
509
+ * from before: rules the account can no longer use must not go on shaping
510
+ * its output. Any other failure keeps the cache and says so.
511
+ */
512
+ export async function runRulesPull(io) {
513
+ const credential = readCredential(io.home);
514
+ if (!credential)
515
+ return notSignedIn(io);
516
+ let fetched;
517
+ try {
518
+ fetched = await listRules(credential);
519
+ }
520
+ catch (err) {
521
+ if (err instanceof CloudError && err.kind === 'unentitled') {
522
+ const removed = removeRules(io.home);
523
+ io.stderr(`veilio: this account's plan does not include custom rules${removed ? ' - the cached rules were removed' : ''}.\n`);
524
+ return EXIT_ERROR;
525
+ }
526
+ return reportCloudFailure(err, io);
527
+ }
528
+ const personal = fetched.rules ?? [];
529
+ const team = fetched.teamRules ?? [];
530
+ const rules = mergeRules(personal, team);
531
+ writeRules({
532
+ instance: credential.instance,
533
+ account: credential.account,
534
+ pulledAt: new Date().toISOString(),
535
+ rules,
536
+ }, io.home);
537
+ const skipped = personal.length + team.length - rules.length;
538
+ io.stdout(`Pulled ${rules.length} custom rule${rules.length === 1 ? '' : 's'} ` +
539
+ `(${personal.length} personal, ${team.length} team${skipped > 0 ? `, ${skipped} disabled and skipped` : ''}). ` +
540
+ '`veilio scrub` applies them.\n');
541
+ return EXIT_OK;
542
+ }
543
+ // ─── team: unlock, lock ──────────────────────────────────────────────────────
544
+ /**
545
+ * Unlock this team's keys for processes that cannot ask for a passphrase.
546
+ *
547
+ * The MCP server starts inside a coding agent with no terminal attached, so the
548
+ * keys it needs have to be put on disk by a run like this one, where a person
549
+ * is present to type the passphrase. See `team-unlock.ts` for what is stored
550
+ * and why it is the team key rather than the vault key.
551
+ */
552
+ export async function runTeamUnlock(io, days) {
553
+ const credential = readCredential(io.home);
554
+ if (!credential) {
555
+ io.stderr('veilio: not signed in. Run `veilio login` first.\n');
556
+ return EXIT_ERROR;
557
+ }
558
+ try {
559
+ const list = await listMaps(credential);
560
+ const teamId = list.team?.id;
561
+ if (!teamId) {
562
+ io.stderr('veilio: this account is not in a team, so there are no team keys to unlock. ' +
563
+ 'Shared placeholders are a Team-plan feature.\n');
564
+ return EXIT_ERROR;
565
+ }
566
+ const mine = await getUserKeys(credential);
567
+ if (!mine.initialized) {
568
+ io.stderr('veilio: this account has no keypair yet. Open the web app once — that is where a ' +
569
+ 'keypair is created and where a teammate grants you the team key.\n');
570
+ return EXIT_ERROR;
571
+ }
572
+ const { wraps } = await getTeamKeyWraps(credential, teamId);
573
+ if (wraps.length === 0) {
574
+ io.stderr('veilio: no teammate has granted you the team key yet. Ask someone already in the ' +
575
+ 'team to open the web app, which is what performs the grant.\n');
576
+ return EXIT_ERROR;
577
+ }
578
+ const vault = await getVault(credential);
579
+ if (!vault.initialized) {
580
+ io.stderr('veilio: this account has no vault, so there is no key to unwrap anything with. ' +
581
+ 'Create one in the web app first.\n');
582
+ return EXIT_ERROR;
583
+ }
584
+ const passphrase = io.password ? await io.password('Vault passphrase: ') : '';
585
+ if (passphrase === '') {
586
+ io.stderr('veilio: no passphrase given\n');
587
+ return EXIT_ERROR;
588
+ }
589
+ const vaultKey = await deriveVaultKey(passphrase, fromBase64(vault.salt), vault.kdf ? { name: 'PBKDF2-SHA256', iterations: vault.kdf.iterations } : undefined);
590
+ // Named as a wrong passphrase here rather than surfacing later as an
591
+ // authentication-tag failure that reads like corruption.
592
+ if (!(await checkVaultVerifier(vaultKey, vault.verifier))) {
593
+ io.stderr('veilio: that vault passphrase is not right. Nothing was written.\n');
594
+ return EXIT_ERROR;
595
+ }
596
+ const privateKey = await unwrapPrivateKey(vaultKey, mine.privateKeyEncrypted);
597
+ const keys = [];
598
+ for (const wrap of wraps) {
599
+ try {
600
+ const teamKey = await unwrapTeamKey(wrap.wrapped_key, privateKey, {
601
+ teamId,
602
+ version: wrap.version,
603
+ myPublicKey: mine.publicKey,
604
+ });
605
+ keys.push({ version: wrap.version, key: await exportTeamKey(teamKey) });
606
+ }
607
+ catch {
608
+ // A wrap this account cannot open — from a granter whose key has since
609
+ // changed, most likely. Skipped rather than fatal: another version may
610
+ // still open most of the team's maps, and none opening is reported below.
611
+ continue;
612
+ }
613
+ }
614
+ if (keys.length === 0) {
615
+ io.stderr('veilio: none of the team key wraps held for this account could be opened. ' +
616
+ 'Ask a teammate to grant access again from the web app.\n');
617
+ return EXIT_ERROR;
618
+ }
619
+ const now = new Date();
620
+ const expiresAt = expiryFrom(now, days);
621
+ writeTeamUnlock({
622
+ v: 1,
623
+ instance: credential.instance,
624
+ account: credential.account,
625
+ teamId,
626
+ expiresAt,
627
+ keys,
628
+ }, io.home);
629
+ const versions = keys.map((k) => `v${k.version}`).join(', ');
630
+ io.stdout(`Unlocked ${keys.length === 1 ? 'the team key' : 'team keys'} (${versions}) until ` +
631
+ `${expiresAt}.\n` +
632
+ `Stored in ${teamUnlockPath(io.home)}, readable only by you. ` +
633
+ `Run \`veilio team lock\` to remove them.\n`);
634
+ return EXIT_OK;
635
+ }
636
+ catch (err) {
637
+ return reportCloudFailure(err, io);
638
+ }
639
+ }
640
+ /** Remove the unlocked team keys. */
641
+ export function runTeamLock(io) {
642
+ try {
643
+ if (!removeTeamUnlock(io.home)) {
644
+ io.stdout('No team keys were unlocked.\n');
645
+ return EXIT_OK;
646
+ }
647
+ }
648
+ catch (err) {
649
+ io.stderr(`veilio: the unlocked team keys could not be removed ` +
650
+ `(${err instanceof Error ? err.message : String(err)}). ` +
651
+ `Delete ${teamUnlockPath(io.home)} by hand.\n`);
652
+ return EXIT_ERROR;
653
+ }
654
+ io.stdout('Team keys locked.\n');
655
+ return EXIT_OK;
656
+ }
657
+ // ─── restore: the team layer ────────────────────────────────────────────────
658
+ /**
659
+ * The team's maps for `veilio restore` (spec 028), handed to the local command
660
+ * as a callback so that command stays unlinked from the network. Signed out:
661
+ * no request, no layer - a local restore, as before.
662
+ */
663
+ export async function teamLayerFor(home, missing) {
664
+ // Signed out, the resolver answers 'local' without a request. At most 5 s: a
665
+ // hung instance must not stall a `... | veilio restore > file` pipeline.
666
+ const found = await resolveTeamNamespace(home, { deadlineMs: RESTORE_CLOUD_WAIT_MS });
667
+ if (found.status === 'team' && found.conflictDetection)
668
+ return { team: found.analysis, note: null };
669
+ return { team: null, note: teamLayerNote(found, missing) };
670
+ }
671
+ const RESTORE_CLOUD_WAIT_MS = 5000;
394
672
  //# sourceMappingURL=cloud-commands.js.map