synomem 0.8.0 → 0.9.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.
Files changed (93) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/README.md +47 -68
  3. package/dist/backend.d.ts +18 -6
  4. package/dist/backend.d.ts.map +1 -1
  5. package/dist/backend.js +55 -41
  6. package/dist/backend.js.map +1 -1
  7. package/dist/cli.d.ts +20 -33
  8. package/dist/cli.d.ts.map +1 -1
  9. package/dist/cli.js +1391 -1321
  10. package/dist/cli.js.map +1 -1
  11. package/dist/configure.d.ts +12 -46
  12. package/dist/configure.d.ts.map +1 -1
  13. package/dist/configure.js +51 -192
  14. package/dist/configure.js.map +1 -1
  15. package/dist/credentials.d.ts +82 -33
  16. package/dist/credentials.d.ts.map +1 -1
  17. package/dist/credentials.js +270 -44
  18. package/dist/credentials.js.map +1 -1
  19. package/dist/discover.d.ts +8 -35
  20. package/dist/discover.d.ts.map +1 -1
  21. package/dist/discover.js +42 -38
  22. package/dist/discover.js.map +1 -1
  23. package/dist/errors.d.ts +1 -1
  24. package/dist/errors.d.ts.map +1 -1
  25. package/dist/errors.js +4 -0
  26. package/dist/errors.js.map +1 -1
  27. package/dist/import.d.ts +3 -0
  28. package/dist/import.d.ts.map +1 -1
  29. package/dist/import.js +3 -0
  30. package/dist/import.js.map +1 -1
  31. package/dist/index.d.ts +10 -8
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +6 -5
  34. package/dist/index.js.map +1 -1
  35. package/dist/mcp/index.d.ts +18 -18
  36. package/dist/mcp/index.d.ts.map +1 -1
  37. package/dist/mcp/index.js +402 -231
  38. package/dist/mcp/index.js.map +1 -1
  39. package/dist/mcp-server.d.ts +5 -1
  40. package/dist/mcp-server.d.ts.map +1 -1
  41. package/dist/mcp-server.js +27 -105
  42. package/dist/mcp-server.js.map +1 -1
  43. package/dist/oauth.d.ts +32 -33
  44. package/dist/oauth.d.ts.map +1 -1
  45. package/dist/oauth.js +196 -126
  46. package/dist/oauth.js.map +1 -1
  47. package/dist/profiles.d.ts +243 -0
  48. package/dist/profiles.d.ts.map +1 -0
  49. package/dist/profiles.js +479 -0
  50. package/dist/profiles.js.map +1 -0
  51. package/dist/project.d.ts +8 -39
  52. package/dist/project.d.ts.map +1 -1
  53. package/dist/project.js +36 -94
  54. package/dist/project.js.map +1 -1
  55. package/dist/remote.d.ts +24 -17
  56. package/dist/remote.d.ts.map +1 -1
  57. package/dist/remote.js +54 -52
  58. package/dist/remote.js.map +1 -1
  59. package/dist/resolvers.d.ts +54 -0
  60. package/dist/resolvers.d.ts.map +1 -0
  61. package/dist/resolvers.js +336 -0
  62. package/dist/resolvers.js.map +1 -0
  63. package/dist/service.d.ts +3 -2
  64. package/dist/service.d.ts.map +1 -1
  65. package/dist/skill-install.d.ts +4 -6
  66. package/dist/skill-install.d.ts.map +1 -1
  67. package/dist/skill-install.js +13 -12
  68. package/dist/skill-install.js.map +1 -1
  69. package/dist/types.d.ts +45 -15
  70. package/dist/types.d.ts.map +1 -1
  71. package/docs/cli.md +173 -196
  72. package/docs/mcp.md +69 -65
  73. package/package.json +1 -1
  74. package/skills/synomem/SKILL.md +29 -26
  75. package/skills/synomem/references/examples.md +13 -11
  76. package/src/backend.ts +66 -64
  77. package/src/cli.ts +2123 -2219
  78. package/src/configure.ts +62 -241
  79. package/src/credentials.ts +316 -85
  80. package/src/discover.ts +53 -59
  81. package/src/errors.ts +4 -0
  82. package/src/import.ts +5 -0
  83. package/src/index.ts +15 -19
  84. package/src/mcp/index.ts +473 -277
  85. package/src/mcp-server.ts +32 -114
  86. package/src/oauth.ts +249 -131
  87. package/src/profiles.ts +661 -0
  88. package/src/project.ts +42 -108
  89. package/src/remote.ts +69 -63
  90. package/src/resolvers.ts +385 -0
  91. package/src/service.ts +2 -7
  92. package/src/skill-install.ts +17 -18
  93. package/src/types.ts +40 -15
package/dist/configure.js CHANGED
@@ -1,220 +1,79 @@
1
1
  /**
2
- * `synomem config` — the onboarding wizard, and its deterministic equivalent.
2
+ * Setup helpers shared by `connection` and `setup`.
3
3
  *
4
4
  * Two rules shape this file. Every interactive step has a non-interactive
5
- * counterpart, so an agent can configure a machine without a terminal. And the
6
- * wizard refuses to run at all when nobody is there to answer: a setup program
7
- * that blocks forever on a pipe is worse than one that says which flags it
8
- * needs.
5
+ * counterpart, so an agent can configure a machine without a terminal. And a
6
+ * secret is never accepted as a command-line argument: an argument is kept by
7
+ * the shell history and visible in the process list, so access keys arrive on
8
+ * stdin.
9
9
  */
10
- import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
11
- import { join } from 'node:path';
12
- import { cloudApiUrl } from './cloud.js';
13
10
  import { SynomemError } from './errors.js';
14
- import { resolveHome } from './config.js';
15
- import { ask, askSecret, confirm, select } from './prompt.js';
11
+ import { askSecret } from './prompt.js';
16
12
  /**
17
- * Where a credential can actually be kept on this platform.
13
+ * Where a credential can be kept on this platform, recommended first.
18
14
  *
19
- * Reported rather than assumed: offering macOS Keychain on Linux, or a Secret
20
- * Service that is not running, produces a setup that appears to succeed and
21
- * then cannot read its own credential back.
15
+ * Reported rather than assumed: offering the macOS Keychain on Linux, or a
16
+ * Secret Service that is not running, produces a setup that appears to succeed
17
+ * and then cannot read its own credential back.
22
18
  */
23
19
  export function credentialStoreChoices(platform = process.platform) {
24
20
  const native = platform === 'darwin'
25
- ? { value: 'keychain', label: 'macOS Keychain', detail: 'Recommended.' }
26
- : platform === 'win32'
27
- ? /*
28
- * Windows has no native option here yet, so the restricted file is
29
- * the recommendation rather than Credential Manager. Offering a
30
- * store the credential layer cannot actually read back would fail
31
- * at the first use, after the wizard had already told the person
32
- * their credential was safely stored.
33
- */
21
+ ? [{ value: 'keychain', label: 'macOS Keychain', detail: 'Recommended.' }]
22
+ : platform === 'linux'
23
+ ? [
34
24
  {
35
- value: 'file',
36
- label: 'A file in the Synomem home',
37
- // Not called "restricted" on Windows: `chmod` there only toggles
38
- // the read-only bit, so the protection is the user profile
39
- // directory's access control, not a mode of 0600.
40
- detail: 'Protected by your user profile. Recommended until Credential Manager lands.',
41
- }
42
- : {
43
- value: 'keychain',
44
- label: 'Secret Service (libsecret)',
45
- detail: 'Recommended where a desktop keyring is running.',
46
- };
47
- return [
48
- native,
49
- ...(native.value === 'file'
50
- ? []
51
- : [
52
- {
53
- value: 'file',
54
- label: 'A restricted file in the Synomem home',
55
- detail: 'Mode 0600. Use on headless machines with no keyring.',
25
+ value: 'keychain',
26
+ label: 'Secret Service (libsecret)',
27
+ detail: 'Recommended where a desktop keyring is running.',
56
28
  },
57
- ]),
29
+ ]
30
+ : [];
31
+ return [
32
+ ...native,
33
+ {
34
+ value: 'file',
35
+ label: 'A restricted file in the Synomem home',
36
+ detail: 'Mode 0600. Use on headless machines with no keyring.',
37
+ },
58
38
  {
59
39
  value: 'environment',
60
- label: 'Print environment-variable instructions',
61
- detail: 'Nothing is stored. Synomem never edits your shell profile.',
40
+ label: 'SYNOMEM_ACCESS_TOKEN (access keys only)',
41
+ detail: 'Nothing is stored; the key is read from the environment each run.',
62
42
  },
63
43
  ];
64
44
  }
45
+ /** The default store: the OS keychain where one exists, otherwise refused. */
46
+ export function defaultCredentialBackend(platform = process.platform) {
47
+ if (platform === 'darwin' || platform === 'linux')
48
+ return 'keychain';
49
+ throw new SynomemError('CONFIG_INVALID', 'This platform has no supported credential store. Pass --store file (a mode-0600 file), or --store environment for an access key.');
50
+ }
51
+ export function parseCredentialBackend(value, platform = process.platform) {
52
+ if (value === undefined)
53
+ return defaultCredentialBackend(platform);
54
+ if (value === 'keychain' || value === 'file' || value === 'environment')
55
+ return value;
56
+ throw new SynomemError('INVALID_INPUT', '--store must be keychain, file, or environment.');
57
+ }
65
58
  /** Refuses to guess when there is nobody to ask. */
66
- export function assertInteractive(io) {
59
+ export function assertInteractive(io, alternative) {
67
60
  if (io.interactive)
68
61
  return;
69
- throw new SynomemError('INVALID_INPUT', [
70
- 'synomem config needs an interactive terminal.',
71
- '',
72
- 'For automation, use the deterministic form instead:',
73
- '',
74
- ' synomem config init --backend local --yes',
75
- '',
76
- ' synomem config init --backend remote --auth access-key \\',
77
- ' --workspace <workspace-id> --access-token-stdin --yes',
78
- '',
79
- 'Pipe the token in rather than passing it as an argument: an argument is',
80
- 'kept by both the shell history and the process list.',
81
- ].join('\n'));
82
- }
83
- /**
84
- * Stores an access key in a restricted file.
85
- *
86
- * Separate from `config.json` so a configuration file can be read, copied or
87
- * pasted into an issue without carrying a secret with it.
88
- */
89
- function credentialFilePath(home) {
90
- return join(home, 'credentials', 'installation.json');
91
- }
92
- export function writeCredentialFile(home, token) {
93
- const directory = join(home, 'credentials');
94
- mkdirSync(directory, { recursive: true, mode: 0o700 });
95
- chmodSync(directory, 0o700);
96
- const path = credentialFilePath(home);
97
- writeFileSync(path, `${JSON.stringify({ accessToken: token }, null, 2)}\n`, { mode: 0o600 });
98
- chmodSync(path, 0o600);
99
- return path;
62
+ throw new SynomemError('INVALID_INPUT', `This step needs an interactive terminal. For automation: ${alternative}`);
100
63
  }
101
- /**
102
- * Reads back what `writeCredentialFile` wrote.
103
- *
104
- * Without this, choosing the restricted-file store at `synomem config` wrote
105
- * a credential nothing ever read again: every later command still asked the
106
- * OS keychain, found nothing there, and failed with AUTH_REQUIRED even though
107
- * the key was sitting right there on disk.
108
- */
109
- export function readCredentialFile(home) {
110
- const path = credentialFilePath(home);
111
- if (!existsSync(path))
112
- return undefined;
113
- try {
114
- const parsed = JSON.parse(readFileSync(path, 'utf8'));
115
- return typeof parsed.accessToken === 'string' ? parsed.accessToken : undefined;
116
- }
117
- catch {
118
- return undefined;
64
+ /** Reads an access key from stdin (or a prompt), never from an argument. */
65
+ export async function readAccessKey(io) {
66
+ const key = await askSecret(io, 'Access key');
67
+ if (!key)
68
+ throw new SynomemError('INVALID_INPUT', 'No access key was provided on stdin.');
69
+ if (!key.startsWith('syn_')) {
70
+ throw new SynomemError('INVALID_INPUT', 'That does not look like a Synomem access key (syn_…).');
119
71
  }
72
+ return key;
120
73
  }
121
74
  /** A key's identifying prefix. Never the key. */
122
75
  export function credentialFingerprint(token) {
123
76
  const head = token.slice(0, 12);
124
- return `${head}${token.length > 12 ? '\u2026' : ''}`;
125
- }
126
- export function environmentInstructions(token) {
127
- return [
128
- 'Set this value for the current shell:',
129
- '',
130
- ` export SYNOMEM_ACCESS_TOKEN='${token}'`,
131
- '',
132
- 'To persist it, add that to a secret-aware shell configuration or to your',
133
- 'agent runtime environment. Synomem will not edit your shell profile for',
134
- 'you: silently rewriting a dotfile is not a thing a setup program should do.',
135
- ].join('\n');
136
- }
137
- /** The interactive flow, returning the plan it settled on. */
138
- export async function runConfigWizard(io, options = {}) {
139
- assertInteractive(io);
140
- const env = options.env ?? process.env;
141
- io.output.write([
142
- '',
143
- 'Welcome to Synomem',
144
- '',
145
- 'Synomem gives agents durable notes, messages, tasks, todos, kudos,',
146
- 'and shared coordination.',
147
- '',
148
- ].join('\n'));
149
- const backend = await select(io, 'Where should Synomem store canonical state?', [
150
- {
151
- value: 'local',
152
- label: 'Local \u2014 SQLite on this machine',
153
- detail: 'Nothing is uploaded. One implicit workspace.',
154
- },
155
- {
156
- value: 'remote',
157
- label: 'Synomem Cloud \u2014 shared across machines and agents',
158
- detail: 'Organizations, workspaces, roles and administration.',
159
- },
160
- ]);
161
- const home = await ask(io, 'Where should Synomem store its data?', resolveHome(options.home));
162
- if (backend === 'local') {
163
- return { backend, home };
164
- }
165
- const serviceUrl = cloudApiUrl(env);
166
- io.output.write(`\nConnecting to Synomem Cloud at ${serviceUrl}\n`);
167
- const auth = await select(io, 'How would you like to sign in?', [
168
- {
169
- value: 'browser',
170
- label: 'Sign in with your browser',
171
- detail: 'Opens the authorization server and returns through a loopback callback.',
172
- },
173
- {
174
- value: 'access-key',
175
- label: 'Use an access key',
176
- detail: 'Create one at https://portal.synomem.ai/access-keys/new',
177
- },
178
- ]);
179
- /*
180
- * Deliberately no workspace prompt here.
181
- *
182
- * A hosted workspace ID looks like `ws-04psqx2rkt8ttft7a1t2z69r97`, and the
183
- * credential authorized in the next step already knows the answer -- an
184
- * access key can list every workspace its organization has, and a browser
185
- * sign-in can list the ones the account belongs to across every
186
- * organization. Asking first means asking a person to go and look something
187
- * up that we are about to be told.
188
- */
189
- const credentialStore = auth === 'access-key'
190
- ? await select(io, 'Where should Synomem store this credential?', credentialStoreChoices())
191
- : 'auto';
192
- return { backend, home, serviceUrl, auth, credentialStore };
193
- }
194
- /** Reads an access key without ever accepting it as an argument. */
195
- export async function readAccessToken(io) {
196
- const token = await askSecret(io, 'Access key');
197
- if (!token)
198
- throw new SynomemError('INVALID_INPUT', 'No access key was provided.');
199
- return token;
200
- }
201
- export async function confirmPlan(io, plan) {
202
- io.output.write([
203
- '',
204
- 'Synomem will be configured as:',
205
- '',
206
- ` Backend: ${plan.backend === 'local' ? 'Local SQLite' : 'Synomem Cloud'}`,
207
- ` Home: ${plan.home}`,
208
- ...(plan.serviceUrl ? [` Service: ${plan.serviceUrl}`] : []),
209
- ...(plan.workspaceId ? [` Workspace: ${plan.workspaceId}`] : []),
210
- ...(plan.credentialStore && plan.credentialStore !== 'auto'
211
- ? [` Credential: ${plan.credentialStore}`]
212
- : []),
213
- '',
214
- ].join('\n'));
215
- return await confirm(io, 'Apply this?');
216
- }
217
- export function homeExists(home) {
218
- return existsSync(home);
77
+ return `${head}${token.length > 12 ? '…' : ''}`;
219
78
  }
220
79
  //# sourceMappingURL=configure.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"configure.js","sourceRoot":"","sources":["../src/configure.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"configure.js","sourceRoot":"","sources":["../src/configure.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAiB,MAAM,aAAa,CAAC;AAGvD;;;;;;GAMG;AACH,MAAM,UAAU,sBAAsB,CACpC,WAA4B,OAAO,CAAC,QAAQ;IAE5C,MAAM,MAAM,GACV,QAAQ,KAAK,QAAQ;QACnB,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,UAAmB,EAAE,KAAK,EAAE,gBAAgB,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC;QACnF,CAAC,CAAC,QAAQ,KAAK,OAAO;YACpB,CAAC,CAAC;gBACE;oBACE,KAAK,EAAE,UAAmB;oBAC1B,KAAK,EAAE,4BAA4B;oBACnC,MAAM,EAAE,iDAAiD;iBAC1D;aACF;YACH,CAAC,CAAC,EAAE,CAAC;IACX,OAAO;QACL,GAAG,MAAM;QACT;YACE,KAAK,EAAE,MAAM;YACb,KAAK,EAAE,uCAAuC;YAC9C,MAAM,EAAE,sDAAsD;SAC/D;QACD;YACE,KAAK,EAAE,aAAa;YACpB,KAAK,EAAE,yCAAyC;YAChD,MAAM,EAAE,mEAAmE;SAC5E;KACF,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,wBAAwB,CACtC,WAA4B,OAAO,CAAC,QAAQ;IAE5C,IAAI,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,OAAO;QAAE,OAAO,UAAU,CAAC;IACrE,MAAM,IAAI,YAAY,CACpB,gBAAgB,EAChB,kIAAkI,CACnI,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,KAAyB,EACzB,WAA4B,OAAO,CAAC,QAAQ;IAE5C,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,wBAAwB,CAAC,QAAQ,CAAC,CAAC;IACnE,IAAI,KAAK,KAAK,UAAU,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,aAAa;QAAE,OAAO,KAAK,CAAC;IACtF,MAAM,IAAI,YAAY,CAAC,eAAe,EAAE,iDAAiD,CAAC,CAAC;AAC7F,CAAC;AAED,oDAAoD;AACpD,MAAM,UAAU,iBAAiB,CAAC,EAAY,EAAE,WAAmB;IACjE,IAAI,EAAE,CAAC,WAAW;QAAE,OAAO;IAC3B,MAAM,IAAI,YAAY,CACpB,eAAe,EACf,4DAA4D,WAAW,EAAE,CAC1E,CAAC;AACJ,CAAC;AAED,4EAA4E;AAC5E,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,EAAY;IAC9C,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,EAAE,EAAE,YAAY,CAAC,CAAC;IAC9C,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,YAAY,CAAC,eAAe,EAAE,sCAAsC,CAAC,CAAC;IAC1F,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,YAAY,CACpB,eAAe,EACf,uDAAuD,CACxD,CAAC;IACJ,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,iDAAiD;AACjD,MAAM,UAAU,qBAAqB,CAAC,KAAa;IACjD,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAChC,OAAO,GAAG,IAAI,GAAG,KAAK,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;AAClD,CAAC"}
@@ -1,45 +1,55 @@
1
- import type { ActorIdentity } from './types.js';
2
- /**
3
- * A member-owned access key.
4
- *
5
- * Not an OAuth credential: it has no refresh, no token endpoint and no
6
- * client, and it authorizes the MEMBER who created it, reaching every
7
- * workspace their organization membership allows -- never a single machine
8
- * or a single workspace. Keeping it a distinct shape stops code treating it
9
- * as refreshable, which would mean silently failing to renew something that
10
- * never expires that way.
11
- *
12
- * The `kind` value and this type's own name predate member-owned access
13
- * keys; both still say "installation" because renaming either changes the
14
- * shape already written to disk and the OS keychain on every machine that
15
- * has run `synomem config`, for no behavioral gain.
16
- */
17
- export interface StoredInstallationKey {
18
- kind: 'installation-key';
19
- accessToken: string;
20
- }
21
- export type StoredCredential = StoredOAuthCredential | StoredInstallationKey;
22
- export interface StoredOAuthCredential {
23
- accessToken: string;
24
- refreshToken?: string;
25
- expiresAt?: number;
26
- tokenEndpoint: string;
27
- clientId: string;
28
- resource: string;
29
- scope: string;
30
- }
1
+ import { z } from 'zod';
2
+ export declare const storedOAuthCredentialSchema: z.ZodObject<{
3
+ kind: z.ZodLiteral<"oauth">;
4
+ issuer: z.ZodString;
5
+ resource: z.ZodString;
6
+ clientId: z.ZodString;
7
+ tokenEndpoint: z.ZodString;
8
+ scope: z.ZodString;
9
+ accessToken: z.ZodString;
10
+ refreshToken: z.ZodOptional<z.ZodString>;
11
+ expiresAt: z.ZodNumber;
12
+ generation: z.ZodNumber;
13
+ }, z.core.$strip>;
14
+ export declare const storedAccessKeySchema: z.ZodObject<{
15
+ kind: z.ZodLiteral<"access-key">;
16
+ secret: z.ZodString;
17
+ }, z.core.$strip>;
18
+ export declare const storedCredentialSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
19
+ kind: z.ZodLiteral<"oauth">;
20
+ issuer: z.ZodString;
21
+ resource: z.ZodString;
22
+ clientId: z.ZodString;
23
+ tokenEndpoint: z.ZodString;
24
+ scope: z.ZodString;
25
+ accessToken: z.ZodString;
26
+ refreshToken: z.ZodOptional<z.ZodString>;
27
+ expiresAt: z.ZodNumber;
28
+ generation: z.ZodNumber;
29
+ }, z.core.$strip>, z.ZodObject<{
30
+ kind: z.ZodLiteral<"access-key">;
31
+ secret: z.ZodString;
32
+ }, z.core.$strip>], "kind">;
33
+ export type StoredOAuthCredential = z.infer<typeof storedOAuthCredentialSchema>;
34
+ export type StoredAccessKey = z.infer<typeof storedAccessKeySchema>;
35
+ export type StoredCredential = z.infer<typeof storedCredentialSchema>;
36
+ /** Where a connection's secret lives. `environment` stores nothing. */
37
+ export type CredentialBackendKind = 'keychain' | 'file' | 'environment';
31
38
  export interface CredentialStore {
32
39
  get(reference: string): Promise<StoredCredential | undefined>;
33
40
  set(reference: string, credential: StoredCredential): Promise<void>;
34
41
  delete(reference: string): Promise<boolean>;
35
42
  }
36
- export declare function credentialReference(baseUrl: string, workspaceId: string, actor: ActorIdentity): string;
43
+ /** An opaque, non-secret handle for a stored secret. Never derived from names. */
44
+ export declare function newSecretReference(): string;
45
+ export declare function parseStoredCredential(value: string): StoredCredential;
37
46
  interface CommandResult {
38
47
  stdout: string;
39
48
  stderr: string;
40
49
  code: number;
41
50
  }
42
51
  export type CredentialCommandRunner = (executable: string, arguments_: string[], input?: string) => Promise<CommandResult>;
52
+ /** macOS Keychain or Linux Secret Service. */
43
53
  export declare class OsCredentialStore implements CredentialStore {
44
54
  private readonly platform;
45
55
  private readonly run;
@@ -47,10 +57,49 @@ export declare class OsCredentialStore implements CredentialStore {
47
57
  platform?: NodeJS.Platform;
48
58
  run?: CredentialCommandRunner;
49
59
  });
50
- get(reference: string): Promise<StoredOAuthCredential | undefined>;
51
- set(reference: string, credential: StoredOAuthCredential): Promise<void>;
60
+ get(reference: string): Promise<StoredCredential | undefined>;
61
+ set(reference: string, credential: StoredCredential): Promise<void>;
52
62
  delete(reference: string): Promise<boolean>;
53
63
  private unsupported;
54
64
  }
65
+ /**
66
+ * One restricted file per secret under `<home>/credentials/`, mode 0600 in a
67
+ * 0700 directory. Chosen explicitly (`--store file`), never as a fallback.
68
+ */
69
+ export declare class FileCredentialStore implements CredentialStore {
70
+ private readonly directory;
71
+ constructor(home: string);
72
+ private path;
73
+ get(reference: string): Promise<StoredCredential | undefined>;
74
+ set(reference: string, credential: StoredCredential): Promise<void>;
75
+ delete(reference: string): Promise<boolean>;
76
+ }
77
+ export interface CredentialStores {
78
+ keychain: CredentialStore;
79
+ file: CredentialStore;
80
+ }
81
+ export declare function defaultCredentialStores(home: string): CredentialStores;
82
+ /**
83
+ * A cross-process lock around one credential's refresh.
84
+ *
85
+ * `O_EXCL` creation is the mutual exclusion. The lock file records its owner
86
+ * (pid, host) and a random token. A lock is broken only when its owner is
87
+ * provably gone — a dead pid on this host — or, for an owner on another host
88
+ * or an unreadable file, once it is older than `staleMs`. A live owner is never
89
+ * preempted however long its refresh takes (the refresh request itself times
90
+ * out well inside `staleMs`).
91
+ *
92
+ * Breaking renames the file aside first and checks the token: if another
93
+ * process already broke and re-acquired it in between, the fresh lock is put
94
+ * back rather than deleted. Correctness against a concurrent writer is still
95
+ * the generation compare-and-swap in the refresh path; the lock exists so that
96
+ * only one process ever spends a given refresh token. Locks assume one host's
97
+ * filesystem; a home shared over a network filesystem is not supported.
98
+ */
99
+ export declare function withCredentialLock<T>(home: string, name: string, operation: () => Promise<T>, options?: {
100
+ staleMs?: number;
101
+ timeoutMs?: number;
102
+ pollMs?: number;
103
+ }): Promise<T>;
55
104
  export {};
56
105
  //# sourceMappingURL=credentials.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAKhD;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,kBAAkB,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,MAAM,gBAAgB,GAAG,qBAAqB,GAAG,qBAAqB,CAAC;AAE7E,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC9B,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAAC;IAC9D,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpE,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC7C;AAED,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,aAAa,GACnB,MAAM,CAUR;AAED,UAAU,aAAa;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,uBAAuB,GAAG,CACpC,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAAE,EACpB,KAAK,CAAC,EAAE,MAAM,KACX,OAAO,CAAC,aAAa,CAAC,CAAC;AAqD5B,qBAAa,iBAAkB,YAAW,eAAe;IACvD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkB;IAC3C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAA0B;gBAElC,OAAO,GAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;QAAC,GAAG,CAAC,EAAE,uBAAuB,CAAA;KAAO;IAKjF,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,GAAG,SAAS,CAAC;IAkBlE,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC;IAyCxE,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAsBjD,OAAO,CAAC,WAAW;CAQpB"}
1
+ {"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"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"}