@corenel/tools-node 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,93 @@
1
+ Elastic License 2.0
2
+
3
+ URL: https://www.elastic.co/licensing/elastic-license
4
+
5
+ ## Acceptance
6
+
7
+ By using the software, you agree to all of the terms and conditions below.
8
+
9
+ ## Copyright License
10
+
11
+ The licensor grants you a non-exclusive, royalty-free, worldwide,
12
+ non-sublicensable, non-transferable license to use, copy, distribute, make
13
+ available, and prepare derivative works of the software, in each case subject to
14
+ the limitations and conditions below.
15
+
16
+ ## Limitations
17
+
18
+ You may not provide the software to third parties as a hosted or managed
19
+ service, where the service provides users with access to any substantial set of
20
+ the features or functionality of the software.
21
+
22
+ You may not move, change, disable, or circumvent the license key functionality
23
+ in the software, and you may not remove or obscure any functionality in the
24
+ software that is protected by the license key.
25
+
26
+ You may not alter, remove, or obscure any licensing, copyright, or other notices
27
+ of the licensor in the software. Any use of the licensor's trademarks is subject
28
+ to applicable law.
29
+
30
+ ## Patents
31
+
32
+ The licensor grants you a license, under any patent claims the licensor can
33
+ license, or becomes able to license, to make, have made, use, sell, offer for
34
+ sale, import and have imported the software, in each case subject to the
35
+ limitations and conditions in this license. This license does not cover any
36
+ patent claims that you cause to be infringed by modifications or additions to
37
+ the software. If you or your company make any written claim that the software
38
+ infringes or contributes to infringement of any patent, your patent license for
39
+ the software granted under these terms ends immediately. If your company makes
40
+ such a claim, your patent license ends immediately for work on behalf of your
41
+ company.
42
+
43
+ ## Notices
44
+
45
+ You must ensure that anyone who gets a copy of any part of the software from you
46
+ also gets a copy of these terms.
47
+
48
+ If you modify the software, you must include in any modified copies of the
49
+ software prominent notices stating that you have modified the software.
50
+
51
+ ## No Other Rights
52
+
53
+ These terms do not imply any licenses other than those expressly granted in
54
+ these terms.
55
+
56
+ ## Termination
57
+
58
+ If you use the software in violation of these terms, such use is not licensed,
59
+ and your licenses will automatically terminate. If the licensor provides you
60
+ with a notice of your violation, and you cease all violation of this license no
61
+ later than 30 days after you receive that notice, your licenses will be
62
+ reinstated retroactively. However, if you violate these terms after such
63
+ reinstatement, any additional violation of these terms will cause your licenses
64
+ to terminate automatically and permanently.
65
+
66
+ ## No Liability
67
+
68
+ *As far as the law allows, the software comes as is, without any warranty or
69
+ condition, and the licensor will not be liable to you for any damages arising out
70
+ of these terms or the use or nature of the software, under any kind of legal
71
+ claim.*
72
+
73
+ ## Definitions
74
+
75
+ The **licensor** is the entity offering these terms, and the **software** is the
76
+ software the licensor makes available under these terms, including any portion of
77
+ it.
78
+
79
+ **you** refers to the individual or entity agreeing to these terms.
80
+
81
+ **your company** is any legal entity, sole proprietorship, or other kind of
82
+ organization that you work for, plus all organizations that have control over, are
83
+ under the control of, or are under common control with that organization.
84
+ **control** means ownership of substantially all the assets of an entity, or the
85
+ power to direct its management and policies by vote, contract, or otherwise.
86
+ Control can be direct or indirect.
87
+
88
+ **your licenses** are all the licenses granted to you for the software under these
89
+ terms.
90
+
91
+ **use** means anything you do with the software requiring one of your licenses.
92
+
93
+ **trademark** means trademarks, service marks, and similar rights.
package/dist/auth.d.ts CHANGED
@@ -1,9 +1,165 @@
1
1
  import type { IAuthTokenProvider } from '@corenel/protocol';
2
- export declare function corenelDir(): string;
3
- export declare function authTokenPath(): string;
4
- export declare function writeAuthToken(token: string): Promise<void>;
5
- export declare function readAuthToken(): Promise<string | null>;
6
- export declare function clearAuthToken(): Promise<void>;
7
- /** The IAuthTokenProvider for node: the stored login token, else CORENEL_TOKEN env. */
8
- export declare function nodeAuthToken(): IAuthTokenProvider;
2
+ /** The state dir: `<home>/.corenel`. ALSO the global crew root -- global agents
3
+ * resolve as `<stateDir>/crew` -- so this never moves. */
4
+ export declare function corenelDir(base?: string): string;
5
+ /** Where the daemon keeps its OWN files: identity, pairing token, TLS material,
6
+ * host mirrors. A subdirectory of the state dir, never a replacement for it. */
7
+ export declare function sidecarDir(base?: string): string;
8
+ /** The ACCOUNT token from the device flow. Top level, and staying there: it is
9
+ * not the daemon's, and moving it would sign the user out on upgrade. */
10
+ export declare function authTokenPath(base?: string): string;
11
+ /**
12
+ * The directory both credential files live in.
13
+ *
14
+ * STATE-DIR DECISION, made deliberately: the token file stays HOME-scoped by
15
+ * default and does NOT move under a daemon-private directory. @corenel/cli
16
+ * resolves it from homedir() with no notion of a state dir, and `corenel login`
17
+ * writes it there; relocating it would sign every existing user out on upgrade
18
+ * and leave the CLI unable to find the credential it just wrote. What
19
+ * `--state-dir` does instead is redirect the whole state dir, exactly as the
20
+ * sidecar's `authDir` already does — so `<stateDir>/token` and
21
+ * `<stateDir>/auth.json` stay siblings, an isolated state dir stays isolated
22
+ * (nothing reaches back into the real home), and with no `--state-dir` this
23
+ * resolves to the same `~/.corenel/token` the CLI reads. Identical computation
24
+ * to packages/sidecar/src/auth/store.ts `authDir`, and it must stay identical.
25
+ */
26
+ export declare function credentialDir(stateDir?: string): string;
27
+ /** `<credentialDir>/token` — equals authTokenPath() when no state dir is given. */
28
+ export declare function tokenFilePath(stateDir?: string): string;
29
+ /** `<credentialDir>/auth.json` — the sidecar's richer credential record. */
30
+ export declare function credentialFilePath(stateDir?: string): string;
31
+ /** The environment variable that carries a headless credential. */
32
+ export declare const TOKEN_ENV = "CORENEL_TOKEN";
33
+ /** The environment variable that names the API. Same spelling @corenel/cli's
34
+ * `apiBase()` reads, because two names for one decision is how they drift. */
35
+ export declare const API_BASE_ENV = "CORENEL_API_BASE";
36
+ /** The credential file's shape. `expiresAt` absent means the issuer did not say
37
+ * — which is NOT the same as "not expired". */
38
+ export interface StoredCredential {
39
+ accessToken: string;
40
+ refreshToken?: string;
41
+ /** Epoch ms. Absent means the issuer did not say. */
42
+ expiresAt?: number;
43
+ /** For display only — never used for authorization. */
44
+ account?: string;
45
+ /**
46
+ * The API base this credential was MINTED against.
47
+ *
48
+ * A token is only valid at the host that issued it, so the base belongs to
49
+ * the login, not to the machine: a daemon defaulting to a different host
50
+ * spends a token nobody there has heard of, and the failure is a 401 a long
51
+ * way from the sign-in that caused it. Absent on every credential written
52
+ * before this was recorded, which is why every reader falls back to the
53
+ * default rather than treating absence as an error.
54
+ */
55
+ apiBase?: string;
56
+ }
57
+ export declare function writeAuthToken(token: string, stateDir?: string): Promise<void>;
58
+ /**
59
+ * Record a completed sign-in in BOTH stores, including WHERE it was minted.
60
+ *
61
+ * `writeAuthToken` alone leaves the token file holding a bearer token with no
62
+ * record of which API issued it -- which is fine right up until the machine is
63
+ * pointed somewhere else by a default, and then it is a 401 with no visible
64
+ * cause. The base goes in auth.json because the token file is one line by
65
+ * contract and every existing reader of it splits on nothing.
66
+ *
67
+ * The credential record is REPLACED, not merged: a new sign-in may be a
68
+ * different account at a different host, and carrying the previous one's
69
+ * account or base onto it would report something nobody established.
70
+ */
71
+ export declare function writeLoginCredential(token: string, opts?: {
72
+ apiBase?: string;
73
+ stateDir?: string;
74
+ account?: string;
75
+ }): Promise<void>;
76
+ export declare function readAuthToken(stateDir?: string): Promise<string | null>;
77
+ /** Remove the token file only. Prefer clearAllCredentials for anything a user
78
+ * would call signing out — see the warning there. */
79
+ export declare function clearAuthToken(stateDir?: string): Promise<void>;
80
+ /** Read `<dir>/auth.json`, or null when there is none. A malformed file is
81
+ * treated as absent rather than fatal — a corrupt credential should send the
82
+ * user through sign-in, not wedge the daemon. */
83
+ export declare function readCredentialFile(stateDir?: string): Promise<StoredCredential | null>;
84
+ /**
85
+ * Sign out of BOTH stores.
86
+ *
87
+ * Clearing one while the other still authenticates is the same divergence bug
88
+ * pointing the other way, and worse: the operator believes they signed out
89
+ * while the gateway keeps sending a credential. Every sign-out path must land
90
+ * here rather than removing a single file.
91
+ */
92
+ export declare function clearAllCredentials(stateDir?: string): Promise<void>;
93
+ /** Which store answered. */
94
+ export type CredentialSource = 'env' | 'token-file' | 'credential-file' | 'none';
95
+ export interface ResolvedCredential {
96
+ token: string | null;
97
+ source: CredentialSource;
98
+ /** Where it was read from on disk. Absent for 'env' and 'none'. */
99
+ path?: string;
100
+ /** Epoch ms, when a store recorded one. Absent means UNKNOWN, not "fresh". */
101
+ expiresAt?: number;
102
+ /** True only when an expiry is known AND has passed. */
103
+ expired?: boolean;
104
+ /** Display only, never used for authorization. */
105
+ account?: string;
106
+ /** The API this credential was minted against, when the sign-in recorded one.
107
+ * Absent for an older credential — read that as "not recorded", never as
108
+ * "the default". */
109
+ apiBase?: string;
110
+ }
111
+ export interface ResolveCredentialOptions {
112
+ env?: NodeJS.ProcessEnv;
113
+ stateDir?: string;
114
+ now?: () => number;
115
+ }
116
+ /**
117
+ * Resolve the credential this machine authenticates with, per the precedence
118
+ * documented at the top of this file.
119
+ *
120
+ * An expired stored credential is REPORTED, not skipped: the caller decides
121
+ * whether to refresh or re-prompt, and one that ignores `expired` fails at the
122
+ * gateway rather than here. A token file records no expiry at all, so
123
+ * `expiresAt` stays undefined for it unless the credential file beside it
124
+ * describes the same token — the absence of an expiry must never be read as
125
+ * evidence of freshness.
126
+ */
127
+ export declare function resolveNodeCredential(opts?: ResolveCredentialOptions): Promise<ResolvedCredential>;
128
+ /** Which answer resolveApiBase gave. Reported so a startup banner can say why
129
+ * it is talking to the host it is talking to. */
130
+ export type ApiBaseSource = 'explicit' | 'env' | 'credential' | 'default';
131
+ export interface ResolvedApiBase {
132
+ base: string;
133
+ source: ApiBaseSource;
134
+ }
135
+ export interface ResolveApiBaseOptions {
136
+ /** A flag the operator typed (`--endpoint`, `--base`). Empty means absent —
137
+ * that is how a missing flag arrives from every caller here. */
138
+ explicit?: string;
139
+ env?: NodeJS.ProcessEnv;
140
+ stateDir?: string;
141
+ }
142
+ /**
143
+ * Which API to talk to.
144
+ *
145
+ * 1. an explicit flag — the operator is pointing somewhere on purpose
146
+ * 2. CORENEL_API_BASE — a container/CI statement of present intent
147
+ * 3. the credential's base — where the token this machine holds was minted
148
+ * 4. DEFAULT_API_BASE — nothing has been said, so say the product's own
149
+ *
150
+ * (3) is the change worth stating: the sidecar carried a literal default, so a
151
+ * user who signed in against one deployment had their daemon talk to another,
152
+ * and the only symptom was a 401 or a 404 far from the login. Preferring the
153
+ * credential's own base makes the common case need no flag at all, while (1)
154
+ * keeps `--endpoint` meaning exactly what it says for local dev.
155
+ */
156
+ export declare function resolveApiBase(opts?: ResolveApiBaseOptions): Promise<ResolvedApiBase>;
157
+ /** A token is a credential; printing one puts it in scrollback, shell history
158
+ * and any screen share. Four leading characters identify WHICH token this is
159
+ * without being usable if the output is pasted somewhere. */
160
+ export declare function maskToken(token: string): string;
161
+ /** The IAuthTokenProvider for node. Resolves exactly what `auth` reports, which
162
+ * is the whole point: the status command must describe the credential the
163
+ * gateway will actually send. */
164
+ export declare function nodeAuthToken(stateDir?: string): IAuthTokenProvider;
9
165
  //# sourceMappingURL=auth.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../auth.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAG5D,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AACD,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,wBAAsB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAcjE;AAED,wBAAsB,aAAa,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAO5D;AAED,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAEpD;AAED,uFAAuF;AACvF,wBAAgB,aAAa,IAAI,kBAAkB,CAElD"}
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../auth.ts"],"names":[],"mappings":"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"}
package/dist/auth.js CHANGED
@@ -1,19 +1,107 @@
1
- /* Node auth token store — ~/<state dir>/token (default ~/.corenel/token, owner-only).
2
- * `corenel login` writes it via the device flow; the CLI's token guard + gateway
3
- * client read it through the IAuthTokenProvider port (falling back to the
4
- * CORENEL_TOKEN env). Separate from the sidecar's ~/<state dir>/daemon.token
5
- * (default ~/.corenel/daemon.token — that's the local pairing token). */
1
+ /* Node auth credential store — the ONE place that decides which credential this
2
+ * machine authenticates with.
3
+ *
4
+ * TWO STORES, ONE ANSWER. A sign-in can land in either of two files, written by
5
+ * different halves of the product:
6
+ *
7
+ * <dir>/token a bare bearer token, one line. Written by `corenel login`
8
+ * (@corenel/cli's device flow) and read by the gateway
9
+ * client. This is the file real users are signed in with.
10
+ * <dir>/auth.json the richer record from the sidecar's PKCE flow
11
+ * (packages/sidecar/src/auth/store.ts): accessToken plus
12
+ * refreshToken, expiresAt and account.
13
+ *
14
+ * They used to be resolved independently, so `corenel-sidecar auth` could
15
+ * answer "Not signed in" about auth.json on a machine whose gateway calls were
16
+ * succeeding with the token file. That is the bug this module exists to close:
17
+ * everything that asks "is this machine signed in?" and everything that asks
18
+ * "what do I send?" now goes through resolveNodeCredential below.
19
+ *
20
+ * PRECEDENCE, stated once so nobody has to derive it:
21
+ *
22
+ * 1. CORENEL_TOKEN in the environment.
23
+ * 2. <dir>/token — the token file.
24
+ * 3. <dir>/auth.json — the credential file.
25
+ *
26
+ * (1) is first because the environment is a present-tense statement of intent:
27
+ * it is how a container, a CI job or an SSH session supplies identity, and
28
+ * those are exactly the places where a file on disk may be a stale artifact of
29
+ * an image build. It also means a `logout` cannot silently appear to fail — the
30
+ * commands say so explicitly when the variable is set.
31
+ *
32
+ * (2) beats (3) because the token file is the credential that already works:
33
+ * the gateway client and @corenel/cli have always read it, and real installs
34
+ * are signed in through it right now. Making the newer store win would change
35
+ * which token a working machine sends. The two only ever diverge on a machine
36
+ * that signed in both ways, because saveCredential writes BOTH and
37
+ * clearAllCredentials removes BOTH — so login and logout leave the two readers
38
+ * agreeing rather than leaning on the precedence at all. When the credential
39
+ * file describes the SAME token, its account/expiry metadata is carried over,
40
+ * which is the only reason (3) is consulted after (2) has already answered.
41
+ *
42
+ * Separate from the sidecar's <dir>/sidecar/daemon.token, which is the local
43
+ * PAIRING token: that authenticates a connection to a port, it does not say who
44
+ * the user is, and merging the two would turn "can reach the port" into "is the
45
+ * account owner".
46
+ */
6
47
  import { promises as fs } from 'node:fs';
7
48
  import { homedir } from 'node:os';
8
49
  import { join } from 'node:path';
9
- import { stateDirName } from '@corenel/protocol';
10
- export function corenelDir() {
11
- return join(homedir(), stateDirName());
50
+ import { stateDirName, DEFAULT_API_BASE } from '@corenel/protocol';
51
+ /* Every path helper takes an explicit base, defaulting to the real home.
52
+ *
53
+ * Not a convenience. The layout migration built on these MOVES files, and a
54
+ * helper that can only resolve homedir() would force every test of it to run
55
+ * against the developer's own ~/.corenel -- the one holding their edited
56
+ * personas, and the token they are signed in with right now. Taking a base
57
+ * makes that mistake impossible rather than discouraged. */
58
+ /** The state dir: `<home>/.corenel`. ALSO the global crew root -- global agents
59
+ * resolve as `<stateDir>/crew` -- so this never moves. */
60
+ export function corenelDir(base = homedir()) {
61
+ return join(base, stateDirName());
12
62
  }
13
- export function authTokenPath() {
14
- return join(corenelDir(), 'token');
63
+ /** Where the daemon keeps its OWN files: identity, pairing token, TLS material,
64
+ * host mirrors. A subdirectory of the state dir, never a replacement for it. */
65
+ export function sidecarDir(base = homedir()) {
66
+ return join(corenelDir(base), 'sidecar');
15
67
  }
16
- export async function writeAuthToken(token) {
68
+ /** The ACCOUNT token from the device flow. Top level, and staying there: it is
69
+ * not the daemon's, and moving it would sign the user out on upgrade. */
70
+ export function authTokenPath(base = homedir()) {
71
+ return join(corenelDir(base), 'token');
72
+ }
73
+ /**
74
+ * The directory both credential files live in.
75
+ *
76
+ * STATE-DIR DECISION, made deliberately: the token file stays HOME-scoped by
77
+ * default and does NOT move under a daemon-private directory. @corenel/cli
78
+ * resolves it from homedir() with no notion of a state dir, and `corenel login`
79
+ * writes it there; relocating it would sign every existing user out on upgrade
80
+ * and leave the CLI unable to find the credential it just wrote. What
81
+ * `--state-dir` does instead is redirect the whole state dir, exactly as the
82
+ * sidecar's `authDir` already does — so `<stateDir>/token` and
83
+ * `<stateDir>/auth.json` stay siblings, an isolated state dir stays isolated
84
+ * (nothing reaches back into the real home), and with no `--state-dir` this
85
+ * resolves to the same `~/.corenel/token` the CLI reads. Identical computation
86
+ * to packages/sidecar/src/auth/store.ts `authDir`, and it must stay identical.
87
+ */
88
+ export function credentialDir(stateDir) {
89
+ return stateDir ?? corenelDir();
90
+ }
91
+ /** `<credentialDir>/token` — equals authTokenPath() when no state dir is given. */
92
+ export function tokenFilePath(stateDir) {
93
+ return join(credentialDir(stateDir), 'token');
94
+ }
95
+ /** `<credentialDir>/auth.json` — the sidecar's richer credential record. */
96
+ export function credentialFilePath(stateDir) {
97
+ return join(credentialDir(stateDir), 'auth.json');
98
+ }
99
+ /** The environment variable that carries a headless credential. */
100
+ export const TOKEN_ENV = 'CORENEL_TOKEN';
101
+ /** The environment variable that names the API. Same spelling @corenel/cli's
102
+ * `apiBase()` reads, because two names for one decision is how they drift. */
103
+ export const API_BASE_ENV = 'CORENEL_API_BASE';
104
+ export async function writeAuthToken(token, stateDir) {
17
105
  /* 0o700 on the DIRECTORY, not just 0o600 on the file. Without a mode, mkdir
18
106
  * lands on the process umask -- typically 0o755, so the directory holding a
19
107
  * bearer token is world-listable. The file's own contents stay protected
@@ -21,36 +109,200 @@ export async function writeAuthToken(token) {
21
109
  * has a Corenel token and when they last refreshed it. `recursive: true`
22
110
  * applies the mode only to directories it actually CREATES, so this never
23
111
  * tightens a pre-existing ~/.corenel a user set up deliberately. */
24
- await fs.mkdir(corenelDir(), { recursive: true, mode: 0o700 });
25
- await fs.writeFile(authTokenPath(), token.trim() + '\n', { mode: 0o600 });
112
+ const dir = credentialDir(stateDir);
113
+ const path = tokenFilePath(stateDir);
114
+ await fs.mkdir(dir, { recursive: true, mode: 0o700 });
115
+ await fs.writeFile(path, token.trim() + '\n', { mode: 0o600 });
26
116
  // Both chmods are best-effort: non-POSIX filesystems reject them, and a
27
117
  // failure here must not lose a token that is already written correctly.
28
118
  try {
29
- await fs.chmod(authTokenPath(), 0o600);
119
+ await fs.chmod(path, 0o600);
30
120
  }
31
121
  catch { /* non-POSIX */ }
32
122
  try {
33
- await fs.chmod(corenelDir(), 0o700);
123
+ await fs.chmod(dir, 0o700);
124
+ }
125
+ catch { /* non-POSIX */ }
126
+ }
127
+ /**
128
+ * Record a completed sign-in in BOTH stores, including WHERE it was minted.
129
+ *
130
+ * `writeAuthToken` alone leaves the token file holding a bearer token with no
131
+ * record of which API issued it -- which is fine right up until the machine is
132
+ * pointed somewhere else by a default, and then it is a 401 with no visible
133
+ * cause. The base goes in auth.json because the token file is one line by
134
+ * contract and every existing reader of it splits on nothing.
135
+ *
136
+ * The credential record is REPLACED, not merged: a new sign-in may be a
137
+ * different account at a different host, and carrying the previous one's
138
+ * account or base onto it would report something nobody established.
139
+ */
140
+ export async function writeLoginCredential(token, opts = {}) {
141
+ const cred = {
142
+ accessToken: token.trim(),
143
+ ...(opts.account ? { account: opts.account } : {}),
144
+ ...(opts.apiBase ? { apiBase: opts.apiBase } : {}),
145
+ };
146
+ const path = credentialFilePath(opts.stateDir);
147
+ await fs.mkdir(credentialDir(opts.stateDir), { recursive: true, mode: 0o700 });
148
+ await fs.writeFile(path, `${JSON.stringify(cred, null, 2)}\n`, { mode: 0o600 });
149
+ try {
150
+ await fs.chmod(path, 0o600);
34
151
  }
35
152
  catch { /* non-POSIX */ }
153
+ await writeAuthToken(cred.accessToken, opts.stateDir);
36
154
  }
37
- export async function readAuthToken() {
155
+ export async function readAuthToken(stateDir) {
38
156
  try {
39
- const t = (await fs.readFile(authTokenPath(), 'utf8')).trim();
157
+ const t = (await fs.readFile(tokenFilePath(stateDir), 'utf8')).trim();
40
158
  return t || null;
41
159
  }
42
160
  catch {
43
161
  return null;
44
162
  }
45
163
  }
46
- export async function clearAuthToken() {
164
+ /** Remove the token file only. Prefer clearAllCredentials for anything a user
165
+ * would call signing out — see the warning there. */
166
+ export async function clearAuthToken(stateDir) {
47
167
  try {
48
- await fs.rm(authTokenPath(), { force: true });
168
+ await fs.rm(tokenFilePath(stateDir), { force: true });
49
169
  }
50
170
  catch { /* already gone */ }
51
171
  }
52
- /** The IAuthTokenProvider for node: the stored login token, else CORENEL_TOKEN env. */
53
- export function nodeAuthToken() {
54
- return { getToken: async () => (await readAuthToken()) ?? process.env.CORENEL_TOKEN ?? null };
172
+ /** Read `<dir>/auth.json`, or null when there is none. A malformed file is
173
+ * treated as absent rather than fatal — a corrupt credential should send the
174
+ * user through sign-in, not wedge the daemon. */
175
+ export async function readCredentialFile(stateDir) {
176
+ let raw;
177
+ try {
178
+ raw = await fs.readFile(credentialFilePath(stateDir), 'utf8');
179
+ }
180
+ catch {
181
+ // ENOENT is the ordinary case. EACCES/EISDIR read the same way here because
182
+ // a caller can do nothing different with them: there is no usable
183
+ // credential either way, and crashing the daemon over it helps nobody.
184
+ return null;
185
+ }
186
+ try {
187
+ const parsed = JSON.parse(raw);
188
+ if (typeof parsed !== 'object' || parsed === null)
189
+ return null;
190
+ const c = parsed;
191
+ if (typeof c.accessToken !== 'string' || !c.accessToken)
192
+ return null;
193
+ return {
194
+ accessToken: c.accessToken,
195
+ ...(typeof c.refreshToken === 'string' ? { refreshToken: c.refreshToken } : {}),
196
+ ...(typeof c.expiresAt === 'number' ? { expiresAt: c.expiresAt } : {}),
197
+ ...(typeof c.account === 'string' ? { account: c.account } : {}),
198
+ ...(typeof c.apiBase === 'string' && c.apiBase ? { apiBase: c.apiBase } : {}),
199
+ };
200
+ }
201
+ catch {
202
+ return null;
203
+ }
204
+ }
205
+ /**
206
+ * Sign out of BOTH stores.
207
+ *
208
+ * Clearing one while the other still authenticates is the same divergence bug
209
+ * pointing the other way, and worse: the operator believes they signed out
210
+ * while the gateway keeps sending a credential. Every sign-out path must land
211
+ * here rather than removing a single file.
212
+ */
213
+ export async function clearAllCredentials(stateDir) {
214
+ await clearAuthToken(stateDir);
215
+ try {
216
+ await fs.rm(credentialFilePath(stateDir), { force: true });
217
+ }
218
+ catch { /* already gone */ }
219
+ }
220
+ /**
221
+ * Resolve the credential this machine authenticates with, per the precedence
222
+ * documented at the top of this file.
223
+ *
224
+ * An expired stored credential is REPORTED, not skipped: the caller decides
225
+ * whether to refresh or re-prompt, and one that ignores `expired` fails at the
226
+ * gateway rather than here. A token file records no expiry at all, so
227
+ * `expiresAt` stays undefined for it unless the credential file beside it
228
+ * describes the same token — the absence of an expiry must never be read as
229
+ * evidence of freshness.
230
+ */
231
+ export async function resolveNodeCredential(opts = {}) {
232
+ const env = opts.env ?? process.env;
233
+ const now = opts.now ?? Date.now;
234
+ const stateDir = opts.stateDir;
235
+ const fromEnv = env[TOKEN_ENV]?.trim();
236
+ if (fromEnv)
237
+ return { token: fromEnv, source: 'env' };
238
+ const cred = await readCredentialFile(stateDir);
239
+ const fileToken = await readAuthToken(stateDir);
240
+ if (fileToken) {
241
+ // Metadata is borrowed ONLY when the credential file describes this same
242
+ // token. Two different tokens mean two different sign-ins, and attaching
243
+ // one's expiry to the other would report a freshness nobody established.
244
+ const same = cred && cred.accessToken === fileToken ? cred : null;
245
+ return withExpiry({ token: fileToken, source: 'token-file', path: tokenFilePath(stateDir) }, same, now);
246
+ }
247
+ if (cred) {
248
+ return withExpiry({ token: cred.accessToken, source: 'credential-file', path: credentialFilePath(stateDir) }, cred, now);
249
+ }
250
+ return { token: null, source: 'none' };
251
+ }
252
+ function withExpiry(base, cred, now) {
253
+ if (!cred)
254
+ return base;
255
+ const expired = typeof cred.expiresAt === 'number' && cred.expiresAt <= now();
256
+ return {
257
+ ...base,
258
+ ...(typeof cred.expiresAt === 'number' ? { expiresAt: cred.expiresAt } : {}),
259
+ ...(expired ? { expired: true } : {}),
260
+ ...(cred.account ? { account: cred.account } : {}),
261
+ ...(cred.apiBase ? { apiBase: cred.apiBase } : {}),
262
+ };
263
+ }
264
+ /**
265
+ * Which API to talk to.
266
+ *
267
+ * 1. an explicit flag — the operator is pointing somewhere on purpose
268
+ * 2. CORENEL_API_BASE — a container/CI statement of present intent
269
+ * 3. the credential's base — where the token this machine holds was minted
270
+ * 4. DEFAULT_API_BASE — nothing has been said, so say the product's own
271
+ *
272
+ * (3) is the change worth stating: the sidecar carried a literal default, so a
273
+ * user who signed in against one deployment had their daemon talk to another,
274
+ * and the only symptom was a 401 or a 404 far from the login. Preferring the
275
+ * credential's own base makes the common case need no flag at all, while (1)
276
+ * keeps `--endpoint` meaning exactly what it says for local dev.
277
+ */
278
+ export async function resolveApiBase(opts = {}) {
279
+ const explicit = opts.explicit?.trim();
280
+ if (explicit)
281
+ return { base: explicit, source: 'explicit' };
282
+ const fromEnv = (opts.env ?? process.env)[API_BASE_ENV]?.trim();
283
+ if (fromEnv)
284
+ return { base: fromEnv, source: 'env' };
285
+ const cred = await resolveNodeCredential({
286
+ env: {},
287
+ ...(opts.stateDir ? { stateDir: opts.stateDir } : {}),
288
+ });
289
+ if (cred.apiBase)
290
+ return { base: cred.apiBase, source: 'credential' };
291
+ return { base: DEFAULT_API_BASE, source: 'default' };
292
+ }
293
+ /** A token is a credential; printing one puts it in scrollback, shell history
294
+ * and any screen share. Four leading characters identify WHICH token this is
295
+ * without being usable if the output is pasted somewhere. */
296
+ export function maskToken(token) {
297
+ const t = token.trim();
298
+ if (t.length <= 8)
299
+ return '****';
300
+ return `${t.slice(0, 4)}…${t.slice(-2)} (${t.length} chars)`;
301
+ }
302
+ /** The IAuthTokenProvider for node. Resolves exactly what `auth` reports, which
303
+ * is the whole point: the status command must describe the credential the
304
+ * gateway will actually send. */
305
+ export function nodeAuthToken(stateDir) {
306
+ return { getToken: async () => (await resolveNodeCredential(stateDir ? { stateDir } : {})).token };
55
307
  }
56
308
  //# sourceMappingURL=auth.js.map
package/dist/auth.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"auth.js","sourceRoot":"","sources":["../auth.ts"],"names":[],"mappings":"AAAA;;;;yEAIyE;AACzE,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,MAAM,UAAU,UAAU;IACxB,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,YAAY,EAAE,CAAC,CAAC;AACzC,CAAC;AACD,MAAM,UAAU,aAAa;IAC3B,OAAO,IAAI,CAAC,UAAU,EAAE,EAAE,OAAO,CAAC,CAAC;AACrC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,KAAa;IAChD;;;;;;wEAMoE;IACpE,MAAM,EAAE,CAAC,KAAK,CAAC,UAAU,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC/D,MAAM,EAAE,CAAC,SAAS,CAAC,aAAa,EAAE,EAAE,KAAK,CAAC,IAAI,EAAE,GAAG,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC1E,wEAAwE;IACxE,wEAAwE;IACxE,IAAI,CAAC;QAAC,MAAM,EAAE,CAAC,KAAK,CAAC,aAAa,EAAE,EAAE,KAAK,CAAC,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC;IACzE,IAAI,CAAC;QAAC,MAAM,EAAE,CAAC,KAAK,CAAC,UAAU,EAAE,EAAE,KAAK,CAAC,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC;AACxE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,aAAa,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC9D,OAAO,CAAC,IAAI,IAAI,CAAC;IACnB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,IAAI,CAAC;QAAC,MAAM,EAAE,CAAC,EAAE,CAAC,aAAa,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC,CAAC,kBAAkB,CAAC,CAAC;AACrF,CAAC;AAED,uFAAuF;AACvF,MAAM,UAAU,aAAa;IAC3B,OAAO,EAAE,QAAQ,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,aAAa,EAAE,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,IAAI,EAAE,CAAC;AAChG,CAAC"}
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../auth.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"fileService.d.ts","sourceRoot":"","sources":["../fileService.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAsE1F;;;;;;;;;;uBAUuB;AACvB,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,GAAE,MAAY,GAAG,OAAO,CAgB3E;AAED,qBAAa,eAAgB,YAAW,WAAW;IACjD,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAe;IAC7C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,QAAQ;IAC5B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;gBAElB,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAO;IAM3D,yEAAyE;IACzE,OAAO,CAAC,MAAM;IAId;sFACkF;IAClF,OAAO,CAAC,GAAG;IAMX;;uFAEmF;YACrE,UAAU;IAoBxB,mFAAmF;YACrE,OAAO;IAMf,IAAI,CAAC,GAAG,SAAK,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAuBnC,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAInC,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IAS5C,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOnD,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAO1D,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,SAAK,GAAG,OAAO,CAAC,IAAI,CAAC;IAYjD,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAInC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAO/C,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlC,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAU9C,QAAQ,IAAI,MAAM,IAAI;CAGvB"}
1
+ {"version":3,"file":"fileService.d.ts","sourceRoot":"","sources":["../fileService.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAsE1F;;;;;;;;;;uBAUuB;AACvB,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,GAAE,MAAY,GAAG,OAAO,CAgB3E;AAED,qBAAa,eAAgB,YAAW,WAAW;IACjD,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAe;IAC7C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,QAAQ;IAC5B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;gBAElB,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAO;IAM3D,yEAAyE;IACzE,OAAO,CAAC,MAAM;IAId;sFACkF;IAClF,OAAO,CAAC,GAAG;IAMX;;uFAEmF;YACrE,UAAU;IAoBxB,mFAAmF;YACrE,OAAO;IAMf,IAAI,CAAC,GAAG,SAAK,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IA4BnC,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAInC,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IAS5C,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOnD,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAO1D,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,SAAK,GAAG,OAAO,CAAC,IAAI,CAAC;IAYjD,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAInC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAO/C,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlC,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAU9C,QAAQ,IAAI,MAAM,IAAI;CAGvB"}
@@ -206,8 +206,13 @@ export class NodeFileService {
206
206
  out.push({ name: e.name, path, kind: 'directory', children: await walk(absChild) });
207
207
  }
208
208
  else {
209
+ // The stat is already being paid for `size`; `mtime` rides along for
210
+ // free. It is what lets a caller ORDER files without reading them
211
+ // (the session store pages its newest-first list off this), so the
212
+ // node backend now matches DirectoryHandleFileService, which has
213
+ // always supplied both.
209
214
  const st = await fs.stat(absChild).catch(() => null);
210
- out.push({ name: e.name, path, kind: 'file', size: st?.size, ext: extOf(e.name) });
215
+ out.push({ name: e.name, path, kind: 'file', size: st?.size, mtime: st?.mtimeMs, ext: extOf(e.name) });
211
216
  }
212
217
  }
213
218
  return out;
@@ -220,7 +225,7 @@ export class NodeFileService {
220
225
  async stat(path) {
221
226
  try {
222
227
  const st = await fs.stat(this.abs(path));
223
- return { path: normalizeFilePath(path), kind: st.isDirectory() ? 'directory' : 'file', size: st.size, ext: extOf(path) };
228
+ return { path: normalizeFilePath(path), kind: st.isDirectory() ? 'directory' : 'file', size: st.size, mtime: st.mtimeMs, ext: extOf(path) };
224
229
  }
225
230
  catch {
226
231
  return null;
@@ -1 +1 @@
1
- {"version":3,"file":"fileService.js","sourceRoot":"","sources":["../fileService.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"fileService.js","sourceRoot":"","sources":["../fileService.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export { NodeFileService } from './fileService';
2
- export { corenelDir, authTokenPath, writeAuthToken, readAuthToken, clearAuthToken, nodeAuthToken, } from './auth';
2
+ export { corenelDir, sidecarDir, authTokenPath, credentialDir, tokenFilePath, credentialFilePath, writeAuthToken, readAuthToken, readCredentialFile, clearAuthToken, clearAllCredentials, resolveNodeCredential, nodeAuthToken, maskToken, TOKEN_ENV, writeLoginCredential, resolveApiBase, API_BASE_ENV, type StoredCredential, type CredentialSource, type ResolvedCredential, type ResolveCredentialOptions, type ApiBaseSource, type ResolvedApiBase, type ResolveApiBaseOptions, } from './auth';
3
3
  export { nodePromptHost } from './promptHost';
4
+ export { migrateHomeLayout, type MigrationReport } from './migrateHome';
4
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EACL,UAAU,EAAE,aAAa,EAAE,cAAc,EAAE,aAAa,EAAE,cAAc,EAAE,aAAa,GACxF,MAAM,QAAQ,CAAC;AAChB,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EACL,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,kBAAkB,EACvF,cAAc,EAAE,aAAa,EAAE,kBAAkB,EAAE,cAAc,EAAE,mBAAmB,EACtF,qBAAqB,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,EAC1D,oBAAoB,EAAE,cAAc,EAAE,YAAY,EAClD,KAAK,gBAAgB,EAAE,KAAK,gBAAgB,EAAE,KAAK,kBAAkB,EAAE,KAAK,wBAAwB,EACpG,KAAK,aAAa,EAAE,KAAK,eAAe,EAAE,KAAK,qBAAqB,GACrE,MAAM,QAAQ,CAAC;AAChB,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC"}
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  /* @corenel/tools-node — node capabilities (the tools-web twin). */
2
2
  export { NodeFileService } from './fileService';
3
- export { corenelDir, authTokenPath, writeAuthToken, readAuthToken, clearAuthToken, nodeAuthToken, } from './auth';
3
+ export { corenelDir, sidecarDir, authTokenPath, credentialDir, tokenFilePath, credentialFilePath, writeAuthToken, readAuthToken, readCredentialFile, clearAuthToken, clearAllCredentials, resolveNodeCredential, nodeAuthToken, maskToken, TOKEN_ENV, writeLoginCredential, resolveApiBase, API_BASE_ENV, } from './auth';
4
4
  export { nodePromptHost } from './promptHost';
5
+ export { migrateHomeLayout } from './migrateHome';
5
6
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EACL,UAAU,EAAE,aAAa,EAAE,cAAc,EAAE,aAAa,EAAE,cAAc,EAAE,aAAa,GACxF,MAAM,QAAQ,CAAC;AAChB,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EACL,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,kBAAkB,EACvF,cAAc,EAAE,aAAa,EAAE,kBAAkB,EAAE,cAAc,EAAE,mBAAmB,EACtF,qBAAqB,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,EAC1D,oBAAoB,EAAE,cAAc,EAAE,YAAY,GAGnD,MAAM,QAAQ,CAAC;AAChB,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAwB,MAAM,eAAe,CAAC"}
@@ -0,0 +1,15 @@
1
+ export interface MigrationReport {
2
+ /** Destination paths that now hold something they did not before. */
3
+ moved: string[];
4
+ /** Sources deliberately left in place, with the reason. */
5
+ skipped: {
6
+ path: string;
7
+ reason: string;
8
+ }[];
9
+ }
10
+ /**
11
+ * Bring `<base>/.corenel` to the current layout. Safe to call on every start:
12
+ * with nothing to do it is a stat and a return.
13
+ */
14
+ export declare function migrateHomeLayout(base?: string): Promise<MigrationReport>;
15
+ //# sourceMappingURL=migrateHome.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrateHome.d.ts","sourceRoot":"","sources":["../migrateHome.ts"],"names":[],"mappings":"AA+BA,MAAM,WAAW,eAAe;IAC9B,qEAAqE;IACrE,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,2DAA2D;IAC3D,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC7C;AAiFD;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,GAAE,MAAkB,GAAG,OAAO,CAAC,eAAe,CAAC,CAwB1F"}
@@ -0,0 +1,139 @@
1
+ /* One-time move from the old `~/.corenel` layout to the current one.
2
+ *
3
+ * Two moves. `config/*` comes up a level, because that directory existed only
4
+ * because the CLI happened to append it. The daemon's private files go down
5
+ * into `sidecar/`, because they were sitting at the top level where the user's
6
+ * own material belongs.
7
+ *
8
+ * WHAT DOES NOT MOVE, and why each would hurt:
9
+ * - `crew/` global agents resolve as `<stateDir>/crew`; moving it
10
+ * orphans every installed one
11
+ * - `token` the ACCOUNT token; moving it signs the user out on upgrade
12
+ * - `policy.yaml` the user's default policy; moving it silently drops it
13
+ *
14
+ * NEVER CLOBBERS. A destination that already exists wins: the source is left
15
+ * alone and reported. That one rule buys three properties at once — a partial
16
+ * migration is safe to finish, a complete one is safe to repeat, and two
17
+ * processes racing at startup are safe by construction, because `rename`
18
+ * failing with EEXIST is precisely the outcome we wanted.
19
+ *
20
+ * NEVER DELETES BEFORE IT HAS WRITTEN. Across filesystems, where `rename` can't
21
+ * work, it copies and then removes — in that order, so an interruption leaves
22
+ * two copies of a file rather than none.
23
+ *
24
+ * Takes an explicit base so a test cannot be pointed at a real home directory.
25
+ * This function moves the user's edited personas; that guarantee is the point.
26
+ */
27
+ import { promises as fs } from 'node:fs';
28
+ import { homedir } from 'node:os';
29
+ import { join, dirname } from 'node:path';
30
+ import { corenelDir, sidecarDir } from './auth';
31
+ /** Files the daemon owns. */
32
+ const SIDECAR_FILES = [
33
+ 'daemon.id',
34
+ 'daemon.token',
35
+ 'hosts.json',
36
+ 'sidecar.crt',
37
+ 'sidecar.key',
38
+ 'sidecar.sans.json',
39
+ ];
40
+ /** Directories the daemon owns. `hosts/` holds mirrored client trees. */
41
+ const SIDECAR_DIRS = ['hosts'];
42
+ async function isDir(p) {
43
+ return fs.stat(p).then((s) => s.isDirectory()).catch(() => false);
44
+ }
45
+ async function present(p) {
46
+ return fs.stat(p).then(() => true).catch(() => false);
47
+ }
48
+ function code(e) {
49
+ return e?.code;
50
+ }
51
+ /** Move one file or directory, refusing to overwrite anything. */
52
+ async function moveEntry(from, to, report) {
53
+ if (!(await present(from)))
54
+ return;
55
+ if (await present(to)) {
56
+ report.skipped.push({ path: to, reason: 'destination already exists' });
57
+ return;
58
+ }
59
+ await fs.mkdir(dirname(to), { recursive: true });
60
+ try {
61
+ await fs.rename(from, to);
62
+ report.moved.push(to);
63
+ }
64
+ catch (e) {
65
+ const c = code(e);
66
+ if (c === 'EEXIST' || c === 'ENOTEMPTY') {
67
+ // Another process got there first. That is the result we wanted.
68
+ report.skipped.push({ path: to, reason: 'moved concurrently' });
69
+ return;
70
+ }
71
+ if (c === 'ENOENT') {
72
+ // Another process moved the SOURCE out from under us, same reasoning.
73
+ report.skipped.push({ path: to, reason: 'moved concurrently' });
74
+ return;
75
+ }
76
+ if (c === 'EXDEV') {
77
+ // Different filesystems. Copy first, remove second — never the reverse.
78
+ await fs.cp(from, to, { recursive: true });
79
+ await fs.rm(from, { recursive: true, force: true });
80
+ report.moved.push(to);
81
+ return;
82
+ }
83
+ throw e;
84
+ }
85
+ }
86
+ /**
87
+ * Move a directory's CONTENTS into `to`, merging with whatever is already
88
+ * there rather than replacing it.
89
+ *
90
+ * The merge matters for exactly one case today: a tree with a `config/crew/`
91
+ * would otherwise land on the real global crew root and take it out.
92
+ */
93
+ async function mergeDir(from, to, report) {
94
+ const entries = await fs.readdir(from, { withFileTypes: true }).catch(() => []);
95
+ for (const e of entries) {
96
+ const src = join(from, e.name);
97
+ const dst = join(to, e.name);
98
+ if (e.isDirectory() && (await isDir(dst)))
99
+ await mergeDir(src, dst, report);
100
+ else
101
+ await moveEntry(src, dst, report);
102
+ }
103
+ // Succeeds only when nothing was skipped inside; a refused file keeps its
104
+ // parent alive, which is what makes the leftovers findable.
105
+ await fs.rmdir(from).catch(() => { });
106
+ }
107
+ /**
108
+ * Bring `<base>/.corenel` to the current layout. Safe to call on every start:
109
+ * with nothing to do it is a stat and a return.
110
+ */
111
+ export async function migrateHomeLayout(base = homedir()) {
112
+ const report = { moved: [], skipped: [] };
113
+ const home = corenelDir(base);
114
+ if (!(await present(home)))
115
+ return report;
116
+ const config = join(home, 'config');
117
+ if (await isDir(config))
118
+ await mergeDir(config, home, report);
119
+ const side = sidecarDir(base);
120
+ for (const name of SIDECAR_FILES) {
121
+ await moveEntry(join(home, name), join(side, name), report);
122
+ }
123
+ for (const name of SIDECAR_DIRS) {
124
+ const src = join(home, name);
125
+ if (!(await isDir(src)))
126
+ continue;
127
+ const dst = join(side, name);
128
+ if (await isDir(dst))
129
+ await mergeDir(src, dst, report);
130
+ else
131
+ await moveEntry(src, dst, report);
132
+ }
133
+ // The home dir holds tokens; keep it owner-only. Best-effort — a non-POSIX
134
+ // filesystem rejecting this must not fail a migration that already worked.
135
+ if (report.moved.length)
136
+ await fs.chmod(home, 0o700).catch(() => { });
137
+ return report;
138
+ }
139
+ //# sourceMappingURL=migrateHome.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrateHome.js","sourceRoot":"","sources":["../migrateHome.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAShD,6BAA6B;AAC7B,MAAM,aAAa,GAAG;IACpB,WAAW;IACX,cAAc;IACd,YAAY;IACZ,aAAa;IACb,aAAa;IACb,mBAAmB;CACpB,CAAC;AAEF,yEAAyE;AACzE,MAAM,YAAY,GAAG,CAAC,OAAO,CAAC,CAAC;AAE/B,KAAK,UAAU,KAAK,CAAC,CAAS;IAC5B,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC;AACpE,CAAC;AAED,KAAK,UAAU,OAAO,CAAC,CAAS;IAC9B,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC;AACxD,CAAC;AAED,SAAS,IAAI,CAAC,CAAU;IACtB,OAAQ,CAAuC,EAAE,IAAI,CAAC;AACxD,CAAC;AAED,kEAAkE;AAClE,KAAK,UAAU,SAAS,CAAC,IAAY,EAAE,EAAU,EAAE,MAAuB;IACxE,IAAI,CAAC,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;QAAE,OAAO;IACnC,IAAI,MAAM,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC;QACtB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,4BAA4B,EAAE,CAAC,CAAC;QACxE,OAAO;IACT,CAAC;IACD,MAAM,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACjD,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAC1B,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACxB,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,IAAI,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,WAAW,EAAE,CAAC;YACxC,iEAAiE;YACjE,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,oBAAoB,EAAE,CAAC,CAAC;YAChE,OAAO;QACT,CAAC;QACD,IAAI,CAAC,KAAK,QAAQ,EAAE,CAAC;YACnB,sEAAsE;YACtE,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,oBAAoB,EAAE,CAAC,CAAC;YAChE,OAAO;QACT,CAAC;QACD,IAAI,CAAC,KAAK,OAAO,EAAE,CAAC;YAClB,wEAAwE;YACxE,MAAM,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC3C,MAAM,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACpD,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACtB,OAAO;QACT,CAAC;QACD,MAAM,CAAC,CAAC;IACV,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,QAAQ,CAAC,IAAY,EAAE,EAAU,EAAE,MAAuB;IACvE,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;IAChF,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;QAC/B,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;QAC7B,IAAI,CAAC,CAAC,WAAW,EAAE,IAAI,CAAC,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;YAAE,MAAM,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;;YACvE,MAAM,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;IACzC,CAAC;IACD,0EAA0E;IAC1E,4DAA4D;IAC5D,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;AACvC,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,OAAe,OAAO,EAAE;IAC9D,MAAM,MAAM,GAAoB,EAAE,KAAK,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IAC3D,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAC9B,IAAI,CAAC,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;QAAE,OAAO,MAAM,CAAC;IAE1C,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACpC,IAAI,MAAM,KAAK,CAAC,MAAM,CAAC;QAAE,MAAM,QAAQ,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IAE9D,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAC9B,KAAK,MAAM,IAAI,IAAI,aAAa,EAAE,CAAC;QACjC,MAAM,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC;IAC9D,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;QAChC,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC7B,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;YAAE,SAAS;QAClC,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC7B,IAAI,MAAM,KAAK,CAAC,GAAG,CAAC;YAAE,MAAM,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;;YAClD,MAAM,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;IACzC,CAAC;IAED,2EAA2E;IAC3E,2EAA2E;IAC3E,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM;QAAE,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IACrE,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -2,5 +2,5 @@ import type { FileService } from '@corenel/protocol';
2
2
  import type { PromptHost } from '@corenel/harness/prompts/host';
3
3
  /** A node PromptHost over a FileService workspace. setPromptHost(nodePromptHost(ws))
4
4
  * then makes the harness prompt subsystem (composeAgentSystem) run in node. */
5
- export declare function nodePromptHost(workspace: FileService): PromptHost;
5
+ export declare function nodePromptHost(workspace: FileService, project?: FileService): PromptHost;
6
6
  //# sourceMappingURL=promptHost.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"promptHost.d.ts","sourceRoot":"","sources":["../promptHost.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,OAAO,KAAK,EAAE,UAAU,EAAiB,MAAM,+BAA+B,CAAC;AAuC/E;+EAC+E;AAC/E,wBAAgB,cAAc,CAAC,SAAS,EAAE,WAAW,GAAG,UAAU,CAkBjE"}
1
+ {"version":3,"file":"promptHost.d.ts","sourceRoot":"","sources":["../promptHost.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,OAAO,KAAK,EAAE,UAAU,EAAiB,MAAM,+BAA+B,CAAC;AAuC/E;+EAC+E;AAC/E,wBAAgB,cAAc,CAAC,SAAS,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,UAAU,CAuBxF"}
@@ -49,9 +49,14 @@ async function compile(src, values, fileSystem, mainPath) {
49
49
  }
50
50
  /** A node PromptHost over a FileService workspace. setPromptHost(nodePromptHost(ws))
51
51
  * then makes the harness prompt subsystem (composeAgentSystem) run in node. */
52
- export function nodePromptHost(workspace) {
52
+ export function nodePromptHost(workspace, project) {
53
53
  return {
54
54
  workspace,
55
+ /* The user's PROJECT files, when the caller has them, so skills installed
56
+ * into `.prompd/skills/` are visible. Omitted rather than faked when there
57
+ * is none: a CLI invoked outside a project genuinely has no installed
58
+ * skills, and saying so beats inventing an empty directory. */
59
+ ...(project ? { projectWorkspace: () => project } : {}),
55
60
  seed: async (defaults) => {
56
61
  for (const [p, content] of Object.entries(defaults)) {
57
62
  if (!(await workspace.stat(p)))
@@ -1 +1 @@
1
- {"version":3,"file":"promptHost.js","sourceRoot":"","sources":["../promptHost.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"promptHost.js","sourceRoot":"","sources":["../promptHost.ts"],"names":[],"mappings":"AAAA;;;;;qEAKqE;AACrE,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAGhG,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGpE,MAAM,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;AAClC,MAAM,QAAQ,GAAG,IAAI,cAAc,EAAE,CAAC;AAEtC,mFAAmF;AACnF,SAAS,OAAO,CAAC,GAAgB;IAC/B,OAAO;QACL,KAAK,CAAC,QAAQ,CAAC,CAAS;YACtB,IAAI,CAAC;gBAAC,OAAO,MAAM,GAAG,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC;gBAAC,OAAO,IAAI,CAAC;YAAC,CAAC;QAC7E,CAAC;QACD,KAAK,CAAC,WAAW,CAAC,CAAS;YACzB,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,KAAK,WAAW,CAAC;QACtE,CAAC;QACD,KAAK,CAAC,OAAO,CAAC,CAAS;YACrB,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACnE,CAAC;KACF,CAAC;AACJ,CAAC;AAED;mDACmD;AACnD,KAAK,UAAU,OAAO,CAAC,GAAgB;IACrC,MAAM,GAAG,GAA2B,EAAE,CAAC;IACvC,KAAK,MAAM,CAAC,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;QAC/C,IAAI,CAAC;YAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,qBAAqB,CAAC,CAAC;IAC/E,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,KAAK,UAAU,OAAO,CAAC,GAAW,EAAE,MAA+B,EAAE,UAAwB,EAAE,QAAiB;IAC9G,MAAM,EAAE,GAAG,QAAQ,IAAI,YAAY,CAAC;IACpC,MAAM,EAAE,GAAG,UAAU,IAAI,IAAI,gBAAgB,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;IAC7D,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,kBAAkB,CAAC,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,IAAI,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC,CAAC;IAC1H,MAAM,QAAQ,GAAG,GAAG,CAAC,cAAc,CAAC;IACpC,MAAM,MAAM,GAAG,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5G,OAAO,EAAE,MAAM,EAAE,CAAC;AACpB,CAAC;AAED;+EAC+E;AAC/E,MAAM,UAAU,cAAc,CAAC,SAAsB,EAAE,OAAqB;IAC1E,OAAO;QACL,SAAS;QACT;;;uEAG+D;QAC/D,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,GAAgB,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACpE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE;YACvB,KAAK,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACpD,IAAI,CAAC,CAAC,MAAM,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;oBAAE,MAAM,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;YACpE,CAAC;QACH,CAAC;QACD,KAAK,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,QAAQ,IAAI,EAAE,CAAuC,EAAE,CAAC;QACjH,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC;QACxD,eAAe,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE;YAC/C,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,SAAS,CAAC,CAAC;YACzC,MAAM,CAAC,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;YAClC,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,mDAAmD;YACzE,OAAO,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC;QACzF,CAAC;QACD,SAAS,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,wDAAwD;KAC9E,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@corenel/tools-node",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
+ "license": "Elastic-2.0",
4
5
  "type": "module",
5
6
  "description": "Corenel node capabilities — the tools-web twin. A disk-backed FileService (the harness file tools + node PromptHost workspace) over node:fs, confined to a root. Shell/secrets/~/.corenel to follow.",
6
7
  "exports": {
@@ -15,8 +16,8 @@
15
16
  },
16
17
  "dependencies": {
17
18
  "@prompd/core": "0.5.0-beta.10",
18
- "@corenel/protocol": "0.4.0",
19
- "@corenel/harness": "0.4.0"
19
+ "@corenel/harness": "0.6.0",
20
+ "@corenel/protocol": "0.6.0"
20
21
  },
21
22
  "devDependencies": {
22
23
  "@types/node": "^24.13.1",
@@ -29,6 +30,11 @@
29
30
  "files": [
30
31
  "dist"
31
32
  ],
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "git+https://github.com/Prompd/prompd-web.git",
36
+ "directory": "packages/tools-node"
37
+ },
32
38
  "scripts": {
33
39
  "typecheck": "tsc --noEmit",
34
40
  "preverify": "pnpm --filter @corenel/protocol build && pnpm --filter @corenel/harness build",