@sherwoodagent/cli 0.15.1 → 0.15.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{cron-RG46PYWA.js → cron-SKYKVZ6K.js} +10 -6
- package/dist/cron-SKYKVZ6K.js.map +1 -0
- package/dist/index.js +10 -6
- package/dist/index.js.map +1 -1
- package/dist/{session-RMZPTWNY.js → session-UPNQXTMI.js} +2 -2
- package/package.json +1 -1
- package/dist/cron-RG46PYWA.js.map +0 -1
- /package/dist/{session-RMZPTWNY.js.map → session-UPNQXTMI.js.map} +0 -0
|
@@ -28,16 +28,20 @@ function silentPrompt(subdomain, testnet) {
|
|
|
28
28
|
`You are a sherwood syndicate member. Your syndicate: ${subdomain}.sherwoodagent.eth`,
|
|
29
29
|
"",
|
|
30
30
|
`Step 1: Run \`${envPrefix}sherwood session check ${subdomain}${chainFlag}\``,
|
|
31
|
-
"Step 2: Parse the JSON output
|
|
32
|
-
"
|
|
33
|
-
`
|
|
34
|
-
"
|
|
31
|
+
"Step 2: Parse the JSON output.",
|
|
32
|
+
" - If the output shows 0 messages and 0 events, you may still be pending approval.",
|
|
33
|
+
" Check: `" + envPrefix + "sherwood vault info" + chainFlag + "`",
|
|
34
|
+
" If your wallet is not listed as a registered agent, you are still pending. Reply HEARTBEAT_OK.",
|
|
35
|
+
" If you ARE registered but this is your first time seeing it, alert your human that you've been approved and are now active.",
|
|
36
|
+
" - If there are new messages from OTHER agents, respond thoughtfully via:",
|
|
37
|
+
` \`${envPrefix}sherwood chat ${subdomain} send "<response>"${chainFlag}\``,
|
|
38
|
+
"Step 3: If you responded to anything, summarize what you did (for your own session log).",
|
|
35
39
|
" If nothing happened, reply HEARTBEAT_OK",
|
|
36
40
|
"",
|
|
37
41
|
"Rules:",
|
|
38
42
|
"- Be a real syndicate member \u2014 discuss strategies, share opinions, ask questions",
|
|
39
43
|
"- Keep responses concise and on-topic",
|
|
40
|
-
"- Do NOT alert your human unless something requires their approval",
|
|
44
|
+
"- Do NOT alert your human unless something requires their approval (or you were just approved)",
|
|
41
45
|
`- You can use \`sherwood research\` commands if you need data to back up your response`
|
|
42
46
|
].join("\n");
|
|
43
47
|
}
|
|
@@ -200,4 +204,4 @@ export {
|
|
|
200
204
|
registerSyndicateCrons,
|
|
201
205
|
unregisterSyndicateCrons
|
|
202
206
|
};
|
|
203
|
-
//# sourceMappingURL=cron-
|
|
207
|
+
//# sourceMappingURL=cron-SKYKVZ6K.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/cron.ts"],"sourcesContent":["/**\n * OpenClaw cron integration — auto-register participation crons for syndicate agents.\n *\n * When an agent creates or joins a syndicate, the CLI registers two cron jobs:\n * 1. Silent check (every 15m) — processes messages/events, responds autonomously\n * 2. Human summary (every 1h) — brief activity report delivered to the human's channel\n *\n * Non-OpenClaw agents skip silently — the caller prints guidance instead.\n */\n\nimport { execFileSync } from \"node:child_process\";\n\n// ── OpenClaw detection (cached per process) ──\n\nlet _isOpenClaw: boolean | null = null;\n\nexport function isOpenClaw(): boolean {\n if (_isOpenClaw !== null) return _isOpenClaw;\n try {\n execFileSync(\"openclaw\", [\"cron\", \"list\"], {\n encoding: \"utf8\",\n timeout: 10_000,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n _isOpenClaw = true;\n } catch {\n _isOpenClaw = false;\n }\n return _isOpenClaw;\n}\n\n// ── Types ──\n\nexport interface CronResult {\n registered: boolean;\n isOpenClaw: boolean;\n cronNames: string[];\n}\n\nexport interface CronStatus {\n isOpenClaw: boolean;\n crons: { name: string; every: string; lastRun?: string }[];\n}\n\n// ── Cron naming ──\n\nfunction cronName(subdomain: string, testnet: boolean): string {\n return `sherwood-${subdomain}${testnet ? \"-testnet\" : \"\"}`;\n}\n\nfunction summaryCronName(subdomain: string, testnet: boolean): string {\n return `${cronName(subdomain, testnet)}-summary`;\n}\n\n// ── Prompts ──\n\nfunction silentPrompt(subdomain: string, testnet: boolean): string {\n const chainFlag = testnet ? \" --chain base-sepolia\" : \"\";\n const envPrefix = testnet ? \"ENABLE_TESTNET=true \" : \"\";\n return [\n `You are a sherwood syndicate member. Your syndicate: ${subdomain}.sherwoodagent.eth`,\n \"\",\n `Step 1: Run \\`${envPrefix}sherwood session check ${subdomain}${chainFlag}\\``,\n \"Step 2: Parse the JSON output.\",\n \" - If the output shows 0 messages and 0 events, you may still be pending approval.\",\n \" Check: `\" + envPrefix + \"sherwood vault info\" + chainFlag + \"`\",\n \" If your wallet is not listed as a registered agent, you are still pending. Reply HEARTBEAT_OK.\",\n \" If you ARE registered but this is your first time seeing it, alert your human that you've been approved and are now active.\",\n \" - If there are new messages from OTHER agents, respond thoughtfully via:\",\n ` \\`${envPrefix}sherwood chat ${subdomain} send \"<response>\"${chainFlag}\\``,\n \"Step 3: If you responded to anything, summarize what you did (for your own session log).\",\n \" If nothing happened, reply HEARTBEAT_OK\",\n \"\",\n \"Rules:\",\n \"- Be a real syndicate member — discuss strategies, share opinions, ask questions\",\n \"- Keep responses concise and on-topic\",\n \"- Do NOT alert your human unless something requires their approval (or you were just approved)\",\n `- You can use \\`sherwood research\\` commands if you need data to back up your response`,\n ].join(\"\\n\");\n}\n\nfunction summaryPrompt(subdomain: string, testnet: boolean): string {\n const chainFlag = testnet ? \" --chain base-sepolia\" : \"\";\n const envPrefix = testnet ? \"ENABLE_TESTNET=true \" : \"\";\n return [\n \"You are reporting syndicate activity to your human operator.\",\n \"\",\n `Run: \\`${envPrefix}sherwood session check ${subdomain}${chainFlag}\\``,\n \"\",\n \"If there was activity (messages, events, proposals) since last check:\",\n \" Send a brief summary — who said what, any decisions made, any actions you took.\",\n \" Keep it to 3-5 lines max.\",\n \"\",\n \"If there was no activity:\",\n \" Reply HEARTBEAT_OK\",\n \"\",\n \"Only escalate (flag as urgent) if:\",\n \"- A proposal needs human sign-off\",\n \"- An agent left the syndicate\",\n \"- Risk alert or health factor warning\",\n \"- Human was directly asked for input\",\n ].join(\"\\n\");\n}\n\n// ── Helpers ──\n\n/** Parse `openclaw cron list --json` and return job names. */\nfunction listCronNames(): string[] {\n try {\n const raw = execFileSync(\"openclaw\", [\"cron\", \"list\", \"--json\"], {\n encoding: \"utf8\",\n timeout: 10_000,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n const parsed = JSON.parse(raw);\n const jobs: { name: string }[] = parsed.jobs || parsed || [];\n return jobs.map((j) => j.name);\n } catch {\n return [];\n }\n}\n\n/** Parse `openclaw cron list --json` with full details for status display. */\nfunction listCronDetails(): { name: string; every: string; lastRun?: string }[] {\n try {\n const raw = execFileSync(\"openclaw\", [\"cron\", \"list\", \"--json\"], {\n encoding: \"utf8\",\n timeout: 10_000,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n const parsed = JSON.parse(raw);\n const jobs: { name: string; every?: string; interval?: string; lastRun?: string }[] =\n parsed.jobs || parsed || [];\n return jobs.map((j) => ({\n name: j.name,\n every: j.every || j.interval || \"unknown\",\n lastRun: j.lastRun,\n }));\n } catch {\n return [];\n }\n}\n\n// ── Public API ──\n\nexport function registerSyndicateCrons(\n subdomain: string,\n testnet: boolean,\n notifyTo?: string,\n): CronResult {\n if (!isOpenClaw()) {\n return { registered: false, isOpenClaw: false, cronNames: [] };\n }\n\n const checkName = cronName(subdomain, testnet);\n const summaryName = summaryCronName(subdomain, testnet);\n const existing = listCronNames();\n const created: string[] = [];\n\n // Cron 1: Silent participation check (every 15m)\n if (!existing.includes(checkName)) {\n try {\n execFileSync(\"openclaw\", [\n \"cron\", \"create\",\n \"--name\", checkName,\n \"--every\", \"15m\",\n \"--session\", \"isolated\",\n \"--timeout-seconds\", \"120\",\n \"--no-deliver\",\n \"--message\", silentPrompt(subdomain, testnet),\n ], {\n encoding: \"utf8\",\n timeout: 30_000,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n created.push(checkName);\n } catch (err) {\n console.warn(`Could not create silent cron: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n // Cron 2: Human summary (every 1h)\n if (!existing.includes(summaryName)) {\n try {\n const args = [\n \"cron\", \"create\",\n \"--name\", summaryName,\n \"--every\", \"1h\",\n \"--session\", \"isolated\",\n \"--timeout-seconds\", \"90\",\n \"--announce\",\n ];\n\n // Use explicit destination if configured, otherwise auto-route via --channel last\n if (notifyTo) {\n args.push(\"--to\", notifyTo);\n } else {\n args.push(\"--channel\", \"last\");\n }\n\n args.push(\"--message\", summaryPrompt(subdomain, testnet));\n\n execFileSync(\"openclaw\", args, {\n encoding: \"utf8\",\n timeout: 30_000,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n created.push(summaryName);\n } catch (err) {\n console.warn(`Could not create summary cron: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n return {\n registered: created.length > 0,\n isOpenClaw: true,\n cronNames: created,\n };\n}\n\nexport function unregisterSyndicateCrons(\n subdomain: string,\n testnet: boolean,\n): { removed: boolean; isOpenClaw: boolean } {\n if (!isOpenClaw()) {\n return { removed: false, isOpenClaw: false };\n }\n\n const names = [cronName(subdomain, testnet), summaryCronName(subdomain, testnet)];\n let removed = false;\n\n for (const name of names) {\n try {\n execFileSync(\"openclaw\", [\"cron\", \"remove\", \"--name\", name], {\n encoding: \"utf8\",\n timeout: 10_000,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n removed = true;\n } catch {\n // Cron may not exist — that's fine\n }\n }\n\n return { removed, isOpenClaw: true };\n}\n\nexport function getSyndicateCronStatus(\n subdomain: string,\n testnet: boolean,\n): CronStatus {\n if (!isOpenClaw()) {\n return { isOpenClaw: false, crons: [] };\n }\n\n const prefix = cronName(subdomain, testnet);\n const all = listCronDetails();\n const matching = all.filter((c) => c.name.startsWith(prefix));\n\n return { isOpenClaw: true, crons: matching };\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.js
CHANGED
|
@@ -2515,7 +2515,7 @@ async function loadXmtp() {
|
|
|
2515
2515
|
return import("./xmtp-HSOIJAUU.js");
|
|
2516
2516
|
}
|
|
2517
2517
|
async function loadCron() {
|
|
2518
|
-
return import("./cron-
|
|
2518
|
+
return import("./cron-SKYKVZ6K.js");
|
|
2519
2519
|
}
|
|
2520
2520
|
var G3 = chalk7.green;
|
|
2521
2521
|
var W3 = chalk7.white;
|
|
@@ -3025,14 +3025,16 @@ syndicate.command("requests").description("View pending join requests for a synd
|
|
|
3025
3025
|
try {
|
|
3026
3026
|
let creatorAddress;
|
|
3027
3027
|
let subdomain;
|
|
3028
|
+
let syndicateVault;
|
|
3028
3029
|
if (opts.subdomain) {
|
|
3029
3030
|
const syndicateInfo = await resolveSyndicate(opts.subdomain);
|
|
3030
3031
|
creatorAddress = syndicateInfo.creator;
|
|
3031
3032
|
subdomain = opts.subdomain;
|
|
3033
|
+
syndicateVault = syndicateInfo.vault;
|
|
3032
3034
|
} else {
|
|
3033
3035
|
resolveVault(opts);
|
|
3034
|
-
|
|
3035
|
-
const syndicateInfo = await resolveVaultSyndicate(
|
|
3036
|
+
syndicateVault = getVaultAddress();
|
|
3037
|
+
const syndicateInfo = await resolveVaultSyndicate(syndicateVault);
|
|
3036
3038
|
creatorAddress = syndicateInfo.creator;
|
|
3037
3039
|
subdomain = syndicateInfo.subdomain;
|
|
3038
3040
|
}
|
|
@@ -3046,9 +3048,11 @@ syndicate.command("requests").description("View pending join requests for a synd
|
|
|
3046
3048
|
queryJoinRequests(creatorAddress),
|
|
3047
3049
|
queryApprovals(creatorAddress)
|
|
3048
3050
|
]);
|
|
3049
|
-
const
|
|
3051
|
+
const approvedKeys = new Set(
|
|
3052
|
+
approvals.filter((a) => a.decoded.vault.toLowerCase() === syndicateVault.toLowerCase()).map((a) => a.decoded.agentId.toString())
|
|
3053
|
+
);
|
|
3050
3054
|
const requests = allRequests.filter(
|
|
3051
|
-
(r) => !
|
|
3055
|
+
(r) => !approvedKeys.has(r.decoded.agentId.toString()) && r.decoded.vault.toLowerCase() === syndicateVault.toLowerCase()
|
|
3052
3056
|
);
|
|
3053
3057
|
spinner.stop();
|
|
3054
3058
|
if (requests.length === 0) {
|
|
@@ -3334,7 +3338,7 @@ try {
|
|
|
3334
3338
|
process.exit(1);
|
|
3335
3339
|
});
|
|
3336
3340
|
}
|
|
3337
|
-
var { registerSessionCommands } = await import("./session-
|
|
3341
|
+
var { registerSessionCommands } = await import("./session-UPNQXTMI.js");
|
|
3338
3342
|
registerSessionCommands(program);
|
|
3339
3343
|
registerVeniceCommands(program);
|
|
3340
3344
|
registerAllowanceCommands(program);
|