@dev.sail.money/sailor 1.1.0-61 → 1.1.0-62
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/package.json
CHANGED
|
@@ -43604,6 +43604,7 @@ async function runCommand(opts) {
|
|
|
43604
43604
|
for (const [k, v] of Object.entries(env)) {
|
|
43605
43605
|
if (v && !process.env[k]) process.env[k] = v;
|
|
43606
43606
|
}
|
|
43607
|
+
const runReason = opts.reason ?? process.env.SAIL_RUN_REASON ?? "manual";
|
|
43607
43608
|
const configChainId = readJsonFile(sailPath("config.json"))?.chainId;
|
|
43608
43609
|
const chainIdRaw = opts.chain != null ? String(opts.chain) : process.env.CHAIN_ID ?? env.CHAIN_ID ?? (configChainId != null ? String(configChainId) : void 0);
|
|
43609
43610
|
if (!chainIdRaw) {
|
|
@@ -43733,7 +43734,7 @@ Configure the chain in the SDK chain registry or set KERNEL_ADDRESS in .sail/.en
|
|
|
43733
43734
|
return d;
|
|
43734
43735
|
};
|
|
43735
43736
|
async function runTick() {
|
|
43736
|
-
appendActivity({ ts: nowIso(), actor: "agent", type: "tick_start", chainId });
|
|
43737
|
+
appendActivity({ ts: nowIso(), actor: "agent", type: "tick_start", chainId, reason: runReason });
|
|
43737
43738
|
let blockInfo = { number: 0n, timestamp: 0n };
|
|
43738
43739
|
try {
|
|
43739
43740
|
const block = await publicClient.getBlock();
|
|
@@ -43896,6 +43897,7 @@ Configure the chain in the SDK chain registry or set KERNEL_ADDRESS in .sail/.en
|
|
|
43896
43897
|
console.log(`Account: ${accountAddr}`);
|
|
43897
43898
|
console.log(`Chain: ${chainName2} (${chainId})`);
|
|
43898
43899
|
console.log(once ? "Mode: single tick (--once)" : `Interval: ${intervalSec}s`);
|
|
43900
|
+
console.log(`Reason: ${runReason}`);
|
|
43899
43901
|
console.log("Press Ctrl+C to stop");
|
|
43900
43902
|
console.log("");
|
|
43901
43903
|
writeAgentPid(chainId);
|
|
@@ -44042,6 +44044,110 @@ async function scan(options) {
|
|
|
44042
44044
|
);
|
|
44043
44045
|
}
|
|
44044
44046
|
|
|
44047
|
+
// src/commands/trigger.ts
|
|
44048
|
+
var import_node_child_process2 = require("node:child_process");
|
|
44049
|
+
var GH_API = "https://api.github.com";
|
|
44050
|
+
function parseRepoFromRemoteUrl(url) {
|
|
44051
|
+
const trimmed = url.trim().replace(/\.git$/, "");
|
|
44052
|
+
const m = trimmed.match(/github\.com[/:]([^/]+)\/([^/]+?)$/);
|
|
44053
|
+
return m ? `${m[1]}/${m[2]}` : null;
|
|
44054
|
+
}
|
|
44055
|
+
function resolveRepo(explicit) {
|
|
44056
|
+
if (explicit) {
|
|
44057
|
+
if (!/^[^/\s]+\/[^/\s]+$/.test(explicit)) {
|
|
44058
|
+
throw new Error(`--repo must be in "owner/repo" form \u2014 got: "${explicit}"`);
|
|
44059
|
+
}
|
|
44060
|
+
return explicit;
|
|
44061
|
+
}
|
|
44062
|
+
let url;
|
|
44063
|
+
try {
|
|
44064
|
+
url = (0, import_node_child_process2.execFileSync)("git", ["remote", "get-url", "origin"], {
|
|
44065
|
+
encoding: "utf-8",
|
|
44066
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
44067
|
+
}).trim();
|
|
44068
|
+
} catch {
|
|
44069
|
+
throw new Error(
|
|
44070
|
+
'Could not read the git remote "origin".\nPass --repo <owner/repo> explicitly.'
|
|
44071
|
+
);
|
|
44072
|
+
}
|
|
44073
|
+
const repo = parseRepoFromRemoteUrl(url);
|
|
44074
|
+
if (!repo) {
|
|
44075
|
+
throw new Error(
|
|
44076
|
+
`Could not parse a GitHub owner/repo from the origin remote (${url}).
|
|
44077
|
+
Pass --repo <owner/repo>.`
|
|
44078
|
+
);
|
|
44079
|
+
}
|
|
44080
|
+
return repo;
|
|
44081
|
+
}
|
|
44082
|
+
function resolveToken() {
|
|
44083
|
+
const token = process.env.SAIL_GH_TOKEN ?? process.env.GITHUB_TOKEN;
|
|
44084
|
+
if (!token) {
|
|
44085
|
+
throw new Error(
|
|
44086
|
+
"No GitHub token found. Set SAIL_GH_TOKEN (or GITHUB_TOKEN) in your environment.\nIt needs the `actions: write` permission on the repo (a fine-grained PAT or a GitHub App token).\nThe token is read from the environment only \u2014 it is never passed as an argument or stored."
|
|
44087
|
+
);
|
|
44088
|
+
}
|
|
44089
|
+
return token;
|
|
44090
|
+
}
|
|
44091
|
+
function buildDispatchRequest(args) {
|
|
44092
|
+
return {
|
|
44093
|
+
url: `${GH_API}/repos/${args.repo}/actions/workflows/${encodeURIComponent(args.workflow)}/dispatches`,
|
|
44094
|
+
method: "POST",
|
|
44095
|
+
headers: {
|
|
44096
|
+
Authorization: `Bearer ${args.token}`,
|
|
44097
|
+
Accept: "application/vnd.github+json",
|
|
44098
|
+
"X-GitHub-Api-Version": "2022-11-28",
|
|
44099
|
+
"User-Agent": "sailor-cli",
|
|
44100
|
+
"Content-Type": "application/json"
|
|
44101
|
+
},
|
|
44102
|
+
body: JSON.stringify({ ref: args.ref, inputs: { reason: args.reason } })
|
|
44103
|
+
};
|
|
44104
|
+
}
|
|
44105
|
+
async function triggerGithub(options = {}) {
|
|
44106
|
+
const workflow = options.workflow ?? "agent-tick.yml";
|
|
44107
|
+
const ref = options.ref ?? "main";
|
|
44108
|
+
const reason = options.reason ?? "manual";
|
|
44109
|
+
const repo = resolveRepo(options.repo);
|
|
44110
|
+
const token = resolveToken();
|
|
44111
|
+
const req = buildDispatchRequest({ repo, workflow, ref, reason, token });
|
|
44112
|
+
let res;
|
|
44113
|
+
try {
|
|
44114
|
+
res = await fetch(req.url, { method: req.method, headers: req.headers, body: req.body });
|
|
44115
|
+
} catch (err) {
|
|
44116
|
+
throw new Error(`Could not reach GitHub to fire workflow_dispatch: ${err.message}`);
|
|
44117
|
+
}
|
|
44118
|
+
if (res.status === 204) {
|
|
44119
|
+
emit(
|
|
44120
|
+
options.json,
|
|
44121
|
+
() => {
|
|
44122
|
+
console.log(`\u2713 Triggered ${workflow} on ${repo}@${ref}`);
|
|
44123
|
+
console.log(` reason: ${reason}`);
|
|
44124
|
+
console.log(` runs: https://github.com/${repo}/actions/workflows/${workflow}`);
|
|
44125
|
+
},
|
|
44126
|
+
{ status: "ok", repo, workflow, ref, reason }
|
|
44127
|
+
);
|
|
44128
|
+
return;
|
|
44129
|
+
}
|
|
44130
|
+
let detail = "";
|
|
44131
|
+
try {
|
|
44132
|
+
detail = await res.text();
|
|
44133
|
+
} catch {
|
|
44134
|
+
}
|
|
44135
|
+
let message = `GitHub returned ${res.status}`;
|
|
44136
|
+
if (res.status === 401) message += " \u2014 bad or expired token";
|
|
44137
|
+
else if (res.status === 403) message += " \u2014 token lacks `actions: write` on this repo";
|
|
44138
|
+
else if (res.status === 404)
|
|
44139
|
+
message += ` \u2014 workflow "${workflow}" or repo "${repo}" not found (or the token can't see it)`;
|
|
44140
|
+
if (detail) {
|
|
44141
|
+
try {
|
|
44142
|
+
const parsed = JSON.parse(detail);
|
|
44143
|
+
if (parsed.message) message += `: ${parsed.message}`;
|
|
44144
|
+
} catch {
|
|
44145
|
+
message += `: ${detail.slice(0, 200)}`;
|
|
44146
|
+
}
|
|
44147
|
+
}
|
|
44148
|
+
throw new Error(message);
|
|
44149
|
+
}
|
|
44150
|
+
|
|
44045
44151
|
// src/commands/session.ts
|
|
44046
44152
|
function requireAccount() {
|
|
44047
44153
|
const account2 = readJsonFile(sailPath("account.json"));
|
|
@@ -44241,7 +44347,7 @@ async function status() {
|
|
|
44241
44347
|
}
|
|
44242
44348
|
|
|
44243
44349
|
// src/commands/ui.ts
|
|
44244
|
-
var
|
|
44350
|
+
var import_node_child_process3 = require("node:child_process");
|
|
44245
44351
|
var import_node_fs17 = __toESM(require("node:fs"), 1);
|
|
44246
44352
|
var import_node_net2 = __toESM(require("node:net"), 1);
|
|
44247
44353
|
var import_node_path13 = __toESM(require("node:path"), 1);
|
|
@@ -44311,7 +44417,7 @@ async function uiCommand() {
|
|
|
44311
44417
|
import_node_fs17.default.mkdirSync(runtimeDir, { recursive: true });
|
|
44312
44418
|
const logFile = import_node_path13.default.join(runtimeDir, "ui.log");
|
|
44313
44419
|
const logFd = import_node_fs17.default.openSync(logFile, "a");
|
|
44314
|
-
const child = (0,
|
|
44420
|
+
const child = (0, import_node_child_process3.spawn)(process.execPath, [serverBundle], {
|
|
44315
44421
|
detached: true,
|
|
44316
44422
|
stdio: ["ignore", logFd, logFd],
|
|
44317
44423
|
env: { ...process.env, SAIL_DIR: sailDir2, SERVE_DIST: "1", PORT: String(port), SAILOR_UI_DIST: uiDistDir }
|
|
@@ -44462,9 +44568,16 @@ owner.command("connect").description("Open the signing station, wait for your wa
|
|
|
44462
44568
|
owner.command("show").description("Show the saved project owner").option("--json", "Emit machine-readable JSON").action(actionWith(ownerShow));
|
|
44463
44569
|
program2.command("scan").description("Discover the owner's SMAs, their permissions, and local keys; save to context.json").option("--owner <address>", "Owner address to scan (defaults to the saved project owner)").option("--json", "Emit machine-readable JSON").action(actionWith(scan));
|
|
44464
44570
|
program2.command("status").description("Show current account, permission, and session status").action(action(status));
|
|
44465
|
-
program2.command("run").description("Run the agent execution loop (use --once for a single tick)").option("--once", "Run a single tick then exit").option("--chain <chainId>", "Chain ID to run on (overrides CHAIN_ID env and .env.local)").
|
|
44571
|
+
program2.command("run").description("Run the agent execution loop (use --once for a single tick)").option("--once", "Run a single tick then exit").option("--chain <chainId>", "Chain ID to run on (overrides CHAIN_ID env and .env.local)").option(
|
|
44572
|
+
"--reason <text>",
|
|
44573
|
+
"Label why this run fired (observability only; also read from SAIL_RUN_REASON)"
|
|
44574
|
+
).action(async (opts) => {
|
|
44466
44575
|
try {
|
|
44467
|
-
await runCommand({
|
|
44576
|
+
await runCommand({
|
|
44577
|
+
once: opts.once,
|
|
44578
|
+
chain: opts.chain ? Number(opts.chain) : void 0,
|
|
44579
|
+
reason: opts.reason
|
|
44580
|
+
});
|
|
44468
44581
|
} catch (err) {
|
|
44469
44582
|
console.error(`Error: ${err.message}`);
|
|
44470
44583
|
closePrompts();
|
|
@@ -44472,6 +44585,8 @@ program2.command("run").description("Run the agent execution loop (use --once fo
|
|
|
44472
44585
|
}
|
|
44473
44586
|
closePrompts();
|
|
44474
44587
|
});
|
|
44588
|
+
var trigger = program2.command("trigger").description("Wake the agent on demand from an external system");
|
|
44589
|
+
trigger.command("github").description("Fire the agent's GitHub Actions workflow_dispatch (the same job the cron runs)").option("--workflow <file>", "Workflow file to dispatch", "agent-tick.yml").option("--ref <branch>", "Git ref to run the workflow on", "main").option("--reason <text>", "Why this run fired \u2014 recorded as the workflow's reason input").option("--repo <owner/repo>", "Override the repository (default: from the git origin remote)").option("--json", "Emit machine-readable JSON").action(actionWith(triggerGithub));
|
|
44475
44590
|
var session = program2.command("session").description("Control the agent session");
|
|
44476
44591
|
session.command("pause").description("Pause the agent session (revoke dispatch rights)").action(action(sessionPause));
|
|
44477
44592
|
session.command("resume").description("Resume a paused session").action(action(sessionResume));
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Do not edit manually — run `pnpm build` to regenerate.
|
|
6
6
|
*
|
|
7
7
|
* Spec version : 1.2.0
|
|
8
|
-
* Generated at : 2026-06-15T17:
|
|
8
|
+
* Generated at : 2026-06-15T17:43:57.156Z
|
|
9
9
|
*/
|
|
10
10
|
export declare const SAIL_INTELLIGENCE_BASE_URL = "https://api.sail.money";
|
|
11
11
|
export declare const SAIL_INTELLIGENCE_DOCS_URL = "https://api.sail.money/docs";
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Do not edit manually — run `pnpm build` to regenerate.
|
|
6
6
|
*
|
|
7
7
|
* Spec version : 1.2.0
|
|
8
|
-
* Generated at : 2026-06-15T17:
|
|
8
|
+
* Generated at : 2026-06-15T17:43:57.156Z
|
|
9
9
|
*/
|
|
10
10
|
export const SAIL_INTELLIGENCE_BASE_URL = "https://api.sail.money";
|
|
11
11
|
export const SAIL_INTELLIGENCE_DOCS_URL = "https://api.sail.money/docs";
|
|
@@ -1,10 +1,35 @@
|
|
|
1
1
|
name: Agent Tick
|
|
2
2
|
|
|
3
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
4
|
+
# WHEN does your agent run? Two mechanisms — you almost certainly need to tune
|
|
5
|
+
# the first one for your strategy.
|
|
6
|
+
#
|
|
7
|
+
# 1. schedule (cron, below) — a heartbeat / backstop. GitHub Actions cron is
|
|
8
|
+
# NON-PUNCTUAL: it drifts and is SKIPPED under load, so it is the wrong
|
|
9
|
+
# PRIMARY driver for anything latency-sensitive. Tune the cadence to your
|
|
10
|
+
# strategy's volatility:
|
|
11
|
+
# • LP / perps / liquidations → minutes — but don't rely on cron for it;
|
|
12
|
+
# use an external trigger (#2). Here cron is only a safety net.
|
|
13
|
+
# • DCA / periodic rebalance → daily.
|
|
14
|
+
# • treasury / slow rebalances → hourly to daily.
|
|
15
|
+
# The default below (hourly) is a GENERIC PLACEHOLDER — change it.
|
|
16
|
+
#
|
|
17
|
+
# 2. workflow_dispatch — an on-demand trigger. Anything that can make an HTTP
|
|
18
|
+
# call can wake this job the instant a condition is met (a price band, an
|
|
19
|
+
# on-chain event, a webhook). Fire it from the CLI: sailor trigger github
|
|
20
|
+
# This is how you get low-latency reaction that cron cannot give you.
|
|
21
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
22
|
+
|
|
3
23
|
on:
|
|
4
24
|
schedule:
|
|
5
|
-
#
|
|
6
|
-
- cron: "0
|
|
25
|
+
# Generic placeholder — hourly. TUNE THIS to your strategy (see above).
|
|
26
|
+
- cron: "0 * * * *"
|
|
7
27
|
workflow_dispatch:
|
|
28
|
+
inputs:
|
|
29
|
+
reason:
|
|
30
|
+
description: "Why this run fired (recorded in the run log for auditability)"
|
|
31
|
+
required: false
|
|
32
|
+
default: "manual"
|
|
8
33
|
|
|
9
34
|
jobs:
|
|
10
35
|
tick:
|
|
@@ -30,4 +55,6 @@ jobs:
|
|
|
30
55
|
RPC_URL: ${{ secrets.RPC_URL }}
|
|
31
56
|
SAIL_PASSPHRASE: ${{ secrets.SAIL_PASSPHRASE }}
|
|
32
57
|
CHAIN_ID: ${{ vars.CHAIN_ID || '8453' }}
|
|
58
|
+
# Labels the run: the dispatch reason, or "scheduled" for cron runs.
|
|
59
|
+
SAIL_RUN_REASON: ${{ github.event.inputs.reason || 'scheduled' }}
|
|
33
60
|
run: npx sailor run --once
|