toolstile 0.1.2 → 0.2.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.
@@ -0,0 +1,48 @@
1
+ import type { ClientId } from "./types.js";
2
+ export declare const DEFAULT_SERVER = "https://toolstile.com";
3
+ export interface AgentLink {
4
+ /** The agent's authorization ID in Toolstile, valid in one workspace. */
5
+ id: string;
6
+ workspaceId: string;
7
+ /** The Toolstile origin that issued the token; the proxy sends it nowhere else. */
8
+ server: string;
9
+ label: string;
10
+ /** The agent's own gateway token; only `toolstile mcp proxy` reads it. */
11
+ token: string;
12
+ }
13
+ /** Everything `auth` and `mcp` keep on this machine, in one owner-only file. */
14
+ export interface State {
15
+ /** The origin `auth login` last signed in to. */
16
+ server: string;
17
+ session?: {
18
+ token: string;
19
+ email: string;
20
+ expiresAt: string;
21
+ server: string;
22
+ };
23
+ workspace?: {
24
+ id: string;
25
+ slug: string;
26
+ name: string;
27
+ };
28
+ device?: {
29
+ id: string;
30
+ label: string;
31
+ };
32
+ agents: Partial<Record<ClientId, AgentLink>>;
33
+ }
34
+ export interface StateEnv {
35
+ home?: string;
36
+ env?: Record<string, string | undefined>;
37
+ platform?: NodeJS.Platform;
38
+ }
39
+ /** `TOOLSTILE_CONFIG_DIR`, else the platform's per-user config folder. */
40
+ export declare function stateDir({ home, env, platform }?: StateEnv): string;
41
+ export declare const statePath: (opts?: StateEnv) => string;
42
+ /**
43
+ * The saved server always wins over `TOOLSTILE_URL`, which only picks the server for a new
44
+ * `auth login`: an environment variable set by a project must not redirect saved tokens.
45
+ */
46
+ export declare function loadState(opts?: StateEnv): State;
47
+ /** Written to a temporary file and renamed, so a crash never leaves half a file. */
48
+ export declare function saveState(state: State, opts?: StateEnv): void;
package/dist/state.js ADDED
@@ -0,0 +1,51 @@
1
+ import { chmodSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { join } from "node:path";
4
+ export const DEFAULT_SERVER = "https://toolstile.com";
5
+ /** `TOOLSTILE_CONFIG_DIR`, else the platform's per-user config folder. */
6
+ export function stateDir({ home = homedir(), env = process.env, platform = process.platform } = {}) {
7
+ if (env.TOOLSTILE_CONFIG_DIR)
8
+ return env.TOOLSTILE_CONFIG_DIR;
9
+ if (platform === "win32")
10
+ return join(env.APPDATA ?? join(home, "AppData", "Roaming"), "toolstile");
11
+ return join(env.XDG_CONFIG_HOME ?? join(home, ".config"), "toolstile");
12
+ }
13
+ export const statePath = (opts) => join(stateDir(opts), "credentials.json");
14
+ /**
15
+ * The saved server always wins over `TOOLSTILE_URL`, which only picks the server for a new
16
+ * `auth login`: an environment variable set by a project must not redirect saved tokens.
17
+ */
18
+ export function loadState(opts) {
19
+ const fallback = { server: DEFAULT_SERVER, agents: {} };
20
+ let text;
21
+ try {
22
+ text = readFileSync(statePath(opts), "utf8");
23
+ }
24
+ catch (error) {
25
+ if (error.code === "ENOENT")
26
+ return fallback;
27
+ throw error;
28
+ }
29
+ try {
30
+ const data = JSON.parse(text);
31
+ return { ...fallback, ...data, agents: data.agents ?? {} };
32
+ }
33
+ catch {
34
+ throw new Error(`${statePath(opts)} is not valid JSON. Delete it and run toolstile auth login again.`);
35
+ }
36
+ }
37
+ /** Written to a temporary file and renamed, so a crash never leaves half a file. */
38
+ export function saveState(state, opts) {
39
+ const dir = stateDir(opts);
40
+ mkdirSync(dir, { recursive: true, mode: 0o700 });
41
+ const path = statePath(opts);
42
+ const temp = `${path}.${process.pid}.tmp`;
43
+ try {
44
+ writeFileSync(temp, `${JSON.stringify(state, null, 2)}\n`, { mode: 0o600 });
45
+ chmodSync(temp, 0o600);
46
+ renameSync(temp, path);
47
+ }
48
+ finally {
49
+ rmSync(temp, { force: true });
50
+ }
51
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "toolstile",
3
- "version": "0.1.2",
4
- "description": "Audit the MCP server configs your AI agents use for plaintext secrets, unpinned packages, auto-approved tools and duplicated setups. Local and read-only.",
3
+ "version": "0.2.0",
4
+ "description": "Audit the MCP server configs your AI agents use for plaintext secrets, unpinned packages, auto-approved tools and duplicated setups, and connect those agents to Toolstile without putting tokens in their configs.",
5
5
  "keywords": [
6
6
  "mcp",
7
7
  "model-context-protocol",
@@ -10,7 +10,9 @@
10
10
  "claude",
11
11
  "cursor",
12
12
  "codex",
13
- "secrets"
13
+ "secrets",
14
+ "mcp-proxy",
15
+ "device-login"
14
16
  ],
15
17
  "homepage": "https://github.com/toolstile/cli#readme",
16
18
  "repository": {