@kimchi-dev/kimchictl 0.0.4 → 0.0.5
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/dist/auth/auth-file.d.ts +8 -8
- package/dist/auth/auth-file.d.ts.map +1 -1
- package/dist/auth/auth-file.js +37 -34
- package/dist/auth/auth-file.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -3
- package/src/auth/auth-file.ts +37 -33
- package/src/version.ts +1 -1
package/dist/auth/auth-file.d.ts
CHANGED
|
@@ -5,15 +5,15 @@
|
|
|
5
5
|
*
|
|
6
6
|
* { "<providerId>": { "type": "api_key", "key": "…" }, … }
|
|
7
7
|
*
|
|
8
|
-
* written pretty-printed (2-space indent, trailing newline), mode 0600
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* written pretty-printed (2-space indent, trailing newline), mode 0600.
|
|
9
|
+
* kimchictl must stay byte-compatible: the harness reads the entries this
|
|
10
|
+
* writes, and vice versa.
|
|
11
11
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
12
|
+
* Locking: the harness uses proper-lockfile for the same file. kimchictl
|
|
13
|
+
* writes atomically via temp-file-and-rename (POSIX atomic) instead —
|
|
14
|
+
* zero transitive dependencies, which matters because this module runs
|
|
15
|
+
* inside the harness's dynamically-imported package tree where CJS
|
|
16
|
+
* transitive deps (graceful-fs) don't always resolve.
|
|
17
17
|
*/
|
|
18
18
|
/** Read the raw auth.json map. Returns {} when the file is absent or blank. */
|
|
19
19
|
export declare function readAuthJson(authPath: string): Record<string, unknown>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-file.d.ts","sourceRoot":"../src/","sources":["auth/auth-file.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"auth-file.d.ts","sourceRoot":"../src/","sources":["auth/auth-file.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;;GAgBG;AAEH,+EAA+E;AAC/E,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAGtE;AAED,sEAAsE;AACtE,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAMpE;AAED;;;;;;;;;GASG;AACH,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAqCpH;AAED,qFAAqF;AACrF,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAErE;AAED,iGAAiG;AACjG,wBAAgB,+BAA+B,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,CAa5E"}
|
package/dist/auth/auth-file.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
-
import { dirname } from "node:path";
|
|
1
|
+
import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { basename, dirname, join } from "node:path";
|
|
3
3
|
import { isDeepStrictEqual } from "node:util";
|
|
4
|
-
import { lock } from "proper-lockfile";
|
|
5
4
|
import { isKimchiProvider } from "./provider-ids.js";
|
|
6
5
|
/**
|
|
7
6
|
* Shared auth.json access — a port of the kimchi harness's `syncPiAuth`
|
|
@@ -10,15 +9,15 @@ import { isKimchiProvider } from "./provider-ids.js";
|
|
|
10
9
|
*
|
|
11
10
|
* { "<providerId>": { "type": "api_key", "key": "…" }, … }
|
|
12
11
|
*
|
|
13
|
-
* written pretty-printed (2-space indent, trailing newline), mode 0600
|
|
14
|
-
*
|
|
15
|
-
*
|
|
12
|
+
* written pretty-printed (2-space indent, trailing newline), mode 0600.
|
|
13
|
+
* kimchictl must stay byte-compatible: the harness reads the entries this
|
|
14
|
+
* writes, and vice versa.
|
|
16
15
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
16
|
+
* Locking: the harness uses proper-lockfile for the same file. kimchictl
|
|
17
|
+
* writes atomically via temp-file-and-rename (POSIX atomic) instead —
|
|
18
|
+
* zero transitive dependencies, which matters because this module runs
|
|
19
|
+
* inside the harness's dynamically-imported package tree where CJS
|
|
20
|
+
* transitive deps (graceful-fs) don't always resolve.
|
|
22
21
|
*/
|
|
23
22
|
/** Read the raw auth.json map. Returns {} when the file is absent or blank. */
|
|
24
23
|
export function readAuthJson(authPath) {
|
|
@@ -46,33 +45,37 @@ export function readSavedApiKey(authPath) {
|
|
|
46
45
|
*/
|
|
47
46
|
export async function syncSharedAuth(authPath, apiKey, providerIds) {
|
|
48
47
|
mkdirSync(dirname(authPath), { recursive: true, mode: 0o700 });
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
if (isKimchiProvider(providerId)) {
|
|
58
|
-
delete nextCredentials[providerId];
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
if (apiKey) {
|
|
62
|
-
const ids = new Set([...providerIds.filter(isKimchiProvider), "kimchi-dev"]);
|
|
63
|
-
for (const providerId of ids) {
|
|
64
|
-
nextCredentials[providerId] = { type: "api_key", key: apiKey };
|
|
65
|
-
}
|
|
48
|
+
const authExists = existsSync(authPath);
|
|
49
|
+
if (!apiKey && !authExists)
|
|
50
|
+
return;
|
|
51
|
+
const credentials = authExists ? readAuthJson(authPath) : {};
|
|
52
|
+
const nextCredentials = { ...credentials };
|
|
53
|
+
for (const providerId of Object.keys(nextCredentials)) {
|
|
54
|
+
if (isKimchiProvider(providerId)) {
|
|
55
|
+
delete nextCredentials[providerId];
|
|
66
56
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
57
|
+
}
|
|
58
|
+
if (apiKey) {
|
|
59
|
+
const ids = new Set([...providerIds.filter(isKimchiProvider), "kimchi-dev"]);
|
|
60
|
+
for (const providerId of ids) {
|
|
61
|
+
nextCredentials[providerId] = { type: "api_key", key: apiKey };
|
|
70
62
|
}
|
|
71
|
-
|
|
63
|
+
}
|
|
64
|
+
if (authExists && isDeepStrictEqual(credentials, nextCredentials)) {
|
|
65
|
+
chmodSync(authPath, 0o600);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
// Atomic write: temp file + rename (POSIX), so the harness never sees a
|
|
69
|
+
// partially-written auth.json. The temp file is cleaned up on failure.
|
|
70
|
+
const tempPath = join(dirname(authPath), `.${basename(authPath)}.tmp-${process.pid}`);
|
|
71
|
+
try {
|
|
72
|
+
writeFileSync(tempPath, `${JSON.stringify(nextCredentials, null, 2)}\n`, { encoding: "utf-8", mode: 0o600 });
|
|
73
|
+
renameSync(tempPath, authPath);
|
|
72
74
|
chmodSync(authPath, 0o600);
|
|
73
75
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
+
catch (err) {
|
|
77
|
+
rmSync(tempPath, { force: true });
|
|
78
|
+
throw err;
|
|
76
79
|
}
|
|
77
80
|
}
|
|
78
81
|
/** Remove all Kimchi credentials from auth.json (logout path). No-op when absent. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-file.js","sourceRoot":"../src/","sources":["auth/auth-file.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"auth-file.js","sourceRoot":"../src/","sources":["auth/auth-file.ts"],"names":[],"mappings":"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"}
|
package/dist/version.d.ts
CHANGED
package/dist/version.js
CHANGED
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"//name": "Scoped under the kimchi-dev npm org (the GitHub org is getkimchi)",
|
|
3
3
|
"name": "@kimchi-dev/kimchictl",
|
|
4
4
|
"//version": "Placeholder, never bumped: the git tag is the version, stamped by release.yml at publish time",
|
|
5
|
-
"version": "0.0.
|
|
5
|
+
"version": "0.0.5",
|
|
6
6
|
"description": "Create and connect to kimchi remote workspaces from the terminal.",
|
|
7
7
|
"keywords": [
|
|
8
8
|
"kimchi",
|
|
@@ -75,14 +75,12 @@
|
|
|
75
75
|
"devDependencies": {
|
|
76
76
|
"@biomejs/biome": "^2.5.6",
|
|
77
77
|
"@types/node": "^22.19.18",
|
|
78
|
-
"@types/proper-lockfile": "^4.1.4",
|
|
79
78
|
"@types/ws": "^8.18.1",
|
|
80
79
|
"typescript": "^5.9.3",
|
|
81
80
|
"vitest": "^3.2.4"
|
|
82
81
|
},
|
|
83
82
|
"dependencies": {
|
|
84
83
|
"open": "^11.0.4",
|
|
85
|
-
"proper-lockfile": "^4.1.2",
|
|
86
84
|
"ws": "^8.21.3"
|
|
87
85
|
}
|
|
88
86
|
}
|
package/src/auth/auth-file.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs"
|
|
2
|
-
import { dirname } from "node:path"
|
|
1
|
+
import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs"
|
|
2
|
+
import { basename, dirname, join } from "node:path"
|
|
3
3
|
import { isDeepStrictEqual } from "node:util"
|
|
4
|
-
import { lock } from "proper-lockfile"
|
|
5
4
|
import { isKimchiProvider } from "./provider-ids.js"
|
|
6
5
|
|
|
7
6
|
/**
|
|
@@ -11,15 +10,15 @@ import { isKimchiProvider } from "./provider-ids.js"
|
|
|
11
10
|
*
|
|
12
11
|
* { "<providerId>": { "type": "api_key", "key": "…" }, … }
|
|
13
12
|
*
|
|
14
|
-
* written pretty-printed (2-space indent, trailing newline), mode 0600
|
|
15
|
-
*
|
|
16
|
-
*
|
|
13
|
+
* written pretty-printed (2-space indent, trailing newline), mode 0600.
|
|
14
|
+
* kimchictl must stay byte-compatible: the harness reads the entries this
|
|
15
|
+
* writes, and vice versa.
|
|
17
16
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
17
|
+
* Locking: the harness uses proper-lockfile for the same file. kimchictl
|
|
18
|
+
* writes atomically via temp-file-and-rename (POSIX atomic) instead —
|
|
19
|
+
* zero transitive dependencies, which matters because this module runs
|
|
20
|
+
* inside the harness's dynamically-imported package tree where CJS
|
|
21
|
+
* transitive deps (graceful-fs) don't always resolve.
|
|
23
22
|
*/
|
|
24
23
|
|
|
25
24
|
/** Read the raw auth.json map. Returns {} when the file is absent or blank. */
|
|
@@ -49,35 +48,40 @@ export function readSavedApiKey(authPath: string): string | undefined {
|
|
|
49
48
|
*/
|
|
50
49
|
export async function syncSharedAuth(authPath: string, apiKey: string, providerIds: readonly string[]): Promise<void> {
|
|
51
50
|
mkdirSync(dirname(authPath), { recursive: true, mode: 0o700 })
|
|
52
|
-
const release = await lock(authPath, { realpath: false, retries: 10 })
|
|
53
|
-
try {
|
|
54
|
-
const authExists = existsSync(authPath)
|
|
55
|
-
if (!apiKey && !authExists) return
|
|
56
51
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
for (const providerId of Object.keys(nextCredentials)) {
|
|
60
|
-
if (isKimchiProvider(providerId)) {
|
|
61
|
-
delete nextCredentials[providerId]
|
|
62
|
-
}
|
|
63
|
-
}
|
|
52
|
+
const authExists = existsSync(authPath)
|
|
53
|
+
if (!apiKey && !authExists) return
|
|
64
54
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
55
|
+
const credentials = authExists ? readAuthJson(authPath) : {}
|
|
56
|
+
const nextCredentials = { ...credentials }
|
|
57
|
+
for (const providerId of Object.keys(nextCredentials)) {
|
|
58
|
+
if (isKimchiProvider(providerId)) {
|
|
59
|
+
delete nextCredentials[providerId]
|
|
70
60
|
}
|
|
61
|
+
}
|
|
71
62
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
63
|
+
if (apiKey) {
|
|
64
|
+
const ids = new Set([...providerIds.filter(isKimchiProvider), "kimchi-dev"])
|
|
65
|
+
for (const providerId of ids) {
|
|
66
|
+
nextCredentials[providerId] = { type: "api_key", key: apiKey }
|
|
75
67
|
}
|
|
68
|
+
}
|
|
76
69
|
|
|
77
|
-
|
|
70
|
+
if (authExists && isDeepStrictEqual(credentials, nextCredentials)) {
|
|
71
|
+
chmodSync(authPath, 0o600)
|
|
72
|
+
return
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Atomic write: temp file + rename (POSIX), so the harness never sees a
|
|
76
|
+
// partially-written auth.json. The temp file is cleaned up on failure.
|
|
77
|
+
const tempPath = join(dirname(authPath), `.${basename(authPath)}.tmp-${process.pid}`)
|
|
78
|
+
try {
|
|
79
|
+
writeFileSync(tempPath, `${JSON.stringify(nextCredentials, null, 2)}\n`, { encoding: "utf-8", mode: 0o600 })
|
|
80
|
+
renameSync(tempPath, authPath)
|
|
78
81
|
chmodSync(authPath, 0o600)
|
|
79
|
-
}
|
|
80
|
-
|
|
82
|
+
} catch (err) {
|
|
83
|
+
rmSync(tempPath, { force: true })
|
|
84
|
+
throw err
|
|
81
85
|
}
|
|
82
86
|
}
|
|
83
87
|
|
package/src/version.ts
CHANGED