agent-cards-admin 0.3.13 → 0.3.15
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/package.json +1 -1
- package/dist/src/commands/wizard.d.ts.map +1 -1
- package/dist/src/commands/wizard.js +65 -40
- package/dist/src/commands/wizard.js.map +1 -1
- package/dist/src/lib/wizard/onboard.d.ts +24 -0
- package/dist/src/lib/wizard/onboard.d.ts.map +1 -0
- package/dist/src/lib/wizard/onboard.js +124 -0
- package/dist/src/lib/wizard/onboard.js.map +1 -0
- package/dist/src/lib/wizard/playbook.d.ts +8 -1
- package/dist/src/lib/wizard/playbook.d.ts.map +1 -1
- package/dist/src/lib/wizard/playbook.js +36 -17
- package/dist/src/lib/wizard/playbook.js.map +1 -1
- package/dist/src/lib/wizard/secrets.d.ts +11 -0
- package/dist/src/lib/wizard/secrets.d.ts.map +1 -0
- package/dist/src/lib/wizard/secrets.js +49 -0
- package/dist/src/lib/wizard/secrets.js.map +1 -0
- package/dist/src/lib/wizard/theme.d.ts +49 -0
- package/dist/src/lib/wizard/theme.d.ts.map +1 -0
- package/dist/src/lib/wizard/theme.js +89 -0
- package/dist/src/lib/wizard/theme.js.map +1 -0
- package/package.json +1 -1
package/dist/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wizard.d.ts","sourceRoot":"","sources":["../../../src/commands/wizard.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"wizard.d.ts","sourceRoot":"","sources":["../../../src/commands/wizard.ts"],"names":[],"mappings":"AAcA,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CA6KtE"}
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import { resolve } from 'path';
|
|
1
|
+
import { resolve, basename } from 'path';
|
|
2
2
|
import inquirer from 'inquirer';
|
|
3
3
|
import chalk from 'chalk';
|
|
4
4
|
import ora from 'ora';
|
|
5
|
-
import {
|
|
5
|
+
import { getApiUrl, getJwt } from '../lib/config.js';
|
|
6
6
|
import { detectRepo } from '../lib/wizard/detect.js';
|
|
7
7
|
import { INTEGRATION_PLAYBOOK, buildInitialPrompt } from '../lib/wizard/playbook.js';
|
|
8
8
|
import { runIntegrationAgent } from '../lib/wizard/agent.js';
|
|
9
|
+
import { ensureOnboarded } from '../lib/wizard/onboard.js';
|
|
10
|
+
import { writeAgentcardEnv } from '../lib/wizard/secrets.js';
|
|
11
|
+
import { banner, note, ui, glyph, outroSuccess, outroError } from '../lib/wizard/theme.js';
|
|
9
12
|
const MODEL = 'claude-opus-4-8';
|
|
10
13
|
/**
|
|
11
14
|
* `agent-cards-admin wizard` — runs an AI agent (the Claude Agent SDK, on OUR
|
|
@@ -14,46 +17,63 @@ const MODEL = 'claude-opus-4-8';
|
|
|
14
17
|
* real card issues in SANDBOX.
|
|
15
18
|
*/
|
|
16
19
|
export async function wizardCommand(opts) {
|
|
17
|
-
await requireAuth();
|
|
18
20
|
const repoRoot = resolve(opts.path ?? process.cwd());
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
console.log(chalk.dim('Implements Connect with Agentcard (OAuth 2.1 + PKCE) + per-user card issuance via MCP.'));
|
|
27
|
-
console.log();
|
|
28
|
-
// v1 always verifies against sandbox — make sure we're in sandbox mode.
|
|
29
|
-
if (getMode() !== 'sandbox') {
|
|
30
|
-
console.log(chalk.yellow('This wizard runs against SANDBOX. Switching mode to sandbox for this run.'));
|
|
31
|
-
setMode('sandbox');
|
|
32
|
-
}
|
|
33
|
-
// Detect the repo and show the partner what we found before they consent.
|
|
21
|
+
const appName = basename(repoRoot);
|
|
22
|
+
banner('Agentcard integration wizard', [
|
|
23
|
+
'Sets up your account + credentials, then wires Connect with Agentcard',
|
|
24
|
+
"(OAuth 2.1 + PKCE) + per-user cards via MCP into this repo.",
|
|
25
|
+
"Runs on Agentcard's tokens — your secrets go to a local .env, never to the AI.",
|
|
26
|
+
]);
|
|
27
|
+
// Detect the repo up front (also gives us the app name for provisioning).
|
|
34
28
|
const detection = detectRepo(repoRoot);
|
|
35
|
-
|
|
36
|
-
|
|
29
|
+
// Phase 1 — Onboard: account → org → confidential OAuth client → sandbox key.
|
|
30
|
+
// ensureOnboarded runs the signup/login flow first if there's no session yet.
|
|
31
|
+
const prov = await ensureOnboarded(appName);
|
|
32
|
+
note('Provisioned in sandbox', [
|
|
33
|
+
`org ${prov.orgName}`,
|
|
34
|
+
`client ${prov.clientId}`,
|
|
35
|
+
`api key ${prov.apiKeyPrefix}`,
|
|
36
|
+
`callback ${prov.redirectUri}`,
|
|
37
|
+
]);
|
|
38
|
+
// Phase 2 — Integrate. Show the repo + consent before writing ANY files (the env
|
|
39
|
+
// write below mutates the repo, so it must be gated by this consent too).
|
|
37
40
|
console.log();
|
|
41
|
+
console.log(`${ui.accent(glyph.diamond)} ${ui.bold('Integrate')} ${ui.muted('·')} ${repoRoot}`);
|
|
42
|
+
for (const l of detection.summary.split('\n'))
|
|
43
|
+
console.log(`${ui.muted(glyph.gutter)} ${ui.dim(l)}`);
|
|
44
|
+
console.log(ui.muted(glyph.gutter));
|
|
38
45
|
if (!opts.yes) {
|
|
39
46
|
const { proceed } = await inquirer.prompt([
|
|
40
47
|
{
|
|
41
48
|
type: 'confirm',
|
|
42
49
|
name: 'proceed',
|
|
43
|
-
message: chalk.yellow(`An AI agent will READ and MODIFY files in ${repoRoot} to add the Agentcard integration. Continue?`),
|
|
50
|
+
message: chalk.yellow(`An AI agent will READ and MODIFY files in ${repoRoot} to add the Agentcard integration (and write your AGENTCARD_* secrets to a local env file). Continue?`),
|
|
44
51
|
default: false,
|
|
45
52
|
},
|
|
46
53
|
]);
|
|
47
54
|
if (!proceed) {
|
|
48
|
-
console.log(chalk.dim('Aborted.
|
|
55
|
+
console.log(chalk.dim('Aborted. Credentials were provisioned in your Agentcard org, but no files in the repo were modified.'));
|
|
49
56
|
return;
|
|
50
57
|
}
|
|
51
58
|
}
|
|
59
|
+
const jwt = getJwt(); // ensureOnboarded guarantees a session
|
|
60
|
+
// Secret-vault: now that the user has consented to repo changes, write the
|
|
61
|
+
// provisioned credentials into the app's env so the agent never sees the secrets
|
|
62
|
+
// (its code reads process.env). Non-secret values may go in the prompt;
|
|
63
|
+
// AGENTCARD_OAUTH_CLIENT_SECRET / AGENTCARD_API_KEY never do.
|
|
64
|
+
const envFile = writeAgentcardEnv(repoRoot, {
|
|
65
|
+
AGENTCARD_API_URL: 'https://mcp.agentcard.sh',
|
|
66
|
+
AGENTCARD_PUBLIC_URL: prov.appBaseUrl,
|
|
67
|
+
AGENTCARD_OAUTH_CLIENT_ID: prov.clientId,
|
|
68
|
+
...(prov.clientSecret ? { AGENTCARD_OAUTH_CLIENT_SECRET: prov.clientSecret } : {}),
|
|
69
|
+
AGENTCARD_API_KEY: prov.apiKey,
|
|
70
|
+
});
|
|
71
|
+
console.log(`${ui.muted(glyph.gutter)} ${ui.success(glyph.check)} secrets written to ${ui.bold(envFile)} ${ui.dim('(kept out of the AI prompt)')}`);
|
|
52
72
|
const gatewayUrl = `${getApiUrl()}/wizard`;
|
|
53
73
|
console.log();
|
|
54
|
-
console.log(
|
|
55
|
-
console.log(
|
|
56
|
-
console.log(
|
|
74
|
+
console.log(`${ui.accent(glyph.diamond)} ${ui.bold('Running the integration agent')}`);
|
|
75
|
+
console.log(`${ui.muted(glyph.gutter)} ${ui.dim('Explores, edits files, and verifies the integration. This can take several minutes.')}`);
|
|
76
|
+
console.log(`${ui.muted(glyph.gutter)} ${ui.dim('Press')} ${ui.bold('Ctrl+B')} ${ui.dim('to toggle detailed logs (full tool inputs + outputs).')}`);
|
|
57
77
|
console.log();
|
|
58
78
|
// Live status: a spinner whose text ticks every second with the current action
|
|
59
79
|
// and elapsed time, so long model-thinking pauses never look hung. The agent's
|
|
@@ -109,7 +129,11 @@ export async function wizardCommand(opts) {
|
|
|
109
129
|
jwt,
|
|
110
130
|
model: MODEL,
|
|
111
131
|
systemPromptAppend: INTEGRATION_PLAYBOOK,
|
|
112
|
-
initialPrompt: buildInitialPrompt(detection.summary
|
|
132
|
+
initialPrompt: buildInitialPrompt(detection.summary, {
|
|
133
|
+
clientId: prov.clientId,
|
|
134
|
+
redirectUri: prov.redirectUri,
|
|
135
|
+
envFile,
|
|
136
|
+
}),
|
|
113
137
|
onText: (text) => {
|
|
114
138
|
const t = text.trim();
|
|
115
139
|
if (t)
|
|
@@ -118,13 +142,13 @@ export async function wizardCommand(opts) {
|
|
|
118
142
|
},
|
|
119
143
|
onToolStart: (name, summary, detail) => {
|
|
120
144
|
action = summary ? `${name} ${chalk.dim(summary)}` : name;
|
|
121
|
-
log(`${
|
|
145
|
+
log(`${ui.accent(glyph.arrow)} ${ui.bold(name)}${summary ? ' ' + ui.dim(summary) : ''}`);
|
|
122
146
|
if (verbose)
|
|
123
147
|
showDetail(detail);
|
|
124
148
|
},
|
|
125
149
|
onToolEnd: (name, isError, resultText) => {
|
|
126
150
|
if (isError)
|
|
127
|
-
log(`${
|
|
151
|
+
log(`${ui.error(glyph.cross)} ${ui.dim(`${name} failed`)}`);
|
|
128
152
|
if (verbose && resultText)
|
|
129
153
|
showDetail(resultText);
|
|
130
154
|
action = 'thinking';
|
|
@@ -140,23 +164,24 @@ export async function wizardCommand(opts) {
|
|
|
140
164
|
stdin.pause();
|
|
141
165
|
}
|
|
142
166
|
}
|
|
143
|
-
console.log();
|
|
144
|
-
if (result.outcome === 'success') {
|
|
145
|
-
console.log(chalk.green('✓ Integration agent finished.'));
|
|
146
|
-
}
|
|
147
|
-
else {
|
|
148
|
-
console.log(chalk.red('✗ Integration agent stopped with an error.'));
|
|
149
|
-
}
|
|
150
167
|
if (result.finalText) {
|
|
151
168
|
console.log();
|
|
152
169
|
console.log(result.finalText);
|
|
153
170
|
}
|
|
154
|
-
|
|
155
|
-
|
|
171
|
+
const turns = typeof result.numTurns === 'number' ? `${result.numTurns} turns. ` : '';
|
|
172
|
+
if (result.outcome === 'success') {
|
|
173
|
+
outroSuccess({
|
|
174
|
+
message: 'Agentcard integration complete',
|
|
175
|
+
nextSteps: [
|
|
176
|
+
`Issue a live card: open ${ui.primary(`${prov.appBaseUrl}/api/agentcard/connect?user=<id>`)} in a browser to connect a user`,
|
|
177
|
+
'Review the diff and commit when you are happy',
|
|
178
|
+
],
|
|
179
|
+
reviewNote: `${turns}Re-run \`wizard\` to continue or fix up.`,
|
|
180
|
+
});
|
|
156
181
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
if (result.outcome !== 'success')
|
|
182
|
+
else {
|
|
183
|
+
outroError('Integration agent stopped with an error', `${turns}See the log above; re-run \`wizard\` to retry.`);
|
|
160
184
|
process.exit(1);
|
|
185
|
+
}
|
|
161
186
|
}
|
|
162
187
|
//# sourceMappingURL=wizard.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wizard.js","sourceRoot":"","sources":["../../../src/commands/wizard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"wizard.js","sourceRoot":"","sources":["../../../src/commands/wizard.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wizard onboarding (Phase 1) — provisions everything the integration needs on a
|
|
3
|
+
* user's FIRST interaction with the Agentcard admin tool, then hands the credentials
|
|
4
|
+
* to the integration (Phase 2). Idempotent where it can be: reuses the user's org;
|
|
5
|
+
* always mints a fresh confidential OAuth client (the client_secret is shown once and
|
|
6
|
+
* can't be re-fetched, so we can't "reuse" one) + a sandbox API key.
|
|
7
|
+
*
|
|
8
|
+
* Everything is provisioned in SANDBOX. The client_secret + api key it returns are
|
|
9
|
+
* written to the app's .env by the caller and never put in the LLM prompt.
|
|
10
|
+
*/
|
|
11
|
+
export interface Provisioning {
|
|
12
|
+
orgId: string;
|
|
13
|
+
orgName: string;
|
|
14
|
+
appBaseUrl: string;
|
|
15
|
+
redirectUri: string;
|
|
16
|
+
clientId: string;
|
|
17
|
+
clientSecret?: string;
|
|
18
|
+
apiKey: string;
|
|
19
|
+
apiKeyPrefix: string;
|
|
20
|
+
}
|
|
21
|
+
/** The fixed callback path the integration implements; the OAuth client is registered with it. */
|
|
22
|
+
export declare const CALLBACK_PATH = "/api/agentcard/callback";
|
|
23
|
+
export declare function ensureOnboarded(appName: string): Promise<Provisioning>;
|
|
24
|
+
//# sourceMappingURL=onboard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"onboard.d.ts","sourceRoot":"","sources":["../../../../src/lib/wizard/onboard.ts"],"names":[],"mappings":"AAQA;;;;;;;;;GASG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;CACtB;AAoBD,kGAAkG;AAClG,eAAO,MAAM,aAAa,4BAA4B,CAAC;AAgBvD,wBAAsB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAsG5E"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import inquirer from 'inquirer';
|
|
2
|
+
import ora from 'ora';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { api } from '../api.js';
|
|
5
|
+
import { getJwt, getEmail, setMode, getApiUrl, clearAuth } from '../config.js';
|
|
6
|
+
import { login } from '../../commands/login.js';
|
|
7
|
+
import { step, line, row, ui } from './theme.js';
|
|
8
|
+
/** The fixed callback path the integration implements; the OAuth client is registered with it. */
|
|
9
|
+
export const CALLBACK_PATH = '/api/agentcard/callback';
|
|
10
|
+
/** Sentinel value for the "create a new organization" choice in the org picker. */
|
|
11
|
+
const CREATE_ORG = '__create_org__';
|
|
12
|
+
/** Prompt for a name and create a new organization. */
|
|
13
|
+
async function createOrgInteractive(defaultName) {
|
|
14
|
+
const { name } = await inquirer.prompt([
|
|
15
|
+
{ type: 'input', name: 'name', message: 'New organization name:', default: defaultName, validate: (v) => v.trim().length > 0 || 'Required' },
|
|
16
|
+
]);
|
|
17
|
+
const spinner = ora('Creating organization…').start();
|
|
18
|
+
const org = await api('/orgs', { method: 'POST', body: { name: String(name).trim(), billingEmail: getEmail() } });
|
|
19
|
+
spinner.succeed(chalk.green(`Organization "${org.name}" created`));
|
|
20
|
+
return org;
|
|
21
|
+
}
|
|
22
|
+
export async function ensureOnboarded(appName) {
|
|
23
|
+
// --- Step 1: account (signup / login) ---
|
|
24
|
+
// Validate any stored session first. Gate on a validity FLAG, not on getJwt() being
|
|
25
|
+
// falsy: a bare getJwt() can't tell a fresh token from an expired one, and a stale
|
|
26
|
+
// token exported via AGENT_CARDS_ADMIN_JWT can't be cleared (clearAuth only deletes
|
|
27
|
+
// the config-file token). When invalid we always run login(), which writes a fresh
|
|
28
|
+
// config token that takes precedence over the env var in getJwt().
|
|
29
|
+
let sessionValid = false;
|
|
30
|
+
const stored = getJwt();
|
|
31
|
+
if (stored) {
|
|
32
|
+
try {
|
|
33
|
+
const res = await fetch(`${getApiUrl()}/auth/me`, {
|
|
34
|
+
headers: { Authorization: `Bearer ${stored}` },
|
|
35
|
+
signal: AbortSignal.timeout(5_000),
|
|
36
|
+
});
|
|
37
|
+
if (res.status === 401 || res.status === 403) {
|
|
38
|
+
clearAuth();
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
sessionValid = true; // usable (or a transient non-auth error the real call will surface)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
sessionValid = true; // network blip — keep the token; the real call surfaces issues
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
step(1, 4, 'Account');
|
|
49
|
+
if (!sessionValid) {
|
|
50
|
+
line(ui.dim('First time? This creates your account via a magic link.'));
|
|
51
|
+
await login();
|
|
52
|
+
if (!getJwt()) {
|
|
53
|
+
line(ui.error('Sign-in did not complete. Run the wizard again once you have clicked the magic link.'));
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
row('Signed in', getEmail() ?? 'your account');
|
|
59
|
+
}
|
|
60
|
+
// Everything below is provisioned in sandbox.
|
|
61
|
+
setMode('sandbox');
|
|
62
|
+
// --- Step 2: organization (reuse an existing one or create a new one) ---
|
|
63
|
+
step(2, 4, 'Organization');
|
|
64
|
+
const { organizations } = await api('/orgs');
|
|
65
|
+
let org;
|
|
66
|
+
if (organizations.length === 0) {
|
|
67
|
+
// No org yet → create one.
|
|
68
|
+
org = await createOrgInteractive(appName);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
// Has org(s) → let them reuse one OR create a new org for this app.
|
|
72
|
+
const { picked } = await inquirer.prompt([
|
|
73
|
+
{
|
|
74
|
+
type: 'list',
|
|
75
|
+
name: 'picked',
|
|
76
|
+
message: 'Which organization is this app for?',
|
|
77
|
+
choices: [
|
|
78
|
+
...organizations.map((o) => ({ name: `${o.name}${o.billingEmail ? ` (${o.billingEmail})` : ''}`, value: o.id })),
|
|
79
|
+
new inquirer.Separator(),
|
|
80
|
+
{ name: '+ Create a new organization', value: CREATE_ORG },
|
|
81
|
+
],
|
|
82
|
+
},
|
|
83
|
+
]);
|
|
84
|
+
org = picked === CREATE_ORG ? await createOrgInteractive(appName) : organizations.find((o) => o.id === picked);
|
|
85
|
+
}
|
|
86
|
+
// --- Step 3: OAuth client (confidential) ---
|
|
87
|
+
step(3, 4, 'Register a Connect-with-Agentcard client');
|
|
88
|
+
const { appBaseUrl } = await inquirer.prompt([
|
|
89
|
+
{
|
|
90
|
+
type: 'input',
|
|
91
|
+
name: 'appBaseUrl',
|
|
92
|
+
message: `Your app's base URL (used for the OAuth callback ${CALLBACK_PATH}):`,
|
|
93
|
+
default: 'http://localhost:3000',
|
|
94
|
+
validate: (v) => /^https?:\/\/.+/.test(v.trim()) || 'Enter a URL like http://localhost:3000',
|
|
95
|
+
},
|
|
96
|
+
]);
|
|
97
|
+
const base = String(appBaseUrl).trim().replace(/\/+$/, '');
|
|
98
|
+
const redirectUri = `${base}${CALLBACK_PATH}`;
|
|
99
|
+
const spinner3 = ora('Creating confidential OAuth client…').start();
|
|
100
|
+
const client = await api(`/orgs/${org.id}/oauth-clients`, {
|
|
101
|
+
method: 'POST',
|
|
102
|
+
body: { name: `${appName} (wizard)`, redirectUris: [redirectUri], public: false },
|
|
103
|
+
});
|
|
104
|
+
spinner3.succeed(chalk.green(`OAuth client created (${client.clientId})`));
|
|
105
|
+
// --- Step 4: sandbox API key ---
|
|
106
|
+
step(4, 4, 'Create a sandbox API key');
|
|
107
|
+
const spinner4 = ora('Creating sandbox API key…').start();
|
|
108
|
+
const key = await api(`/orgs/${org.id}/keys`, {
|
|
109
|
+
method: 'POST',
|
|
110
|
+
body: { name: `${appName} wizard key`, mode: 'sandbox' },
|
|
111
|
+
});
|
|
112
|
+
spinner4.succeed(chalk.green(`Sandbox API key created (${key.keyPrefix})`));
|
|
113
|
+
return {
|
|
114
|
+
orgId: org.id,
|
|
115
|
+
orgName: org.name,
|
|
116
|
+
appBaseUrl: base,
|
|
117
|
+
redirectUri,
|
|
118
|
+
clientId: client.clientId,
|
|
119
|
+
clientSecret: client.clientSecret,
|
|
120
|
+
apiKey: key.key,
|
|
121
|
+
apiKeyPrefix: key.keyPrefix,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=onboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"onboard.js","sourceRoot":"","sources":["../../../../src/lib/wizard/onboard.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,5 +14,12 @@
|
|
|
14
14
|
*/
|
|
15
15
|
export declare const INTEGRATION_PLAYBOOK: string;
|
|
16
16
|
/** The initial user turn that kicks the agent off inside the partner's repo. */
|
|
17
|
-
|
|
17
|
+
/** Details of a confidential OAuth client the wizard already provisioned + pinned to env. */
|
|
18
|
+
export interface PinnedClient {
|
|
19
|
+
clientId: string;
|
|
20
|
+
redirectUri: string;
|
|
21
|
+
/** The env file the wizard wrote the secrets to (AGENTCARD_* are already set there). */
|
|
22
|
+
envFile: string;
|
|
23
|
+
}
|
|
24
|
+
export declare function buildInitialPrompt(detection: string, pinned?: PinnedClient): string;
|
|
18
25
|
//# sourceMappingURL=playbook.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"playbook.d.ts","sourceRoot":"","sources":["../../../../src/lib/wizard/playbook.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,oBAAoB,
|
|
1
|
+
{"version":3,"file":"playbook.d.ts","sourceRoot":"","sources":["../../../../src/lib/wizard/playbook.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,oBAAoB,QA+IzB,CAAC;AAET,gFAAgF;AAChF,6FAA6F;AAC7F,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,wFAAwF;IACxF,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,YAAY,GAAG,MAAM,CA+BnF"}
|
|
@@ -70,10 +70,18 @@ Part 3 - MCP (Streamable HTTP):
|
|
|
70
70
|
POST https://mcp.agentcard.sh/mcp, headers Authorization: Bearer <user token>,
|
|
71
71
|
Accept: application/json, text/event-stream. Handshake initialize ->
|
|
72
72
|
notifications/initialized -> tools/list -> tools/call; echo Mcp-Session-Id.
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
73
|
+
Expose EVERY tool the server advertises. Call tools/list at RUNTIME and register
|
|
74
|
+
ALL returned tools dynamically, deriving each tool's name, description, and
|
|
75
|
+
parameters from its advertised inputSchema. Do NOT hardcode a tool list and do NOT
|
|
76
|
+
curate/drop any tool - the integration must forward whatever tools/list returns so
|
|
77
|
+
that tools Agentcard adds later are supported automatically with ZERO code change.
|
|
78
|
+
(At the time of writing the server exposes create_card, list_cards,
|
|
79
|
+
get_card_details, check_balance, close_card, approve_request, list_transactions,
|
|
80
|
+
get_plan, buy, ... - treat that only as an example, never as a fixed allowlist.)
|
|
81
|
+
Prefer the Vercel AI SDK MCP client (\`experimental_createMCPClient(...).tools()\`
|
|
82
|
+
returns the full live toolset already mapped to the host's tool type) over
|
|
83
|
+
hand-rolling JSON-RPC if the host already uses the AI SDK. If a denylist is ever
|
|
84
|
+
needed it must be config/env-driven and default to EMPTY (all tools on).
|
|
77
85
|
|
|
78
86
|
## Implementation steps (in order)
|
|
79
87
|
0. Read discovery + confirm endpoints.
|
|
@@ -94,12 +102,14 @@ Part 3 - MCP (Streamable HTTP):
|
|
|
94
102
|
/authorize) and GET /callback (exchange code -> store token). Same process as
|
|
95
103
|
the brain; publicly reachable (tunnel for local dev). redirect_uri must equal
|
|
96
104
|
<public-base>/callback exactly.
|
|
97
|
-
6. Part 3: per user, build an MCP client with the user's token; expose
|
|
98
|
-
|
|
105
|
+
6. Part 3: per user, build an MCP client with the user's token; expose ALL tools
|
|
106
|
+
returned by tools/list dynamically (no hardcoded allowlist, no curated subset);
|
|
107
|
+
refresh on near-expiry and on 401.
|
|
99
108
|
7. Wire into the brain: look up the token; if none, hand the user the
|
|
100
|
-
/connect?user=<id> link; if present, expose
|
|
101
|
-
them in a multi-step loop.
|
|
102
|
-
8. Clean up:
|
|
109
|
+
/connect?user=<id> link; if present, expose the full live toolset and let the
|
|
110
|
+
model call any of them in a multi-step loop.
|
|
111
|
+
8. Clean up: never log PAN/CVV, redact debug logging. Do NOT prune the toolset -
|
|
112
|
+
forward every tool the server advertises.
|
|
103
113
|
|
|
104
114
|
## Gotchas (check every one)
|
|
105
115
|
- resource param mandatory on /authorize AND /token (=https://mcp.agentcard.sh/mcp).
|
|
@@ -110,6 +120,11 @@ Part 3 - MCP (Streamable HTTP):
|
|
|
110
120
|
approval_id; resolve with approve_request. Decide auto-approve vs ask-the-user.
|
|
111
121
|
- Card isolation is per (client, user) - an empty list_cards on a new client is
|
|
112
122
|
correct, not a bug.
|
|
123
|
+
- Toolset is DYNAMIC: register every tool from tools/list and pass through each
|
|
124
|
+
tool's inputSchema; never hardcode tool names or a curated subset, so server-side
|
|
125
|
+
tool additions work without touching the integration. A verification step that
|
|
126
|
+
asserts "exactly these N tools" is WRONG - assert the live tools/list is forwarded
|
|
127
|
+
in full instead.
|
|
113
128
|
- Connect server must be public + co-process with the store.
|
|
114
129
|
- NEVER log PAN/CVV; redact tool-result logging.
|
|
115
130
|
- Identify the user by a stable key.
|
|
@@ -120,7 +135,10 @@ Part 3 - MCP (Streamable HTTP):
|
|
|
120
135
|
A. Offline unit tests: PKCE (challenge === base64url(sha256(verifier))); token
|
|
121
136
|
exchange/refresh against a mock /token asserting grant_type, code_verifier,
|
|
122
137
|
resource, and client_secret when confidential; MCP flow against a mock JSON-RPC
|
|
123
|
-
server incl. the approval-required -> approve_request path.
|
|
138
|
+
server incl. the approval-required -> approve_request path. Add a dynamic-toolset
|
|
139
|
+
test: point the mock server at an ARBITRARY tools/list (including an invented
|
|
140
|
+
future tool the code has never seen) and assert the integration registers ALL of
|
|
141
|
+
them - never assert a fixed/expected set of tool names.
|
|
124
142
|
B. Discovery checks: curl the two .well-known endpoints; for confidential clients,
|
|
125
143
|
prove refresh requires the secret (with -> 200, without -> 400 invalid_client).
|
|
126
144
|
C. Live sandbox: register the client (DCR or org) with <public-base>/callback,
|
|
@@ -138,9 +156,8 @@ When you finish, end your final message with a short summary that begins with
|
|
|
138
156
|
"INTEGRATION COMPLETE:" (or "INTEGRATION BLOCKED:" with the reason if you could
|
|
139
157
|
not proceed), then list the files you created or changed.
|
|
140
158
|
`.trim();
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
return [
|
|
159
|
+
export function buildInitialPrompt(detection, pinned) {
|
|
160
|
+
const lines = [
|
|
144
161
|
"Integrate Agentcard (the OAuth 2.1 + PKCE + MCP company integration described in",
|
|
145
162
|
"your system prompt) into this repository. Your working directory IS the repo root;",
|
|
146
163
|
"all file paths are relative to it. Use bash/grep to explore and the editor to make",
|
|
@@ -148,9 +165,11 @@ export function buildInitialPrompt(detection) {
|
|
|
148
165
|
'',
|
|
149
166
|
'What the wizard already detected about this repo:',
|
|
150
167
|
detection,
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
'OAuth
|
|
154
|
-
|
|
168
|
+
];
|
|
169
|
+
if (pinned) {
|
|
170
|
+
lines.push('', 'IMPORTANT — a CONFIDENTIAL OAuth client is ALREADY provisioned for this app. Do', 'NOT register a new client (no DCR). Use the pinned credentials, which the wizard', `has ALREADY written to ${pinned.envFile}:`, ' AGENTCARD_OAUTH_CLIENT_ID, AGENTCARD_OAUTH_CLIENT_SECRET, AGENTCARD_API_KEY,', ' AGENTCARD_PUBLIC_URL.', `The client_id is ${pinned.clientId} and its registered redirect_uri is`, `${pinned.redirectUri} — so implement the OAuth callback at EXACTLY that path`, `(${pinned.redirectUri.replace(/^https?:\/\/[^/]+/, '')}). Read every secret from`, 'process.env — NEVER hardcode or log AGENTCARD_OAUTH_CLIENT_SECRET / AGENTCARD_API_KEY.', 'Confidential client: send client_secret on BOTH the token exchange and refresh.');
|
|
171
|
+
}
|
|
172
|
+
lines.push('', 'Start with Step 0 (discovery) and Step 1/1b (scope the repo + mirror existing', 'OAuth/MCP patterns), then proceed through the playbook. Verify against SANDBOX.');
|
|
173
|
+
return lines.join('\n');
|
|
155
174
|
}
|
|
156
175
|
//# sourceMappingURL=playbook.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"playbook.js","sourceRoot":"","sources":["../../../../src/lib/wizard/playbook.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG
|
|
1
|
+
{"version":3,"file":"playbook.js","sourceRoot":"","sources":["../../../../src/lib/wizard/playbook.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+InC,CAAC,IAAI,EAAE,CAAC;AAWT,MAAM,UAAU,kBAAkB,CAAC,SAAiB,EAAE,MAAqB;IACzE,MAAM,KAAK,GAAG;QACZ,kFAAkF;QAClF,oFAAoF;QACpF,oFAAoF;QACpF,oDAAoD;QACpD,EAAE;QACF,mDAAmD;QACnD,SAAS;KACV,CAAC;IACF,IAAI,MAAM,EAAE,CAAC;QACX,KAAK,CAAC,IAAI,CACR,EAAE,EACF,iFAAiF,EACjF,kFAAkF,EAClF,0BAA0B,MAAM,CAAC,OAAO,GAAG,EAC3C,gFAAgF,EAChF,yBAAyB,EACzB,oBAAoB,MAAM,CAAC,QAAQ,qCAAqC,EACxE,GAAG,MAAM,CAAC,WAAW,yDAAyD,EAC9E,IAAI,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC,2BAA2B,EAClF,wFAAwF,EACxF,iFAAiF,CAClF,CAAC;IACJ,CAAC;IACD,KAAK,CAAC,IAAI,CACR,EAAE,EACF,+EAA+E,EAC/E,iFAAiF,CAClF,CAAC;IACF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Write the provisioned Agentcard credentials into the app's local env file so the
|
|
3
|
+
* agent never sees the secrets — it writes code that reads `process.env.AGENTCARD_*`,
|
|
4
|
+
* and we put the actual `client_secret` / API key here (secret-vault pattern).
|
|
5
|
+
*
|
|
6
|
+
* Picks the env file by the repo's convention: an existing .env.local / .env, else
|
|
7
|
+
* .env.local when a `.env.local.example` is present (Next.js style), else .env.
|
|
8
|
+
* Upserts each key (replaces an existing line, appends otherwise). Returns the file.
|
|
9
|
+
*/
|
|
10
|
+
export declare function writeAgentcardEnv(repoRoot: string, vars: Record<string, string>): string;
|
|
11
|
+
//# sourceMappingURL=secrets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secrets.d.ts","sourceRoot":"","sources":["../../../../src/lib/wizard/secrets.ts"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAgCxF"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, existsSync, chmodSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
/**
|
|
4
|
+
* Write the provisioned Agentcard credentials into the app's local env file so the
|
|
5
|
+
* agent never sees the secrets — it writes code that reads `process.env.AGENTCARD_*`,
|
|
6
|
+
* and we put the actual `client_secret` / API key here (secret-vault pattern).
|
|
7
|
+
*
|
|
8
|
+
* Picks the env file by the repo's convention: an existing .env.local / .env, else
|
|
9
|
+
* .env.local when a `.env.local.example` is present (Next.js style), else .env.
|
|
10
|
+
* Upserts each key (replaces an existing line, appends otherwise). Returns the file.
|
|
11
|
+
*/
|
|
12
|
+
export function writeAgentcardEnv(repoRoot, vars) {
|
|
13
|
+
const pick = () => {
|
|
14
|
+
for (const f of ['.env.local', '.env', '.env.development.local']) {
|
|
15
|
+
if (existsSync(join(repoRoot, f)))
|
|
16
|
+
return f;
|
|
17
|
+
}
|
|
18
|
+
return existsSync(join(repoRoot, '.env.local.example')) ? '.env.local' : '.env';
|
|
19
|
+
};
|
|
20
|
+
const file = pick();
|
|
21
|
+
const path = join(repoRoot, file);
|
|
22
|
+
let content = existsSync(path) ? readFileSync(path, 'utf8') : '';
|
|
23
|
+
if (content && !content.endsWith('\n'))
|
|
24
|
+
content += '\n';
|
|
25
|
+
for (const [k, v] of Object.entries(vars)) {
|
|
26
|
+
if (v == null)
|
|
27
|
+
continue;
|
|
28
|
+
const line = `${k}=${v}`;
|
|
29
|
+
const re = new RegExp(`^${k}=.*$`, 'm');
|
|
30
|
+
if (re.test(content)) {
|
|
31
|
+
content = content.replace(re, line);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
content += `${line}\n`;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
writeFileSync(path, content, { mode: 0o600 });
|
|
38
|
+
// `mode` on writeFileSync only applies when CREATING the file — an existing env
|
|
39
|
+
// file keeps its (often 0644) perms. We just wrote a client_secret + API key into
|
|
40
|
+
// it, so restrict it explicitly.
|
|
41
|
+
try {
|
|
42
|
+
chmodSync(path, 0o600);
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
// Best-effort (e.g. unusual filesystems); the secrets are still written.
|
|
46
|
+
}
|
|
47
|
+
return file;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=secrets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secrets.js","sourceRoot":"","sources":["../../../../src/lib/wizard/secrets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACxE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAgB,EAAE,IAA4B;IAC9E,MAAM,IAAI,GAAG,GAAW,EAAE;QACxB,KAAK,MAAM,CAAC,IAAI,CAAC,YAAY,EAAE,MAAM,EAAE,wBAAwB,CAAC,EAAE,CAAC;YACjE,IAAI,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;gBAAE,OAAO,CAAC,CAAC;QAC9C,CAAC;QACD,OAAO,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,oBAAoB,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC;IAClF,CAAC,CAAC;IACF,MAAM,IAAI,GAAG,IAAI,EAAE,CAAC;IACpB,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAClC,IAAI,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACjE,IAAI,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,IAAI,CAAC;IAExD,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1C,IAAI,CAAC,IAAI,IAAI;YAAE,SAAS;QACxB,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;QACzB,MAAM,EAAE,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QACxC,IAAI,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YACrB,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QACtC,CAAC;aAAM,CAAC;YACN,OAAO,IAAI,GAAG,IAAI,IAAI,CAAC;QACzB,CAAC;IACH,CAAC;IACD,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC9C,gFAAgF;IAChF,kFAAkF;IAClF,iCAAiC;IACjC,IAAI,CAAC;QACH,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,yEAAyE;IAC3E,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Small presentation theme for the wizard, inspired by PostHog's setup wizard:
|
|
3
|
+
* a brand banner, an accent color, status icons, a connected left gutter, and a
|
|
4
|
+
* structured outro. Layered on top of chalk/inquirer/ora — no UI-framework rewrite.
|
|
5
|
+
*/
|
|
6
|
+
export declare const ui: {
|
|
7
|
+
primary: import("chalk").ChalkInstance;
|
|
8
|
+
accent: import("chalk").ChalkInstance;
|
|
9
|
+
success: import("chalk").ChalkInstance;
|
|
10
|
+
error: import("chalk").ChalkInstance;
|
|
11
|
+
warn: import("chalk").ChalkInstance;
|
|
12
|
+
muted: import("chalk").ChalkInstance;
|
|
13
|
+
bold: import("chalk").ChalkInstance;
|
|
14
|
+
dim: import("chalk").ChalkInstance;
|
|
15
|
+
};
|
|
16
|
+
export declare const glyph: {
|
|
17
|
+
check: string;
|
|
18
|
+
cross: string;
|
|
19
|
+
warn: string;
|
|
20
|
+
diamond: string;
|
|
21
|
+
diamondOpen: string;
|
|
22
|
+
sqOpen: string;
|
|
23
|
+
sqFilled: string;
|
|
24
|
+
play: string;
|
|
25
|
+
pointer: string;
|
|
26
|
+
bullet: string;
|
|
27
|
+
arrow: string;
|
|
28
|
+
gutter: string;
|
|
29
|
+
};
|
|
30
|
+
/** Branded intro banner: three brand blocks + title + dim subtitle lines. */
|
|
31
|
+
export declare function banner(title: string, subtitle?: string[]): void;
|
|
32
|
+
/** A numbered step header, with a blank gutter line under it for grouping. */
|
|
33
|
+
export declare function step(n: number, total: number, title: string): void;
|
|
34
|
+
/** A line inside the current step, hung under the gutter. */
|
|
35
|
+
export declare function line(text?: string): void;
|
|
36
|
+
/** A "label ✔ value" detection/summary row, under the gutter. */
|
|
37
|
+
export declare function row(label: string, value: string): void;
|
|
38
|
+
/** A boxed-ish note: a titled block hung under the gutter (clack-style left rail). */
|
|
39
|
+
export declare function note(title: string, lines: string[]): void;
|
|
40
|
+
/** A success outro: green header, optional "what changed" + "next steps" + review note. */
|
|
41
|
+
export declare function outroSuccess(opts: {
|
|
42
|
+
message: string;
|
|
43
|
+
changes?: string[];
|
|
44
|
+
nextSteps?: string[];
|
|
45
|
+
reviewNote?: string;
|
|
46
|
+
}): void;
|
|
47
|
+
/** An error outro: red header + optional body. */
|
|
48
|
+
export declare function outroError(message: string, body?: string): void;
|
|
49
|
+
//# sourceMappingURL=theme.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../../../src/lib/wizard/theme.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,eAAO,MAAM,EAAE;;;;;;;;;CASd,CAAC;AAEF,eAAO,MAAM,KAAK;;;;;;;;;;;;;CAajB,CAAC;AAIF,6EAA6E;AAC7E,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAM,EAAO,GAAG,IAAI,CAKnE;AAED,8EAA8E;AAC9E,wBAAgB,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAIlE;AAED,6DAA6D;AAC7D,wBAAgB,IAAI,CAAC,IAAI,SAAK,GAAG,IAAI,CAEpC;AAED,iEAAiE;AACjE,wBAAgB,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAEtD;AAED,sFAAsF;AACtF,wBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAIzD;AAED,2FAA2F;AAC3F,wBAAgB,YAAY,CAAC,IAAI,EAAE;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,GAAG,IAAI,CAiBP;AAED,kDAAkD;AAClD,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAI/D"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
/**
|
|
3
|
+
* Small presentation theme for the wizard, inspired by PostHog's setup wizard:
|
|
4
|
+
* a brand banner, an accent color, status icons, a connected left gutter, and a
|
|
5
|
+
* structured outro. Layered on top of chalk/inquirer/ora — no UI-framework rewrite.
|
|
6
|
+
*/
|
|
7
|
+
export const ui = {
|
|
8
|
+
primary: chalk.cyan,
|
|
9
|
+
accent: chalk.hex('#F59E0B'), // warm amber accent (focus / step markers)
|
|
10
|
+
success: chalk.green,
|
|
11
|
+
error: chalk.red,
|
|
12
|
+
warn: chalk.yellow,
|
|
13
|
+
muted: chalk.gray,
|
|
14
|
+
bold: chalk.bold,
|
|
15
|
+
dim: chalk.dim,
|
|
16
|
+
};
|
|
17
|
+
export const glyph = {
|
|
18
|
+
check: '✔',
|
|
19
|
+
cross: '✘',
|
|
20
|
+
warn: '⚠',
|
|
21
|
+
diamond: '◆',
|
|
22
|
+
diamondOpen: '◇',
|
|
23
|
+
sqOpen: '◻',
|
|
24
|
+
sqFilled: '◼',
|
|
25
|
+
play: '▶',
|
|
26
|
+
pointer: '▸',
|
|
27
|
+
bullet: '•',
|
|
28
|
+
arrow: '→',
|
|
29
|
+
gutter: '│',
|
|
30
|
+
};
|
|
31
|
+
const g = () => ui.muted(glyph.gutter);
|
|
32
|
+
/** Branded intro banner: three brand blocks + title + dim subtitle lines. */
|
|
33
|
+
export function banner(title, subtitle = []) {
|
|
34
|
+
const blocks = chalk.cyan('█') + chalk.hex('#F59E0B')('█') + chalk.magentaBright('█');
|
|
35
|
+
console.log();
|
|
36
|
+
console.log(`${blocks} ${ui.bold(title)}`);
|
|
37
|
+
for (const s of subtitle)
|
|
38
|
+
console.log(` ${ui.dim(s)}`);
|
|
39
|
+
}
|
|
40
|
+
/** A numbered step header, with a blank gutter line under it for grouping. */
|
|
41
|
+
export function step(n, total, title) {
|
|
42
|
+
console.log();
|
|
43
|
+
console.log(`${ui.accent(glyph.diamond)} ${ui.bold(`Step ${n}/${total}`)} ${ui.muted('·')} ${title}`);
|
|
44
|
+
console.log(g());
|
|
45
|
+
}
|
|
46
|
+
/** A line inside the current step, hung under the gutter. */
|
|
47
|
+
export function line(text = '') {
|
|
48
|
+
console.log(`${g()} ${text}`);
|
|
49
|
+
}
|
|
50
|
+
/** A "label ✔ value" detection/summary row, under the gutter. */
|
|
51
|
+
export function row(label, value) {
|
|
52
|
+
console.log(`${g()} ${label} ${ui.success(glyph.check)} ${value}`);
|
|
53
|
+
}
|
|
54
|
+
/** A boxed-ish note: a titled block hung under the gutter (clack-style left rail). */
|
|
55
|
+
export function note(title, lines) {
|
|
56
|
+
console.log(g());
|
|
57
|
+
console.log(`${g()} ${ui.bold(title)}`);
|
|
58
|
+
for (const l of lines)
|
|
59
|
+
console.log(`${g()} ${ui.dim(l)}`);
|
|
60
|
+
}
|
|
61
|
+
/** A success outro: green header, optional "what changed" + "next steps" + review note. */
|
|
62
|
+
export function outroSuccess(opts) {
|
|
63
|
+
console.log();
|
|
64
|
+
console.log(`${ui.success(glyph.check)} ${ui.success.bold(opts.message)}`);
|
|
65
|
+
if (opts.changes?.length) {
|
|
66
|
+
console.log();
|
|
67
|
+
console.log(ui.primary.bold('What the agent did:'));
|
|
68
|
+
for (const c of opts.changes)
|
|
69
|
+
console.log(` ${ui.muted(glyph.bullet)} ${c}`);
|
|
70
|
+
}
|
|
71
|
+
if (opts.nextSteps?.length) {
|
|
72
|
+
console.log();
|
|
73
|
+
console.log(ui.primary.bold('Next steps:'));
|
|
74
|
+
for (const s of opts.nextSteps)
|
|
75
|
+
console.log(` ${ui.muted(glyph.bullet)} ${s}`);
|
|
76
|
+
}
|
|
77
|
+
if (opts.reviewNote) {
|
|
78
|
+
console.log();
|
|
79
|
+
console.log(ui.dim(opts.reviewNote));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/** An error outro: red header + optional body. */
|
|
83
|
+
export function outroError(message, body) {
|
|
84
|
+
console.log();
|
|
85
|
+
console.log(`${ui.error(glyph.cross)} ${ui.error.bold(message)}`);
|
|
86
|
+
if (body)
|
|
87
|
+
console.log(ui.dim(body));
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=theme.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.js","sourceRoot":"","sources":["../../../../src/lib/wizard/theme.ts"],"names":[],"mappings":"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"}
|