agent-sin 0.1.2 → 0.1.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/CHANGELOG.md +32 -0
- package/dist/cli/index.js +23 -1
- package/dist/core/update-notifier.d.ts +3 -1
- package/dist/core/update-notifier.js +31 -6
- package/dist/core/version.d.ts +2 -0
- package/dist/core/version.js +25 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -15,6 +15,38 @@ See the [compatibility policy](https://agent.shingoirie.com/versioning) for deta
|
|
|
15
15
|
|
|
16
16
|
---
|
|
17
17
|
|
|
18
|
+
## [0.1.5] — 2026-05-14
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- The interactive CLI (`agent-sin start` / `agent-sin chat`) now hits the npm registry on every startup instead of trusting the 24-hour cache, so new releases are surfaced immediately. Background paths (gateway, mid-conversation polls) still use the cache.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## [0.1.4] — 2026-05-14
|
|
27
|
+
|
|
28
|
+
### Added
|
|
29
|
+
|
|
30
|
+
- `agent-sin --version` / `-v` / `agent-sin version` now print the installed version. Previously these printed an "unknown command" error.
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
|
|
34
|
+
- Update-notifier now refreshes its cache when the installed version has caught up to or passed the previously cached "latest". Previously, after upgrading to the cached latest, the cache stayed valid for 24 hours and hid the banner for the next release. The CLI also fetches synchronously (with a short timeout) on the very first run so the banner appears immediately when a new version is available.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## [0.1.3] — 2026-05-14
|
|
39
|
+
|
|
40
|
+
### Added
|
|
41
|
+
|
|
42
|
+
- The long-running `agent-sin gateway` (the launchd / Task Scheduler service) now self-detects upgrades. Every 5 minutes it re-reads its own `package.json` version, and if it differs from the version it started with, it exits gracefully so launchd / Task Scheduler restarts it on the new code. This means `npm i -g agent-sin@latest` is enough — no manual `service restart` is required.
|
|
43
|
+
|
|
44
|
+
### Fixed
|
|
45
|
+
|
|
46
|
+
- The CLI banner used to print a hard-coded `v0.1.0` because the version string was inlined. It now reads `package.json` at runtime, so the displayed version always matches the installed one.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
18
50
|
## [0.1.2] — 2026-05-14
|
|
19
51
|
|
|
20
52
|
### Fixed
|
package/dist/cli/index.js
CHANGED
|
@@ -26,9 +26,14 @@ import { extractTelegramIdentityCandidates, runTelegramBot, } from "../telegram/
|
|
|
26
26
|
import { Spinner } from "./spinner.js";
|
|
27
27
|
import { formatModelRow, modelSummary, modelsLines, skillsLines, } from "../core/info-lines.js";
|
|
28
28
|
import { inferLocaleFromText, l, lLines, t, withLocale } from "../core/i18n.js";
|
|
29
|
+
import { agentSinVersion, agentSinVersionFresh } from "../core/version.js";
|
|
29
30
|
import { appendHistory, chatRespond, makeSpinnerProgress, } from "../core/chat-engine.js";
|
|
30
31
|
async function main() {
|
|
31
32
|
const [command, ...args] = process.argv.slice(2);
|
|
33
|
+
if (command === "--version" || command === "-v" || command === "version") {
|
|
34
|
+
console.log(agentSinVersion());
|
|
35
|
+
return 0;
|
|
36
|
+
}
|
|
32
37
|
try {
|
|
33
38
|
const dotenv = await loadDotenv();
|
|
34
39
|
if (dotenv.permission_warning) {
|
|
@@ -368,6 +373,12 @@ async function cmdRun(args) {
|
|
|
368
373
|
async function cmdChat(args) {
|
|
369
374
|
const config = await loadConfig();
|
|
370
375
|
scheduleUpdateCheck(config.workspace);
|
|
376
|
+
// Interactive CLI: always check the registry on startup so the user sees
|
|
377
|
+
// any new release immediately, not on the next session.
|
|
378
|
+
const startupBanner = await consumeUpdateBanner(config.workspace, { force: true });
|
|
379
|
+
if (startupBanner) {
|
|
380
|
+
console.log(startupBanner);
|
|
381
|
+
}
|
|
371
382
|
const history = [];
|
|
372
383
|
if (args.length > 0) {
|
|
373
384
|
const lines = await handleChatMessage(config, args.join(" "), history);
|
|
@@ -1436,7 +1447,7 @@ function formatAssistantNarrative(text) {
|
|
|
1436
1447
|
.map((line, idx) => (idx === 0 ? `${bullet} ${line}` : ` ${line}`))
|
|
1437
1448
|
.join("\n");
|
|
1438
1449
|
}
|
|
1439
|
-
const AGENT_SIN_VERSION =
|
|
1450
|
+
const AGENT_SIN_VERSION = agentSinVersion();
|
|
1440
1451
|
async function withCliBuildHooks(config, trimmed, run) {
|
|
1441
1452
|
const hooks = cliBuildHooks(config, trimmed);
|
|
1442
1453
|
try {
|
|
@@ -2382,6 +2393,16 @@ macOS で常駐させるには agent-sin service install を使ってくださ
|
|
|
2382
2393
|
return 0;
|
|
2383
2394
|
}
|
|
2384
2395
|
console.log(l(`agent-sin gateway: starting (${startScheduler ? `${enabled.length} schedule(s)` : "scheduler idle"}, ${startDiscord ? "discord on" : "discord off"}, ${startTelegram ? "telegram on" : "telegram off"})`, `agent-sin gateway: 起動します (${startScheduler ? `${enabled.length}件のスケジュール` : "scheduler 待機"}, ${startDiscord ? "discord 有効" : "discord 無効"}, ${startTelegram ? "telegram 有効" : "telegram 無効"})`));
|
|
2396
|
+
const startupVersion = agentSinVersionFresh();
|
|
2397
|
+
const versionCheckInterval = setInterval(() => {
|
|
2398
|
+
const current = agentSinVersionFresh();
|
|
2399
|
+
if (current !== startupVersion && current !== "unknown") {
|
|
2400
|
+
console.log(l(`agent-sin gateway: detected upgrade ${startupVersion} -> ${current}, exiting so launchd restarts with the new code.`, `agent-sin gateway: アップデートを検知 (${startupVersion} -> ${current}). launchd が新しいコードで再起動できるように終了します。`));
|
|
2401
|
+
clearInterval(versionCheckInterval);
|
|
2402
|
+
process.exit(0);
|
|
2403
|
+
}
|
|
2404
|
+
}, 5 * 60 * 1000);
|
|
2405
|
+
versionCheckInterval.unref?.();
|
|
2385
2406
|
const tasks = [];
|
|
2386
2407
|
if (startScheduler) {
|
|
2387
2408
|
tasks.push(runScheduleDaemon(config, { once: Boolean(options.once) }));
|
|
@@ -2399,6 +2420,7 @@ macOS で常駐させるには agent-sin service install を使ってくださ
|
|
|
2399
2420
|
console.log(l("agent-sin gateway: Telegram not configured.", "agent-sin gateway: Telegram は未設定です。"));
|
|
2400
2421
|
}
|
|
2401
2422
|
const results = await Promise.all(tasks);
|
|
2423
|
+
clearInterval(versionCheckInterval);
|
|
2402
2424
|
return Math.max(...results);
|
|
2403
2425
|
}
|
|
2404
2426
|
async function cmdService(args) {
|
|
@@ -1,2 +1,4 @@
|
|
|
1
1
|
export declare function scheduleUpdateCheck(workspace?: string): void;
|
|
2
|
-
export declare function consumeUpdateBanner(workspace?: string
|
|
2
|
+
export declare function consumeUpdateBanner(workspace?: string, options?: {
|
|
3
|
+
force?: boolean;
|
|
4
|
+
}): Promise<string | null>;
|
|
@@ -104,14 +104,25 @@ function isDisabled() {
|
|
|
104
104
|
const flag = (process.env.AGENT_SIN_DISABLE_UPDATE_CHECK || "").trim().toLowerCase();
|
|
105
105
|
return flag === "1" || flag === "true" || flag === "yes";
|
|
106
106
|
}
|
|
107
|
+
function isCacheStale(cache, current) {
|
|
108
|
+
if (!cache.latestVersion)
|
|
109
|
+
return true;
|
|
110
|
+
// The cached "latest" trailing the installed version means we upgraded past
|
|
111
|
+
// the previously seen latest. Re-check immediately rather than waiting 24h.
|
|
112
|
+
if (compareSemver(cache.latestVersion, current) <= 0)
|
|
113
|
+
return true;
|
|
114
|
+
const lastChecked = cache.lastCheckedAt ? Date.parse(cache.lastCheckedAt) : 0;
|
|
115
|
+
if (!Number.isFinite(lastChecked))
|
|
116
|
+
return true;
|
|
117
|
+
return Date.now() - lastChecked >= CHECK_INTERVAL_MS;
|
|
118
|
+
}
|
|
107
119
|
export function scheduleUpdateCheck(workspace = defaultWorkspace()) {
|
|
108
120
|
if (isDisabled())
|
|
109
121
|
return;
|
|
110
122
|
void (async () => {
|
|
111
123
|
const cache = await loadCache(workspace);
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
if (Number.isFinite(lastChecked) && now - lastChecked < CHECK_INTERVAL_MS)
|
|
124
|
+
const current = await readCurrentVersion();
|
|
125
|
+
if (!isCacheStale(cache, current))
|
|
115
126
|
return;
|
|
116
127
|
const latest = await fetchLatestVersion();
|
|
117
128
|
if (!latest)
|
|
@@ -123,13 +134,27 @@ export function scheduleUpdateCheck(workspace = defaultWorkspace()) {
|
|
|
123
134
|
});
|
|
124
135
|
})();
|
|
125
136
|
}
|
|
126
|
-
export async function consumeUpdateBanner(workspace = defaultWorkspace()) {
|
|
137
|
+
export async function consumeUpdateBanner(workspace = defaultWorkspace(), options = {}) {
|
|
127
138
|
if (isDisabled())
|
|
128
139
|
return null;
|
|
129
|
-
|
|
140
|
+
let cache = await loadCache(workspace);
|
|
141
|
+
const current = await readCurrentVersion();
|
|
142
|
+
// Interactive entry points pass force=true to always fetch the latest
|
|
143
|
+
// version on startup; background paths (services, mid-conversation polls)
|
|
144
|
+
// fall back to the cache to avoid hammering the registry.
|
|
145
|
+
if (options.force || isCacheStale(cache, current)) {
|
|
146
|
+
const latest = await fetchLatestVersion();
|
|
147
|
+
if (latest) {
|
|
148
|
+
cache = {
|
|
149
|
+
...cache,
|
|
150
|
+
lastCheckedAt: new Date().toISOString(),
|
|
151
|
+
latestVersion: latest,
|
|
152
|
+
};
|
|
153
|
+
await saveCache(workspace, cache);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
130
156
|
if (!cache.latestVersion)
|
|
131
157
|
return null;
|
|
132
|
-
const current = await readCurrentVersion();
|
|
133
158
|
if (compareSemver(cache.latestVersion, current) <= 0)
|
|
134
159
|
return null;
|
|
135
160
|
const today = todayKey();
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
const FILENAME = fileURLToPath(import.meta.url);
|
|
5
|
+
const PKG_PATH = path.resolve(path.dirname(FILENAME), "..", "..", "package.json");
|
|
6
|
+
let cached = null;
|
|
7
|
+
function readVersionFromDisk() {
|
|
8
|
+
try {
|
|
9
|
+
const raw = readFileSync(PKG_PATH, "utf8");
|
|
10
|
+
const parsed = JSON.parse(raw);
|
|
11
|
+
return typeof parsed.version === "string" ? parsed.version : "unknown";
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return "unknown";
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export function agentSinVersion() {
|
|
18
|
+
if (cached === null) {
|
|
19
|
+
cached = readVersionFromDisk();
|
|
20
|
+
}
|
|
21
|
+
return cached;
|
|
22
|
+
}
|
|
23
|
+
export function agentSinVersionFresh() {
|
|
24
|
+
return readVersionFromDisk();
|
|
25
|
+
}
|