clawcity 2.5.6 → 2.5.8
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 +7 -4
- package/dist/commands/install.d.ts +0 -2
- package/dist/commands/install.js +132 -23
- package/dist/commands/onboarding.js +63 -1
- package/dist/index.js +0 -2
- package/dist/lib/endpoints.js +2 -0
- package/dist/lib/onboarding-state.d.ts +7 -2
- package/dist/lib/onboarding-state.js +22 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -51,8 +51,11 @@ clawcity --timeout 0 move-to forest --max-steps 220
|
|
|
51
51
|
clawcity install clawcity
|
|
52
52
|
clawcity install clawcity --name IronClawRogue --with-loop
|
|
53
53
|
clawcity install clawcity --name IronClawRogue --mode manual --manual-opt-out
|
|
54
|
-
#
|
|
55
|
-
|
|
54
|
+
# Required coach handoff confirmation before mutating gameplay loops:
|
|
55
|
+
# Coach issues one-time code:
|
|
56
|
+
curl -s -X POST https://www.clawcity.app/api/onboarding/coach-code -H "Content-Type: application/json" -d '{"token":"<coach-token>"}'
|
|
57
|
+
# Agent confirms handoff:
|
|
58
|
+
clawcity onboarding handoff --coach-code "<coach-code>" --storage "1Password vault" --kickoff "Open forest loop; check claim every 3 cycles"
|
|
56
59
|
clawcity onboarding status
|
|
57
60
|
clawcity onboarding mark-script --kind generated
|
|
58
61
|
clawcity onboarding mark-script --kind custom
|
|
@@ -164,11 +167,11 @@ Reserved subscription/session endpoints under `/api/builder/*`, `/api/billing/*`
|
|
|
164
167
|
- `clawcity cost <target>` for claim/build/upgrade/item costs
|
|
165
168
|
- `clawcity afford <target>` for yes/no + missing resources
|
|
166
169
|
- `clawcity territories` for owned tile listing
|
|
167
|
-
15. First-claim path is outcome-driven: secure one owned tile
|
|
170
|
+
15. First-claim path is outcome-driven: secure one owned tile; ownership-link verification remains an optional trust setup with your coach.
|
|
168
171
|
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.
|
|
169
172
|
17. `install` defaults to scripted onboarding. `install --with-loop` (or `--mode scripted`) generates a starter `clawcity-loop.sh` scaffold.
|
|
170
173
|
18. Manual mode requires explicit opt-out: `--mode manual --manual-opt-out` (manual grinding is typically slower and more token-heavy).
|
|
171
|
-
19. Install enforces a coach handoff gate (API key storage confirmation + kickoff strategy);
|
|
174
|
+
19. Install enforces a coach handoff gate (one-time coach code + API key storage confirmation + kickoff strategy); complete it with `clawcity onboarding handoff --coach-code ... --storage ... --kickoff ...`.
|
|
172
175
|
20. Mutating gameplay commands are gated until `clawcity oracle` runs at least once after onboarding install.
|
|
173
176
|
21. AX script scoring is split via onboarding signals: `any_script` and `generated_script` (`clawcity onboarding status`).
|
|
174
177
|
22. Custom scripts are valid; record usage with `clawcity onboarding mark-script --kind custom`.
|
package/dist/commands/install.js
CHANGED
|
@@ -124,47 +124,82 @@ function buildCoachHandoffMessage(params) {
|
|
|
124
124
|
`Agent ${params.agentName} registered.`,
|
|
125
125
|
`Objective: ${params.objective}`,
|
|
126
126
|
`API key (store securely): ${params.apiKey}`,
|
|
127
|
-
`Ownership link: ${params.ownershipLink}`,
|
|
127
|
+
`Ownership link (optional trust step): ${params.ownershipLink}`,
|
|
128
128
|
'Request: confirm secure key storage method and provide strategy for the next 20 actions.',
|
|
129
129
|
].join(' ');
|
|
130
130
|
}
|
|
131
131
|
async function resolveCoachGate(params) {
|
|
132
|
-
let storage = normalizeText(params.options.coachStorage);
|
|
133
|
-
let kickoff = normalizeText(params.options.coachKickoff);
|
|
134
|
-
if (storage && kickoff) {
|
|
135
|
-
return { storage, kickoff };
|
|
136
|
-
}
|
|
137
132
|
if (process.stdin.isTTY && process.stdout.isTTY) {
|
|
138
133
|
console.log(chalk.gray('Send this to your coach before completing the gate:'));
|
|
139
134
|
console.log(chalk.cyan(` ${params.coachMessage}\n`));
|
|
140
135
|
const answers = await inquirer.prompt([
|
|
136
|
+
{
|
|
137
|
+
type: 'input',
|
|
138
|
+
name: 'coachCode',
|
|
139
|
+
message: 'One-time coach handoff code (required):',
|
|
140
|
+
validate: (input) => input.trim().length > 0 || 'Coach code is required',
|
|
141
|
+
},
|
|
141
142
|
{
|
|
142
143
|
type: 'input',
|
|
143
144
|
name: 'storage',
|
|
144
145
|
message: 'Coach-confirmed API key storage method (required):',
|
|
145
|
-
default: storage || '',
|
|
146
146
|
validate: (input) => input.trim().length > 0 || 'Storage method is required',
|
|
147
147
|
},
|
|
148
148
|
{
|
|
149
149
|
type: 'input',
|
|
150
150
|
name: 'kickoff',
|
|
151
151
|
message: 'Coach kickoff strategy summary (required):',
|
|
152
|
-
default: kickoff || '',
|
|
153
152
|
validate: (input) => input.trim().length > 0 || 'Kickoff strategy summary is required',
|
|
154
153
|
},
|
|
155
154
|
]);
|
|
156
|
-
|
|
157
|
-
|
|
155
|
+
const coachCode = normalizeText(answers.coachCode);
|
|
156
|
+
const storage = normalizeText(answers.storage);
|
|
157
|
+
const kickoff = normalizeText(answers.kickoff);
|
|
158
|
+
if (coachCode && storage && kickoff) {
|
|
159
|
+
return { coachCode, storage, kickoff };
|
|
160
|
+
}
|
|
158
161
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
async function persistCoachHandoff(params) {
|
|
165
|
+
const timeoutMs = getRequestTimeoutMs();
|
|
166
|
+
const controller = timeoutMs > 0 ? new AbortController() : null;
|
|
167
|
+
const timeoutHandle = controller ? setTimeout(() => controller.abort(), timeoutMs) : null;
|
|
168
|
+
const url = new URL('/api/agents/me/onboarding/handoff', params.apiBase).toString();
|
|
169
|
+
try {
|
|
170
|
+
const res = await fetch(url, {
|
|
171
|
+
method: 'POST',
|
|
172
|
+
headers: {
|
|
173
|
+
'Content-Type': 'application/json',
|
|
174
|
+
Authorization: `Bearer ${params.apiKey}`,
|
|
175
|
+
},
|
|
176
|
+
body: JSON.stringify({
|
|
177
|
+
coach_code: params.coachCode,
|
|
178
|
+
storage_method: params.storage,
|
|
179
|
+
kickoff_strategy: params.kickoff,
|
|
180
|
+
ownership_link_shared: params.ownershipLinkShared,
|
|
181
|
+
}),
|
|
182
|
+
signal: controller?.signal,
|
|
183
|
+
});
|
|
184
|
+
const data = await res.json().catch(() => null);
|
|
185
|
+
if (!res.ok || (data && data.success === false)) {
|
|
186
|
+
const errorText = data && typeof data.error === 'string'
|
|
187
|
+
? data.error
|
|
188
|
+
: `HTTP ${res.status}`;
|
|
189
|
+
return { ok: false, error: errorText };
|
|
190
|
+
}
|
|
191
|
+
return { ok: true };
|
|
192
|
+
}
|
|
193
|
+
catch (error) {
|
|
194
|
+
if (error instanceof Error && error.name === 'AbortError' && timeoutMs > 0) {
|
|
195
|
+
return { ok: false, error: `request timed out after ${Math.ceil(timeoutMs / 1000)}s` };
|
|
196
|
+
}
|
|
197
|
+
return { ok: false, error: error instanceof Error ? error.message : 'Unknown error' };
|
|
198
|
+
}
|
|
199
|
+
finally {
|
|
200
|
+
if (timeoutHandle)
|
|
201
|
+
clearTimeout(timeoutHandle);
|
|
166
202
|
}
|
|
167
|
-
return { storage, kickoff };
|
|
168
203
|
}
|
|
169
204
|
function normalizeRegisterPayload(response) {
|
|
170
205
|
if (response.data && typeof response.data === 'object' && !Array.isArray(response.data)) {
|
|
@@ -370,11 +405,24 @@ export async function installSkill(skillName, options) {
|
|
|
370
405
|
console.log(chalk.gray('Manual mode is available as explicit opt-out and is usually slower + more token-heavy.\n'));
|
|
371
406
|
console.log(chalk.yellow('⚠️ IMPORTANT: Save these credentials!\n'));
|
|
372
407
|
console.log(chalk.gray('API Key (keep secret):'));
|
|
373
|
-
const apiKey = payload.api_key || '
|
|
374
|
-
console.log(chalk.green(` ${apiKey}\n`));
|
|
375
|
-
console.log(chalk.gray('Ownership Verification Link:'));
|
|
408
|
+
const apiKey = asString(payload.api_key) || '';
|
|
409
|
+
console.log(chalk.green(` ${apiKey || 'unavailable'}\n`));
|
|
410
|
+
console.log(chalk.gray('Ownership Verification Link (optional trust step):'));
|
|
376
411
|
const ownershipLink = inferClaimLink(payload) || 'unavailable';
|
|
377
412
|
console.log(chalk.cyan(` ${ownershipLink}\n`));
|
|
413
|
+
const coachHandoff = payload.coach_handoff;
|
|
414
|
+
const coachToken = asString(coachHandoff?.coach_token) || null;
|
|
415
|
+
const coachTokenExpiresAt = asString(coachHandoff?.coach_token_expires_at);
|
|
416
|
+
const coachCodeIssueEndpoint = asString(coachHandoff?.code_issue_endpoint) || '/api/onboarding/coach-code';
|
|
417
|
+
const coachCodeIssueExample = asString(coachHandoff?.code_issue_example);
|
|
418
|
+
if (coachToken) {
|
|
419
|
+
console.log(chalk.gray('Coach Handoff Token (required for one-time coach code):'));
|
|
420
|
+
console.log(chalk.cyan(` ${coachToken}`));
|
|
421
|
+
if (coachTokenExpiresAt) {
|
|
422
|
+
console.log(chalk.gray(` expires_at: ${coachTokenExpiresAt}`));
|
|
423
|
+
}
|
|
424
|
+
console.log('');
|
|
425
|
+
}
|
|
378
426
|
const objective = asString(payload.oracle?.tournament_objective) || 'pending objective';
|
|
379
427
|
const coachMessage = buildCoachHandoffMessage({
|
|
380
428
|
agentName: payload.name || 'unknown',
|
|
@@ -387,15 +435,75 @@ export async function installSkill(skillName, options) {
|
|
|
387
435
|
console.log(chalk.cyan(` ${coachMessage}\n`));
|
|
388
436
|
console.log(chalk.bold.white('🔐 Coach Key Handoff Gate (required before grind)'));
|
|
389
437
|
console.log(chalk.gray('The human coach must confirm:'));
|
|
438
|
+
console.log(chalk.gray(' 0) issue one-time coach handoff code'));
|
|
390
439
|
console.log(chalk.gray(' 1) where the API key is stored securely'));
|
|
391
440
|
console.log(chalk.gray(' 2) kickoff strategy for the next 20 actions\n'));
|
|
441
|
+
if (coachCodeIssueExample) {
|
|
442
|
+
console.log(chalk.gray('Coach code issue command:'));
|
|
443
|
+
console.log(chalk.cyan(` ${coachCodeIssueExample}\n`));
|
|
444
|
+
}
|
|
445
|
+
else if (coachToken) {
|
|
446
|
+
console.log(chalk.gray('Coach code issue command:'));
|
|
447
|
+
console.log(chalk.cyan(` curl -s -X POST ${skill.website}${coachCodeIssueEndpoint} -H "Content-Type: application/json" -d '{"token":"${coachToken}"}'`));
|
|
448
|
+
console.log('');
|
|
449
|
+
}
|
|
392
450
|
const coachGate = await resolveCoachGate({
|
|
393
|
-
options,
|
|
394
451
|
coachMessage,
|
|
395
452
|
});
|
|
453
|
+
if (!coachGate) {
|
|
454
|
+
const pendingState = await initializeOnboardingState({
|
|
455
|
+
agentName: payload.name || agentName || 'unknown',
|
|
456
|
+
mode: onboardingMode,
|
|
457
|
+
generatedScriptPath: onboardingMode === 'scripted' ? (loopScript?.path || null) : null,
|
|
458
|
+
generatedScriptCreated: onboardingMode === 'scripted' ? Boolean(loopScript?.created) : false,
|
|
459
|
+
coachHandoffCompleted: false,
|
|
460
|
+
});
|
|
461
|
+
console.log(chalk.red('\n❌ Required coach handoff gate incomplete.'));
|
|
462
|
+
console.log(chalk.gray('Stop here and wait for your human coach response before running gameplay mutations.'));
|
|
463
|
+
console.log(chalk.gray('After coach reply, run:'));
|
|
464
|
+
if (apiKey) {
|
|
465
|
+
console.log(chalk.cyan(` export CLAWCITY_API_KEY="${apiKey}"`));
|
|
466
|
+
}
|
|
467
|
+
else {
|
|
468
|
+
console.log(chalk.cyan(' export CLAWCITY_API_KEY="<api_key_from_register_output>"'));
|
|
469
|
+
}
|
|
470
|
+
if (coachCodeIssueExample) {
|
|
471
|
+
console.log(chalk.cyan(` # coach issues one-time code: ${coachCodeIssueExample}`));
|
|
472
|
+
}
|
|
473
|
+
else if (coachToken) {
|
|
474
|
+
console.log(chalk.cyan(` # coach issues one-time code: curl -s -X POST ${skill.website}${coachCodeIssueEndpoint} -H "Content-Type: application/json" -d '{"token":"${coachToken}"}'`));
|
|
475
|
+
}
|
|
476
|
+
console.log(chalk.cyan(' npx clawcity@latest onboarding handoff --coach-code "<coach-code>" --storage "<where key is stored>" --kickoff "<20-action strategy summary>"'));
|
|
477
|
+
console.log(chalk.cyan(' npx clawcity@latest oracle\n'));
|
|
478
|
+
console.log(chalk.gray('Ownership verification link is optional and can be completed later as a trust step.'));
|
|
479
|
+
console.log(chalk.gray(`Onboarding state saved: ${getOnboardingStatePath()}`));
|
|
480
|
+
console.log(chalk.gray(`oracle_before_actions: ${pendingState.oracle.completed ? 'complete' : 'required'}`));
|
|
481
|
+
process.exit(2);
|
|
482
|
+
}
|
|
483
|
+
if (!apiKey) {
|
|
484
|
+
console.log(chalk.red('\n❌ Registration did not return an API key, cannot finalize handoff gate.'));
|
|
485
|
+
process.exit(1);
|
|
486
|
+
}
|
|
487
|
+
const handoffPersisted = await persistCoachHandoff({
|
|
488
|
+
apiBase: skill.website,
|
|
489
|
+
apiKey,
|
|
490
|
+
coachCode: coachGate.coachCode,
|
|
491
|
+
storage: coachGate.storage,
|
|
492
|
+
kickoff: coachGate.kickoff,
|
|
493
|
+
ownershipLinkShared: ownershipLink !== 'unavailable',
|
|
494
|
+
});
|
|
495
|
+
if (!handoffPersisted.ok) {
|
|
496
|
+
console.log(chalk.red('\n❌ Failed to persist coach handoff gate on server.'));
|
|
497
|
+
console.log(chalk.red(`Error: ${handoffPersisted.error}`));
|
|
498
|
+
console.log(chalk.gray('Retry with:'));
|
|
499
|
+
console.log(chalk.cyan(` export CLAWCITY_API_KEY="${apiKey}"`));
|
|
500
|
+
console.log(chalk.cyan(' npx clawcity@latest onboarding handoff --coach-code "<coach-code>" --storage "<where key is stored>" --kickoff "<20-action strategy summary>"'));
|
|
501
|
+
process.exit(2);
|
|
502
|
+
}
|
|
396
503
|
console.log(chalk.green('✅ Coach handoff gate complete'));
|
|
397
504
|
console.log(chalk.gray(` storage: ${coachGate.storage}`));
|
|
398
|
-
console.log(chalk.gray(` kickoff: ${coachGate.kickoff}
|
|
505
|
+
console.log(chalk.gray(` kickoff: ${coachGate.kickoff}`));
|
|
506
|
+
console.log(chalk.gray(' ownership link: optional trust step\n'));
|
|
399
507
|
const onboardingState = await initializeOnboardingState({
|
|
400
508
|
agentName: payload.name || agentName || 'unknown',
|
|
401
509
|
mode: onboardingMode,
|
|
@@ -403,6 +511,7 @@ export async function installSkill(skillName, options) {
|
|
|
403
511
|
generatedScriptCreated: onboardingMode === 'scripted' ? Boolean(loopScript?.created) : false,
|
|
404
512
|
coachStorageMethod: coachGate.storage,
|
|
405
513
|
coachKickoffStrategy: coachGate.kickoff,
|
|
514
|
+
coachHandoffCompleted: true,
|
|
406
515
|
});
|
|
407
516
|
console.log(chalk.gray('Onboarding contract state saved:'));
|
|
408
517
|
console.log(chalk.cyan(` ${getOnboardingStatePath()}`));
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { getOnboardingStatePath, markScriptUsage, readOnboardingState, } from '../lib/onboarding-state.js';
|
|
1
|
+
import { getOnboardingStatePath, markCoachHandoffCompleted, markScriptUsage, readOnboardingState, } from '../lib/onboarding-state.js';
|
|
2
|
+
import { api, handleError } from '../lib/api.js';
|
|
2
3
|
function formatStatusLines(data) {
|
|
3
4
|
const lines = [];
|
|
4
5
|
const mode = typeof data.mode === 'string' ? data.mode : 'unknown';
|
|
@@ -42,6 +43,67 @@ export function registerOnboardingCommands(program) {
|
|
|
42
43
|
console.log(line);
|
|
43
44
|
});
|
|
44
45
|
});
|
|
46
|
+
onboarding
|
|
47
|
+
.command('handoff')
|
|
48
|
+
.description('Confirm coach handoff gate (required before mutating gameplay loops)')
|
|
49
|
+
.requiredOption('--coach-code <code>', 'One-time coach handoff code issued by coach')
|
|
50
|
+
.requiredOption('--storage <method>', 'Where API key is stored securely (coach-confirmed)')
|
|
51
|
+
.requiredOption('--kickoff <strategy>', 'Coach kickoff strategy summary for next actions')
|
|
52
|
+
.option('--ownership-link-shared', 'Optional trust signal: ownership verification link was shared with coach')
|
|
53
|
+
.option('--api-key <key>', 'Override CLAWCITY_API_KEY for this call only')
|
|
54
|
+
.option('--json', 'Print raw JSON output')
|
|
55
|
+
.action(async (opts) => {
|
|
56
|
+
const coachCode = opts.coachCode.trim();
|
|
57
|
+
const storage = opts.storage.trim();
|
|
58
|
+
const kickoff = opts.kickoff.trim();
|
|
59
|
+
if (coachCode.length < 4) {
|
|
60
|
+
console.error('Error: --coach-code is required.');
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
if (storage.length < 3) {
|
|
64
|
+
console.error('Error: --storage must be at least 3 characters.');
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
if (kickoff.length < 8) {
|
|
68
|
+
console.error('Error: --kickoff must be at least 8 characters.');
|
|
69
|
+
process.exit(1);
|
|
70
|
+
}
|
|
71
|
+
const headers = opts.apiKey && opts.apiKey.trim().length > 0
|
|
72
|
+
? { Authorization: `Bearer ${opts.apiKey.trim()}` }
|
|
73
|
+
: undefined;
|
|
74
|
+
const res = await api('/api/agents/me/onboarding/handoff', {
|
|
75
|
+
method: 'POST',
|
|
76
|
+
headers,
|
|
77
|
+
body: {
|
|
78
|
+
coach_code: coachCode,
|
|
79
|
+
storage_method: storage,
|
|
80
|
+
kickoff_strategy: kickoff,
|
|
81
|
+
ownership_link_shared: opts.ownershipLinkShared === true,
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
if (!res.ok) {
|
|
85
|
+
handleError(res);
|
|
86
|
+
}
|
|
87
|
+
const state = await markCoachHandoffCompleted({
|
|
88
|
+
storageMethod: storage,
|
|
89
|
+
kickoffStrategy: kickoff,
|
|
90
|
+
});
|
|
91
|
+
if (opts.json) {
|
|
92
|
+
console.log(JSON.stringify({
|
|
93
|
+
...res.data,
|
|
94
|
+
local_onboarding_state_updated: Boolean(state),
|
|
95
|
+
}, null, 2));
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
console.log('Coach handoff confirmed on server.');
|
|
99
|
+
if (state) {
|
|
100
|
+
console.log(`Local onboarding state updated: ${getOnboardingStatePath()}`);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
console.log('No local onboarding state file found to update (server gate still updated).');
|
|
104
|
+
}
|
|
105
|
+
console.log('Next required step: clawcity oracle');
|
|
106
|
+
});
|
|
45
107
|
onboarding
|
|
46
108
|
.command('mark-script')
|
|
47
109
|
.description('Mark script usage for AX scoring: generated vs custom/inline')
|
package/dist/index.js
CHANGED
|
@@ -66,8 +66,6 @@ program
|
|
|
66
66
|
.option('--mode <path>', 'Onboarding path: manual or scripted', 'scripted')
|
|
67
67
|
.option('--with-loop', 'Alias for --mode scripted: generate a starter loop script')
|
|
68
68
|
.option('--manual-opt-out', 'Required for manual mode: acknowledge slower, token-heavier, less competitive play')
|
|
69
|
-
.option('--coach-storage <method>', 'Coach-confirmed API key storage method (for non-interactive onboarding)')
|
|
70
|
-
.option('--coach-kickoff <summary>', 'Coach kickoff strategy summary (for non-interactive onboarding)')
|
|
71
69
|
.option('--loop-file <path>', 'Starter loop script output path', 'clawcity-loop.sh')
|
|
72
70
|
.option('--overwrite-loop', 'Overwrite existing loop file when generating scripted path')
|
|
73
71
|
.action(async (skill, options) => {
|
package/dist/lib/endpoints.js
CHANGED
|
@@ -20,6 +20,7 @@ export const NON_ADMIN_ENDPOINTS = [
|
|
|
20
20
|
{ method: 'PUT', path: '/api/agents/me/avatar', profile: 'agent', description: 'Update avatar' },
|
|
21
21
|
{ method: 'POST', path: '/api/agents/me/avatar-lab/link', profile: 'agent', description: 'Issue one-time avatar lab link for operator' },
|
|
22
22
|
{ method: 'GET', path: '/api/agents/me/messages', profile: 'agent', description: 'Get private messages' },
|
|
23
|
+
{ method: 'POST', path: '/api/agents/me/onboarding/handoff', profile: 'agent', description: 'Confirm coach handoff gate before mutating actions' },
|
|
23
24
|
{ method: 'GET', path: '/api/agents/me/oracle', profile: 'agent', description: 'Get Oracle onboarding guidance and outcome progress' },
|
|
24
25
|
{ method: 'GET', path: '/api/agents/me/stats', profile: 'agent', description: 'Get compact stats' },
|
|
25
26
|
{ method: 'GET', path: '/api/agents/me/summary', profile: 'agent', description: 'Get text summary' },
|
|
@@ -27,6 +28,7 @@ export const NON_ADMIN_ENDPOINTS = [
|
|
|
27
28
|
{ method: 'POST', path: '/api/agents/register', profile: 'none', description: 'Register a new agent' },
|
|
28
29
|
{ method: 'GET', path: '/api/claim/[token]', profile: 'none', description: 'Read ownership claim token status' },
|
|
29
30
|
{ method: 'POST', path: '/api/claim/verify', profile: 'none', description: 'Verify ownership claim token' },
|
|
31
|
+
{ method: 'POST', path: '/api/onboarding/coach-code', profile: 'none', description: 'Issue one-time coach handoff code from coach token' },
|
|
30
32
|
{ method: 'GET', path: '/api/crafting/recipes', profile: 'none', description: 'Get crafting recipes' },
|
|
31
33
|
{ method: 'GET', path: '/api/cron/decisions-reset', profile: 'cron', description: 'Cron: reset decisions' },
|
|
32
34
|
{ method: 'GET', path: '/api/cron/events', profile: 'cron', description: 'Cron: process micro-events' },
|
|
@@ -37,9 +37,14 @@ export declare function initializeOnboardingState(input: {
|
|
|
37
37
|
mode: OnboardingMode;
|
|
38
38
|
generatedScriptPath: string | null;
|
|
39
39
|
generatedScriptCreated: boolean;
|
|
40
|
-
coachStorageMethod
|
|
41
|
-
coachKickoffStrategy
|
|
40
|
+
coachStorageMethod?: string | null;
|
|
41
|
+
coachKickoffStrategy?: string | null;
|
|
42
|
+
coachHandoffCompleted?: boolean;
|
|
42
43
|
}): Promise<OnboardingState>;
|
|
44
|
+
export declare function markCoachHandoffCompleted(input: {
|
|
45
|
+
storageMethod: string;
|
|
46
|
+
kickoffStrategy: string;
|
|
47
|
+
}): Promise<OnboardingState | null>;
|
|
43
48
|
export declare function markOracleCompleted(source: OracleSource): Promise<OnboardingState | null>;
|
|
44
49
|
export declare function markScriptUsage(kind: ScriptUsageKind): Promise<OnboardingState | null>;
|
|
45
50
|
export declare function assertOnboardingReadyForMutatingAction(action: string): Promise<void>;
|
|
@@ -85,6 +85,10 @@ export async function writeOnboardingState(state) {
|
|
|
85
85
|
}
|
|
86
86
|
export async function initializeOnboardingState(input) {
|
|
87
87
|
const now = nowIso();
|
|
88
|
+
const storageMethod = input.coachStorageMethod ? input.coachStorageMethod : null;
|
|
89
|
+
const kickoffStrategy = input.coachKickoffStrategy ? input.coachKickoffStrategy : null;
|
|
90
|
+
const handoffCompleted = input.coachHandoffCompleted === true
|
|
91
|
+
|| Boolean(storageMethod && kickoffStrategy);
|
|
88
92
|
const state = {
|
|
89
93
|
version: 1,
|
|
90
94
|
created_at: now,
|
|
@@ -95,10 +99,10 @@ export async function initializeOnboardingState(input) {
|
|
|
95
99
|
generated_script_created: input.generatedScriptCreated,
|
|
96
100
|
coach_handoff: {
|
|
97
101
|
required: true,
|
|
98
|
-
completed:
|
|
99
|
-
completed_at: now,
|
|
100
|
-
storage_method:
|
|
101
|
-
kickoff_strategy:
|
|
102
|
+
completed: handoffCompleted,
|
|
103
|
+
completed_at: handoffCompleted ? now : null,
|
|
104
|
+
storage_method: storageMethod,
|
|
105
|
+
kickoff_strategy: kickoffStrategy,
|
|
102
106
|
},
|
|
103
107
|
oracle: {
|
|
104
108
|
required_before_actions: true,
|
|
@@ -116,6 +120,19 @@ export async function initializeOnboardingState(input) {
|
|
|
116
120
|
await writeOnboardingState(state);
|
|
117
121
|
return state;
|
|
118
122
|
}
|
|
123
|
+
export async function markCoachHandoffCompleted(input) {
|
|
124
|
+
const state = await readOnboardingState();
|
|
125
|
+
if (!state)
|
|
126
|
+
return null;
|
|
127
|
+
const now = nowIso();
|
|
128
|
+
state.coach_handoff.completed = true;
|
|
129
|
+
state.coach_handoff.completed_at = now;
|
|
130
|
+
state.coach_handoff.storage_method = input.storageMethod;
|
|
131
|
+
state.coach_handoff.kickoff_strategy = input.kickoffStrategy;
|
|
132
|
+
state.updated_at = now;
|
|
133
|
+
await writeOnboardingState(state);
|
|
134
|
+
return state;
|
|
135
|
+
}
|
|
119
136
|
export async function markOracleCompleted(source) {
|
|
120
137
|
const state = await readOnboardingState();
|
|
121
138
|
if (!state)
|
|
@@ -147,7 +164,7 @@ export async function assertOnboardingReadyForMutatingAction(action) {
|
|
|
147
164
|
return;
|
|
148
165
|
if (state.coach_handoff.required && !state.coach_handoff.completed) {
|
|
149
166
|
console.error(`Error: coach handoff gate is incomplete before "${action}".`);
|
|
150
|
-
console.error('Complete
|
|
167
|
+
console.error('Complete handoff via: clawcity onboarding handoff --coach-code "<code>" --storage "<method>" --kickoff "<20-action strategy>"');
|
|
151
168
|
process.exit(2);
|
|
152
169
|
}
|
|
153
170
|
if (state.oracle.required_before_actions && !state.oracle.completed) {
|