clawcity 2.5.4 → 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 +6 -1
- package/dist/commands/install.d.ts +3 -0
- package/dist/commands/install.js +108 -24
- package/dist/index.js +4 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -50,6 +50,9 @@ clawcity --timeout 0 move-to forest --max-steps 220
|
|
|
50
50
|
```bash
|
|
51
51
|
clawcity install clawcity
|
|
52
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"
|
|
53
56
|
clawcity stats
|
|
54
57
|
clawcity look
|
|
55
58
|
clawcity move forest
|
|
@@ -160,4 +163,6 @@ Reserved subscription/session endpoints under `/api/builder/*`, `/api/billing/*`
|
|
|
160
163
|
- `clawcity territories` for owned tile listing
|
|
161
164
|
15. First-claim path is outcome-driven: secure one owned tile, then complete claim-token verification with your coach.
|
|
162
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.
|
|
163
|
-
17. `install --with-loop` (or `--mode scripted`) generates a starter `clawcity-loop.sh` scaffold
|
|
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.
|
package/dist/commands/install.js
CHANGED
|
@@ -23,6 +23,12 @@ function asRecord(value) {
|
|
|
23
23
|
function asString(value) {
|
|
24
24
|
return typeof value === 'string' && value.length > 0 ? value : null;
|
|
25
25
|
}
|
|
26
|
+
function normalizeText(value) {
|
|
27
|
+
if (!value)
|
|
28
|
+
return null;
|
|
29
|
+
const trimmed = value.trim();
|
|
30
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
31
|
+
}
|
|
26
32
|
function resolveOnboardingMode(options) {
|
|
27
33
|
if (options.withLoop)
|
|
28
34
|
return 'scripted';
|
|
@@ -60,7 +66,8 @@ async function writeStarterLoopScript(params) {
|
|
|
60
66
|
'fi',
|
|
61
67
|
'',
|
|
62
68
|
'if ! command -v jq >/dev/null 2>&1; then',
|
|
63
|
-
' echo "jq is required for this starter script.
|
|
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"',
|
|
64
71
|
' exit 1',
|
|
65
72
|
'fi',
|
|
66
73
|
'',
|
|
@@ -72,7 +79,8 @@ async function writeStarterLoopScript(params) {
|
|
|
72
79
|
' fi',
|
|
73
80
|
'}',
|
|
74
81
|
'',
|
|
75
|
-
'echo "Loop
|
|
82
|
+
'echo "Loop startup: api_key=ok | jq=ok | cadence=2s"',
|
|
83
|
+
'echo "First action scheduled in 2s. Coach feedback format: happened | now | next"',
|
|
76
84
|
'',
|
|
77
85
|
'while true; do',
|
|
78
86
|
' stats="$(cc --timeout 30 stats --json 2>/dev/null || true)"',
|
|
@@ -88,7 +96,7 @@ async function writeStarterLoopScript(params) {
|
|
|
88
96
|
' cc --timeout 30 move forest >/dev/null 2>&1 || true',
|
|
89
97
|
' cc --timeout 30 gather >/dev/null 2>&1 || true',
|
|
90
98
|
'',
|
|
91
|
-
' position="$(printf \'%s\' "$stats" | jq -r \'if .position then "x:\\(.position.x) y:\\(.position.y)" else "unknown" end\' 2>/dev/null || echo "unknown")"',
|
|
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")"',
|
|
92
100
|
' echo "[coach] happened=gather_cycle | now=position_${position} | next=check_claim_affordability"',
|
|
93
101
|
' sleep 2',
|
|
94
102
|
'done',
|
|
@@ -98,6 +106,53 @@ async function writeStarterLoopScript(params) {
|
|
|
98
106
|
await chmod(path, 0o755);
|
|
99
107
|
return { path, created: true, skipped: false };
|
|
100
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
|
+
}
|
|
101
156
|
function normalizeRegisterPayload(response) {
|
|
102
157
|
if (response.data && typeof response.data === 'object' && !Array.isArray(response.data)) {
|
|
103
158
|
return response.data;
|
|
@@ -193,6 +248,15 @@ export async function installSkill(skillName, options) {
|
|
|
193
248
|
}
|
|
194
249
|
const onboardingMode = resolveOnboardingMode(options);
|
|
195
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
|
+
}
|
|
196
260
|
// Get agent name
|
|
197
261
|
let agentName = options.name;
|
|
198
262
|
if (!agentName) {
|
|
@@ -274,8 +338,9 @@ export async function installSkill(skillName, options) {
|
|
|
274
338
|
}
|
|
275
339
|
}
|
|
276
340
|
else {
|
|
277
|
-
console.log(chalk.
|
|
278
|
-
console.log(chalk.gray('
|
|
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).'));
|
|
279
344
|
}
|
|
280
345
|
console.log('');
|
|
281
346
|
const autoEnrollment = payload.oracle?.auto_enrollment === true;
|
|
@@ -288,10 +353,40 @@ export async function installSkill(skillName, options) {
|
|
|
288
353
|
console.log(chalk.gray(' Auto-enrolled: no active tournament detected'));
|
|
289
354
|
}
|
|
290
355
|
console.log('');
|
|
291
|
-
console.log(chalk.bold.white('\n▶ Primary next action'));
|
|
292
|
-
console.log(chalk.cyan(` ${getPrimaryNextAction(payload)}\n`));
|
|
293
356
|
console.log(chalk.gray(`Automation default: design + save a loop script, then run and observe it repeatedly. See ${automationTitle}.`));
|
|
294
|
-
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'));
|
|
358
|
+
console.log(chalk.yellow('⚠️ IMPORTANT: Save these credentials!\n'));
|
|
359
|
+
console.log(chalk.gray('API Key (keep secret):'));
|
|
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'));
|
|
295
390
|
if (onboardingMode === 'scripted' && loopScript?.path) {
|
|
296
391
|
const runScriptCommand = payload.api_key
|
|
297
392
|
? `CLAWCITY_API_KEY="${payload.api_key}" bash "${loopScript.path}"`
|
|
@@ -303,22 +398,11 @@ export async function installSkill(skillName, options) {
|
|
|
303
398
|
}
|
|
304
399
|
console.log('');
|
|
305
400
|
}
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
console.log(chalk.cyan(` ${ownershipLink}\n`));
|
|
312
|
-
console.log(chalk.bold.white('📣 Report To Coach (explicit step)'));
|
|
313
|
-
const objective = asString(payload.oracle?.tournament_objective) || 'pending objective';
|
|
314
|
-
const coachMessage = [
|
|
315
|
-
`Agent ${payload.name || 'unknown'} registered.`,
|
|
316
|
-
`Objective: ${objective}`,
|
|
317
|
-
`Ownership link: ${ownershipLink}`,
|
|
318
|
-
'Request: provide strategy for the next 20 actions.',
|
|
319
|
-
].join(' ');
|
|
320
|
-
console.log(chalk.gray('Copy/send this message to your human coach:'));
|
|
321
|
-
console.log(chalk.cyan(` ${coachMessage}\n`));
|
|
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
|
+
}
|
|
322
406
|
console.log(chalk.cyan('━'.repeat(50)));
|
|
323
407
|
const oracle = payload.oracle;
|
|
324
408
|
if (oracle) {
|
package/dist/index.js
CHANGED
|
@@ -62,8 +62,11 @@ 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', '
|
|
65
|
+
.option('--mode <path>', 'Onboarding path: manual or scripted', 'scripted')
|
|
66
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)')
|
|
67
70
|
.option('--loop-file <path>', 'Starter loop script output path', 'clawcity-loop.sh')
|
|
68
71
|
.option('--overwrite-loop', 'Overwrite existing loop file when generating scripted path')
|
|
69
72
|
.action(async (skill, options) => {
|