synomem 0.7.1 → 0.8.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/dist/cli.d.ts +9 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +63 -20
- package/dist/cli.js.map +1 -1
- package/dist/discover.d.ts +24 -0
- package/dist/discover.d.ts.map +1 -1
- package/dist/discover.js +11 -0
- package/dist/discover.js.map +1 -1
- package/dist/errors.d.ts +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +1 -0
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp/index.d.ts +11 -0
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +51 -3
- package/dist/mcp/index.js.map +1 -1
- package/dist/remote.d.ts +2 -1
- package/dist/remote.d.ts.map +1 -1
- package/dist/remote.js +3 -0
- package/dist/remote.js.map +1 -1
- package/dist/service.d.ts +2 -1
- package/dist/service.d.ts.map +1 -1
- package/dist/types.d.ts +21 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/skills/synomem/SKILL.md +43 -0
- package/skills/synomem/references/examples.md +27 -0
- package/src/cli.ts +89 -24
- package/src/discover.ts +30 -0
- package/src/errors.ts +1 -0
- package/src/index.ts +7 -1
- package/src/mcp/index.ts +86 -3
- package/src/remote.ts +5 -0
- package/src/service.ts +7 -0
- package/src/types.ts +21 -0
package/dist/cli.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from 'commander';
|
|
3
|
-
import { type DiscoveredWorkspace } from './discover.js';
|
|
3
|
+
import { type DiscoveredWorkspace, type WorkspaceMembership } from './discover.js';
|
|
4
4
|
import { type PromptIo } from './prompt.js';
|
|
5
5
|
import { type CredentialStore } from './credentials.js';
|
|
6
6
|
import { type OAuthLoginOptions } from './oauth.js';
|
|
@@ -31,6 +31,14 @@ export interface CliDependencies {
|
|
|
31
31
|
organizationId: string;
|
|
32
32
|
workspaces: DiscoveredWorkspace[];
|
|
33
33
|
}>;
|
|
34
|
+
/** Injected so `remote workspace list` can be tested without a network. */
|
|
35
|
+
discoverIdentity?: (options: {
|
|
36
|
+
baseUrl: string;
|
|
37
|
+
accessToken: string;
|
|
38
|
+
}) => Promise<{
|
|
39
|
+
workspaceId: string;
|
|
40
|
+
workspaces: WorkspaceMembership[];
|
|
41
|
+
}>;
|
|
34
42
|
createImportBundle?: (home: string) => Promise<ImportBundle>;
|
|
35
43
|
remoteImport?: (options: {
|
|
36
44
|
baseUrl: string;
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAKA,OAAO,EAAE,OAAO,EAA0B,MAAM,WAAW,CAAC;AAkB5D,OAAO,
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAKA,OAAO,EAAE,OAAO,EAA0B,MAAM,WAAW,CAAC;AAkB5D,OAAO,EAGL,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACzB,MAAM,eAAe,CAAC;AAOvB,OAAO,EAA2B,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,EAA0C,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAIhG,OAAO,EAA4C,KAAK,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE9F,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,YAAY,EAClB,MAAM,aAAa,CAAC;AASrB,OAAO,KAAK,EACV,aAAa,EASd,MAAM,YAAY,CAAC;AAEpB,OAAO,KAAK,EAAkB,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAE1E,MAAM,WAAW,KAAK;IACpB,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAChC;AAED,MAAM,WAAW,eAAe;IAC9B,yEAAyE;IACzE,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3D,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,sBAAsB,CAAC,EAAE,CAAC,OAAO,EAAE;QACjC,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,EAAE,MAAM,CAAC;QACpB,KAAK,EAAE,aAAa,CAAC;QACrB,SAAS,EAAE,MAAM,CAAC;QAClB,eAAe,EAAE,eAAe,CAAC;KAClC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAKpB,2BAA2B,CAAC,EAAE,CAAC,OAAO,EAAE;QACtC,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,EAAE,MAAM,CAAC;KACrB,KAAK,OAAO,CAAC;QAAE,cAAc,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,mBAAmB,EAAE,CAAA;KAAE,CAAC,CAAC;IAC7E,2EAA2E;IAC3E,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE;QAC3B,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,EAAE,MAAM,CAAC;KACrB,KAAK,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,mBAAmB,EAAE,CAAA;KAAE,CAAC,CAAC;IAC1E,kBAAkB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;IAC7D,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE;QACvB,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,EAAE,MAAM,CAAC;QACpB,KAAK,EAAE,aAAa,CAAC;QACrB,MAAM,EAAE,YAAY,CAAC;QACrB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,KAAK,OAAO,CAAC,aAAa,GAAG,YAAY,CAAC,CAAC;CAC7C;AAuRD,wBAAgB,SAAS,CACvB,EAAE,GAAE,KAAiB,EACrB,cAAc,GAAE,qBAAgD,EAChE,YAAY,GAAE,eAAoB,EAClC,IAAI,GAAE,MAAM,EAAiB,GAC5B,OAAO,CA81FT;AAED,wBAAsB,MAAM,CAC1B,IAAI,WAAe,EACnB,EAAE,GAAE,KAAiB,EACrB,cAAc,GAAE,qBAAgD,EAChE,YAAY,GAAE,eAAoB,GACjC,OAAO,CAAC,MAAM,CAAC,CAqBjB"}
|
package/dist/cli.js
CHANGED
|
@@ -8,7 +8,7 @@ import { configuredServiceFactory, readSynomemConfig, writeSynomemBackend } from
|
|
|
8
8
|
import { cloudApiUrl } from './cloud.js';
|
|
9
9
|
import { resolveHome } from './config.js';
|
|
10
10
|
import { assertInteractive, confirmPlan, credentialFingerprint, credentialStoreChoices, environmentInstructions, readAccessToken, runConfigWizard, writeCredentialFile, } from './configure.js';
|
|
11
|
-
import { discoverAccessKeyWorkspaces,
|
|
11
|
+
import { discoverAccessKeyWorkspaces, discoverIdentity, } from './discover.js';
|
|
12
12
|
import { DEFAULT_WORKSPACE, listLocalWorkspaces, localWorkspaceHome } from './workspaces.js';
|
|
13
13
|
import { findProjectSelection, resolveWorkspaceSelection, writeProjectSelection, } from './project.js';
|
|
14
14
|
import { defaultPromptIo, select } from './prompt.js';
|
|
@@ -305,6 +305,7 @@ export function createCli(io = defaultIo, serviceFactory = configuredServiceFact
|
|
|
305
305
|
const credentialStore = dependencies.credentialStore ?? new OsCredentialStore();
|
|
306
306
|
const oauthLogin = dependencies.oauthLogin ?? loginWithOAuth;
|
|
307
307
|
const discoverWorkspaces = dependencies.discoverAccessKeyWorkspaces ?? discoverAccessKeyWorkspaces;
|
|
308
|
+
const discoverAccountIdentity = dependencies.discoverIdentity ?? discoverIdentity;
|
|
308
309
|
const promptIo = dependencies.promptIo ?? defaultPromptIo();
|
|
309
310
|
const verifyRemoteCredential = dependencies.verifyRemoteCredential ??
|
|
310
311
|
(async (options) => {
|
|
@@ -410,17 +411,62 @@ export function createCli(io = defaultIo, serviceFactory = configuredServiceFact
|
|
|
410
411
|
output(io, global.json, { name, home }, `Created workspace ${name} at ${home}.\nAct in it with --workspace ${name}.`);
|
|
411
412
|
});
|
|
412
413
|
const remoteCommand = program.command('remote').description('Administer a remote workspace');
|
|
414
|
+
const remoteWorkspaceCommand = remoteCommand
|
|
415
|
+
.command('workspace')
|
|
416
|
+
.description('List or switch the workspace this credential addresses');
|
|
417
|
+
/*
|
|
418
|
+
* Every workspace this credential's account belongs to, and which are
|
|
419
|
+
* reachable right now with it — no new token needed for any workspace
|
|
420
|
+
* flagged reachable, since a human credential authorizes its whole
|
|
421
|
+
* organization, not permanently one workspace (see `workspace use`). Data
|
|
422
|
+
* plane (`/v1/identity`), not `/v1/me`: the latter is a first-party
|
|
423
|
+
* control-plane route gated by a service secret this CLI never holds, and
|
|
424
|
+
* would 401 unconditionally against the real hosted API.
|
|
425
|
+
*/
|
|
426
|
+
remoteWorkspaceCommand
|
|
427
|
+
.command('list')
|
|
428
|
+
.description("List this credential's account's workspaces, and which are reachable now")
|
|
429
|
+
.option('--url <url>', 'internal: alternate HTTPS origin')
|
|
430
|
+
.action(async (options, command) => {
|
|
431
|
+
const global = globals(command);
|
|
432
|
+
const config = readSynomemConfig(global.home, env);
|
|
433
|
+
const baseUrl = options.url ??
|
|
434
|
+
(config?.backend.kind === 'remote' ? config.backend.baseUrl : cloudApiUrl(env));
|
|
435
|
+
const accessToken = env.SYNOMEM_ACCESS_TOKEN;
|
|
436
|
+
if (!accessToken) {
|
|
437
|
+
throw new SynomemError('AUTH_REQUIRED', 'Set SYNOMEM_ACCESS_TOKEN, or run `synomem auth login` first.');
|
|
438
|
+
}
|
|
439
|
+
const identity = await discoverAccountIdentity({ baseUrl, accessToken });
|
|
440
|
+
const human = identity.workspaces.length
|
|
441
|
+
? identity.workspaces
|
|
442
|
+
.map((workspace) => `${workspace.id} ${workspace.displayName}` +
|
|
443
|
+
(workspace.addressableWithThisToken
|
|
444
|
+
? ''
|
|
445
|
+
: ' (not reachable with this credential)'))
|
|
446
|
+
.join('\n')
|
|
447
|
+
: 'This credential belongs to no workspaces yet.';
|
|
448
|
+
output(io, global.json, identity, human);
|
|
449
|
+
});
|
|
413
450
|
/*
|
|
414
|
-
*
|
|
415
|
-
*
|
|
416
|
-
*
|
|
417
|
-
*
|
|
418
|
-
* alongside the names is the point: the ID is what `backend use remote
|
|
419
|
-
* --workspace` takes.
|
|
451
|
+
* A workspace flagged `addressableWithThisToken` by `workspace list` needs
|
|
452
|
+
* no new token or re-authentication — the credential already covers it.
|
|
453
|
+
* This only ever rewrites local config to point at it; see `backend use
|
|
454
|
+
* remote --workspace`, which this delegates to.
|
|
420
455
|
*/
|
|
456
|
+
remoteWorkspaceCommand
|
|
457
|
+
.command('use <workspace-id>')
|
|
458
|
+
.description('Address a different workspace with the current remote credential')
|
|
459
|
+
.option('--url <url>', 'internal: alternate HTTPS origin')
|
|
460
|
+
.action((workspaceId, options, command) => {
|
|
461
|
+
const global = globals(command);
|
|
462
|
+
const config = writeSynomemBackend({ kind: 'remote', baseUrl: options.url ?? cloudApiUrl(env), workspaceId }, global.home);
|
|
463
|
+
output(io, global.json, { backend: config.backend }, `Now addressing workspace ${workspaceId}.`);
|
|
464
|
+
});
|
|
465
|
+
// Deprecated alias for `remote workspace list`, kept working rather than
|
|
466
|
+
// breaking anyone who already scripted the old name.
|
|
421
467
|
remoteCommand
|
|
422
468
|
.command('workspaces')
|
|
423
|
-
.description('
|
|
469
|
+
.description('Deprecated: use `remote workspace list`')
|
|
424
470
|
.option('--url <url>', 'internal: alternate HTTPS origin')
|
|
425
471
|
.action(async (options, command) => {
|
|
426
472
|
const global = globals(command);
|
|
@@ -431,19 +477,16 @@ export function createCli(io = defaultIo, serviceFactory = configuredServiceFact
|
|
|
431
477
|
if (!accessToken) {
|
|
432
478
|
throw new SynomemError('AUTH_REQUIRED', 'Set SYNOMEM_ACCESS_TOKEN, or run `synomem auth login` first.');
|
|
433
479
|
}
|
|
434
|
-
const
|
|
435
|
-
const
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
.
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
? organization.workspaces.map((workspace) => ` ${workspace.id} ${workspace.displayName}`)
|
|
442
|
-
: [' (no workspaces yet)']),
|
|
443
|
-
].join('\n'))
|
|
480
|
+
const identity = await discoverAccountIdentity({ baseUrl, accessToken });
|
|
481
|
+
const human = identity.workspaces.length
|
|
482
|
+
? identity.workspaces
|
|
483
|
+
.map((workspace) => `${workspace.id} ${workspace.displayName}` +
|
|
484
|
+
(workspace.addressableWithThisToken
|
|
485
|
+
? ''
|
|
486
|
+
: ' (not reachable with this credential)'))
|
|
444
487
|
.join('\n')
|
|
445
|
-
: 'This
|
|
446
|
-
output(io, global.json,
|
|
488
|
+
: 'This credential belongs to no workspaces yet.';
|
|
489
|
+
output(io, global.json, identity, human);
|
|
447
490
|
});
|
|
448
491
|
remoteCommand
|
|
449
492
|
.command('import')
|