instar 0.7.50 → 0.7.52
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/core/AutoUpdater.js +15 -16
- package/dist/core/UpdateChecker.d.ts +1 -2
- package/dist/core/UpdateChecker.js +10 -37
- package/dist/lifeline/TelegramLifeline.js +16 -1
- package/dist/server/routes.js +1 -1
- package/package.json +1 -1
- package/.vercel/README.txt +0 -11
- package/.vercel/project.json +0 -1
package/dist/core/AutoUpdater.js
CHANGED
|
@@ -54,11 +54,17 @@ export class AutoUpdater {
|
|
|
54
54
|
if (this.interval)
|
|
55
55
|
return;
|
|
56
56
|
const intervalMs = this.config.checkIntervalMinutes * 60 * 1000;
|
|
57
|
-
//
|
|
57
|
+
// Detect npx cache — auto-apply and restart cause infinite loops when
|
|
58
|
+
// running from npx because the cache still resolves to the old version
|
|
59
|
+
// after npm installs the update. The restart finds the update again,
|
|
60
|
+
// applies it again, restarts again — forever, killing all sessions each time.
|
|
58
61
|
const scriptPath = process.argv[1] || '';
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
+
const runningFromNpx = scriptPath.includes('.npm/_npx') || scriptPath.includes('/_npx/');
|
|
63
|
+
if (runningFromNpx) {
|
|
64
|
+
this.config.autoApply = false;
|
|
65
|
+
this.config.autoRestart = false;
|
|
66
|
+
console.warn('[AutoUpdater] Running from npx cache. Auto-apply and auto-restart disabled to prevent restart loops.\n' +
|
|
67
|
+
'[AutoUpdater] Run: npm install -g instar (then restart with: instar server start)');
|
|
62
68
|
}
|
|
63
69
|
console.log(`[AutoUpdater] Started (every ${this.config.checkIntervalMinutes}m, ` +
|
|
64
70
|
`autoApply: ${this.config.autoApply}, autoRestart: ${this.config.autoRestart})`);
|
|
@@ -122,8 +128,7 @@ export class AutoUpdater {
|
|
|
122
128
|
if (!this.config.autoApply) {
|
|
123
129
|
// Just notify — don't apply
|
|
124
130
|
await this.notify(`Update available: v${info.currentVersion} → v${info.latestVersion}\n\n` +
|
|
125
|
-
(info.changeSummary ? `
|
|
126
|
-
`Details: ${info.changelogUrl || 'https://github.com/SageMindAI/instar/releases'}\n\n` +
|
|
131
|
+
(info.changeSummary ? `Changes: ${info.changeSummary}\n\n` : '') +
|
|
127
132
|
`Auto-apply is disabled. Apply manually:\n` +
|
|
128
133
|
`curl -X POST http://localhost:${this.getPort()}/updates/apply`);
|
|
129
134
|
return;
|
|
@@ -148,19 +153,13 @@ export class AutoUpdater {
|
|
|
148
153
|
console.log(`[AutoUpdater] Updated: v${result.previousVersion} → v${result.newVersion}`);
|
|
149
154
|
// Step 5: Notify via Telegram
|
|
150
155
|
const restartNote = result.restartNeeded && this.config.autoRestart
|
|
151
|
-
? '
|
|
156
|
+
? 'Server is restarting now...'
|
|
152
157
|
: result.restartNeeded
|
|
153
|
-
? '
|
|
158
|
+
? 'A server restart is needed to use the new version.'
|
|
154
159
|
: '';
|
|
155
|
-
const changeSummary = info.changeSummary
|
|
156
|
-
? `What changed:\n${info.changeSummary}\n`
|
|
157
|
-
: '';
|
|
158
|
-
const detailsUrl = info.changelogUrl || 'https://github.com/SageMindAI/instar/releases';
|
|
159
160
|
await this.notify(`Updated: v${result.previousVersion} → v${result.newVersion}\n\n` +
|
|
160
|
-
changeSummary +
|
|
161
|
-
|
|
162
|
-
restartNote +
|
|
163
|
-
`\n\nTo disable auto-updates, set "autoApply": false in .instar/config.json under "updates".`);
|
|
161
|
+
(info.changeSummary ? `What changed:\n${info.changeSummary}\n\n` : '') +
|
|
162
|
+
restartNote);
|
|
164
163
|
// Step 6: Self-restart if needed and configured
|
|
165
164
|
if (result.restartNeeded && this.config.autoRestart) {
|
|
166
165
|
// Brief delay to let the Telegram notification send
|
|
@@ -60,8 +60,7 @@ export declare class UpdateChecker {
|
|
|
60
60
|
updatedAt: string;
|
|
61
61
|
} | null;
|
|
62
62
|
/**
|
|
63
|
-
* Fetch human-readable changelog from GitHub releases
|
|
64
|
-
* recent commit messages if no release exists for this version.
|
|
63
|
+
* Fetch human-readable changelog from GitHub releases.
|
|
65
64
|
*/
|
|
66
65
|
fetchChangelog(version: string): Promise<string | undefined>;
|
|
67
66
|
/**
|
|
@@ -226,11 +226,9 @@ export class UpdateChecker {
|
|
|
226
226
|
}
|
|
227
227
|
}
|
|
228
228
|
/**
|
|
229
|
-
* Fetch human-readable changelog from GitHub releases
|
|
230
|
-
* recent commit messages if no release exists for this version.
|
|
229
|
+
* Fetch human-readable changelog from GitHub releases.
|
|
231
230
|
*/
|
|
232
231
|
async fetchChangelog(version) {
|
|
233
|
-
// Try GitHub release first
|
|
234
232
|
try {
|
|
235
233
|
const tag = version.startsWith('v') ? version : `v${version}`;
|
|
236
234
|
const response = await fetch(`${GITHUB_RELEASES_URL}/tags/${tag}`, {
|
|
@@ -240,41 +238,16 @@ export class UpdateChecker {
|
|
|
240
238
|
},
|
|
241
239
|
signal: AbortSignal.timeout(10000),
|
|
242
240
|
});
|
|
243
|
-
if (response.ok)
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
return release.name;
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
catch {
|
|
254
|
-
// Non-critical — try commit fallback
|
|
255
|
-
}
|
|
256
|
-
// Fallback: fetch recent commits from GitHub
|
|
257
|
-
try {
|
|
258
|
-
const response = await fetch('https://api.github.com/repos/SageMindAI/instar/commits?per_page=5', {
|
|
259
|
-
headers: {
|
|
260
|
-
'Accept': 'application/vnd.github.v3+json',
|
|
261
|
-
'User-Agent': 'instar-update-checker',
|
|
262
|
-
},
|
|
263
|
-
signal: AbortSignal.timeout(10000),
|
|
264
|
-
});
|
|
265
|
-
if (response.ok) {
|
|
266
|
-
const commits = await response.json();
|
|
267
|
-
if (commits.length > 0) {
|
|
268
|
-
const lines = commits
|
|
269
|
-
.map(c => {
|
|
270
|
-
// Take first line of commit message only
|
|
271
|
-
const firstLine = c.commit.message.split('\n')[0];
|
|
272
|
-
return `• ${firstLine}`;
|
|
273
|
-
})
|
|
274
|
-
.join('\n');
|
|
275
|
-
return `Recent changes:\n${lines}`;
|
|
276
|
-
}
|
|
241
|
+
if (!response.ok)
|
|
242
|
+
return undefined;
|
|
243
|
+
const release = await response.json();
|
|
244
|
+
if (release.body) {
|
|
245
|
+
// Truncate to first 500 chars for concise summary
|
|
246
|
+
const summary = release.body.slice(0, 500);
|
|
247
|
+
return summary.length < release.body.length ? summary + '...' : summary;
|
|
277
248
|
}
|
|
249
|
+
if (release.name)
|
|
250
|
+
return release.name;
|
|
278
251
|
}
|
|
279
252
|
catch {
|
|
280
253
|
// Non-critical
|
|
@@ -241,8 +241,23 @@ export class TelegramLifeline {
|
|
|
241
241
|
// Forward to server if healthy
|
|
242
242
|
if (this.supervisor.healthy) {
|
|
243
243
|
const forwarded = await this.forwardToServer(topicId, text, msg);
|
|
244
|
-
if (forwarded)
|
|
244
|
+
if (forwarded) {
|
|
245
|
+
// Delivery confirmation — user knows message reached the server
|
|
246
|
+
await this.sendToTopic(topicId, '✓ Delivered');
|
|
245
247
|
return;
|
|
248
|
+
}
|
|
249
|
+
// Server appears healthy but forward failed — queue with accurate message
|
|
250
|
+
this.queue.enqueue({
|
|
251
|
+
id: `tg-${msg.message_id}`,
|
|
252
|
+
topicId,
|
|
253
|
+
text,
|
|
254
|
+
fromUserId: msg.from.id,
|
|
255
|
+
fromUsername: msg.from.username,
|
|
256
|
+
fromFirstName: msg.from.first_name,
|
|
257
|
+
timestamp: new Date(msg.date * 1000).toISOString(),
|
|
258
|
+
});
|
|
259
|
+
await this.sendToTopic(topicId, `Server is restarting. Your message has been queued (${this.queue.length} in queue). It will be delivered when the server recovers.`);
|
|
260
|
+
return;
|
|
246
261
|
}
|
|
247
262
|
// Server is down — queue the message
|
|
248
263
|
this.queue.enqueue({
|
package/dist/server/routes.js
CHANGED
|
@@ -8,6 +8,7 @@ import { Router } from 'express';
|
|
|
8
8
|
import { execFileSync } from 'node:child_process';
|
|
9
9
|
import { createHash, timingSafeEqual } from 'node:crypto';
|
|
10
10
|
import fs from 'node:fs';
|
|
11
|
+
import os from 'node:os';
|
|
11
12
|
import path from 'node:path';
|
|
12
13
|
import { rateLimiter, signViewPath } from './middleware.js';
|
|
13
14
|
// Validation patterns for route parameters
|
|
@@ -64,7 +65,6 @@ export function createRoutes(ctx) {
|
|
|
64
65
|
heapTotal: Math.round(mem.heapTotal / 1024 / 1024),
|
|
65
66
|
};
|
|
66
67
|
// System-wide memory state
|
|
67
|
-
const os = require('node:os');
|
|
68
68
|
const totalMem = os.totalmem();
|
|
69
69
|
const freeMem = os.freemem();
|
|
70
70
|
base.systemMemory = {
|
package/package.json
CHANGED
package/.vercel/README.txt
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
> Why do I have a folder named ".vercel" in my project?
|
|
2
|
-
The ".vercel" folder is created when you link a directory to a Vercel project.
|
|
3
|
-
|
|
4
|
-
> What does the "project.json" file contain?
|
|
5
|
-
The "project.json" file contains:
|
|
6
|
-
- The ID of the Vercel project that you linked ("projectId")
|
|
7
|
-
- The ID of the user or team your Vercel project is owned by ("orgId")
|
|
8
|
-
|
|
9
|
-
> Should I commit the ".vercel" folder?
|
|
10
|
-
No, you should not share the ".vercel" folder with anyone.
|
|
11
|
-
Upon creation, it will be automatically added to your ".gitignore" file.
|
package/.vercel/project.json
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"projectId":"prj_evM5LcItYL3IAmw8zNvEPGrHeaya","orgId":"team_dHctwIDcV3X9ydapQlCPHFGI","projectName":"claude-agent-kit"}
|