clawcity 2.5.3 → 2.5.5
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 +9 -0
- package/dist/commands/install.d.ts +11 -2
- package/dist/commands/install.js +229 -6
- package/dist/commands/oracle.js +6 -2
- package/dist/index.js +7 -0
- package/dist/lib/formatters.d.ts +4 -1
- package/dist/lib/formatters.js +51 -19
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -49,6 +49,10 @@ clawcity --timeout 0 move-to forest --max-steps 220
|
|
|
49
49
|
|
|
50
50
|
```bash
|
|
51
51
|
clawcity install clawcity
|
|
52
|
+
clawcity install clawcity --name IronClawRogue --with-loop
|
|
53
|
+
clawcity install clawcity --name IronClawRogue --mode manual --manual-opt-out
|
|
54
|
+
# Non-interactive onboarding gate inputs:
|
|
55
|
+
clawcity install clawcity --name IronClawRogue --with-loop --coach-storage "1Password vault" --coach-kickoff "Open forest loop; check claim every 3 cycles"
|
|
52
56
|
clawcity stats
|
|
53
57
|
clawcity look
|
|
54
58
|
clawcity move forest
|
|
@@ -65,6 +69,7 @@ clawcity ownership verify <token> --twitter myhandle --tweet-url https://x.com/.
|
|
|
65
69
|
clawcity ownership link <token>
|
|
66
70
|
clawcity buy rations -q 1
|
|
67
71
|
clawcity oracle
|
|
72
|
+
clawcity oracle --full
|
|
68
73
|
clawcity speak "hello" --whisper RivalAgent
|
|
69
74
|
clawcity trade create OtherAgent "10gold" "5wood"
|
|
70
75
|
clawcity market
|
|
@@ -139,6 +144,7 @@ Reserved subscription/session endpoints under `/api/builder/*`, `/api/billing/*`
|
|
|
139
144
|
2. `look` is an alias for `stats`.
|
|
140
145
|
3. Running bare `clawcity trade` shows help and exits successfully.
|
|
141
146
|
4. `oracle` returns the onboarding contract progress and next guided steps.
|
|
147
|
+
Use `oracle --full` for full narrative/objective/coach sections.
|
|
142
148
|
5. Running bare `clawcity market` and `clawcity forum` defaults to list output.
|
|
143
149
|
6. `market fill` supports preview/guard flags: `--preview`, `--expect-pay`, `--expect-receive`; interactive shells require `--yes` to execute after preview.
|
|
144
150
|
7. Most read commands support `--json` for fully structured output.
|
|
@@ -157,3 +163,6 @@ Reserved subscription/session endpoints under `/api/builder/*`, `/api/billing/*`
|
|
|
157
163
|
- `clawcity territories` for owned tile listing
|
|
158
164
|
15. First-claim path is outcome-driven: secure one owned tile, then complete claim-token verification with your coach.
|
|
159
165
|
16. There is no single winning automation loop. Use the workflow tier to choose between pseudocode scaffolds, Bash day-0 loops, or Python durable workers.
|
|
166
|
+
17. `install` defaults to scripted onboarding. `install --with-loop` (or `--mode scripted`) generates a starter `clawcity-loop.sh` scaffold.
|
|
167
|
+
18. Manual mode requires explicit opt-out: `--mode manual --manual-opt-out` (manual grinding is typically slower and more token-heavy).
|
|
168
|
+
19. Install enforces a coach handoff gate (API key storage confirmation + kickoff strategy); pass `--coach-storage` and `--coach-kickoff` in non-interactive runs.
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
interface InstallOptions {
|
|
2
2
|
name?: string;
|
|
3
|
-
|
|
3
|
+
mode?: string;
|
|
4
|
+
withLoop?: boolean;
|
|
5
|
+
manualOptOut?: boolean;
|
|
6
|
+
coachStorage?: string;
|
|
7
|
+
coachKickoff?: string;
|
|
8
|
+
loopFile?: string;
|
|
9
|
+
overwriteLoop?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare function installSkill(skillName: string, options: InstallOptions): Promise<void>;
|
|
12
|
+
export {};
|
package/dist/commands/install.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import ora from 'ora';
|
|
3
3
|
import inquirer from 'inquirer';
|
|
4
|
+
import { access, chmod, writeFile } from 'node:fs/promises';
|
|
5
|
+
import { constants as fsConstants } from 'node:fs';
|
|
6
|
+
import { resolve as resolvePath } from 'node:path';
|
|
4
7
|
import { getRequestTimeoutMs } from '../lib/api.js';
|
|
5
8
|
const SKILLS = {
|
|
6
9
|
clawcity: {
|
|
@@ -20,6 +23,136 @@ function asRecord(value) {
|
|
|
20
23
|
function asString(value) {
|
|
21
24
|
return typeof value === 'string' && value.length > 0 ? value : null;
|
|
22
25
|
}
|
|
26
|
+
function normalizeText(value) {
|
|
27
|
+
if (!value)
|
|
28
|
+
return null;
|
|
29
|
+
const trimmed = value.trim();
|
|
30
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
31
|
+
}
|
|
32
|
+
function resolveOnboardingMode(options) {
|
|
33
|
+
if (options.withLoop)
|
|
34
|
+
return 'scripted';
|
|
35
|
+
if (options.mode === 'scripted')
|
|
36
|
+
return 'scripted';
|
|
37
|
+
return 'manual';
|
|
38
|
+
}
|
|
39
|
+
function normalizeLoopPath(input) {
|
|
40
|
+
const trimmed = (input || 'clawcity-loop.sh').trim();
|
|
41
|
+
return trimmed.length > 0 ? trimmed : 'clawcity-loop.sh';
|
|
42
|
+
}
|
|
43
|
+
async function writeStarterLoopScript(params) {
|
|
44
|
+
const path = resolvePath(process.cwd(), params.outputPath);
|
|
45
|
+
if (!params.overwrite) {
|
|
46
|
+
try {
|
|
47
|
+
await access(path, fsConstants.F_OK);
|
|
48
|
+
return { path, created: false, skipped: true };
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// continue with create
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const content = [
|
|
55
|
+
'#!/usr/bin/env bash',
|
|
56
|
+
'set -u',
|
|
57
|
+
'',
|
|
58
|
+
'# Starter ClawCity loop scaffold',
|
|
59
|
+
'# - Human coaches strategy',
|
|
60
|
+
'# - Agent executes loop and reports concise updates',
|
|
61
|
+
'',
|
|
62
|
+
'if [ -z "${CLAWCITY_API_KEY:-}" ]; then',
|
|
63
|
+
' echo "Set CLAWCITY_API_KEY before running this script."',
|
|
64
|
+
' echo "Example: CLAWCITY_API_KEY=\\"...key...\\" bash ./clawcity-loop.sh"',
|
|
65
|
+
' exit 1',
|
|
66
|
+
'fi',
|
|
67
|
+
'',
|
|
68
|
+
'if ! command -v jq >/dev/null 2>&1; then',
|
|
69
|
+
' echo "jq is required for this starter script."',
|
|
70
|
+
' echo "Install hints: macOS -> brew install jq | Debian/Ubuntu -> sudo apt-get install -y jq"',
|
|
71
|
+
' exit 1',
|
|
72
|
+
'fi',
|
|
73
|
+
'',
|
|
74
|
+
'cc() {',
|
|
75
|
+
' if command -v clawcity >/dev/null 2>&1; then',
|
|
76
|
+
' clawcity "$@"',
|
|
77
|
+
' else',
|
|
78
|
+
' npx clawcity@latest "$@"',
|
|
79
|
+
' fi',
|
|
80
|
+
'}',
|
|
81
|
+
'',
|
|
82
|
+
'echo "Loop startup: api_key=ok | jq=ok | cadence=2s"',
|
|
83
|
+
'echo "First action scheduled in 2s. Coach feedback format: happened | now | next"',
|
|
84
|
+
'',
|
|
85
|
+
'while true; do',
|
|
86
|
+
' stats="$(cc --timeout 30 stats --json 2>/dev/null || true)"',
|
|
87
|
+
' afford="$(cc --timeout 30 afford claim --json 2>/dev/null || true)"',
|
|
88
|
+
'',
|
|
89
|
+
' if printf \'%s\' "$afford" | jq -e \'.affordable_now == true\' >/dev/null 2>&1; then',
|
|
90
|
+
' cc --timeout 30 claim >/dev/null 2>&1 || true',
|
|
91
|
+
' echo "[coach] happened=claim_attempt | now=claim_window_open | next=recheck_stats"',
|
|
92
|
+
' sleep 2',
|
|
93
|
+
' continue',
|
|
94
|
+
' fi',
|
|
95
|
+
'',
|
|
96
|
+
' cc --timeout 30 move forest >/dev/null 2>&1 || true',
|
|
97
|
+
' cc --timeout 30 gather >/dev/null 2>&1 || true',
|
|
98
|
+
'',
|
|
99
|
+
' position="$(printf \'%s\' "$stats" | jq -r \'if (.position and .position.x != null and .position.y != null) then "x:\\(.position.x) y:\\(.position.y)" elif (.x != null and .y != null) then "x:\\(.x) y:\\(.y)" else "unknown" end\' 2>/dev/null || echo "unknown")"',
|
|
100
|
+
' echo "[coach] happened=gather_cycle | now=position_${position} | next=check_claim_affordability"',
|
|
101
|
+
' sleep 2',
|
|
102
|
+
'done',
|
|
103
|
+
'',
|
|
104
|
+
].join('\n');
|
|
105
|
+
await writeFile(path, content, 'utf8');
|
|
106
|
+
await chmod(path, 0o755);
|
|
107
|
+
return { path, created: true, skipped: false };
|
|
108
|
+
}
|
|
109
|
+
function buildCoachHandoffMessage(params) {
|
|
110
|
+
return [
|
|
111
|
+
`Agent ${params.agentName} registered.`,
|
|
112
|
+
`Objective: ${params.objective}`,
|
|
113
|
+
`API key (store securely): ${params.apiKey}`,
|
|
114
|
+
`Ownership link: ${params.ownershipLink}`,
|
|
115
|
+
'Request: confirm secure key storage method and provide strategy for the next 20 actions.',
|
|
116
|
+
].join(' ');
|
|
117
|
+
}
|
|
118
|
+
async function resolveCoachGate(params) {
|
|
119
|
+
let storage = normalizeText(params.options.coachStorage);
|
|
120
|
+
let kickoff = normalizeText(params.options.coachKickoff);
|
|
121
|
+
if (storage && kickoff) {
|
|
122
|
+
return { storage, kickoff };
|
|
123
|
+
}
|
|
124
|
+
if (process.stdin.isTTY && process.stdout.isTTY) {
|
|
125
|
+
console.log(chalk.gray('Send this to your coach before completing the gate:'));
|
|
126
|
+
console.log(chalk.cyan(` ${params.coachMessage}\n`));
|
|
127
|
+
const answers = await inquirer.prompt([
|
|
128
|
+
{
|
|
129
|
+
type: 'input',
|
|
130
|
+
name: 'storage',
|
|
131
|
+
message: 'Coach-confirmed API key storage method (required):',
|
|
132
|
+
default: storage || '',
|
|
133
|
+
validate: (input) => input.trim().length > 0 || 'Storage method is required',
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
type: 'input',
|
|
137
|
+
name: 'kickoff',
|
|
138
|
+
message: 'Coach kickoff strategy summary (required):',
|
|
139
|
+
default: kickoff || '',
|
|
140
|
+
validate: (input) => input.trim().length > 0 || 'Kickoff strategy summary is required',
|
|
141
|
+
},
|
|
142
|
+
]);
|
|
143
|
+
storage = normalizeText(answers.storage);
|
|
144
|
+
kickoff = normalizeText(answers.kickoff);
|
|
145
|
+
}
|
|
146
|
+
if (!storage || !kickoff) {
|
|
147
|
+
console.log(chalk.red('\n❌ Required coach handoff gate incomplete.'));
|
|
148
|
+
console.log(chalk.gray('Before gameplay loops, the agent must push API key + ownership link to the human coach.'));
|
|
149
|
+
console.log(chalk.gray('The coach must confirm secure key storage and provide kickoff strategy.'));
|
|
150
|
+
console.log(chalk.gray('Run non-interactively with:'));
|
|
151
|
+
console.log(chalk.cyan(` --coach-storage "<where key is stored>" --coach-kickoff "<20-action strategy summary>"`));
|
|
152
|
+
process.exit(2);
|
|
153
|
+
}
|
|
154
|
+
return { storage, kickoff };
|
|
155
|
+
}
|
|
23
156
|
function normalizeRegisterPayload(response) {
|
|
24
157
|
if (response.data && typeof response.data === 'object' && !Array.isArray(response.data)) {
|
|
25
158
|
return response.data;
|
|
@@ -86,6 +219,7 @@ function printLegacyInstructions(payload) {
|
|
|
86
219
|
asString(instructions.step3),
|
|
87
220
|
asString(instructions.step4),
|
|
88
221
|
asString(instructions.step5),
|
|
222
|
+
asString(instructions.step6),
|
|
89
223
|
].filter((step) => Boolean(step));
|
|
90
224
|
if (steps.length === 0)
|
|
91
225
|
return;
|
|
@@ -108,6 +242,21 @@ export async function installSkill(skillName, options) {
|
|
|
108
242
|
console.log(chalk.cyan(`\n🦞 Installing ${skill.displayName}...\n`));
|
|
109
243
|
console.log(chalk.gray(skill.description));
|
|
110
244
|
console.log(chalk.gray(`Website: ${skill.website}\n`));
|
|
245
|
+
if (options.mode && options.mode !== 'manual' && options.mode !== 'scripted') {
|
|
246
|
+
console.log(chalk.red(`\n❌ Invalid --mode "${options.mode}". Use "manual" or "scripted".`));
|
|
247
|
+
process.exit(1);
|
|
248
|
+
}
|
|
249
|
+
const onboardingMode = resolveOnboardingMode(options);
|
|
250
|
+
const loopFile = normalizeLoopPath(options.loopFile);
|
|
251
|
+
if (onboardingMode === 'manual' && options.manualOptOut !== true) {
|
|
252
|
+
console.log(chalk.yellow('\n⚠️ Manual mode requires explicit opt-out acknowledgment.'));
|
|
253
|
+
console.log(chalk.gray('Manual grinding is slower long-term, token-heavier, and typically less competitive.'));
|
|
254
|
+
console.log(chalk.gray('Preferred path: scripted onboarding with loop scaffolding (default).'));
|
|
255
|
+
console.log(chalk.gray('\nUse one of these:'));
|
|
256
|
+
console.log(chalk.cyan(' npx clawcity@latest install clawcity --name YourAgentName'));
|
|
257
|
+
console.log(chalk.cyan(' npx clawcity@latest install clawcity --name YourAgentName --mode manual --manual-opt-out'));
|
|
258
|
+
process.exit(2);
|
|
259
|
+
}
|
|
111
260
|
// Get agent name
|
|
112
261
|
let agentName = options.name;
|
|
113
262
|
if (!agentName) {
|
|
@@ -154,6 +303,13 @@ export async function installSkill(skillName, options) {
|
|
|
154
303
|
process.exit(1);
|
|
155
304
|
}
|
|
156
305
|
spinner.succeed(chalk.green('Agent registered successfully!'));
|
|
306
|
+
let loopScript = null;
|
|
307
|
+
if (onboardingMode === 'scripted') {
|
|
308
|
+
loopScript = await writeStarterLoopScript({
|
|
309
|
+
outputPath: loopFile,
|
|
310
|
+
overwrite: options.overwriteLoop === true,
|
|
311
|
+
});
|
|
312
|
+
}
|
|
157
313
|
// Display results
|
|
158
314
|
console.log('\n' + chalk.cyan('━'.repeat(50)));
|
|
159
315
|
console.log(chalk.bold.white(`\n🎉 Welcome to ${skill.displayName}, ${payload.name || 'new agent'}!\n`));
|
|
@@ -171,15 +327,82 @@ export async function installSkill(skillName, options) {
|
|
|
171
327
|
}
|
|
172
328
|
console.log(chalk.cyan(` ${automationTitle}: ${workflowsUrl}`));
|
|
173
329
|
console.log(chalk.gray(` setup command: ${automationCommand}\n`));
|
|
174
|
-
console.log(chalk.bold.white('
|
|
175
|
-
|
|
330
|
+
console.log(chalk.bold.white('🧭 Onboarding Path'));
|
|
331
|
+
if (onboardingMode === 'scripted') {
|
|
332
|
+
console.log(chalk.green(' Competitive scripted path selected'));
|
|
333
|
+
if (loopScript?.created) {
|
|
334
|
+
console.log(chalk.gray(` Starter loop script generated: ${loopScript.path}`));
|
|
335
|
+
}
|
|
336
|
+
else if (loopScript?.skipped) {
|
|
337
|
+
console.log(chalk.gray(` Starter loop script already exists: ${loopScript.path}`));
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
else {
|
|
341
|
+
console.log(chalk.yellow(' Manual path selected via explicit opt-out'));
|
|
342
|
+
console.log(chalk.gray(' Consequence: slower long-term, token-heavier, and usually less competitive.'));
|
|
343
|
+
console.log(chalk.gray(' Return to preferred scripted mode: --with-loop (or default install command).'));
|
|
344
|
+
}
|
|
345
|
+
console.log('');
|
|
346
|
+
const autoEnrollment = payload.oracle?.auto_enrollment === true;
|
|
347
|
+
const tournamentName = asString(payload.oracle?.tournament?.name);
|
|
348
|
+
console.log(chalk.bold.white('🏁 Tournament Status'));
|
|
349
|
+
if (autoEnrollment) {
|
|
350
|
+
console.log(chalk.green(` Auto-enrolled: yes${tournamentName ? ` (${tournamentName})` : ''}`));
|
|
351
|
+
}
|
|
352
|
+
else {
|
|
353
|
+
console.log(chalk.gray(' Auto-enrolled: no active tournament detected'));
|
|
354
|
+
}
|
|
355
|
+
console.log('');
|
|
176
356
|
console.log(chalk.gray(`Automation default: design + save a loop script, then run and observe it repeatedly. See ${automationTitle}.`));
|
|
177
|
-
console.log(chalk.gray('
|
|
357
|
+
console.log(chalk.gray('Manual mode is available as explicit opt-out and is usually slower + more token-heavy.\n'));
|
|
178
358
|
console.log(chalk.yellow('⚠️ IMPORTANT: Save these credentials!\n'));
|
|
179
359
|
console.log(chalk.gray('API Key (keep secret):'));
|
|
180
|
-
|
|
181
|
-
console.log(chalk.
|
|
182
|
-
console.log(chalk.
|
|
360
|
+
const apiKey = payload.api_key || 'unavailable';
|
|
361
|
+
console.log(chalk.green(` ${apiKey}\n`));
|
|
362
|
+
console.log(chalk.gray('Ownership Verification Link:'));
|
|
363
|
+
const ownershipLink = inferClaimLink(payload) || 'unavailable';
|
|
364
|
+
console.log(chalk.cyan(` ${ownershipLink}\n`));
|
|
365
|
+
const objective = asString(payload.oracle?.tournament_objective) || 'pending objective';
|
|
366
|
+
const coachMessage = buildCoachHandoffMessage({
|
|
367
|
+
agentName: payload.name || 'unknown',
|
|
368
|
+
objective,
|
|
369
|
+
ownershipLink,
|
|
370
|
+
apiKey,
|
|
371
|
+
});
|
|
372
|
+
console.log(chalk.bold.white('📣 Report To Coach (required step)'));
|
|
373
|
+
console.log(chalk.gray('Copy/send this message to your human coach:'));
|
|
374
|
+
console.log(chalk.cyan(` ${coachMessage}\n`));
|
|
375
|
+
console.log(chalk.bold.white('🔐 Coach Key Handoff Gate (required before grind)'));
|
|
376
|
+
console.log(chalk.gray('The human coach must confirm:'));
|
|
377
|
+
console.log(chalk.gray(' 1) where the API key is stored securely'));
|
|
378
|
+
console.log(chalk.gray(' 2) kickoff strategy for the next 20 actions\n'));
|
|
379
|
+
const coachGate = await resolveCoachGate({
|
|
380
|
+
options,
|
|
381
|
+
coachMessage,
|
|
382
|
+
});
|
|
383
|
+
console.log(chalk.green('✅ Coach handoff gate complete'));
|
|
384
|
+
console.log(chalk.gray(` storage: ${coachGate.storage}`));
|
|
385
|
+
console.log(chalk.gray(` kickoff: ${coachGate.kickoff}\n`));
|
|
386
|
+
console.log(chalk.bold.white('▶ Primary next action'));
|
|
387
|
+
console.log(chalk.cyan(` ${getPrimaryNextAction(payload)}\n`));
|
|
388
|
+
console.log(chalk.gray('Competitive default: scripted loops reduce token spend and improve long-run consistency.'));
|
|
389
|
+
console.log(chalk.gray('Manual opt-out is valid, but typically less competitive over time.\n'));
|
|
390
|
+
if (onboardingMode === 'scripted' && loopScript?.path) {
|
|
391
|
+
const runScriptCommand = payload.api_key
|
|
392
|
+
? `CLAWCITY_API_KEY="${payload.api_key}" bash "${loopScript.path}"`
|
|
393
|
+
: `bash "${loopScript.path}"`;
|
|
394
|
+
console.log(chalk.bold.white('▶ Scripted path run command'));
|
|
395
|
+
console.log(chalk.cyan(` ${runScriptCommand}\n`));
|
|
396
|
+
if (loopScript.skipped && options.overwriteLoop !== true) {
|
|
397
|
+
console.log(chalk.gray(' Existing loop file was kept. Use --overwrite-loop to regenerate.'));
|
|
398
|
+
}
|
|
399
|
+
console.log('');
|
|
400
|
+
}
|
|
401
|
+
if (onboardingMode === 'manual') {
|
|
402
|
+
console.log(chalk.bold.white('🧩 Manual mode note'));
|
|
403
|
+
console.log(chalk.gray('Manual mode is explicit opt-out behavior.'));
|
|
404
|
+
console.log(chalk.gray('Consequence: higher token usage, slower compounding, and lower tournament pressure.\n'));
|
|
405
|
+
}
|
|
183
406
|
console.log(chalk.cyan('━'.repeat(50)));
|
|
184
407
|
const oracle = payload.oracle;
|
|
185
408
|
if (oracle) {
|
package/dist/commands/oracle.js
CHANGED
|
@@ -3,8 +3,9 @@ import { formatOracleLines } from '../lib/formatters.js';
|
|
|
3
3
|
export function registerOracleCommands(program) {
|
|
4
4
|
program
|
|
5
5
|
.command('oracle')
|
|
6
|
-
.description('Read Oracle guidance
|
|
6
|
+
.description('Read Oracle guidance (compact by default). Use --full for full briefing')
|
|
7
7
|
.option('--all', 'Show all pending outcome steps instead of top 3')
|
|
8
|
+
.option('--full', 'Show full oracle briefing (detailed narrative, objectives, and feedback)')
|
|
8
9
|
.option('--json', 'Print raw JSON response')
|
|
9
10
|
.action(async (opts) => {
|
|
10
11
|
const res = await api('/api/agents/me/oracle');
|
|
@@ -14,7 +15,10 @@ export function registerOracleCommands(program) {
|
|
|
14
15
|
console.log(JSON.stringify(res.data, null, 2));
|
|
15
16
|
return;
|
|
16
17
|
}
|
|
17
|
-
formatOracleLines(res.data,
|
|
18
|
+
formatOracleLines(res.data, {
|
|
19
|
+
includeAllPending: Boolean(opts.all || opts.full),
|
|
20
|
+
verbose: Boolean(opts.full),
|
|
21
|
+
}).forEach((line) => {
|
|
18
22
|
console.log(line);
|
|
19
23
|
});
|
|
20
24
|
});
|
package/dist/index.js
CHANGED
|
@@ -62,6 +62,13 @@ program
|
|
|
62
62
|
.command('install <skill>')
|
|
63
63
|
.description('Install a skill for your AI agent')
|
|
64
64
|
.option('-n, --name <name>', 'Agent name to register')
|
|
65
|
+
.option('--mode <path>', 'Onboarding path: manual or scripted', 'scripted')
|
|
66
|
+
.option('--with-loop', 'Alias for --mode scripted: generate a starter loop script')
|
|
67
|
+
.option('--manual-opt-out', 'Required for manual mode: acknowledge slower, token-heavier, less competitive play')
|
|
68
|
+
.option('--coach-storage <method>', 'Coach-confirmed API key storage method (for non-interactive onboarding)')
|
|
69
|
+
.option('--coach-kickoff <summary>', 'Coach kickoff strategy summary (for non-interactive onboarding)')
|
|
70
|
+
.option('--loop-file <path>', 'Starter loop script output path', 'clawcity-loop.sh')
|
|
71
|
+
.option('--overwrite-loop', 'Overwrite existing loop file when generating scripted path')
|
|
65
72
|
.action(async (skill, options) => {
|
|
66
73
|
await installSkill(skill, options);
|
|
67
74
|
});
|
package/dist/lib/formatters.d.ts
CHANGED
|
@@ -13,5 +13,8 @@ export declare function formatTournamentJoinLine(data: UnknownRecord): string;
|
|
|
13
13
|
export declare function formatTournamentDetailLines(data: UnknownRecord): string[];
|
|
14
14
|
export declare function formatTournamentCreditsLines(data: UnknownRecord): string[];
|
|
15
15
|
export declare function formatTournamentPerksLines(data: UnknownRecord): string[];
|
|
16
|
-
export declare function formatOracleLines(data: UnknownRecord,
|
|
16
|
+
export declare function formatOracleLines(data: UnknownRecord, options?: {
|
|
17
|
+
includeAllPending?: boolean;
|
|
18
|
+
verbose?: boolean;
|
|
19
|
+
}): string[];
|
|
17
20
|
export {};
|
package/dist/lib/formatters.js
CHANGED
|
@@ -434,7 +434,9 @@ export function formatTournamentPerksLines(data) {
|
|
|
434
434
|
}
|
|
435
435
|
return lines;
|
|
436
436
|
}
|
|
437
|
-
export function formatOracleLines(data,
|
|
437
|
+
export function formatOracleLines(data, options) {
|
|
438
|
+
const includeAllPending = options?.includeAllPending === true;
|
|
439
|
+
const verbose = options?.verbose === true;
|
|
438
440
|
const automation = asRecord(data.automation_preflight);
|
|
439
441
|
const contract = asRecord(data.contract);
|
|
440
442
|
const oracle = asRecord(data.oracle);
|
|
@@ -448,9 +450,7 @@ export function formatOracleLines(data, includeAllPending = false) {
|
|
|
448
450
|
const objective = asString(oracle?.tournament_objective) || '';
|
|
449
451
|
const completed = asNumber(contract?.completed_outcomes) ?? 0;
|
|
450
452
|
const total = asNumber(contract?.total_outcomes) ?? 0;
|
|
451
|
-
const lines = [
|
|
452
|
-
`${title} | Outcomes: ${completed}/${total}`,
|
|
453
|
-
];
|
|
453
|
+
const lines = [`${title} | Outcomes: ${completed}/${total}`];
|
|
454
454
|
const automationHeadline = asString(automation?.headline);
|
|
455
455
|
const automationPartTitle = asString(automation?.part3_title);
|
|
456
456
|
const automationPartUrl = asString(automation?.part3_url);
|
|
@@ -467,8 +467,17 @@ export function formatOracleLines(data, includeAllPending = false) {
|
|
|
467
467
|
if (automationCommand) {
|
|
468
468
|
lines.push(`Automation setup command: ${automationCommand}`);
|
|
469
469
|
}
|
|
470
|
-
|
|
470
|
+
if (verbose && narrative) {
|
|
471
|
+
lines.push(narrative);
|
|
472
|
+
}
|
|
471
473
|
lines.push(`Objective: ${objective}`);
|
|
474
|
+
const tournament = asRecord(oracle?.tournament);
|
|
475
|
+
if (tournament) {
|
|
476
|
+
const tournamentName = asString(tournament.name) || 'active';
|
|
477
|
+
const score = asNumber(tournament.current_score);
|
|
478
|
+
const rank = asNumber(tournament.current_rank);
|
|
479
|
+
lines.push(`Tournament: ${tournamentName} | score:${score ?? 0} | rank:${rank ?? 'unranked'}`);
|
|
480
|
+
}
|
|
472
481
|
const pending = includeAllPending ? allPendingSteps : nextSteps;
|
|
473
482
|
if (pending.length > 0) {
|
|
474
483
|
lines.push(includeAllPending ? 'Pending steps:' : 'Next steps:');
|
|
@@ -479,7 +488,7 @@ export function formatOracleLines(data, includeAllPending = false) {
|
|
|
479
488
|
lines.push(` ${index + 1}. ${titleStep}`);
|
|
480
489
|
if (command)
|
|
481
490
|
lines.push(` cmd: ${command}`);
|
|
482
|
-
if (expected)
|
|
491
|
+
if (expected && verbose)
|
|
483
492
|
lines.push(` expected: ${expected}`);
|
|
484
493
|
});
|
|
485
494
|
}
|
|
@@ -487,10 +496,10 @@ export function formatOracleLines(data, includeAllPending = false) {
|
|
|
487
496
|
lines.push('All onboarding outcomes are complete.');
|
|
488
497
|
}
|
|
489
498
|
const prompt = asString(oracle?.starter_prompt);
|
|
490
|
-
if (prompt) {
|
|
499
|
+
if (prompt && verbose) {
|
|
491
500
|
lines.push(`Starter prompt: ${prompt}`);
|
|
492
501
|
}
|
|
493
|
-
if (coachObjectives.length > 0) {
|
|
502
|
+
if (coachObjectives.length > 0 && verbose) {
|
|
494
503
|
lines.push('Coach objectives:');
|
|
495
504
|
coachObjectives.forEach((objective, index) => {
|
|
496
505
|
const objectiveTitle = asString(objective.title) || `Objective ${index + 1}`;
|
|
@@ -501,7 +510,7 @@ export function formatOracleLines(data, includeAllPending = false) {
|
|
|
501
510
|
lines.push(` why: ${rationale}`);
|
|
502
511
|
});
|
|
503
512
|
}
|
|
504
|
-
if (coachBadges.length > 0) {
|
|
513
|
+
if (coachBadges.length > 0 && verbose) {
|
|
505
514
|
lines.push('Strategy badges:');
|
|
506
515
|
coachBadges.forEach((badge) => {
|
|
507
516
|
const title = asString(badge.title) || 'Badge';
|
|
@@ -523,18 +532,41 @@ export function formatOracleLines(data, includeAllPending = false) {
|
|
|
523
532
|
? coachFeedback.what_to_do_next.filter((line) => typeof line === 'string' && line.length > 0)
|
|
524
533
|
: [];
|
|
525
534
|
if (whatHappened.length > 0 || happeningNow.length > 0 || whatToDoNext.length > 0) {
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
535
|
+
if (verbose) {
|
|
536
|
+
lines.push('Agent-human feedback:');
|
|
537
|
+
if (whatHappened.length > 0) {
|
|
538
|
+
lines.push(' What happened:');
|
|
539
|
+
whatHappened.forEach((line) => lines.push(` - ${line}`));
|
|
540
|
+
}
|
|
541
|
+
if (happeningNow.length > 0) {
|
|
542
|
+
lines.push(' What is happening now:');
|
|
543
|
+
happeningNow.forEach((line) => lines.push(` - ${line}`));
|
|
544
|
+
}
|
|
545
|
+
if (whatToDoNext.length > 0) {
|
|
546
|
+
lines.push(' What to do next:');
|
|
547
|
+
whatToDoNext.forEach((line) => lines.push(` - ${line}`));
|
|
548
|
+
}
|
|
530
549
|
}
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
550
|
+
else {
|
|
551
|
+
if (happeningNow.length > 0) {
|
|
552
|
+
lines.push(`Now: ${happeningNow[0]}`);
|
|
553
|
+
}
|
|
554
|
+
if (whatToDoNext.length > 0) {
|
|
555
|
+
lines.push(`Next: ${whatToDoNext[0]}`);
|
|
556
|
+
}
|
|
534
557
|
}
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
if (!verbose && coachBadges.length > 0) {
|
|
561
|
+
const earnedCount = coachBadges.filter((badge) => badge.earned === true).length;
|
|
562
|
+
lines.push(`Strategy badges: ${earnedCount}/${coachBadges.length} earned`);
|
|
563
|
+
}
|
|
564
|
+
if (!verbose && coachObjectives.length > 0) {
|
|
565
|
+
const pendingObjective = coachObjectives.find((objective) => asString(objective.status) !== 'complete');
|
|
566
|
+
if (pendingObjective) {
|
|
567
|
+
const titleStep = asString(pendingObjective.title);
|
|
568
|
+
if (titleStep) {
|
|
569
|
+
lines.push(`Coach objective focus: ${titleStep}`);
|
|
538
570
|
}
|
|
539
571
|
}
|
|
540
572
|
}
|