@ainyc/canonry 1.46.0 → 1.48.0
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 +93 -441
- package/assets/agent-workspace/AGENTS.md +89 -0
- package/assets/agent-workspace/SOUL.md +54 -0
- package/assets/agent-workspace/USER.md +23 -0
- package/assets/agent-workspace/skills/aero/SKILL.md +42 -0
- package/assets/agent-workspace/skills/aero/references/memory-patterns.md +37 -0
- package/assets/agent-workspace/skills/aero/references/orchestration.md +52 -0
- package/assets/agent-workspace/skills/aero/references/regression-playbook.md +34 -0
- package/assets/agent-workspace/skills/aero/references/reporting.md +67 -0
- package/assets/agent-workspace/skills/canonry-setup/SKILL.md +274 -0
- package/assets/agent-workspace/skills/canonry-setup/references/aeo-analysis.md +130 -0
- package/assets/agent-workspace/skills/canonry-setup/references/canonry-cli.md +349 -0
- package/assets/agent-workspace/skills/canonry-setup/references/indexing.md +155 -0
- package/assets/agent-workspace/skills/canonry-setup/references/wordpress-integration.md +57 -0
- package/assets/assets/{index-Cxg_4UWs.js → index-CVk23m8J.js} +1 -1
- package/assets/index.html +1 -1
- package/dist/{chunk-22RIKNII.js → chunk-25QLMK4F.js} +803 -138
- package/dist/cli.js +457 -87
- package/dist/index.d.ts +11 -0
- package/dist/index.js +1 -1
- package/package.json +7 -7
package/dist/cli.js
CHANGED
|
@@ -1,34 +1,53 @@
|
|
|
1
1
|
#!/usr/bin/env node --import tsx
|
|
2
2
|
import {
|
|
3
|
+
AGENT_WEBHOOK_EVENTS,
|
|
4
|
+
AgentManager,
|
|
5
|
+
CliError,
|
|
6
|
+
EXIT_SYSTEM_ERROR,
|
|
7
|
+
EXIT_USER_ERROR,
|
|
3
8
|
ProviderNames,
|
|
4
9
|
RunKinds,
|
|
10
|
+
attachAgentWebhookDirect,
|
|
11
|
+
buildAgentWebhookUrl,
|
|
5
12
|
computeCompetitorOverlap,
|
|
6
13
|
configExists,
|
|
14
|
+
configureOpenClawGateway,
|
|
7
15
|
createServer,
|
|
16
|
+
detectOpenClaw,
|
|
8
17
|
determineAnswerMentioned,
|
|
9
18
|
determineCitationState,
|
|
10
19
|
effectiveDomains,
|
|
11
20
|
extractRecommendedCompetitors,
|
|
12
21
|
formatAuditFactorScore,
|
|
22
|
+
getAeroStateDir,
|
|
13
23
|
getConfigDir,
|
|
14
24
|
getConfigPath,
|
|
15
25
|
getOrCreateAnonymousId,
|
|
26
|
+
initializeOpenClawProfile,
|
|
27
|
+
installOpenClaw,
|
|
16
28
|
isFirstRun,
|
|
17
29
|
isTelemetryEnabled,
|
|
18
30
|
loadConfig,
|
|
19
31
|
notificationEventSchema,
|
|
32
|
+
printCliError,
|
|
33
|
+
providerEnvVar,
|
|
20
34
|
providerQuotaPolicySchema,
|
|
21
35
|
reparseStoredResult,
|
|
22
36
|
reparseStoredResult2,
|
|
23
37
|
reparseStoredResult3,
|
|
24
38
|
reparseStoredResult4,
|
|
39
|
+
resolveAgentCredentials,
|
|
25
40
|
resolveProviderInput,
|
|
26
41
|
saveConfig,
|
|
27
42
|
saveConfigPatch,
|
|
43
|
+
seedWorkspace,
|
|
28
44
|
setGoogleAuthConfig,
|
|
45
|
+
setOpenClawModel,
|
|
29
46
|
showFirstRunNotice,
|
|
30
|
-
trackEvent
|
|
31
|
-
|
|
47
|
+
trackEvent,
|
|
48
|
+
usageError,
|
|
49
|
+
writeAgentEnv
|
|
50
|
+
} from "./chunk-25QLMK4F.js";
|
|
32
51
|
import {
|
|
33
52
|
apiKeys,
|
|
34
53
|
competitors,
|
|
@@ -43,84 +62,14 @@ import {
|
|
|
43
62
|
// src/cli.ts
|
|
44
63
|
import { pathToFileURL } from "url";
|
|
45
64
|
|
|
46
|
-
// src/cli-error.ts
|
|
47
|
-
var EXIT_USER_ERROR = 1;
|
|
48
|
-
var EXIT_SYSTEM_ERROR = 2;
|
|
49
|
-
var CliError = class extends Error {
|
|
50
|
-
code;
|
|
51
|
-
displayMessage;
|
|
52
|
-
details;
|
|
53
|
-
exitCode;
|
|
54
|
-
constructor(options) {
|
|
55
|
-
super(options.message);
|
|
56
|
-
this.name = "CliError";
|
|
57
|
-
this.code = options.code;
|
|
58
|
-
this.displayMessage = options.displayMessage;
|
|
59
|
-
this.details = options.details;
|
|
60
|
-
this.exitCode = options.exitCode ?? EXIT_USER_ERROR;
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
function usageError(displayMessage, options) {
|
|
64
|
-
const firstLine = displayMessage.split("\n", 1)[0] ?? "Error: invalid command usage";
|
|
65
|
-
return new CliError({
|
|
66
|
-
code: "CLI_USAGE_ERROR",
|
|
67
|
-
message: options?.message ?? firstLine.replace(/^Error:\s*/, ""),
|
|
68
|
-
displayMessage,
|
|
69
|
-
details: options?.details
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
function printCliError(err, format) {
|
|
73
|
-
if (format === "json") {
|
|
74
|
-
if (err instanceof CliError) {
|
|
75
|
-
console.error(
|
|
76
|
-
JSON.stringify(
|
|
77
|
-
{
|
|
78
|
-
error: {
|
|
79
|
-
code: err.code,
|
|
80
|
-
message: err.message,
|
|
81
|
-
...err.details ? { details: err.details } : {}
|
|
82
|
-
}
|
|
83
|
-
},
|
|
84
|
-
null,
|
|
85
|
-
2
|
|
86
|
-
)
|
|
87
|
-
);
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
const message = err instanceof Error ? err.message : "An unexpected error occurred";
|
|
91
|
-
console.error(
|
|
92
|
-
JSON.stringify(
|
|
93
|
-
{
|
|
94
|
-
error: {
|
|
95
|
-
code: "CLI_ERROR",
|
|
96
|
-
message
|
|
97
|
-
}
|
|
98
|
-
},
|
|
99
|
-
null,
|
|
100
|
-
2
|
|
101
|
-
)
|
|
102
|
-
);
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
if (err instanceof CliError && err.displayMessage) {
|
|
106
|
-
console.error(err.displayMessage);
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
if (err instanceof Error) {
|
|
110
|
-
console.error(`Error: ${err.message}`);
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
113
|
-
console.error("An unexpected error occurred");
|
|
114
|
-
}
|
|
115
|
-
|
|
116
65
|
// src/cli-dispatch.ts
|
|
117
66
|
import { parseArgs } from "util";
|
|
118
67
|
function commandId(spec) {
|
|
119
68
|
return spec.path.join(".");
|
|
120
69
|
}
|
|
121
|
-
function matchesPath(args,
|
|
122
|
-
if (args.length <
|
|
123
|
-
return
|
|
70
|
+
function matchesPath(args, path7) {
|
|
71
|
+
if (args.length < path7.length) return false;
|
|
72
|
+
return path7.every((segment, index) => args[index] === segment);
|
|
124
73
|
}
|
|
125
74
|
function withFormatOption(options) {
|
|
126
75
|
if (!options) {
|
|
@@ -613,9 +562,9 @@ var ApiClient = class {
|
|
|
613
562
|
}
|
|
614
563
|
return this.probePromise;
|
|
615
564
|
}
|
|
616
|
-
async request(method,
|
|
565
|
+
async request(method, path7, body) {
|
|
617
566
|
await this.probeBasePath();
|
|
618
|
-
const url = `${this.baseUrl}${
|
|
567
|
+
const url = `${this.baseUrl}${path7}`;
|
|
619
568
|
const serializedBody = body != null ? JSON.stringify(body) : void 0;
|
|
620
569
|
const headers = {
|
|
621
570
|
"Authorization": `Bearer ${this.apiKey}`,
|
|
@@ -3523,7 +3472,9 @@ var EVENT_DESCRIPTIONS = {
|
|
|
3523
3472
|
"citation.lost": "A keyword lost its citation status",
|
|
3524
3473
|
"citation.gained": "A keyword gained citation status",
|
|
3525
3474
|
"run.completed": "A visibility run completed successfully",
|
|
3526
|
-
"run.failed": "A visibility run failed"
|
|
3475
|
+
"run.failed": "A visibility run failed",
|
|
3476
|
+
"insight.critical": "A critical-severity insight was generated",
|
|
3477
|
+
"insight.high": "A high-severity insight was generated"
|
|
3527
3478
|
};
|
|
3528
3479
|
function listEvents(format) {
|
|
3529
3480
|
const events = notificationEventSchema.options;
|
|
@@ -6142,6 +6093,15 @@ var DEFAULT_QUOTA = {
|
|
|
6142
6093
|
maxRequestsPerMinute: 10,
|
|
6143
6094
|
maxRequestsPerDay: 500
|
|
6144
6095
|
};
|
|
6096
|
+
var DEFAULT_AGENT_MODELS = {
|
|
6097
|
+
anthropic: "anthropic/claude-sonnet-4-6",
|
|
6098
|
+
openai: "openai/gpt-4o",
|
|
6099
|
+
openrouter: "openrouter/anthropic/claude-sonnet-4-6",
|
|
6100
|
+
groq: "groq/llama-4-scout-17b",
|
|
6101
|
+
google: "google/gemini-2.5-flash",
|
|
6102
|
+
mistral: "mistral/mistral-large-latest",
|
|
6103
|
+
xai: "xai/grok-2"
|
|
6104
|
+
};
|
|
6145
6105
|
async function initCommand(opts) {
|
|
6146
6106
|
const format = opts?.format ?? "text";
|
|
6147
6107
|
if (format !== "json") {
|
|
@@ -6154,11 +6114,11 @@ async function initCommand(opts) {
|
|
|
6154
6114
|
reason: "config_exists",
|
|
6155
6115
|
configPath: getConfigPath()
|
|
6156
6116
|
}, null, 2));
|
|
6157
|
-
return;
|
|
6117
|
+
return void 0;
|
|
6158
6118
|
}
|
|
6159
6119
|
console.log(`Config already exists at ${getConfigPath()}`);
|
|
6160
6120
|
console.log('To reinitialize, run "canonry init --force".');
|
|
6161
|
-
return;
|
|
6121
|
+
return void 0;
|
|
6162
6122
|
}
|
|
6163
6123
|
const configDir = getConfigDir();
|
|
6164
6124
|
if (!fs6.existsSync(configDir)) {
|
|
@@ -6313,6 +6273,29 @@ Config saved to ${getConfigPath()}`);
|
|
|
6313
6273
|
console.log(`API key: ${rawApiKey}`);
|
|
6314
6274
|
console.log(`Providers: ${providerNames.join(", ")}`);
|
|
6315
6275
|
}
|
|
6276
|
+
let agentLLM;
|
|
6277
|
+
const agentProvider = opts?.agentProvider;
|
|
6278
|
+
const agentKey = opts?.agentKey;
|
|
6279
|
+
const agentModel = opts?.agentModel;
|
|
6280
|
+
if (agentProvider || agentKey || agentModel) {
|
|
6281
|
+
const provider = agentProvider ?? "anthropic";
|
|
6282
|
+
agentLLM = {
|
|
6283
|
+
provider,
|
|
6284
|
+
key: agentKey,
|
|
6285
|
+
model: agentModel ?? DEFAULT_AGENT_MODELS[provider]
|
|
6286
|
+
};
|
|
6287
|
+
} else if (!nonInteractive) {
|
|
6288
|
+
console.log("\nConfigure agent LLM (the model that powers the agent):");
|
|
6289
|
+
console.log("Supported providers: anthropic, openai, openrouter, groq, mistral, xai, google, cerebras\n");
|
|
6290
|
+
const provider = await prompt("Provider [anthropic]: ") || "anthropic";
|
|
6291
|
+
const key = await prompt("API key (press Enter to skip): ");
|
|
6292
|
+
if (key) {
|
|
6293
|
+
const defaultModel = DEFAULT_AGENT_MODELS[provider];
|
|
6294
|
+
const modelText = defaultModel ? `Model [${defaultModel}]: ` : "Model: ";
|
|
6295
|
+
const model = await prompt(modelText) || defaultModel;
|
|
6296
|
+
agentLLM = { provider, key, model };
|
|
6297
|
+
}
|
|
6298
|
+
}
|
|
6316
6299
|
if (format !== "json") {
|
|
6317
6300
|
showFirstRunNotice();
|
|
6318
6301
|
console.log('Run "canonry serve" to start the server.');
|
|
@@ -6321,6 +6304,7 @@ Config saved to ${getConfigPath()}`);
|
|
|
6321
6304
|
providerCount: providerNames.length,
|
|
6322
6305
|
providers: providerNames
|
|
6323
6306
|
});
|
|
6307
|
+
return agentLLM;
|
|
6324
6308
|
}
|
|
6325
6309
|
|
|
6326
6310
|
// src/commands/serve.ts
|
|
@@ -6884,8 +6868,8 @@ async function wordpressSetMeta(project, body) {
|
|
|
6884
6868
|
}
|
|
6885
6869
|
async function wordpressBulkSetMeta(project, opts) {
|
|
6886
6870
|
const fs8 = await import("fs/promises");
|
|
6887
|
-
const
|
|
6888
|
-
const filePath =
|
|
6871
|
+
const path7 = await import("path");
|
|
6872
|
+
const filePath = path7.resolve(opts.from);
|
|
6889
6873
|
let raw;
|
|
6890
6874
|
try {
|
|
6891
6875
|
raw = await fs8.readFile(filePath, "utf8");
|
|
@@ -6986,9 +6970,9 @@ async function wordpressSetSchema(project, body) {
|
|
|
6986
6970
|
}
|
|
6987
6971
|
async function wordpressSchemaDeploy(project, opts) {
|
|
6988
6972
|
const fs8 = await import("fs/promises");
|
|
6989
|
-
const
|
|
6973
|
+
const path7 = await import("path");
|
|
6990
6974
|
const yaml = await import("yaml").catch(() => null);
|
|
6991
|
-
const filePath =
|
|
6975
|
+
const filePath = path7.resolve(opts.profile);
|
|
6992
6976
|
let raw;
|
|
6993
6977
|
try {
|
|
6994
6978
|
raw = await fs8.readFile(filePath, "utf8");
|
|
@@ -7097,9 +7081,9 @@ async function wordpressOnboard(project, opts) {
|
|
|
7097
7081
|
let profileData;
|
|
7098
7082
|
if (opts.profile) {
|
|
7099
7083
|
const fs8 = await import("fs/promises");
|
|
7100
|
-
const
|
|
7084
|
+
const path7 = await import("path");
|
|
7101
7085
|
const yaml = await import("yaml").catch(() => null);
|
|
7102
|
-
const filePath =
|
|
7086
|
+
const filePath = path7.resolve(opts.profile);
|
|
7103
7087
|
let raw;
|
|
7104
7088
|
try {
|
|
7105
7089
|
raw = await fs8.readFile(filePath, "utf8");
|
|
@@ -7683,6 +7667,391 @@ var WORDPRESS_CLI_COMMANDS = [
|
|
|
7683
7667
|
}
|
|
7684
7668
|
];
|
|
7685
7669
|
|
|
7670
|
+
// src/commands/agent.ts
|
|
7671
|
+
import path6 from "path";
|
|
7672
|
+
function resolveStateDir(opts) {
|
|
7673
|
+
if (opts?.stateDir) return opts.stateDir;
|
|
7674
|
+
try {
|
|
7675
|
+
const config = loadConfig();
|
|
7676
|
+
const profile = config.agent?.profile ?? "aero";
|
|
7677
|
+
return getAeroStateDir(profile);
|
|
7678
|
+
} catch {
|
|
7679
|
+
return getAeroStateDir();
|
|
7680
|
+
}
|
|
7681
|
+
}
|
|
7682
|
+
function resolveConfig() {
|
|
7683
|
+
try {
|
|
7684
|
+
return loadConfig().agent ?? {};
|
|
7685
|
+
} catch {
|
|
7686
|
+
return {};
|
|
7687
|
+
}
|
|
7688
|
+
}
|
|
7689
|
+
async function agentStatus(opts) {
|
|
7690
|
+
const stateDir = resolveStateDir(opts);
|
|
7691
|
+
const config = resolveConfig();
|
|
7692
|
+
const mgr = new AgentManager(config, stateDir);
|
|
7693
|
+
const status = mgr.status();
|
|
7694
|
+
if (opts?.format === "json") {
|
|
7695
|
+
console.log(JSON.stringify(status, null, 2));
|
|
7696
|
+
return;
|
|
7697
|
+
}
|
|
7698
|
+
if (status.state === "running") {
|
|
7699
|
+
console.log(`Agent: running (PID ${status.pid}, port ${status.port})`);
|
|
7700
|
+
if (status.startedAt) {
|
|
7701
|
+
console.log(`Started: ${status.startedAt}`);
|
|
7702
|
+
}
|
|
7703
|
+
} else {
|
|
7704
|
+
console.log("Agent: stopped");
|
|
7705
|
+
}
|
|
7706
|
+
}
|
|
7707
|
+
async function agentStart(opts) {
|
|
7708
|
+
const stateDir = resolveStateDir(opts);
|
|
7709
|
+
const config = resolveConfig();
|
|
7710
|
+
const mgr = new AgentManager(config, stateDir);
|
|
7711
|
+
await mgr.start();
|
|
7712
|
+
const status = mgr.status();
|
|
7713
|
+
if (opts?.format === "json") {
|
|
7714
|
+
console.log(JSON.stringify(status, null, 2));
|
|
7715
|
+
} else {
|
|
7716
|
+
console.log(`Agent started (PID ${status.pid}, port ${status.port})`);
|
|
7717
|
+
}
|
|
7718
|
+
}
|
|
7719
|
+
async function agentStop(opts) {
|
|
7720
|
+
const stateDir = resolveStateDir(opts);
|
|
7721
|
+
const config = resolveConfig();
|
|
7722
|
+
const mgr = new AgentManager(config, stateDir);
|
|
7723
|
+
await mgr.stop();
|
|
7724
|
+
if (opts?.format === "json") {
|
|
7725
|
+
console.log(JSON.stringify({ state: "stopped" }, null, 2));
|
|
7726
|
+
} else {
|
|
7727
|
+
console.log("Agent stopped");
|
|
7728
|
+
}
|
|
7729
|
+
}
|
|
7730
|
+
async function agentReset(opts) {
|
|
7731
|
+
const stateDir = resolveStateDir(opts);
|
|
7732
|
+
const config = resolveConfig();
|
|
7733
|
+
const mgr = new AgentManager(config, stateDir);
|
|
7734
|
+
await mgr.reset();
|
|
7735
|
+
if (opts?.format === "json") {
|
|
7736
|
+
console.log(JSON.stringify({ state: "reset" }, null, 2));
|
|
7737
|
+
} else {
|
|
7738
|
+
console.log('Agent reset \u2014 workspace wiped. Run "canonry agent setup" to re-initialize.');
|
|
7739
|
+
}
|
|
7740
|
+
}
|
|
7741
|
+
async function agentSetup(opts) {
|
|
7742
|
+
const isJson = opts?.format === "json";
|
|
7743
|
+
let agentLLM;
|
|
7744
|
+
if (!configExists()) {
|
|
7745
|
+
const initOpts = {
|
|
7746
|
+
geminiKey: opts?.geminiKey,
|
|
7747
|
+
openaiKey: opts?.openaiKey,
|
|
7748
|
+
claudeKey: opts?.claudeKey,
|
|
7749
|
+
perplexityKey: opts?.perplexityKey,
|
|
7750
|
+
localUrl: opts?.localUrl,
|
|
7751
|
+
localModel: opts?.localModel,
|
|
7752
|
+
localKey: opts?.localKey,
|
|
7753
|
+
googleClientId: opts?.googleClientId,
|
|
7754
|
+
googleClientSecret: opts?.googleClientSecret,
|
|
7755
|
+
agentProvider: opts?.agentProvider,
|
|
7756
|
+
agentKey: opts?.agentKey,
|
|
7757
|
+
agentModel: opts?.agentModel
|
|
7758
|
+
};
|
|
7759
|
+
if (isJson) {
|
|
7760
|
+
agentLLM = await suppressStdout(() => initCommand(initOpts)) ?? void 0;
|
|
7761
|
+
} else {
|
|
7762
|
+
agentLLM = await initCommand(initOpts) ?? void 0;
|
|
7763
|
+
}
|
|
7764
|
+
}
|
|
7765
|
+
const existingConfig = resolveConfig();
|
|
7766
|
+
let detection = await detectOpenClaw(existingConfig);
|
|
7767
|
+
if (!detection.found) {
|
|
7768
|
+
detection = await autoInstallOrFail(opts?.format);
|
|
7769
|
+
}
|
|
7770
|
+
const profile = existingConfig.profile ?? "aero";
|
|
7771
|
+
const gatewayPort = opts?.gatewayPort ?? existingConfig.gatewayPort ?? 3579;
|
|
7772
|
+
const stateDir = opts?.stateDir ?? getAeroStateDir(profile);
|
|
7773
|
+
saveConfigPatch({
|
|
7774
|
+
agent: {
|
|
7775
|
+
binary: detection.path,
|
|
7776
|
+
profile,
|
|
7777
|
+
gatewayPort,
|
|
7778
|
+
autoStart: existingConfig.autoStart
|
|
7779
|
+
}
|
|
7780
|
+
});
|
|
7781
|
+
initializeOpenClawProfile(detection.path, profile, path6.join(stateDir, "workspace"));
|
|
7782
|
+
configureOpenClawGateway(detection.path, profile, gatewayPort);
|
|
7783
|
+
const creds = agentLLM ?? resolveAgentCredentials({
|
|
7784
|
+
agentProvider: opts?.agentProvider,
|
|
7785
|
+
agentKey: opts?.agentKey,
|
|
7786
|
+
agentModel: opts?.agentModel,
|
|
7787
|
+
stateDir
|
|
7788
|
+
});
|
|
7789
|
+
if (creds.key) {
|
|
7790
|
+
writeAgentEnv(stateDir, providerEnvVar(creds.provider), creds.key);
|
|
7791
|
+
if (opts?.format !== "json") {
|
|
7792
|
+
console.log(`Agent LLM: ${creds.provider} credentials configured`);
|
|
7793
|
+
}
|
|
7794
|
+
}
|
|
7795
|
+
if (creds.model) {
|
|
7796
|
+
setOpenClawModel(detection.path, profile, creds.model);
|
|
7797
|
+
if (opts?.format !== "json") {
|
|
7798
|
+
console.log(`Agent model: ${creds.model}`);
|
|
7799
|
+
}
|
|
7800
|
+
}
|
|
7801
|
+
seedWorkspace(stateDir);
|
|
7802
|
+
const attachSummary = await attachAgentWebhookToAllProjects(gatewayPort);
|
|
7803
|
+
if (opts?.format === "json") {
|
|
7804
|
+
console.log(JSON.stringify({
|
|
7805
|
+
state: "configured",
|
|
7806
|
+
binary: detection.path,
|
|
7807
|
+
version: detection.version,
|
|
7808
|
+
profile,
|
|
7809
|
+
gatewayPort,
|
|
7810
|
+
stateDir,
|
|
7811
|
+
attached: attachSummary
|
|
7812
|
+
}, null, 2));
|
|
7813
|
+
} else {
|
|
7814
|
+
console.log(`OpenClaw: ${detection.path} (${detection.version})`);
|
|
7815
|
+
console.log(`Profile: ${profile}`);
|
|
7816
|
+
console.log(`Gateway port: ${gatewayPort}`);
|
|
7817
|
+
console.log(`State dir: ${stateDir}`);
|
|
7818
|
+
if (attachSummary.attached > 0 || attachSummary.alreadyAttached > 0) {
|
|
7819
|
+
console.log(
|
|
7820
|
+
`Agent webhook: ${attachSummary.attached} attached, ${attachSummary.alreadyAttached} already present (via ${attachSummary.path})`
|
|
7821
|
+
);
|
|
7822
|
+
}
|
|
7823
|
+
console.log("Agent setup complete.");
|
|
7824
|
+
}
|
|
7825
|
+
}
|
|
7826
|
+
async function attachAgentWebhookToAllProjects(gatewayPort) {
|
|
7827
|
+
let config;
|
|
7828
|
+
try {
|
|
7829
|
+
config = loadConfig();
|
|
7830
|
+
} catch {
|
|
7831
|
+
return { path: "skipped", attached: 0, alreadyAttached: 0 };
|
|
7832
|
+
}
|
|
7833
|
+
try {
|
|
7834
|
+
const client = createApiClient();
|
|
7835
|
+
const projectList = await client.listProjects();
|
|
7836
|
+
const agentUrl = buildAgentWebhookUrl(gatewayPort);
|
|
7837
|
+
let attached2 = 0;
|
|
7838
|
+
let alreadyAttached2 = 0;
|
|
7839
|
+
for (const project of projectList) {
|
|
7840
|
+
const existing = await client.listNotifications(project.name);
|
|
7841
|
+
if (existing.some((n) => n.source === "agent")) {
|
|
7842
|
+
alreadyAttached2++;
|
|
7843
|
+
continue;
|
|
7844
|
+
}
|
|
7845
|
+
await client.createNotification(project.name, {
|
|
7846
|
+
channel: "webhook",
|
|
7847
|
+
url: agentUrl,
|
|
7848
|
+
events: [...AGENT_WEBHOOK_EVENTS],
|
|
7849
|
+
source: "agent"
|
|
7850
|
+
});
|
|
7851
|
+
attached2++;
|
|
7852
|
+
}
|
|
7853
|
+
return { path: "api", attached: attached2, alreadyAttached: alreadyAttached2 };
|
|
7854
|
+
} catch (err) {
|
|
7855
|
+
if (!isConnectionError(err)) throw err;
|
|
7856
|
+
}
|
|
7857
|
+
const db = createClient(config.database);
|
|
7858
|
+
migrate(db);
|
|
7859
|
+
const rows = db.select({ id: projects.id }).from(projects).all();
|
|
7860
|
+
let attached = 0;
|
|
7861
|
+
let alreadyAttached = 0;
|
|
7862
|
+
for (const row of rows) {
|
|
7863
|
+
const result = attachAgentWebhookDirect(db, row.id, gatewayPort);
|
|
7864
|
+
if (result === "attached") attached++;
|
|
7865
|
+
else alreadyAttached++;
|
|
7866
|
+
}
|
|
7867
|
+
return { path: "db", attached, alreadyAttached };
|
|
7868
|
+
}
|
|
7869
|
+
function isConnectionError(err) {
|
|
7870
|
+
if (!(err instanceof Error)) return false;
|
|
7871
|
+
const msg = err.message.toLowerCase();
|
|
7872
|
+
const code = err.code ?? "";
|
|
7873
|
+
return code === "CONNECTION_ERROR" || code === "ECONNREFUSED" || code === "ENOTFOUND" || msg.includes("could not connect") || msg.includes("econnrefused") || msg.includes("fetch failed") || msg.includes("connection refused");
|
|
7874
|
+
}
|
|
7875
|
+
async function agentAttach(opts) {
|
|
7876
|
+
const config = loadConfig();
|
|
7877
|
+
const gatewayPort = config.agent?.gatewayPort ?? 3579;
|
|
7878
|
+
const agentUrl = buildAgentWebhookUrl(gatewayPort);
|
|
7879
|
+
const client = createApiClient();
|
|
7880
|
+
const existing = await client.listNotifications(opts.project);
|
|
7881
|
+
const hasAgent = existing.some((n) => n.source === "agent");
|
|
7882
|
+
if (hasAgent) {
|
|
7883
|
+
if (opts.format === "json") {
|
|
7884
|
+
console.log(JSON.stringify({ status: "already-attached", project: opts.project }));
|
|
7885
|
+
} else {
|
|
7886
|
+
console.log(`Agent webhook already attached to "${opts.project}"`);
|
|
7887
|
+
}
|
|
7888
|
+
return;
|
|
7889
|
+
}
|
|
7890
|
+
const result = await client.createNotification(opts.project, {
|
|
7891
|
+
channel: "webhook",
|
|
7892
|
+
url: agentUrl,
|
|
7893
|
+
events: [...AGENT_WEBHOOK_EVENTS],
|
|
7894
|
+
source: "agent"
|
|
7895
|
+
});
|
|
7896
|
+
if (opts.format === "json") {
|
|
7897
|
+
console.log(JSON.stringify({ status: "attached", project: opts.project, notificationId: result.id }));
|
|
7898
|
+
} else {
|
|
7899
|
+
console.log(`Agent webhook attached to "${opts.project}"`);
|
|
7900
|
+
}
|
|
7901
|
+
}
|
|
7902
|
+
async function agentDetach(opts) {
|
|
7903
|
+
const client = createApiClient();
|
|
7904
|
+
const existing = await client.listNotifications(opts.project);
|
|
7905
|
+
const agentNotif = existing.find((n) => n.source === "agent");
|
|
7906
|
+
if (!agentNotif) {
|
|
7907
|
+
if (opts.format === "json") {
|
|
7908
|
+
console.log(JSON.stringify({ status: "not-attached", project: opts.project }));
|
|
7909
|
+
} else {
|
|
7910
|
+
console.log(`No agent webhook found on "${opts.project}"`);
|
|
7911
|
+
}
|
|
7912
|
+
return;
|
|
7913
|
+
}
|
|
7914
|
+
await client.deleteNotification(opts.project, agentNotif.id);
|
|
7915
|
+
if (opts.format === "json") {
|
|
7916
|
+
console.log(JSON.stringify({ status: "detached", project: opts.project }));
|
|
7917
|
+
} else {
|
|
7918
|
+
console.log(`Agent webhook detached from "${opts.project}"`);
|
|
7919
|
+
}
|
|
7920
|
+
}
|
|
7921
|
+
async function autoInstallOrFail(format) {
|
|
7922
|
+
if (format !== "json") {
|
|
7923
|
+
console.log("OpenClaw not found, installing via npm...");
|
|
7924
|
+
}
|
|
7925
|
+
const install = await installOpenClaw({ silent: format === "json" });
|
|
7926
|
+
if (!install.success) {
|
|
7927
|
+
const msg = `Failed to install OpenClaw: ${install.error}`;
|
|
7928
|
+
if (format === "json") {
|
|
7929
|
+
console.error(JSON.stringify({ error: { code: "AGENT_INSTALL_FAILED", message: msg } }));
|
|
7930
|
+
} else {
|
|
7931
|
+
console.error(msg);
|
|
7932
|
+
}
|
|
7933
|
+
process.exitCode = 1;
|
|
7934
|
+
throw new Error(msg);
|
|
7935
|
+
}
|
|
7936
|
+
if (format !== "json") {
|
|
7937
|
+
console.log(`Installed OpenClaw ${install.detection.version}`);
|
|
7938
|
+
}
|
|
7939
|
+
return install.detection;
|
|
7940
|
+
}
|
|
7941
|
+
async function suppressStdout(fn) {
|
|
7942
|
+
const original = console.log;
|
|
7943
|
+
console.log = () => {
|
|
7944
|
+
};
|
|
7945
|
+
try {
|
|
7946
|
+
return await fn();
|
|
7947
|
+
} finally {
|
|
7948
|
+
console.log = original;
|
|
7949
|
+
}
|
|
7950
|
+
}
|
|
7951
|
+
|
|
7952
|
+
// src/cli-commands/agent.ts
|
|
7953
|
+
var AGENT_CLI_COMMANDS = [
|
|
7954
|
+
{
|
|
7955
|
+
path: ["agent", "status"],
|
|
7956
|
+
usage: "canonry agent status [--format json]",
|
|
7957
|
+
options: {},
|
|
7958
|
+
run: async (input) => {
|
|
7959
|
+
await agentStatus({ format: input.format });
|
|
7960
|
+
}
|
|
7961
|
+
},
|
|
7962
|
+
{
|
|
7963
|
+
path: ["agent", "start"],
|
|
7964
|
+
usage: "canonry agent start [--format json]",
|
|
7965
|
+
options: {},
|
|
7966
|
+
run: async (input) => {
|
|
7967
|
+
await agentStart({ format: input.format });
|
|
7968
|
+
}
|
|
7969
|
+
},
|
|
7970
|
+
{
|
|
7971
|
+
path: ["agent", "stop"],
|
|
7972
|
+
usage: "canonry agent stop [--format json]",
|
|
7973
|
+
options: {},
|
|
7974
|
+
run: async (input) => {
|
|
7975
|
+
await agentStop({ format: input.format });
|
|
7976
|
+
}
|
|
7977
|
+
},
|
|
7978
|
+
{
|
|
7979
|
+
path: ["agent", "reset"],
|
|
7980
|
+
usage: "canonry agent reset [--format json]",
|
|
7981
|
+
options: {},
|
|
7982
|
+
run: async (input) => {
|
|
7983
|
+
await agentReset({ format: input.format });
|
|
7984
|
+
}
|
|
7985
|
+
},
|
|
7986
|
+
{
|
|
7987
|
+
path: ["agent", "attach"],
|
|
7988
|
+
usage: "canonry agent attach <project> [--format json]",
|
|
7989
|
+
options: {},
|
|
7990
|
+
run: async (input) => {
|
|
7991
|
+
const project = input.positionals[0];
|
|
7992
|
+
if (!project) {
|
|
7993
|
+
console.error("Usage: canonry agent attach <project>");
|
|
7994
|
+
process.exitCode = 1;
|
|
7995
|
+
return;
|
|
7996
|
+
}
|
|
7997
|
+
await agentAttach({ project, format: input.format });
|
|
7998
|
+
}
|
|
7999
|
+
},
|
|
8000
|
+
{
|
|
8001
|
+
path: ["agent", "detach"],
|
|
8002
|
+
usage: "canonry agent detach <project> [--format json]",
|
|
8003
|
+
options: {},
|
|
8004
|
+
run: async (input) => {
|
|
8005
|
+
const project = input.positionals[0];
|
|
8006
|
+
if (!project) {
|
|
8007
|
+
console.error("Usage: canonry agent detach <project>");
|
|
8008
|
+
process.exitCode = 1;
|
|
8009
|
+
return;
|
|
8010
|
+
}
|
|
8011
|
+
await agentDetach({ project, format: input.format });
|
|
8012
|
+
}
|
|
8013
|
+
},
|
|
8014
|
+
{
|
|
8015
|
+
path: ["agent", "setup"],
|
|
8016
|
+
usage: "canonry agent setup [--agent-provider <id>] [--agent-key <key>] [--agent-model <model>] [--gateway-port <port>] [--gemini-key <key>] [--openai-key <key>] [--claude-key <key>] [--perplexity-key <key>] [--format json]",
|
|
8017
|
+
options: {
|
|
8018
|
+
"agent-provider": stringOption(),
|
|
8019
|
+
"agent-key": stringOption(),
|
|
8020
|
+
"agent-model": stringOption(),
|
|
8021
|
+
"gateway-port": { type: "string" },
|
|
8022
|
+
"gemini-key": stringOption(),
|
|
8023
|
+
"openai-key": stringOption(),
|
|
8024
|
+
"claude-key": stringOption(),
|
|
8025
|
+
"perplexity-key": stringOption(),
|
|
8026
|
+
"local-url": stringOption(),
|
|
8027
|
+
"local-model": stringOption(),
|
|
8028
|
+
"local-key": stringOption(),
|
|
8029
|
+
"google-client-id": stringOption(),
|
|
8030
|
+
"google-client-secret": stringOption()
|
|
8031
|
+
},
|
|
8032
|
+
run: async (input) => {
|
|
8033
|
+
const portStr = input.values["gateway-port"];
|
|
8034
|
+
const gatewayPort = typeof portStr === "string" ? Number.parseInt(portStr, 10) : void 0;
|
|
8035
|
+
await agentSetup({
|
|
8036
|
+
agentProvider: getString(input.values, "agent-provider"),
|
|
8037
|
+
agentKey: getString(input.values, "agent-key"),
|
|
8038
|
+
agentModel: getString(input.values, "agent-model"),
|
|
8039
|
+
gatewayPort,
|
|
8040
|
+
format: input.format,
|
|
8041
|
+
geminiKey: getString(input.values, "gemini-key"),
|
|
8042
|
+
openaiKey: getString(input.values, "openai-key"),
|
|
8043
|
+
claudeKey: getString(input.values, "claude-key"),
|
|
8044
|
+
perplexityKey: getString(input.values, "perplexity-key"),
|
|
8045
|
+
localUrl: getString(input.values, "local-url"),
|
|
8046
|
+
localModel: getString(input.values, "local-model"),
|
|
8047
|
+
localKey: getString(input.values, "local-key"),
|
|
8048
|
+
googleClientId: getString(input.values, "google-client-id"),
|
|
8049
|
+
googleClientSecret: getString(input.values, "google-client-secret")
|
|
8050
|
+
});
|
|
8051
|
+
}
|
|
8052
|
+
}
|
|
8053
|
+
];
|
|
8054
|
+
|
|
7686
8055
|
// src/cli-commands.ts
|
|
7687
8056
|
var REGISTERED_CLI_COMMANDS = [
|
|
7688
8057
|
...BACKFILL_CLI_COMMANDS,
|
|
@@ -7701,7 +8070,8 @@ var REGISTERED_CLI_COMMANDS = [
|
|
|
7701
8070
|
...WORDPRESS_CLI_COMMANDS,
|
|
7702
8071
|
...CDP_CLI_COMMANDS,
|
|
7703
8072
|
...GA_CLI_COMMANDS,
|
|
7704
|
-
...INTELLIGENCE_CLI_COMMANDS
|
|
8073
|
+
...INTELLIGENCE_CLI_COMMANDS,
|
|
8074
|
+
...AGENT_CLI_COMMANDS
|
|
7705
8075
|
];
|
|
7706
8076
|
|
|
7707
8077
|
// src/cli.ts
|
package/dist/index.d.ts
CHANGED
|
@@ -73,6 +73,16 @@ interface WordpressConnectionConfigEntry {
|
|
|
73
73
|
interface WordpressConfigEntry {
|
|
74
74
|
connections?: WordpressConnectionConfigEntry[];
|
|
75
75
|
}
|
|
76
|
+
interface AgentConfigEntry {
|
|
77
|
+
/** Path to openclaw binary (auto-detected, persisted after bootstrap) */
|
|
78
|
+
binary?: string;
|
|
79
|
+
/** OpenClaw profile name (default: 'aero') */
|
|
80
|
+
profile?: string;
|
|
81
|
+
/** Start gateway automatically with `canonry serve` */
|
|
82
|
+
autoStart?: boolean;
|
|
83
|
+
/** Gateway port (persisted so restarts reuse same port) */
|
|
84
|
+
gatewayPort?: number;
|
|
85
|
+
}
|
|
76
86
|
interface CanonryConfig {
|
|
77
87
|
apiUrl: string;
|
|
78
88
|
publicUrl?: string;
|
|
@@ -93,6 +103,7 @@ interface CanonryConfig {
|
|
|
93
103
|
dashboardPasswordHash?: string;
|
|
94
104
|
telemetry?: boolean;
|
|
95
105
|
anonymousId?: string;
|
|
106
|
+
agent?: AgentConfigEntry;
|
|
96
107
|
}
|
|
97
108
|
declare function loadConfig(): CanonryConfig;
|
|
98
109
|
|