claude-account-sync 0.2.1 → 0.4.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/commands/bundle.d.ts +3 -0
- package/dist/commands/bundle.js +4 -2
- package/dist/commands/manifest.d.ts +3 -0
- package/dist/commands/manifest.js +14 -4
- package/dist/commands/mcp.d.ts +3 -0
- package/dist/commands/mcp.js +3 -2
- package/dist/commands/profiles.d.ts +3 -0
- package/dist/commands/profiles.js +21 -5
- package/dist/commands/secrets.d.ts +14 -0
- package/dist/commands/secrets.js +37 -3
- package/dist/commands/sync.d.ts +3 -0
- package/dist/commands/sync.js +17 -8
- package/dist/context.d.ts +15 -0
- package/dist/index.d.ts +2 -0
- package/dist/plan.d.ts +6 -0
- package/dist/plan.js +19 -0
- package/dist/ui/api.d.ts +3 -0
- package/dist/ui/api.js +160 -22
- package/dist/ui/command.d.ts +3 -0
- package/dist/ui/http.d.ts +20 -0
- package/dist/ui/server.d.ts +9 -0
- package/dist/ui/static.d.ts +2 -0
- package/dist/ui/token.d.ts +3 -0
- package/dist/webui/assets/index-B9Ee16GZ.css +1 -0
- package/dist/webui/assets/index-dw8cq3Ri.js +143 -0
- package/dist/webui/index.html +2 -2
- package/package.json +32 -7
- package/dist/webui/assets/index-DZPGFb5T.css +0 -1
- package/dist/webui/assets/index-Dr2jwana.js +0 -136
package/dist/commands/bundle.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { exportBundle, importBundle, collectAssets, writeAssets, parseManifest, serializeManifest, saveManifest,
|
|
1
|
+
import { exportBundle, importBundle, collectAssets, writeAssets, parseManifest, serializeManifest, saveManifest, executeApply, backupFiles, } from 'ccprofiles-core';
|
|
2
2
|
import { readFile, writeFile } from 'node:fs/promises';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
import { requireManifest } from '../context.js';
|
|
5
|
+
import { planActions, planActionsPreflight } from '../plan.js';
|
|
5
6
|
function stamp() { return new Date().toISOString().replace(/[:.]/g, '-'); }
|
|
6
7
|
export function registerBundleCommands(program, ctx) {
|
|
7
8
|
program.command('export <file>').description('export manifest + assets as a portable bundle (no secrets)')
|
|
@@ -26,12 +27,13 @@ export function registerBundleCommands(program, ctx) {
|
|
|
26
27
|
process.exitCode = 1;
|
|
27
28
|
return;
|
|
28
29
|
}
|
|
30
|
+
await planActionsPreflight(ctx, m); // abort before touching local state if the bundle has an unresolvable secret ref
|
|
29
31
|
if (!opts.dryRun) {
|
|
30
32
|
await backupFiles([join(ctx.manifestRoot, 'manifest.yaml')], ctx.backupRoot, stamp());
|
|
31
33
|
await saveManifest(ctx.manifestRoot, m);
|
|
32
34
|
await writeAssets(assets, m, ctx.platform);
|
|
33
35
|
}
|
|
34
|
-
const actions =
|
|
36
|
+
const actions = await planActions(ctx, m);
|
|
35
37
|
const res = await executeApply(actions, { backupRoot: ctx.backupRoot, stamp: stamp(), dryRun: !!opts.dryRun });
|
|
36
38
|
for (const line of res.performed)
|
|
37
39
|
console.log(`${opts.dryRun ? '[dry-run] ' : ''}${line}`);
|
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
import { discoverProfiles, buildManifest, saveManifest,
|
|
1
|
+
import { discoverProfiles, buildManifest, saveManifest, loadManifest, preserveSecretRefs, executeApply, } from 'ccprofiles-core';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
2
4
|
import { requireManifest } from '../context.js';
|
|
5
|
+
import { planActions } from '../plan.js';
|
|
6
|
+
import { secretsStore } from './secrets.js';
|
|
3
7
|
function stamp() { return new Date().toISOString().replace(/[:.]/g, '-'); }
|
|
4
8
|
export function registerManifestCommands(program, ctx) {
|
|
5
9
|
program.command('status').description('show live-vs-manifest drift').action(async () => {
|
|
6
10
|
const m = await requireManifest(ctx);
|
|
7
|
-
const actions =
|
|
11
|
+
const actions = await planActions(ctx, m);
|
|
8
12
|
if (actions.length === 0) {
|
|
9
13
|
console.log('in sync');
|
|
10
14
|
return;
|
|
@@ -17,7 +21,7 @@ export function registerManifestCommands(program, ctx) {
|
|
|
17
21
|
.option('--dry-run')
|
|
18
22
|
.action(async (opts) => {
|
|
19
23
|
const m = await requireManifest(ctx);
|
|
20
|
-
const actions =
|
|
24
|
+
const actions = await planActions(ctx, m);
|
|
21
25
|
if (actions.length === 0) {
|
|
22
26
|
console.log('in sync — nothing to do');
|
|
23
27
|
return;
|
|
@@ -30,6 +34,11 @@ export function registerManifestCommands(program, ctx) {
|
|
|
30
34
|
});
|
|
31
35
|
program.command('snapshot').description('overwrite manifest from live state').action(async () => {
|
|
32
36
|
const m = buildManifest(await discoverProfiles(ctx.home), ctx.platform);
|
|
37
|
+
if (existsSync(join(ctx.manifestRoot, 'manifest.yaml'))) {
|
|
38
|
+
const oldM = await loadManifest(ctx.manifestRoot);
|
|
39
|
+
let store = null;
|
|
40
|
+
await preserveSecretRefs(m, oldM, async (name) => { store ??= await secretsStore(ctx); return store.get(name); });
|
|
41
|
+
}
|
|
33
42
|
await saveManifest(ctx.manifestRoot, m);
|
|
34
43
|
console.log(`snapshot: ${m.profiles.length} profiles, ${Object.keys(m.mcpServers).length} mcp servers`);
|
|
35
44
|
});
|
|
@@ -50,9 +59,10 @@ export function registerManifestCommands(program, ctx) {
|
|
|
50
59
|
env: {},
|
|
51
60
|
links: src ? { ...src.links } : (m.hub ? { skills: 'hub', commands: 'hub' } : {}),
|
|
52
61
|
mcp: src ? [...src.mcp] : [],
|
|
62
|
+
settingsEnv: {},
|
|
53
63
|
});
|
|
54
64
|
await saveManifest(ctx.manifestRoot, m);
|
|
55
|
-
const actions =
|
|
65
|
+
const actions = await planActions(ctx, m);
|
|
56
66
|
await executeApply(actions, { backupRoot: ctx.backupRoot, stamp: stamp() });
|
|
57
67
|
console.log(`profile "${name}" created — launcher: cl-${name} (restart your shell)`);
|
|
58
68
|
});
|
package/dist/commands/mcp.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { saveManifest, executeApply, } from 'ccprofiles-core';
|
|
2
2
|
import { requireManifest } from '../context.js';
|
|
3
|
+
import { planActions } from '../plan.js';
|
|
3
4
|
function stamp() { return new Date().toISOString().replace(/[:.]/g, '-'); }
|
|
4
5
|
async function applyNow(ctx, m, dryRun) {
|
|
5
|
-
const actions =
|
|
6
|
+
const actions = await planActions(ctx, m);
|
|
6
7
|
const res = await executeApply(actions, { backupRoot: ctx.backupRoot, stamp: stamp(), dryRun });
|
|
7
8
|
for (const line of res.performed)
|
|
8
9
|
console.log(`${dryRun ? '[dry-run] ' : ''}${line}`);
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { discoverProfiles, buildManifest, saveManifest, loadManifest, ensureRootGitignore } from 'ccprofiles-core';
|
|
1
|
+
import { discoverProfiles, buildManifest, saveManifest, loadManifest, preserveSecretRefs, ensureRootGitignore } from 'ccprofiles-core';
|
|
2
2
|
import { existsSync, readFileSync, lstatSync, readlinkSync, readdirSync } from 'node:fs';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
import { execFileSync } from 'node:child_process';
|
|
5
|
+
import { KEY_VARS, secretsStore } from './secrets.js';
|
|
5
6
|
export function registerProfileCommands(program, ctx) {
|
|
6
7
|
program.command('list').description('list Claude Code profiles').action(async () => {
|
|
7
8
|
const live = await discoverProfiles(ctx.home);
|
|
@@ -24,6 +25,11 @@ export function registerProfileCommands(program, ctx) {
|
|
|
24
25
|
console.log('Re-run with --yes to write the manifest.');
|
|
25
26
|
return;
|
|
26
27
|
}
|
|
28
|
+
if (existsSync(join(ctx.manifestRoot, 'manifest.yaml'))) {
|
|
29
|
+
const oldM = await loadManifest(ctx.manifestRoot);
|
|
30
|
+
let store = null;
|
|
31
|
+
await preserveSecretRefs(manifest, oldM, async (name) => { store ??= await secretsStore(ctx); return store.get(name); });
|
|
32
|
+
}
|
|
27
33
|
if (!existsSync(join(ctx.manifestRoot, '.git'))) {
|
|
28
34
|
try {
|
|
29
35
|
execFileSync('git', ['init', ctx.manifestRoot], { stdio: 'ignore' });
|
|
@@ -37,7 +43,10 @@ export function registerProfileCommands(program, ctx) {
|
|
|
37
43
|
program.command('doctor').description('check setup health').action(async () => {
|
|
38
44
|
const problems = [];
|
|
39
45
|
const live = await discoverProfiles(ctx.home);
|
|
40
|
-
|
|
46
|
+
let m = null;
|
|
47
|
+
if (existsSync(join(ctx.manifestRoot, 'manifest.yaml')))
|
|
48
|
+
m = await loadManifest(ctx.manifestRoot);
|
|
49
|
+
for (const lp of live) {
|
|
41
50
|
for (const name of readdirSync(lp.dir)) {
|
|
42
51
|
const f = join(lp.dir, name);
|
|
43
52
|
try {
|
|
@@ -46,20 +55,27 @@ export function registerProfileCommands(program, ctx) {
|
|
|
46
55
|
}
|
|
47
56
|
catch { /* ignore */ }
|
|
48
57
|
}
|
|
58
|
+
const pname = lp.dirName === '.claude' ? 'default' : lp.dirName.slice('.claude-'.length);
|
|
59
|
+
const decl = m?.profiles.find(p => p.name === pname) ?? null;
|
|
60
|
+
for (const varName of KEY_VARS) {
|
|
61
|
+
if (lp.settingsEnv[varName] && !decl?.settingsEnv[varName])
|
|
62
|
+
problems.push(`plaintext token ${varName} in ${join(lp.dir, 'settings.json')} — adopt profile then run: secrets migrate`);
|
|
63
|
+
if (decl?.settingsEnv[varName] && !decl.settingsEnv[varName].startsWith('secret://'))
|
|
64
|
+
problems.push(`plaintext token ${varName} in manifest for profile "${pname}" — run: secrets migrate`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
49
67
|
if (existsSync(ctx.platform.rcFile)) {
|
|
50
68
|
const rc = readFileSync(ctx.platform.rcFile, 'utf8');
|
|
51
69
|
const outsideBlock = rc.split('# >>> ccprofiles managed >>>')[0] + (rc.split('# <<< ccprofiles managed <<<')[1] ?? '');
|
|
52
70
|
if (/sk-ant-/.test(outsideBlock))
|
|
53
71
|
problems.push(`plaintext Anthropic key found in ${ctx.platform.rcFile} — run: ccprofiles secrets migrate`);
|
|
54
72
|
}
|
|
55
|
-
if (
|
|
56
|
-
const m = await loadManifest(ctx.manifestRoot);
|
|
73
|
+
if (m)
|
|
57
74
|
for (const pr of m.profiles) {
|
|
58
75
|
const dir = pr.dir.replace('{home}', ctx.home);
|
|
59
76
|
if (!existsSync(dir))
|
|
60
77
|
problems.push(`manifest profile "${pr.name}" missing on disk: ${dir} — run: ccprofiles apply`);
|
|
61
78
|
}
|
|
62
|
-
}
|
|
63
79
|
if (problems.length === 0) {
|
|
64
80
|
console.log('ok: no problems found');
|
|
65
81
|
return;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Command } from 'commander';
|
|
2
|
+
import { SecretsStore } from 'ccprofiles-core';
|
|
3
|
+
import type { CliContext } from '../context.js';
|
|
4
|
+
export declare function secretsStore(ctx: CliContext): Promise<SecretsStore>;
|
|
5
|
+
export declare const KEY_VARS: string[];
|
|
6
|
+
/** Move plaintext keys out of the shell rc file into the secrets store. Shared by the CLI and the UI API. */
|
|
7
|
+
export declare function migrateRcSecrets(ctx: CliContext, opts?: {
|
|
8
|
+
dryRun?: boolean;
|
|
9
|
+
}): Promise<string[]>;
|
|
10
|
+
/** Move plaintext token values in manifest settingsEnv into the secrets store as secret:// refs. */
|
|
11
|
+
export declare function migrateSettingsSecrets(ctx: CliContext, opts?: {
|
|
12
|
+
dryRun?: boolean;
|
|
13
|
+
}): Promise<string[]>;
|
|
14
|
+
export declare function registerSecretsCommands(program: Command, ctx: CliContext): void;
|
package/dist/commands/secrets.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { SecretsStore, FileBackend, defaultBackend, backupFiles, atomicWrite } from 'ccprofiles-core';
|
|
1
|
+
import { SecretsStore, FileBackend, defaultBackend, backupFiles, atomicWrite, loadManifest, saveManifest, executeApply } from 'ccprofiles-core';
|
|
2
2
|
import { readFile } from 'node:fs/promises';
|
|
3
3
|
import { existsSync } from 'node:fs';
|
|
4
|
+
import { join } from 'node:path';
|
|
4
5
|
export async function secretsStore(ctx) {
|
|
5
6
|
const pw = ctx.env.CCPROFILES_PASSPHRASE;
|
|
6
7
|
const backend = pw
|
|
@@ -11,7 +12,7 @@ export async function secretsStore(ctx) {
|
|
|
11
12
|
});
|
|
12
13
|
return new SecretsStore(backend, ctx.secretsIndexPath);
|
|
13
14
|
}
|
|
14
|
-
const KEY_VARS = ['ANTHROPIC_API_KEY', 'CLAUDE_CODE_OAUTH_TOKEN', 'ANTHROPIC_AUTH_TOKEN'];
|
|
15
|
+
export const KEY_VARS = ['ANTHROPIC_API_KEY', 'CLAUDE_CODE_OAUTH_TOKEN', 'ANTHROPIC_AUTH_TOKEN'];
|
|
15
16
|
// posix: export VAR="sk-..." powershell: $env:VAR = "sk-..."
|
|
16
17
|
const MIGRATE_RE_POSIX = new RegExp(`^(\\s*(?:export\\s+)?(${KEY_VARS.join('|')})\\s*=\\s*)"?(sk-[A-Za-z0-9_-]+)"?(.*)$`);
|
|
17
18
|
const MIGRATE_RE_PWSH = new RegExp(`^(\\s*\\$env:(${KEY_VARS.join('|')})\\s*=\\s*)"?(sk-[A-Za-z0-9_-]+)"?(.*)$`);
|
|
@@ -47,6 +48,29 @@ export async function migrateRcSecrets(ctx, opts = {}) {
|
|
|
47
48
|
}
|
|
48
49
|
return migrated;
|
|
49
50
|
}
|
|
51
|
+
/** Move plaintext token values in manifest settingsEnv into the secrets store as secret:// refs. */
|
|
52
|
+
export async function migrateSettingsSecrets(ctx, opts = {}) {
|
|
53
|
+
if (!existsSync(join(ctx.manifestRoot, 'manifest.yaml')))
|
|
54
|
+
return [];
|
|
55
|
+
const m = await loadManifest(ctx.manifestRoot);
|
|
56
|
+
const store = await secretsStore(ctx);
|
|
57
|
+
const migrated = [];
|
|
58
|
+
for (const pr of m.profiles) {
|
|
59
|
+
for (const varName of KEY_VARS) {
|
|
60
|
+
const v = pr.settingsEnv[varName];
|
|
61
|
+
if (!v || v.startsWith('secret://'))
|
|
62
|
+
continue;
|
|
63
|
+
const secretName = `${varName.toLowerCase().replaceAll('_', '-')}-${pr.name}`;
|
|
64
|
+
if (!opts.dryRun)
|
|
65
|
+
await store.set(secretName, v);
|
|
66
|
+
pr.settingsEnv[varName] = `secret://${secretName}`;
|
|
67
|
+
migrated.push(secretName);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (migrated.length && !opts.dryRun)
|
|
71
|
+
await saveManifest(ctx.manifestRoot, m);
|
|
72
|
+
return migrated;
|
|
73
|
+
}
|
|
50
74
|
export function registerSecretsCommands(program, ctx) {
|
|
51
75
|
const sec = program.command('secrets').description('manage secrets (values never stored in configs)');
|
|
52
76
|
sec.command('set <name> [value]').action(async (name, value) => {
|
|
@@ -76,12 +100,22 @@ export function registerSecretsCommands(program, ctx) {
|
|
|
76
100
|
console.log(`removed ${name}`);
|
|
77
101
|
});
|
|
78
102
|
sec.command('migrate').option('--dry-run').action(async (opts) => {
|
|
79
|
-
const migrated = await migrateRcSecrets(ctx, opts);
|
|
103
|
+
const migrated = [...await migrateRcSecrets(ctx, opts), ...await migrateSettingsSecrets(ctx, opts)];
|
|
80
104
|
if (migrated.length === 0) {
|
|
81
105
|
console.log('no plaintext keys found');
|
|
82
106
|
return;
|
|
83
107
|
}
|
|
84
108
|
for (const n of migrated)
|
|
85
109
|
console.log(`${opts.dryRun ? '[dry-run] ' : ''}migrated ${n}`);
|
|
110
|
+
// Apply so the manifest's newly-minted secret:// refs are (re-)resolved and written back
|
|
111
|
+
// out — dynamic import avoids a static circular import (plan.ts imports this module for secretsStore).
|
|
112
|
+
if (!opts.dryRun && existsSync(join(ctx.manifestRoot, 'manifest.yaml'))) {
|
|
113
|
+
const { planActions } = await import('../plan.js');
|
|
114
|
+
const m = await loadManifest(ctx.manifestRoot);
|
|
115
|
+
const actions = await planActions(ctx, m);
|
|
116
|
+
const res = await executeApply(actions, { backupRoot: ctx.backupRoot, stamp: new Date().toISOString().replace(/[:.]/g, '-') });
|
|
117
|
+
for (const line of res.performed)
|
|
118
|
+
console.log(`applied: ${line}`);
|
|
119
|
+
}
|
|
86
120
|
});
|
|
87
121
|
}
|
package/dist/commands/sync.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { startSyncServer, pairWithServer, fetchRemote, fetchSecrets, loadDevices, saveDevices, parseManifest, saveManifest, writeAssets,
|
|
1
|
+
import { startSyncServer, pairWithServer, fetchRemote, fetchSecrets, loadDevices, saveDevices, parseManifest, saveManifest, writeAssets, executeApply, backupFiles, } from 'ccprofiles-core';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { secretsStore } from './secrets.js';
|
|
4
|
+
import { planActions, planActionsPreflight } from '../plan.js';
|
|
4
5
|
function stamp() { return new Date().toISOString().replace(/[:.]/g, '-'); }
|
|
5
6
|
export function registerSyncCommands(program, ctx) {
|
|
6
7
|
program.command('serve').description('serve this device for pairing/sync')
|
|
@@ -62,22 +63,30 @@ export function registerSyncCommands(program, ctx) {
|
|
|
62
63
|
const { manifestYaml, assets } = await fetchRemote(device);
|
|
63
64
|
const m = parseManifest(manifestYaml); // validate before touching anything
|
|
64
65
|
console.log(`pulled manifest: ${m.profiles.length} profiles, ${Object.keys(m.mcpServers).length} mcp servers, ${Object.keys(assets).length} asset files`);
|
|
66
|
+
// Fetch+store secrets BEFORE touching local state, so a preflight below that needs a
|
|
67
|
+
// just-transferred secret succeeds instead of failing after the manifest is overwritten.
|
|
68
|
+
let values = {};
|
|
69
|
+
if (opts.withSecrets) {
|
|
70
|
+
values = await fetchSecrets(device, []);
|
|
71
|
+
if (!opts.dryRun) {
|
|
72
|
+
const store = await secretsStore(ctx);
|
|
73
|
+
for (const [k, v] of Object.entries(values))
|
|
74
|
+
await store.set(k, v);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// Validate the pulled manifest resolves cleanly before saving/applying anything — abort
|
|
78
|
+
// (propagating the Error) rather than leave the local manifest overwritten and broken.
|
|
79
|
+
await planActionsPreflight(ctx, m);
|
|
65
80
|
if (!opts.dryRun) {
|
|
66
81
|
await backupFiles([join(ctx.manifestRoot, 'manifest.yaml')], ctx.backupRoot, stamp());
|
|
67
82
|
await saveManifest(ctx.manifestRoot, m);
|
|
68
83
|
await writeAssets(assets, m, ctx.platform);
|
|
69
84
|
}
|
|
70
|
-
const actions =
|
|
85
|
+
const actions = await planActions(ctx, m);
|
|
71
86
|
const res = await executeApply(actions, { backupRoot: ctx.backupRoot, stamp: stamp(), dryRun: !!opts.dryRun });
|
|
72
87
|
for (const line of res.performed)
|
|
73
88
|
console.log(`${opts.dryRun ? '[dry-run] ' : ''}${line}`);
|
|
74
89
|
if (opts.withSecrets) {
|
|
75
|
-
const values = await fetchSecrets(device, []);
|
|
76
|
-
if (!opts.dryRun) {
|
|
77
|
-
const store = await secretsStore(ctx);
|
|
78
|
-
for (const [k, v] of Object.entries(values))
|
|
79
|
-
await store.set(k, v);
|
|
80
|
-
}
|
|
81
90
|
console.log(`${opts.dryRun ? '[dry-run] ' : ''}secrets transferred: ${Object.keys(values).join(', ') || 'none'}`);
|
|
82
91
|
}
|
|
83
92
|
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { type Manifest, type Platform } from 'ccprofiles-core';
|
|
3
|
+
export interface CliContext {
|
|
4
|
+
home: string;
|
|
5
|
+
platform: Platform;
|
|
6
|
+
manifestRoot: string;
|
|
7
|
+
secretsIndexPath: string;
|
|
8
|
+
secretsFilePath: string;
|
|
9
|
+
backupRoot: string;
|
|
10
|
+
env: NodeJS.ProcessEnv;
|
|
11
|
+
}
|
|
12
|
+
export declare function makeContext(env?: NodeJS.ProcessEnv): CliContext;
|
|
13
|
+
/** Load the manifest, or explain how to create one — never a raw ENOENT. */
|
|
14
|
+
export declare function requireManifest(ctx: CliContext): Promise<Manifest>;
|
|
15
|
+
export declare function buildProgram(ctx: CliContext): Command;
|
package/dist/index.d.ts
ADDED
package/dist/plan.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type ApplyAction, type Manifest } from 'ccprofiles-core';
|
|
2
|
+
import type { CliContext } from './context.js';
|
|
3
|
+
/** Plan apply actions with settingsEnv secret refs resolved from the secrets store (lazily opened). */
|
|
4
|
+
export declare function planActions(ctx: CliContext, m: Manifest): Promise<ApplyAction[]>;
|
|
5
|
+
/** Resolve settingsEnv secrets without planning — cheap validation that refs exist. */
|
|
6
|
+
export declare function planActionsPreflight(ctx: CliContext, m: Manifest): Promise<void>;
|
package/dist/plan.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { discoverProfiles, planApply, resolveSettingsEnv } from 'ccprofiles-core';
|
|
2
|
+
import { secretsStore } from './commands/secrets.js';
|
|
3
|
+
/** Plan apply actions with settingsEnv secret refs resolved from the secrets store (lazily opened). */
|
|
4
|
+
export async function planActions(ctx, m) {
|
|
5
|
+
let store = null;
|
|
6
|
+
const resolved = await resolveSettingsEnv(m, async (name) => {
|
|
7
|
+
store ??= await secretsStore(ctx);
|
|
8
|
+
return store.get(name);
|
|
9
|
+
});
|
|
10
|
+
return planApply(m, await discoverProfiles(ctx.home), ctx.platform, resolved);
|
|
11
|
+
}
|
|
12
|
+
/** Resolve settingsEnv secrets without planning — cheap validation that refs exist. */
|
|
13
|
+
export async function planActionsPreflight(ctx, m) {
|
|
14
|
+
let store = null;
|
|
15
|
+
await resolveSettingsEnv(m, async (name) => {
|
|
16
|
+
store ??= await secretsStore(ctx);
|
|
17
|
+
return store.get(name);
|
|
18
|
+
});
|
|
19
|
+
}
|
package/dist/ui/api.d.ts
ADDED