orizu 0.5.24 → 0.5.26
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/README.md +23 -3
- package/dist/credentials.d.ts +15 -0
- package/dist/credentials.d.ts.map +1 -1
- package/dist/credentials.js +279 -59
- package/dist/help.d.ts.map +1 -1
- package/dist/help.js +5 -2
- package/dist/http.d.ts +20 -0
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +239 -19
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +153 -213
- package/dist/keyboard-select.d.ts +7 -0
- package/dist/keyboard-select.d.ts.map +1 -0
- package/dist/keyboard-select.js +72 -0
- package/dist/logout-diagnostic.d.ts +4 -0
- package/dist/logout-diagnostic.d.ts.map +1 -0
- package/dist/logout-diagnostic.js +26 -0
- package/dist/setup-account.d.ts +11 -0
- package/dist/setup-account.d.ts.map +1 -0
- package/dist/setup-account.js +106 -0
- package/dist/setup-onboarding.d.ts +27 -1
- package/dist/setup-onboarding.d.ts.map +1 -1
- package/dist/setup-onboarding.js +95 -11
- package/dist/setup-summary.d.ts +12 -0
- package/dist/setup-summary.d.ts.map +1 -0
- package/dist/setup-summary.js +56 -0
- package/package.json +1 -1
- package/src/credentials.ts +326 -57
- package/src/help.ts +7 -2
- package/src/http.ts +325 -20
- package/src/index.ts +193 -279
- package/src/keyboard-select.ts +97 -0
- package/src/logout-diagnostic.ts +39 -0
- package/src/setup-account.ts +129 -0
- package/src/setup-onboarding.ts +133 -10
- package/src/setup-summary.ts +77 -0
- package/vendor/skills/orizu/SKILL.md +51 -111
- package/vendor/skills/orizu/flows/expand.md +27 -0
- package/vendor/skills/orizu/flows/first-win.md +31 -0
- package/vendor/skills/orizu/flows/onboard.md +31 -0
- package/vendor/skills/orizu/flows/promote.md +33 -0
- package/vendor/skills/orizu/flows/recurse.md +23 -0
- package/vendor/skills/orizu/flows/triage.md +37 -0
- package/vendor/skills/orizu/references/assess-and-plan.md +5 -5
- package/vendor/skills/orizu/references/authority-map.md +20 -0
- package/vendor/skills/orizu/references/building-apps.md +7 -1
- package/vendor/skills/orizu/references/building-judges.md +15 -16
- package/vendor/skills/orizu/references/cli-reference.md +17 -8
- package/vendor/skills/orizu/references/dataset-design.md +16 -6
- package/vendor/skills/orizu/references/eval-strategy.md +18 -15
- package/vendor/skills/orizu/references/instructions-after-prompts.md +2 -2
- package/vendor/skills/orizu/references/migrate-existing-gepa-setup.md +10 -6
- package/vendor/skills/orizu/references/optimization-reports.md +11 -11
- package/vendor/skills/orizu/references/optimization-with-gepa.md +4 -2
- package/vendor/skills/orizu/references/primer.md +18 -22
- package/vendor/skills/orizu/references/prompt-control-plane.md +5 -5
- package/vendor/skills/orizu/references/vocabulary.md +27 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
interface KeyboardSelectOptions<T> {
|
|
2
|
+
onEscape?: () => T;
|
|
3
|
+
escapeLabel?: string;
|
|
4
|
+
}
|
|
5
|
+
export declare function promptKeyboardSelect<T>(title: string, items: T[], label: (item: T, index: number) => string, options?: KeyboardSelectOptions<T>): Promise<T>;
|
|
6
|
+
export {};
|
|
7
|
+
//# sourceMappingURL=keyboard-select.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keyboard-select.d.ts","sourceRoot":"","sources":["../src/keyboard-select.ts"],"names":[],"mappings":"AAUA,UAAU,qBAAqB,CAAC,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAOD,wBAAsB,oBAAoB,CAAC,CAAC,EAC1C,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,CAAC,EAAE,EACV,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,EACzC,OAAO,CAAC,EAAE,qBAAqB,CAAC,CAAC,CAAC,GACjC,OAAO,CAAC,CAAC,CAAC,CAuEZ"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { emitKeypressEvents } from 'readline';
|
|
2
|
+
import { stdin as input, stdout as output } from 'process';
|
|
3
|
+
import { sanitizeTerminalText } from './json-response.js';
|
|
4
|
+
export async function promptKeyboardSelect(title, items, label, options) {
|
|
5
|
+
if (items.length === 0) {
|
|
6
|
+
throw new Error(`No options available for ${title.toLowerCase()}`);
|
|
7
|
+
}
|
|
8
|
+
if (!input.isTTY || !output.isTTY) {
|
|
9
|
+
throw new Error(`${title} selection requires interactive terminal. Provide flags explicitly instead.`);
|
|
10
|
+
}
|
|
11
|
+
output.write(`\n${sanitizeTerminalText(title)}\n`);
|
|
12
|
+
output.write(`Use ↑/↓ to choose, Enter to confirm, or Esc to ${options?.escapeLabel || 'cancel'}.\n`);
|
|
13
|
+
let selected = 0;
|
|
14
|
+
let rendered = false;
|
|
15
|
+
const rawInput = input;
|
|
16
|
+
const wasRaw = Boolean(rawInput.isRaw);
|
|
17
|
+
emitKeypressEvents(input);
|
|
18
|
+
function render() {
|
|
19
|
+
if (rendered)
|
|
20
|
+
output.write(`\x1b[${items.length}A`);
|
|
21
|
+
items.forEach((item, index) => {
|
|
22
|
+
output.write('\x1b[2K');
|
|
23
|
+
const marker = index === selected ? '●' : '○';
|
|
24
|
+
output.write(` ${marker} ${sanitizeTerminalText(label(item, index))}\n`);
|
|
25
|
+
});
|
|
26
|
+
rendered = true;
|
|
27
|
+
}
|
|
28
|
+
render();
|
|
29
|
+
output.write('\x1b[?25l');
|
|
30
|
+
return new Promise((resolvePromise, rejectPromise) => {
|
|
31
|
+
function cleanup() {
|
|
32
|
+
input.off('keypress', onKeypress);
|
|
33
|
+
if (rawInput.setRawMode && !wasRaw)
|
|
34
|
+
rawInput.setRawMode(false);
|
|
35
|
+
input.pause();
|
|
36
|
+
output.write('\x1b[?25h\n');
|
|
37
|
+
}
|
|
38
|
+
function onKeypress(_chunk, key) {
|
|
39
|
+
if (key.ctrl && key.name === 'c') {
|
|
40
|
+
cleanup();
|
|
41
|
+
rejectPromise(new Error('Setup cancelled.'));
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (key.name === 'escape') {
|
|
45
|
+
cleanup();
|
|
46
|
+
if (options?.onEscape)
|
|
47
|
+
resolvePromise(options.onEscape());
|
|
48
|
+
else
|
|
49
|
+
rejectPromise(new Error('Setup cancelled.'));
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (key.name === 'up') {
|
|
53
|
+
selected = (selected - 1 + items.length) % items.length;
|
|
54
|
+
render();
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (key.name === 'down') {
|
|
58
|
+
selected = (selected + 1) % items.length;
|
|
59
|
+
render();
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (key.name === 'return' || key.name === 'enter') {
|
|
63
|
+
const item = items[selected];
|
|
64
|
+
cleanup();
|
|
65
|
+
resolvePromise(item);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
input.on('keypress', onKeypress);
|
|
69
|
+
input.resume();
|
|
70
|
+
rawInput.setRawMode?.(true);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare const LOGOUT_DIAGNOSTIC_LIMIT = 180;
|
|
2
|
+
export declare function describeLogoutHttpFailure(response: Response, secrets: readonly string[]): Promise<string>;
|
|
3
|
+
export declare function describeLogoutTransportFailure(error: unknown, secrets: readonly string[], prefix?: string): string;
|
|
4
|
+
//# sourceMappingURL=logout-diagnostic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logout-diagnostic.d.ts","sourceRoot":"","sources":["../src/logout-diagnostic.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,uBAAuB,MAAM,CAAA;AAQ1C,wBAAsB,yBAAyB,CAC7C,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,SAAS,MAAM,EAAE,GACzB,OAAO,CAAC,MAAM,CAAC,CAYjB;AAED,wBAAgB,8BAA8B,CAC5C,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,MAAM,CAAC,EAAE,MAAM,GACd,MAAM,CAMR"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { sanitizeHumanInlineText, sanitizeTerminalText } from './json-response.js';
|
|
2
|
+
import { redactSecrets } from './secret-redaction.js';
|
|
3
|
+
export const LOGOUT_DIAGNOSTIC_LIMIT = 180;
|
|
4
|
+
function boundedLogoutDiagnostic(value, secrets) {
|
|
5
|
+
const bounded = sanitizeTerminalText(redactSecrets(value, { secrets }))
|
|
6
|
+
.slice(0, LOGOUT_DIAGNOSTIC_LIMIT);
|
|
7
|
+
return sanitizeHumanInlineText(sanitizeTerminalText, bounded).slice(0, LOGOUT_DIAGNOSTIC_LIMIT);
|
|
8
|
+
}
|
|
9
|
+
export async function describeLogoutHttpFailure(response, secrets) {
|
|
10
|
+
let body = '';
|
|
11
|
+
try {
|
|
12
|
+
body = await response.text();
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
return describeLogoutTransportFailure(error, secrets, `HTTP ${response.status} body error`);
|
|
16
|
+
}
|
|
17
|
+
const detail = body.trim();
|
|
18
|
+
return boundedLogoutDiagnostic(detail ? `HTTP ${response.status}: ${detail}` : `HTTP ${response.status}`, secrets);
|
|
19
|
+
}
|
|
20
|
+
export function describeLogoutTransportFailure(error, secrets, prefix) {
|
|
21
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
22
|
+
const isTimeout = error instanceof Error
|
|
23
|
+
&& (error.name === 'AbortError' || error.name === 'TimeoutError');
|
|
24
|
+
const label = prefix ?? (isTimeout ? 'Timeout' : 'Network error');
|
|
25
|
+
return boundedLogoutDiagnostic(`${label}: ${message || 'remote logout failed'}`, secrets);
|
|
26
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type AuthenticatedRequestContext } from './http.js';
|
|
2
|
+
export interface SetupAuthState {
|
|
3
|
+
state: 'signed-in' | 'signed-out';
|
|
4
|
+
baseUrl: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function describeSetupAuthState(): SetupAuthState;
|
|
7
|
+
export declare function validateSetupIdentityEmail(value: unknown): string;
|
|
8
|
+
export declare function confirmExistingSetupAccount(context: AuthenticatedRequestContext, chooseAccount: (displayIdentity: string) => Promise<'continue' | 'switch'>, switchAccount: () => Promise<void>, options?: {
|
|
9
|
+
dryRun?: boolean;
|
|
10
|
+
}): Promise<'continued' | 'switched'>;
|
|
11
|
+
//# sourceMappingURL=setup-account.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup-account.d.ts","sourceRoot":"","sources":["../src/setup-account.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,2BAA2B,EACjC,MAAM,WAAW,CAAA;AAElB,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,WAAW,GAAG,YAAY,CAAA;IACjC,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,wBAAgB,sBAAsB,IAAI,cAAc,CAOvD;AAED,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CA2BjE;AA4DD,wBAAsB,2BAA2B,CAC/C,OAAO,EAAE,2BAA2B,EACpC,aAAa,EAAE,CAAC,eAAe,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,GAAG,QAAQ,CAAC,EAC1E,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EAClC,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GACjC,OAAO,CAAC,WAAW,GAAG,UAAU,CAAC,CAgBnC"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { hasResolvableAuth } from './credentials.js';
|
|
2
|
+
import { getBaseUrl, } from './http.js';
|
|
3
|
+
export function describeSetupAuthState() {
|
|
4
|
+
const baseUrl = getBaseUrl();
|
|
5
|
+
return {
|
|
6
|
+
// An environment bearer (ORIZU_TOKEN / ORIZU_TOKEN_FILE) is signed-in too.
|
|
7
|
+
state: hasResolvableAuth(baseUrl) ? 'signed-in' : 'signed-out',
|
|
8
|
+
baseUrl,
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export function validateSetupIdentityEmail(value) {
|
|
12
|
+
if (typeof value !== 'string' || /[\u0000-\u001f\u007f-\u009f]/.test(value))
|
|
13
|
+
return '';
|
|
14
|
+
const email = value.trim();
|
|
15
|
+
if (!email || email.length > 254 || /\s/.test(email))
|
|
16
|
+
return '';
|
|
17
|
+
const parts = email.split('@');
|
|
18
|
+
if (parts.length !== 2)
|
|
19
|
+
return '';
|
|
20
|
+
const [localPart, domain] = parts;
|
|
21
|
+
if (!localPart
|
|
22
|
+
|| localPart.length > 64
|
|
23
|
+
|| localPart.startsWith('.')
|
|
24
|
+
|| localPart.endsWith('.')
|
|
25
|
+
|| localPart.includes('..')
|
|
26
|
+
|| !/^[A-Za-z0-9.!#$%&'*+/=?^_`{|}~-]+$/.test(localPart))
|
|
27
|
+
return '';
|
|
28
|
+
if (!domain || domain.length > 253)
|
|
29
|
+
return '';
|
|
30
|
+
const labels = domain.split('.');
|
|
31
|
+
if (labels.some(label => !label
|
|
32
|
+
|| label.length > 63
|
|
33
|
+
|| !/^[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?$/.test(label)))
|
|
34
|
+
return '';
|
|
35
|
+
return email;
|
|
36
|
+
}
|
|
37
|
+
function identityRecovery(context) {
|
|
38
|
+
if (context.source === 'ORIZU_TOKEN') {
|
|
39
|
+
return 'Rotate or unset ORIZU_TOKEN and rerun `orizu setup`.';
|
|
40
|
+
}
|
|
41
|
+
if (context.source === 'ORIZU_TOKEN_FILE') {
|
|
42
|
+
return 'Fix, rotate, or unset ORIZU_TOKEN_FILE and rerun `orizu setup`.';
|
|
43
|
+
}
|
|
44
|
+
return 'Run `orizu login` and rerun `orizu setup`.';
|
|
45
|
+
}
|
|
46
|
+
function isRecord(value) {
|
|
47
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
48
|
+
}
|
|
49
|
+
function validateAgentUserId(value) {
|
|
50
|
+
if (typeof value !== 'string')
|
|
51
|
+
return '';
|
|
52
|
+
const userId = value.trim();
|
|
53
|
+
return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(userId)
|
|
54
|
+
? userId
|
|
55
|
+
: '';
|
|
56
|
+
}
|
|
57
|
+
function isCredentialStoreError(error) {
|
|
58
|
+
return error instanceof Error && /^ORIZU_CREDENTIALS_[A-Z_]+:/.test(error.message);
|
|
59
|
+
}
|
|
60
|
+
async function fetchSetupDisplayIdentity(context) {
|
|
61
|
+
let response;
|
|
62
|
+
try {
|
|
63
|
+
response = await context.fetch('/api/cli/auth/whoami');
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
if (isCredentialStoreError(error))
|
|
67
|
+
throw error;
|
|
68
|
+
throw new Error(`Could not identify the authenticated account. ${identityRecovery(context)}`);
|
|
69
|
+
}
|
|
70
|
+
if (!response.ok) {
|
|
71
|
+
throw new Error(`Could not identify the authenticated account. ${identityRecovery(context)}`);
|
|
72
|
+
}
|
|
73
|
+
let data;
|
|
74
|
+
try {
|
|
75
|
+
data = await response.json();
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
throw new Error(`Could not identify the authenticated account. ${identityRecovery(context)}`);
|
|
79
|
+
}
|
|
80
|
+
if (!isRecord(data) || !isRecord(data.user)) {
|
|
81
|
+
throw new Error(`Could not identify the authenticated account. ${identityRecovery(context)}`);
|
|
82
|
+
}
|
|
83
|
+
const email = validateSetupIdentityEmail(data.user.email);
|
|
84
|
+
if (email)
|
|
85
|
+
return email;
|
|
86
|
+
if (data.user.email === null) {
|
|
87
|
+
const agentUserId = validateAgentUserId(data.user.id);
|
|
88
|
+
if (agentUserId)
|
|
89
|
+
return `Agent ${agentUserId}`;
|
|
90
|
+
throw new Error(`The authenticated account has no usable email or agent ID. ${identityRecovery(context)}`);
|
|
91
|
+
}
|
|
92
|
+
throw new Error(`The authenticated account has no usable email. ${identityRecovery(context)}`);
|
|
93
|
+
}
|
|
94
|
+
export async function confirmExistingSetupAccount(context, chooseAccount, switchAccount, options = {}) {
|
|
95
|
+
const choice = await chooseAccount(await fetchSetupDisplayIdentity(context));
|
|
96
|
+
if (choice === 'continue')
|
|
97
|
+
return 'continued';
|
|
98
|
+
if (options.dryRun) {
|
|
99
|
+
throw new Error('Account switching cannot be previewed. Rerun `orizu setup` without `--dry-run` to log in with a different account.');
|
|
100
|
+
}
|
|
101
|
+
if (context.source !== 'stored') {
|
|
102
|
+
throw new Error(`Authentication is supplied by ${context.source}. Unset ${context.source} and rerun \`orizu setup\` to log in with a different account.`);
|
|
103
|
+
}
|
|
104
|
+
await switchAccount();
|
|
105
|
+
return 'switched';
|
|
106
|
+
}
|
|
@@ -1,4 +1,23 @@
|
|
|
1
|
-
|
|
1
|
+
import { type SkillInstallAgent, type SkillInstallTarget } from './skill-installer.js';
|
|
2
|
+
export interface AgentLaunchSpec {
|
|
3
|
+
command: string;
|
|
4
|
+
displayLabel: string;
|
|
5
|
+
buildPromptArgs: (prompt: string) => string[];
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Measured launch contracts:
|
|
9
|
+
* - Local `claude --help`, `codex --help`, and `pi --help` expose a direct
|
|
10
|
+
* positional prompt/message (observed 2026-08-30).
|
|
11
|
+
* - OpenCode's primary CLI reference documents `opencode run [message..]`.
|
|
12
|
+
* - Cursor's primary CLI overview and parameter reference document the Cursor
|
|
13
|
+
* Agent executable as `agent`, with direct `agent "prompt"` and
|
|
14
|
+
* `agent -p "prompt"` initial-prompt forms (retrieved 2026-08-30):
|
|
15
|
+
* https://cursor.com/docs/cli/overview
|
|
16
|
+
* https://cursor.com/docs/cli/reference/parameters
|
|
17
|
+
* Cursor is not installed locally; `cursor` is the editor command and is not
|
|
18
|
+
* detected as Cursor Agent.
|
|
19
|
+
*/
|
|
20
|
+
export declare const AGENT_LAUNCH_SPECS: Readonly<Record<string, AgentLaunchSpec>>;
|
|
2
21
|
export interface SetupSelectionArgs {
|
|
3
22
|
team: string | null;
|
|
4
23
|
createTeam: string | null;
|
|
@@ -13,4 +32,11 @@ export declare function validateSetupSelectionArgs(args: SetupSelectionArgs): vo
|
|
|
13
32
|
export declare function validateSetupAgentArgs(agents: string[], launchAgent: string | null): void;
|
|
14
33
|
export declare function setupLaunchPrompt(teamSlug?: string, projectSlug?: string): string;
|
|
15
34
|
export declare function findExecutable(name: string, pathValue?: string): string | null;
|
|
35
|
+
export interface SetupSkillChoice {
|
|
36
|
+
label: string;
|
|
37
|
+
target: SkillInstallTarget;
|
|
38
|
+
}
|
|
39
|
+
export declare function setupNativeTargetForAgent(agent: SkillInstallAgent): SkillInstallTarget | null;
|
|
40
|
+
export declare function resolveSetupSkillHome(): string;
|
|
41
|
+
export declare function detectedSetupSkillChoices(homeDir: string): SetupSkillChoice[];
|
|
16
42
|
//# sourceMappingURL=setup-onboarding.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup-onboarding.d.ts","sourceRoot":"","sources":["../src/setup-onboarding.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,
|
|
1
|
+
{"version":3,"file":"setup-onboarding.d.ts","sourceRoot":"","sources":["../src/setup-onboarding.ts"],"names":[],"mappings":"AAKA,OAAO,EAKL,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACxB,MAAM,sBAAsB,CAAA;AAE7B,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAA;IACf,YAAY,EAAE,MAAM,CAAA;IACpB,eAAe,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,EAAE,CAAA;CAC9C;AAID;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,kBAAkB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAUxE,CAAA;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,OAAO,EAAE,OAAO,CAAA;IAChB,MAAM,EAAE,OAAO,CAAA;IACf,oBAAoB,EAAE,OAAO,CAAA;CAC9B;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAQ5D;AAED,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,kBAAkB,GAAG,IAAI,CAWzE;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAOzF;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAGjF;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,SAAyB,GAAG,MAAM,GAAG,IAAI,CAa9F;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,kBAAkB,CAAA;CAC3B;AAgBD,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,iBAAiB,GAAG,kBAAkB,GAAG,IAAI,CAG7F;AAED,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C;AAsBD,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB,EAAE,CA6B7E"}
|
package/dist/setup-onboarding.js
CHANGED
|
@@ -1,10 +1,32 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
import { accessSync, constants, statSync } from 'fs';
|
|
2
|
+
import { homedir } from 'os';
|
|
3
|
+
import { delimiter, join, relative, resolve, sep } from 'path';
|
|
4
|
+
import { sanitizeHumanInlineText, sanitizeTerminalText } from './json-response.js';
|
|
5
|
+
import { getSkillInstallPath, getTargetForAgent, isSkillInstallAgent, SKILL_INSTALL_AGENTS, } from './skill-installer.js';
|
|
6
|
+
const directPromptArgs = (prompt) => [prompt];
|
|
7
|
+
/**
|
|
8
|
+
* Measured launch contracts:
|
|
9
|
+
* - Local `claude --help`, `codex --help`, and `pi --help` expose a direct
|
|
10
|
+
* positional prompt/message (observed 2026-08-30).
|
|
11
|
+
* - OpenCode's primary CLI reference documents `opencode run [message..]`.
|
|
12
|
+
* - Cursor's primary CLI overview and parameter reference document the Cursor
|
|
13
|
+
* Agent executable as `agent`, with direct `agent "prompt"` and
|
|
14
|
+
* `agent -p "prompt"` initial-prompt forms (retrieved 2026-08-30):
|
|
15
|
+
* https://cursor.com/docs/cli/overview
|
|
16
|
+
* https://cursor.com/docs/cli/reference/parameters
|
|
17
|
+
* Cursor is not installed locally; `cursor` is the editor command and is not
|
|
18
|
+
* detected as Cursor Agent.
|
|
19
|
+
*/
|
|
20
|
+
export const AGENT_LAUNCH_SPECS = {
|
|
21
|
+
claude: { command: 'claude', displayLabel: 'claude', buildPromptArgs: directPromptArgs },
|
|
22
|
+
codex: { command: 'codex', displayLabel: 'codex', buildPromptArgs: directPromptArgs },
|
|
23
|
+
pi: { command: 'pi', displayLabel: 'pi', buildPromptArgs: directPromptArgs },
|
|
24
|
+
opencode: {
|
|
25
|
+
command: 'opencode',
|
|
26
|
+
displayLabel: 'opencode',
|
|
27
|
+
buildPromptArgs: prompt => ['run', prompt],
|
|
28
|
+
},
|
|
29
|
+
cursor: { command: 'agent', displayLabel: 'cursor', buildPromptArgs: directPromptArgs },
|
|
8
30
|
};
|
|
9
31
|
export function validateSetupFlagValues(args) {
|
|
10
32
|
const valueFlags = new Set(['--team', '--create-team', '--project', '--create-project', '--agent', '--launch', '--mode', '--service-origin', '--attach-workspace']);
|
|
@@ -42,8 +64,8 @@ export function validateSetupAgentArgs(agents, launchAgent) {
|
|
|
42
64
|
if (!isSkillInstallAgent(agent))
|
|
43
65
|
throw new Error(`Unknown agent '${agent}'. Available agents: ${SKILL_INSTALL_AGENTS.join(', ')}`);
|
|
44
66
|
}
|
|
45
|
-
if (launchAgent && !(launchAgent in
|
|
46
|
-
throw new Error(`Unknown --launch agent '${launchAgent}'. Choices: ${Object.keys(
|
|
67
|
+
if (launchAgent && !(launchAgent in AGENT_LAUNCH_SPECS)) {
|
|
68
|
+
throw new Error(`Unknown --launch agent '${launchAgent}'. Choices: ${Object.keys(AGENT_LAUNCH_SPECS).join(', ')}.`);
|
|
47
69
|
}
|
|
48
70
|
}
|
|
49
71
|
export function setupLaunchPrompt(teamSlug, projectSlug) {
|
|
@@ -52,8 +74,70 @@ export function setupLaunchPrompt(teamSlug, projectSlug) {
|
|
|
52
74
|
}
|
|
53
75
|
export function findExecutable(name, pathValue = process.env.PATH || '') {
|
|
54
76
|
for (const directory of pathValue.split(delimiter)) {
|
|
55
|
-
if (directory
|
|
56
|
-
|
|
77
|
+
if (!directory)
|
|
78
|
+
continue;
|
|
79
|
+
const candidate = join(directory, name);
|
|
80
|
+
try {
|
|
81
|
+
if (!statSync(candidate).isFile())
|
|
82
|
+
continue;
|
|
83
|
+
accessSync(candidate, constants.X_OK);
|
|
84
|
+
return resolve(candidate);
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
// A stale PATH entry must not hide a later launchable command.
|
|
88
|
+
}
|
|
57
89
|
}
|
|
58
90
|
return null;
|
|
59
91
|
}
|
|
92
|
+
const SETUP_NATIVE_SKILL_CHOICES = [
|
|
93
|
+
{ agent: 'claude', label: 'Claude Code', directory: ['.claude'], binary: 'claude' },
|
|
94
|
+
{ agent: 'devin', label: 'Devin', directory: ['.devin', 'skills'] },
|
|
95
|
+
{ agent: 'droid', label: 'Droid', directory: ['.factory', 'skills'] },
|
|
96
|
+
{ agent: 'grok', label: 'Grok Build', directory: ['.grok', 'skills'] },
|
|
97
|
+
{ agent: 'windsurf', label: 'Windsurf', directory: ['.windsurf', 'skills'] },
|
|
98
|
+
{ agent: 'opencode', label: 'OpenCode', directory: ['.config', 'opencode'], binary: 'opencode' },
|
|
99
|
+
];
|
|
100
|
+
export function setupNativeTargetForAgent(agent) {
|
|
101
|
+
if (agent === 'codex' || agent === 'pi')
|
|
102
|
+
return null;
|
|
103
|
+
return getTargetForAgent(agent, 'global');
|
|
104
|
+
}
|
|
105
|
+
export function resolveSetupSkillHome() {
|
|
106
|
+
return resolve(process.env.HOME || homedir());
|
|
107
|
+
}
|
|
108
|
+
function isSetupConfigDirectory(path) {
|
|
109
|
+
try {
|
|
110
|
+
return statSync(path).isDirectory();
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
const SETUP_SKILL_CHOICE_MAX_WIDTH = 72;
|
|
117
|
+
function setupSkillChoiceLabel(name, target, homeDir) {
|
|
118
|
+
const destination = getSkillInstallPath(target, { homeDir });
|
|
119
|
+
const userFacingDestination = `~/${relative(homeDir, destination).split(sep).join('/')}`;
|
|
120
|
+
const label = sanitizeHumanInlineText(sanitizeTerminalText, `${name} — ${userFacingDestination}`);
|
|
121
|
+
if (label.length > SETUP_SKILL_CHOICE_MAX_WIDTH) {
|
|
122
|
+
throw new Error(`Setup skill destination label exceeds ${SETUP_SKILL_CHOICE_MAX_WIDTH} columns.`);
|
|
123
|
+
}
|
|
124
|
+
return label;
|
|
125
|
+
}
|
|
126
|
+
export function detectedSetupSkillChoices(homeDir) {
|
|
127
|
+
const detectedNativeChoices = SETUP_NATIVE_SKILL_CHOICES.filter(choice => isSetupConfigDirectory(join(homeDir, ...choice.directory))
|
|
128
|
+
|| Boolean(choice.binary && findExecutable(choice.binary)));
|
|
129
|
+
const priority = (choice) => choice.agent === 'claude' ? 0 : choice.agent === 'opencode' ? 1 : 2;
|
|
130
|
+
const universalTarget = 'agent-user';
|
|
131
|
+
return [{
|
|
132
|
+
label: setupSkillChoiceLabel('Universal (.agents — Codex and others)', universalTarget, homeDir),
|
|
133
|
+
target: universalTarget,
|
|
134
|
+
}, ...detectedNativeChoices
|
|
135
|
+
.sort((left, right) => priority(left) - priority(right))
|
|
136
|
+
.map(choice => {
|
|
137
|
+
const target = getTargetForAgent(choice.agent, 'global');
|
|
138
|
+
return {
|
|
139
|
+
label: setupSkillChoiceLabel(choice.agent === 'claude' ? 'Claude' : choice.label, target, homeDir),
|
|
140
|
+
target,
|
|
141
|
+
};
|
|
142
|
+
})];
|
|
143
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { SkillInstallTarget } from './skill-installer.js';
|
|
2
|
+
export interface SetupSkillSummaryOutcome {
|
|
3
|
+
target: SkillInstallTarget;
|
|
4
|
+
path: string;
|
|
5
|
+
action: 'created' | 'updated' | 'skipped' | 'failed';
|
|
6
|
+
error?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function setupSkillFriendlyName(target: SkillInstallTarget): string;
|
|
9
|
+
export declare function sanitizeSetupHumanInlineText(value: unknown): string;
|
|
10
|
+
export declare function formatSetupSkillDestination(destination: string, setupHome: string): string;
|
|
11
|
+
export declare function renderSetupSkillSummary(outcomes: SetupSkillSummaryOutcome[], setupHome: string): string[];
|
|
12
|
+
//# sourceMappingURL=setup-summary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup-summary.d.ts","sourceRoot":"","sources":["../src/setup-summary.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AAkB9D,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,kBAAkB,CAAA;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAA;IACpD,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,CAEzE;AAED,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAEnE;AAED,wBAAgB,2BAA2B,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAY1F;AAED,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,wBAAwB,EAAE,EACpC,SAAS,EAAE,MAAM,GAChB,MAAM,EAAE,CAuBV"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { isAbsolute, relative, sep } from 'node:path';
|
|
2
|
+
import { sanitizeHumanInlineText, sanitizeTerminalText } from './json-response.js';
|
|
3
|
+
const SETUP_SKILL_FRIENDLY_NAMES = {
|
|
4
|
+
'agent-user': 'Universal',
|
|
5
|
+
'agents-project': 'Universal (project)',
|
|
6
|
+
'codex-user': 'Codex',
|
|
7
|
+
'codex-project': 'Codex (project)',
|
|
8
|
+
'claude-user': 'Claude',
|
|
9
|
+
'claude-project': 'Claude (project)',
|
|
10
|
+
'devin-user': 'Devin',
|
|
11
|
+
'droid-user': 'Droid',
|
|
12
|
+
'grok-user': 'Grok Build',
|
|
13
|
+
'windsurf-user': 'Windsurf',
|
|
14
|
+
'opencode-user': 'OpenCode',
|
|
15
|
+
'opencode-project': 'OpenCode (project)',
|
|
16
|
+
'agents-md': 'Project instructions (AGENTS.md)',
|
|
17
|
+
};
|
|
18
|
+
export function setupSkillFriendlyName(target) {
|
|
19
|
+
return SETUP_SKILL_FRIENDLY_NAMES[target];
|
|
20
|
+
}
|
|
21
|
+
export function sanitizeSetupHumanInlineText(value) {
|
|
22
|
+
return sanitizeHumanInlineText(sanitizeTerminalText, value);
|
|
23
|
+
}
|
|
24
|
+
export function formatSetupSkillDestination(destination, setupHome) {
|
|
25
|
+
if (!isAbsolute(destination) || !isAbsolute(setupHome))
|
|
26
|
+
return destination;
|
|
27
|
+
const relativeDestination = relative(setupHome, destination);
|
|
28
|
+
if (relativeDestination === '')
|
|
29
|
+
return '~';
|
|
30
|
+
if (!isAbsolute(relativeDestination) &&
|
|
31
|
+
relativeDestination !== '..' &&
|
|
32
|
+
!relativeDestination.startsWith(`..${sep}`)) {
|
|
33
|
+
return `~/${relativeDestination.split(sep).join('/')}`;
|
|
34
|
+
}
|
|
35
|
+
return destination;
|
|
36
|
+
}
|
|
37
|
+
export function renderSetupSkillSummary(outcomes, setupHome) {
|
|
38
|
+
const successful = outcomes.filter(outcome => outcome.action === 'created' || outcome.action === 'updated');
|
|
39
|
+
const failures = outcomes.filter(outcome => outcome.action === 'failed');
|
|
40
|
+
const lines = [];
|
|
41
|
+
if (successful.length > 0) {
|
|
42
|
+
lines.push('Skills installed to the following directories:');
|
|
43
|
+
const nameWidth = Math.max(...successful.map(outcome => setupSkillFriendlyName(outcome.target).length));
|
|
44
|
+
for (const outcome of successful) {
|
|
45
|
+
const destination = formatSetupSkillDestination(outcome.path, setupHome);
|
|
46
|
+
lines.push(` ${setupSkillFriendlyName(outcome.target).padEnd(nameWidth)} ${sanitizeSetupHumanInlineText(destination)}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
lines.push('Skills not installed. To install them, run `orizu install-skill`.');
|
|
51
|
+
}
|
|
52
|
+
for (const failure of failures) {
|
|
53
|
+
lines.push(`${setupSkillFriendlyName(failure.target)} failed: ${sanitizeSetupHumanInlineText(failure.error || 'Unknown error')}`);
|
|
54
|
+
}
|
|
55
|
+
return lines;
|
|
56
|
+
}
|