@paradigma-inc/flywheel 0.1.93 → 0.1.99
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 +22 -4
- package/package.json +2 -1
- package/skills/flywheel-llm-proof-paper/SKILL.md +156 -0
- package/skills/flywheel-llm-proof-paper/agents/openai.yaml +4 -0
- package/skills/flywheel-llm-proof-paper/references/checks.md +60 -0
- package/skills/flywheel-llm-proof-paper/scripts/__pycache__/check_paper.cpython-311.pyc +0 -0
- package/skills/flywheel-llm-proof-paper/scripts/check_paper.py +1065 -0
- package/src/agents.mjs +5 -2
- package/src/cli.mjs +27 -3
- package/src/public-command-metadata.mjs +44 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/_wait-polling.d.ts +21 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/_wait-polling.js +68 -2
- package/src/runtime/vendor/flywheel-cli-dist/commands/_wait-polling.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/compute-acquire.js +2 -8
- package/src/runtime/vendor/flywheel-cli-dist/commands/compute-acquire.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/feedback-create.js +4 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/feedback-create.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry/compute.js +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry/compute.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry/resources.js +16 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry/resources.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/generatedProductTelemetryContract.d.ts +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/generatedProductTelemetryContract.js +3 -3
- package/src/runtime/vendor/flywheel-cli-dist/generatedProductTelemetryContract.js.map +1 -1
- package/src/runtime/vendor/manifest.json +1 -1
- package/src/setup/shared/prior-mode-detect.mjs +76 -9
- package/src/unified-cli.mjs +54 -16
- package/src/update/cache.mjs +124 -0
- package/src/update/command.mjs +438 -0
- package/src/update/install-state.mjs +135 -0
- package/src/update/refresh.mjs +393 -0
- package/src/update/registry.mjs +35 -0
- package/src/update/version.mjs +59 -0
- package/src/update/warning.mjs +109 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generatedProductTelemetryContract.js","sourceRoot":"","sources":["../src/generatedProductTelemetryContract.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"generatedProductTelemetryContract.js","sourceRoot":"","sources":["../src/generatedProductTelemetryContract.ts"],"names":[],"mappings":"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"}
|
|
@@ -123,7 +123,34 @@ function isFlywheelMcpUrl(url, targetOrigin) {
|
|
|
123
123
|
return targetOrigin !== null && parsed.origin.toLowerCase() === targetOrigin;
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
-
|
|
126
|
+
function isMcpServerUrl(url) {
|
|
127
|
+
if (typeof url !== "string" || url.trim().length === 0) {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
try {
|
|
131
|
+
return new URL(url).pathname === "/mcp-server";
|
|
132
|
+
} catch {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function shouldTreatAsFlywheelMcpEntry({
|
|
138
|
+
serverName,
|
|
139
|
+
serverUrl,
|
|
140
|
+
targetOrigin,
|
|
141
|
+
trustedServerNames,
|
|
142
|
+
}) {
|
|
143
|
+
return (
|
|
144
|
+
isFlywheelMcpUrl(serverUrl, targetOrigin) ||
|
|
145
|
+
(trustedServerNames.has(serverName) && isMcpServerUrl(serverUrl))
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
async function findFlywheelTomlEntries(
|
|
150
|
+
filePath,
|
|
151
|
+
targetOrigin,
|
|
152
|
+
trustedServerNames,
|
|
153
|
+
) {
|
|
127
154
|
let raw;
|
|
128
155
|
try {
|
|
129
156
|
raw = await readFile(filePath, "utf8");
|
|
@@ -139,9 +166,14 @@ async function findFlywheelTomlEntryNames(filePath, targetOrigin) {
|
|
|
139
166
|
if (
|
|
140
167
|
currentServerName !== null &&
|
|
141
168
|
currentUrl !== null &&
|
|
142
|
-
|
|
169
|
+
shouldTreatAsFlywheelMcpEntry({
|
|
170
|
+
serverName: currentServerName,
|
|
171
|
+
serverUrl: currentUrl,
|
|
172
|
+
targetOrigin,
|
|
173
|
+
trustedServerNames,
|
|
174
|
+
})
|
|
143
175
|
) {
|
|
144
|
-
matches.push(currentServerName);
|
|
176
|
+
matches.push({ serverName: currentServerName, serverUrl: currentUrl });
|
|
145
177
|
}
|
|
146
178
|
currentServerName = null;
|
|
147
179
|
currentUrl = null;
|
|
@@ -176,26 +208,48 @@ async function findFlywheelTomlEntryNames(filePath, targetOrigin) {
|
|
|
176
208
|
}
|
|
177
209
|
commitCurrent();
|
|
178
210
|
|
|
179
|
-
return
|
|
211
|
+
return uniqueEntries(matches);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function uniqueEntries(entries = []) {
|
|
215
|
+
const seen = new Set();
|
|
216
|
+
const out = [];
|
|
217
|
+
for (const entry of entries) {
|
|
218
|
+
const key = `${entry.serverName}\0${entry.serverUrl}`;
|
|
219
|
+
if (seen.has(key)) continue;
|
|
220
|
+
seen.add(key);
|
|
221
|
+
out.push(entry);
|
|
222
|
+
}
|
|
223
|
+
return out.sort((left, right) => {
|
|
224
|
+
const byName = left.serverName.localeCompare(right.serverName);
|
|
225
|
+
if (byName !== 0) return byName;
|
|
226
|
+
return left.serverUrl.localeCompare(right.serverUrl);
|
|
227
|
+
});
|
|
180
228
|
}
|
|
181
229
|
|
|
182
|
-
export async function
|
|
230
|
+
export async function findFlywheelMcpEntries({
|
|
183
231
|
hostName,
|
|
184
232
|
scope,
|
|
185
233
|
cwd = process.cwd(),
|
|
186
234
|
targetOrigin = null,
|
|
235
|
+
trustedServerNames = [],
|
|
187
236
|
getHost = defaultGetHost,
|
|
188
237
|
resolveMcpPath = defaultResolveMcpPath,
|
|
189
238
|
readJsonConfig = defaultReadJsonConfig,
|
|
190
239
|
readYamlConfig = defaultReadYamlConfig,
|
|
191
240
|
}) {
|
|
241
|
+
const trustedServerNameSet = new Set(trustedServerNames);
|
|
192
242
|
try {
|
|
193
243
|
const host = getHost(hostName);
|
|
194
244
|
const candidates = resolveCandidatesForScope(host, scope, cwd);
|
|
195
245
|
const filePath = await resolveMcpPath(candidates);
|
|
196
246
|
|
|
197
247
|
if (host.mcp.configType === "toml") {
|
|
198
|
-
return await
|
|
248
|
+
return await findFlywheelTomlEntries(
|
|
249
|
+
filePath,
|
|
250
|
+
targetOrigin,
|
|
251
|
+
trustedServerNameSet,
|
|
252
|
+
);
|
|
199
253
|
}
|
|
200
254
|
|
|
201
255
|
const config =
|
|
@@ -223,16 +277,29 @@ export async function findFlywheelMcpEntryNames({
|
|
|
223
277
|
const matches = [];
|
|
224
278
|
for (const [entryName, entry] of Object.entries(section)) {
|
|
225
279
|
const entryUrl = readEntryServerUrl(entry);
|
|
226
|
-
if (
|
|
227
|
-
|
|
280
|
+
if (
|
|
281
|
+
entryUrl !== null &&
|
|
282
|
+
shouldTreatAsFlywheelMcpEntry({
|
|
283
|
+
serverName: entryName,
|
|
284
|
+
serverUrl: entryUrl,
|
|
285
|
+
targetOrigin,
|
|
286
|
+
trustedServerNames: trustedServerNameSet,
|
|
287
|
+
})
|
|
288
|
+
) {
|
|
289
|
+
matches.push({ serverName: entryName, serverUrl: entryUrl });
|
|
228
290
|
}
|
|
229
291
|
}
|
|
230
|
-
return
|
|
292
|
+
return uniqueEntries(matches);
|
|
231
293
|
} catch {
|
|
232
294
|
return [];
|
|
233
295
|
}
|
|
234
296
|
}
|
|
235
297
|
|
|
298
|
+
export async function findFlywheelMcpEntryNames(options) {
|
|
299
|
+
const entries = await findFlywheelMcpEntries(options);
|
|
300
|
+
return entries.map((entry) => entry.serverName);
|
|
301
|
+
}
|
|
302
|
+
|
|
236
303
|
/**
|
|
237
304
|
* Determine whether a truly skill-only host's ownership marker is present at
|
|
238
305
|
* the skills-root that `hostName` would write into. The two destination
|
package/src/unified-cli.mjs
CHANGED
|
@@ -7,9 +7,12 @@ import {
|
|
|
7
7
|
} from "./public-command-metadata.mjs";
|
|
8
8
|
import { runRuntimeCli } from "./runtime/delegate.mjs";
|
|
9
9
|
import { RUNTIME_ALIASES } from "./runtime/vendor/flywheel-cli-dist/commands/aliases.js";
|
|
10
|
+
import { runUpdateCommand } from "./update/command.mjs";
|
|
11
|
+
import { runCommandWithDeferredUpdateWarning } from "./update/warning.mjs";
|
|
10
12
|
|
|
11
13
|
const ALIAS_RESERVED_COMMANDS = new Set([
|
|
12
14
|
"setup",
|
|
15
|
+
"update",
|
|
13
16
|
"uninstall",
|
|
14
17
|
"completion",
|
|
15
18
|
"help",
|
|
@@ -100,7 +103,14 @@ async function routeExplicitHelp(argv) {
|
|
|
100
103
|
}
|
|
101
104
|
const setupHelpArgv = setupHelpArgvFor(target, subcommand);
|
|
102
105
|
if (setupHelpArgv) {
|
|
103
|
-
await runSetupCli(
|
|
106
|
+
process.exitCode = await runSetupCli(
|
|
107
|
+
["node", "flywheel", ...setupHelpArgv],
|
|
108
|
+
{ exitOverride: true },
|
|
109
|
+
);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
if (target === "update") {
|
|
113
|
+
process.exitCode = await runUpdateCommand(["--help"]);
|
|
104
114
|
return;
|
|
105
115
|
}
|
|
106
116
|
if (target === undefined) {
|
|
@@ -120,6 +130,17 @@ async function routeExplicitHelp(argv) {
|
|
|
120
130
|
process.exitCode = exitCode;
|
|
121
131
|
}
|
|
122
132
|
|
|
133
|
+
async function runWithDeferredUpdateWarning(argv, runCommand) {
|
|
134
|
+
const exitCode = await runCommandWithDeferredUpdateWarning({
|
|
135
|
+
argv,
|
|
136
|
+
currentVersion: await loadPackageVersion(),
|
|
137
|
+
runCommand,
|
|
138
|
+
});
|
|
139
|
+
if (Number.isInteger(exitCode)) {
|
|
140
|
+
process.exitCode = exitCode;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
123
144
|
export async function runUnifiedCli(argv = process.argv.slice(2)) {
|
|
124
145
|
if (!Array.isArray(argv)) {
|
|
125
146
|
throw new Error("runUnifiedCli expects an argv array.");
|
|
@@ -132,13 +153,14 @@ export async function runUnifiedCli(argv = process.argv.slice(2)) {
|
|
|
132
153
|
}
|
|
133
154
|
|
|
134
155
|
if (argv.length === 1 && USAGE_REQUEST_TOKENS.has(argv[0])) {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
156
|
+
await runWithDeferredUpdateWarning(argv, async () => {
|
|
157
|
+
const publicPackageVersion = await loadPackageVersion();
|
|
158
|
+
return await runRuntimeCli([
|
|
159
|
+
argv[0],
|
|
160
|
+
usageExtrasArg(),
|
|
161
|
+
usageVersionArg(publicPackageVersion),
|
|
162
|
+
]);
|
|
163
|
+
});
|
|
142
164
|
return;
|
|
143
165
|
}
|
|
144
166
|
|
|
@@ -164,8 +186,9 @@ export async function runUnifiedCli(argv = process.argv.slice(2)) {
|
|
|
164
186
|
}
|
|
165
187
|
}
|
|
166
188
|
const passthrough = ["help", helpExtrasArg(), ...formatArgs];
|
|
167
|
-
|
|
168
|
-
|
|
189
|
+
await runWithDeferredUpdateWarning(argv, async () =>
|
|
190
|
+
await runRuntimeCli(passthrough),
|
|
191
|
+
);
|
|
169
192
|
return;
|
|
170
193
|
}
|
|
171
194
|
|
|
@@ -178,8 +201,16 @@ export async function runUnifiedCli(argv = process.argv.slice(2)) {
|
|
|
178
201
|
}
|
|
179
202
|
|
|
180
203
|
const [command] = argv;
|
|
204
|
+
if (command === "update") {
|
|
205
|
+
process.exitCode = await runUpdateCommand(argv.slice(1));
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
|
|
181
209
|
if (command === "help") {
|
|
182
|
-
await
|
|
210
|
+
await runWithDeferredUpdateWarning(argv, async () => {
|
|
211
|
+
await routeExplicitHelp(argv);
|
|
212
|
+
return process.exitCode ?? 0;
|
|
213
|
+
});
|
|
183
214
|
return;
|
|
184
215
|
}
|
|
185
216
|
|
|
@@ -188,16 +219,23 @@ export async function runUnifiedCli(argv = process.argv.slice(2)) {
|
|
|
188
219
|
command === "uninstall" ||
|
|
189
220
|
command === "completion"
|
|
190
221
|
) {
|
|
191
|
-
await
|
|
222
|
+
await runWithDeferredUpdateWarning(argv, async () => {
|
|
223
|
+
return await runSetupCli(["node", "flywheel", ...argv], {
|
|
224
|
+
exitOverride: true,
|
|
225
|
+
});
|
|
226
|
+
});
|
|
192
227
|
return;
|
|
193
228
|
}
|
|
194
229
|
|
|
195
230
|
if (command.includes(":")) {
|
|
196
|
-
|
|
197
|
-
|
|
231
|
+
await runWithDeferredUpdateWarning(argv, async () =>
|
|
232
|
+
await runRuntimeCli(argv),
|
|
233
|
+
);
|
|
198
234
|
return;
|
|
199
235
|
}
|
|
200
236
|
|
|
201
|
-
|
|
202
|
-
|
|
237
|
+
await runWithDeferredUpdateWarning(argv, async () => {
|
|
238
|
+
process.stderr.write(`unknown command: ${command}\n`);
|
|
239
|
+
return 1;
|
|
240
|
+
});
|
|
203
241
|
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
|
|
6
|
+
import { FLYWHEEL_PACKAGE_NAME } from "./version.mjs";
|
|
7
|
+
|
|
8
|
+
export const UPDATE_CHECK_CACHE_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
9
|
+
|
|
10
|
+
export function resolveUpdateCheckCachePath({
|
|
11
|
+
env = process.env,
|
|
12
|
+
homeDir = os.homedir(),
|
|
13
|
+
} = {}) {
|
|
14
|
+
const override = String(env.FLYWHEEL_UPDATE_CHECK_CACHE_PATH || "").trim();
|
|
15
|
+
if (override) {
|
|
16
|
+
return override;
|
|
17
|
+
}
|
|
18
|
+
return path.join(homeDir, ".flywheel", "update-check.json");
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function parseCache(raw) {
|
|
22
|
+
const parsed = JSON.parse(raw);
|
|
23
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
if (parsed.packageName !== FLYWHEEL_PACKAGE_NAME) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
if (typeof parsed.latestVersion !== "string" || !parsed.latestVersion.trim()) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
if (typeof parsed.nextCheckAt !== "string" || !parsed.nextCheckAt.trim()) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
const nextCheckAt = new Date(parsed.nextCheckAt);
|
|
36
|
+
if (Number.isNaN(nextCheckAt.getTime())) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
return parsed;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export async function readFreshUpdateCache({
|
|
43
|
+
cachePath = resolveUpdateCheckCachePath(),
|
|
44
|
+
now = () => new Date(),
|
|
45
|
+
} = {}) {
|
|
46
|
+
let raw;
|
|
47
|
+
try {
|
|
48
|
+
raw = await readFile(cachePath, "utf8");
|
|
49
|
+
} catch {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
const parsed = parseCache(raw);
|
|
55
|
+
if (!parsed) return null;
|
|
56
|
+
if (new Date(parsed.nextCheckAt).getTime() <= now().getTime()) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
return parsed;
|
|
60
|
+
} catch {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function finalCacheIsValid(cachePath) {
|
|
66
|
+
try {
|
|
67
|
+
return parseCache(await readFile(cachePath, "utf8")) !== null;
|
|
68
|
+
} catch {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export async function writeUpdateCacheAtomic({
|
|
74
|
+
cachePath = resolveUpdateCheckCachePath(),
|
|
75
|
+
latestVersion,
|
|
76
|
+
now = () => new Date(),
|
|
77
|
+
intervalMs = UPDATE_CHECK_CACHE_INTERVAL_MS,
|
|
78
|
+
pid = process.pid,
|
|
79
|
+
randomId = randomUUID,
|
|
80
|
+
} = {}) {
|
|
81
|
+
const checkedAt = now();
|
|
82
|
+
const payload = {
|
|
83
|
+
packageName: FLYWHEEL_PACKAGE_NAME,
|
|
84
|
+
latestVersion,
|
|
85
|
+
checkedAt: checkedAt.toISOString(),
|
|
86
|
+
nextCheckAt: new Date(checkedAt.getTime() + intervalMs).toISOString(),
|
|
87
|
+
};
|
|
88
|
+
const tmpPath = `${cachePath}.${pid}.${randomId()}.tmp`;
|
|
89
|
+
await mkdir(path.dirname(cachePath), { recursive: true });
|
|
90
|
+
await writeFile(tmpPath, `${JSON.stringify(payload, null, 2)}\n`, {
|
|
91
|
+
encoding: "utf8",
|
|
92
|
+
mode: 0o600,
|
|
93
|
+
});
|
|
94
|
+
try {
|
|
95
|
+
await rename(tmpPath, cachePath);
|
|
96
|
+
} catch (error) {
|
|
97
|
+
await rm(tmpPath, { force: true }).catch(() => {});
|
|
98
|
+
if (await finalCacheIsValid(cachePath)) {
|
|
99
|
+
return payload;
|
|
100
|
+
}
|
|
101
|
+
throw error;
|
|
102
|
+
}
|
|
103
|
+
return payload;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export async function getLatestVersionWithCache({
|
|
107
|
+
cachePath = resolveUpdateCheckCachePath(),
|
|
108
|
+
now = () => new Date(),
|
|
109
|
+
fetchLatestVersion,
|
|
110
|
+
intervalMs = UPDATE_CHECK_CACHE_INTERVAL_MS,
|
|
111
|
+
} = {}) {
|
|
112
|
+
const cached = await readFreshUpdateCache({ cachePath, now });
|
|
113
|
+
if (cached) {
|
|
114
|
+
return cached.latestVersion;
|
|
115
|
+
}
|
|
116
|
+
const latestVersion = await fetchLatestVersion();
|
|
117
|
+
await writeUpdateCacheAtomic({
|
|
118
|
+
cachePath,
|
|
119
|
+
latestVersion,
|
|
120
|
+
now,
|
|
121
|
+
intervalMs,
|
|
122
|
+
});
|
|
123
|
+
return latestVersion;
|
|
124
|
+
}
|