aislop 0.8.3 → 0.9.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/dist/cli.js +533 -126
- package/dist/index.js +394 -75
- package/dist/{json-D8h2EZW6.js → json-DZfGz2xa.js} +1 -1
- package/dist/{json-BbMwrgyd.js → json-OIzja7OM.js} +1 -1
- package/dist/mcp.js +248 -8
- package/dist/{typecheck-B1MXNAy-.js → typecheck-wVSohmOX.js} +1 -1
- package/dist/{version-BynHxO1X.js → version-D_rqBdyj.js} +1 -1
- package/package.json +1 -1
package/dist/mcp.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { n as runSubprocess, t as isToolInstalled } from "./subprocess-CCnnN_oQ.js";
|
|
3
3
|
import { createRequire, isBuiltin } from "node:module";
|
|
4
|
+
import { performance } from "node:perf_hooks";
|
|
4
5
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
6
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
7
|
import path from "node:path";
|
|
@@ -9,11 +10,11 @@ import { z } from "zod";
|
|
|
9
10
|
import fs from "node:fs";
|
|
10
11
|
import YAML from "yaml";
|
|
11
12
|
import { z as z$1 } from "zod/v4";
|
|
12
|
-
import { performance } from "node:perf_hooks";
|
|
13
13
|
import micromatch from "micromatch";
|
|
14
14
|
import { fileURLToPath } from "node:url";
|
|
15
15
|
import os from "node:os";
|
|
16
16
|
import "typescript";
|
|
17
|
+
import { randomUUID } from "node:crypto";
|
|
17
18
|
|
|
18
19
|
//#region src/config/defaults.ts
|
|
19
20
|
const DEFAULT_CONFIG = {
|
|
@@ -5094,7 +5095,225 @@ const handleAislopBaseline = (input) => {
|
|
|
5094
5095
|
|
|
5095
5096
|
//#endregion
|
|
5096
5097
|
//#region src/version.ts
|
|
5097
|
-
const APP_VERSION = "0.
|
|
5098
|
+
const APP_VERSION = "0.9.0";
|
|
5099
|
+
|
|
5100
|
+
//#endregion
|
|
5101
|
+
//#region src/telemetry/env.ts
|
|
5102
|
+
const detectPackageManager = (env = process.env) => {
|
|
5103
|
+
const execPath = env.npm_execpath ?? "";
|
|
5104
|
+
if (execPath.includes("npx")) return "npx";
|
|
5105
|
+
const userAgent = env.npm_config_user_agent ?? "";
|
|
5106
|
+
if (userAgent.startsWith("pnpm/")) return "pnpm";
|
|
5107
|
+
if (userAgent.startsWith("yarn/")) return "yarn";
|
|
5108
|
+
if (userAgent.startsWith("bun/")) return "bun";
|
|
5109
|
+
if (userAgent.startsWith("npm/")) return "npm";
|
|
5110
|
+
if (execPath.includes("pnpm")) return "pnpm";
|
|
5111
|
+
if (execPath.includes("yarn")) return "yarn";
|
|
5112
|
+
if (execPath.includes("bun")) return "bun";
|
|
5113
|
+
if (execPath.includes("npm")) return "npm";
|
|
5114
|
+
return "unknown";
|
|
5115
|
+
};
|
|
5116
|
+
const CI_ENV_KEYS = [
|
|
5117
|
+
"CI",
|
|
5118
|
+
"GITHUB_ACTIONS",
|
|
5119
|
+
"GITLAB_CI",
|
|
5120
|
+
"CIRCLECI",
|
|
5121
|
+
"TRAVIS",
|
|
5122
|
+
"BUILDKITE",
|
|
5123
|
+
"DRONE",
|
|
5124
|
+
"TEAMCITY_VERSION",
|
|
5125
|
+
"TF_BUILD"
|
|
5126
|
+
];
|
|
5127
|
+
const isCiEnv = (env = process.env) => CI_ENV_KEYS.some((k) => {
|
|
5128
|
+
const v = env[k];
|
|
5129
|
+
return v === "true" || v === "1" || v != null && v.length > 0 && k !== "CI";
|
|
5130
|
+
}) || env.CI === "true" || env.CI === "1";
|
|
5131
|
+
|
|
5132
|
+
//#endregion
|
|
5133
|
+
//#region src/telemetry/identity.ts
|
|
5134
|
+
const FILE_BASENAME = "install_id";
|
|
5135
|
+
const resolveInstallIdPath = (homedir = os.homedir(), env = process.env) => {
|
|
5136
|
+
if (process.platform === "linux" && env.XDG_STATE_HOME) return path.join(env.XDG_STATE_HOME, "aislop", FILE_BASENAME);
|
|
5137
|
+
return path.join(homedir, ".aislop", FILE_BASENAME);
|
|
5138
|
+
};
|
|
5139
|
+
const ensureInstallId = (idPath = resolveInstallIdPath()) => {
|
|
5140
|
+
if (fs.existsSync(idPath)) {
|
|
5141
|
+
const existing = fs.readFileSync(idPath, "utf-8").trim();
|
|
5142
|
+
if (existing.length > 0) return {
|
|
5143
|
+
installId: existing,
|
|
5144
|
+
created: false
|
|
5145
|
+
};
|
|
5146
|
+
}
|
|
5147
|
+
const dir = path.dirname(idPath);
|
|
5148
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
5149
|
+
const installId = randomUUID();
|
|
5150
|
+
const tmpPath = `${idPath}.${process.pid}.tmp`;
|
|
5151
|
+
fs.writeFileSync(tmpPath, `${installId}\n`, { mode: 384 });
|
|
5152
|
+
try {
|
|
5153
|
+
fs.renameSync(tmpPath, idPath);
|
|
5154
|
+
return {
|
|
5155
|
+
installId,
|
|
5156
|
+
created: true
|
|
5157
|
+
};
|
|
5158
|
+
} catch {
|
|
5159
|
+
fs.rmSync(tmpPath, { force: true });
|
|
5160
|
+
return {
|
|
5161
|
+
installId: fs.readFileSync(idPath, "utf-8").trim(),
|
|
5162
|
+
created: false
|
|
5163
|
+
};
|
|
5164
|
+
}
|
|
5165
|
+
};
|
|
5166
|
+
|
|
5167
|
+
//#endregion
|
|
5168
|
+
//#region src/telemetry/redaction.ts
|
|
5169
|
+
const SAFE_PROPERTY_NAMES = new Set([
|
|
5170
|
+
"aislop_version",
|
|
5171
|
+
"node_version",
|
|
5172
|
+
"os",
|
|
5173
|
+
"arch",
|
|
5174
|
+
"schema_version",
|
|
5175
|
+
"anonymous_install_id",
|
|
5176
|
+
"package_manager",
|
|
5177
|
+
"is_ci",
|
|
5178
|
+
"command",
|
|
5179
|
+
"language_summary",
|
|
5180
|
+
"lang_typescript",
|
|
5181
|
+
"lang_javascript",
|
|
5182
|
+
"lang_python",
|
|
5183
|
+
"lang_java",
|
|
5184
|
+
"file_count_bucket",
|
|
5185
|
+
"exit_code",
|
|
5186
|
+
"duration_ms",
|
|
5187
|
+
"error_kind",
|
|
5188
|
+
"score",
|
|
5189
|
+
"score_bucket",
|
|
5190
|
+
"finding_count",
|
|
5191
|
+
"error_count",
|
|
5192
|
+
"warning_count",
|
|
5193
|
+
"fixable_count",
|
|
5194
|
+
"fix_steps",
|
|
5195
|
+
"fix_resolved",
|
|
5196
|
+
"fix_score_delta",
|
|
5197
|
+
"engine_format_issues",
|
|
5198
|
+
"engine_format_ms",
|
|
5199
|
+
"engine_lint_issues",
|
|
5200
|
+
"engine_lint_ms",
|
|
5201
|
+
"engine_code_quality_issues",
|
|
5202
|
+
"engine_code_quality_ms",
|
|
5203
|
+
"engine_ai_slop_issues",
|
|
5204
|
+
"engine_ai_slop_ms",
|
|
5205
|
+
"engine_architecture_issues",
|
|
5206
|
+
"engine_architecture_ms",
|
|
5207
|
+
"engine_security_issues",
|
|
5208
|
+
"engine_security_ms",
|
|
5209
|
+
"tool",
|
|
5210
|
+
"ok",
|
|
5211
|
+
"agent",
|
|
5212
|
+
"score_delta"
|
|
5213
|
+
]);
|
|
5214
|
+
const redactProperties = (props) => {
|
|
5215
|
+
const clean = {};
|
|
5216
|
+
const dropped = [];
|
|
5217
|
+
for (const [key, value] of Object.entries(props)) {
|
|
5218
|
+
if (value === void 0) continue;
|
|
5219
|
+
if (SAFE_PROPERTY_NAMES.has(key)) clean[key] = value;
|
|
5220
|
+
else dropped.push(key);
|
|
5221
|
+
}
|
|
5222
|
+
return {
|
|
5223
|
+
clean,
|
|
5224
|
+
dropped
|
|
5225
|
+
};
|
|
5226
|
+
};
|
|
5227
|
+
|
|
5228
|
+
//#endregion
|
|
5229
|
+
//#region src/telemetry/client.ts
|
|
5230
|
+
const POSTHOG_HOST = "https://eu.i.posthog.com";
|
|
5231
|
+
const POSTHOG_KEY = "phc_eY2cOMFva9q24GrWeOuvuVIOhCIdjOALxeAR3ItrqbJ";
|
|
5232
|
+
const SCHEMA_VERSION = "v2";
|
|
5233
|
+
const REQUEST_TIMEOUT_MS = 3e3;
|
|
5234
|
+
const isTelemetryDisabled = (config) => {
|
|
5235
|
+
const env = process.env;
|
|
5236
|
+
if (env.AISLOP_NO_TELEMETRY === "1" || env.DO_NOT_TRACK === "1") return true;
|
|
5237
|
+
if (config?.enabled === false) return true;
|
|
5238
|
+
if (config?.enabled === true) return false;
|
|
5239
|
+
if (env.CI === "true" || env.CI === "1") return true;
|
|
5240
|
+
return false;
|
|
5241
|
+
};
|
|
5242
|
+
const isDebug = () => process.env.AISLOP_TELEMETRY_DEBUG === "1";
|
|
5243
|
+
const pendingRequests = /* @__PURE__ */ new Set();
|
|
5244
|
+
let cachedInstallId = null;
|
|
5245
|
+
let installCreated = false;
|
|
5246
|
+
const baseProperties = (installId) => ({
|
|
5247
|
+
aislop_version: APP_VERSION,
|
|
5248
|
+
node_version: process.version,
|
|
5249
|
+
os: os.platform(),
|
|
5250
|
+
arch: os.arch(),
|
|
5251
|
+
schema_version: SCHEMA_VERSION,
|
|
5252
|
+
anonymous_install_id: installId,
|
|
5253
|
+
package_manager: detectPackageManager(),
|
|
5254
|
+
is_ci: isCiEnv()
|
|
5255
|
+
});
|
|
5256
|
+
const track = (input) => {
|
|
5257
|
+
if (isTelemetryDisabled(input.config)) return { installCreated: false };
|
|
5258
|
+
if (cachedInstallId == null) {
|
|
5259
|
+
const ensured = ensureInstallId(resolveInstallIdPath());
|
|
5260
|
+
cachedInstallId = ensured.installId;
|
|
5261
|
+
installCreated = ensured.created;
|
|
5262
|
+
}
|
|
5263
|
+
const { clean, dropped } = redactProperties({
|
|
5264
|
+
...baseProperties(cachedInstallId),
|
|
5265
|
+
...input.properties
|
|
5266
|
+
});
|
|
5267
|
+
if (isDebug()) {
|
|
5268
|
+
const compact = JSON.stringify({
|
|
5269
|
+
event: input.event,
|
|
5270
|
+
properties: clean
|
|
5271
|
+
});
|
|
5272
|
+
process.stderr.write(`[telemetry] ${compact}\n`);
|
|
5273
|
+
if (dropped.length > 0) for (const key of dropped) process.stderr.write(`[telemetry] dropped non-allowlisted property: ${key}\n`);
|
|
5274
|
+
}
|
|
5275
|
+
if (process.env.AISLOP_TELEMETRY_DRY_RUN === "1") return { installCreated };
|
|
5276
|
+
const payload = {
|
|
5277
|
+
api_key: POSTHOG_KEY,
|
|
5278
|
+
event: input.event,
|
|
5279
|
+
distinct_id: cachedInstallId,
|
|
5280
|
+
properties: clean,
|
|
5281
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
5282
|
+
};
|
|
5283
|
+
const request = fetch(`${POSTHOG_HOST}/capture/`, {
|
|
5284
|
+
method: "POST",
|
|
5285
|
+
headers: { "Content-Type": "application/json" },
|
|
5286
|
+
body: JSON.stringify(payload),
|
|
5287
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
|
|
5288
|
+
}).then(() => {}).catch(() => {}).finally(() => {
|
|
5289
|
+
pendingRequests.delete(request);
|
|
5290
|
+
});
|
|
5291
|
+
pendingRequests.add(request);
|
|
5292
|
+
return { installCreated };
|
|
5293
|
+
};
|
|
5294
|
+
const flushTelemetry = async () => {
|
|
5295
|
+
if (pendingRequests.size === 0) return;
|
|
5296
|
+
await Promise.all(pendingRequests);
|
|
5297
|
+
};
|
|
5298
|
+
|
|
5299
|
+
//#endregion
|
|
5300
|
+
//#region src/telemetry/events.ts
|
|
5301
|
+
const buildMcpToolCalledProps = (input) => {
|
|
5302
|
+
const props = {
|
|
5303
|
+
tool: input.tool,
|
|
5304
|
+
duration_ms: Math.round(input.durationMs),
|
|
5305
|
+
ok: input.ok
|
|
5306
|
+
};
|
|
5307
|
+
if (input.errorKind) props.error_kind = input.errorKind;
|
|
5308
|
+
return props;
|
|
5309
|
+
};
|
|
5310
|
+
const errorKindFromException = (error) => {
|
|
5311
|
+
const message = error instanceof Error ? error.message.toLowerCase() : String(error).toLowerCase();
|
|
5312
|
+
if (message.includes("timeout") || message.includes("timed out")) return "timeout";
|
|
5313
|
+
if (message.includes("invalid config") || message.includes("config_invalid")) return "config_invalid";
|
|
5314
|
+
if (message.includes("engine") && message.includes("crash")) return "engine_crash";
|
|
5315
|
+
return "unknown";
|
|
5316
|
+
};
|
|
5098
5317
|
|
|
5099
5318
|
//#endregion
|
|
5100
5319
|
//#region src/mcp.ts
|
|
@@ -5109,10 +5328,29 @@ const err = (message) => ({
|
|
|
5109
5328
|
}],
|
|
5110
5329
|
isError: true
|
|
5111
5330
|
});
|
|
5112
|
-
const
|
|
5331
|
+
const instrument = async (tool, fn) => {
|
|
5332
|
+
const startedAt = performance.now();
|
|
5113
5333
|
try {
|
|
5114
|
-
|
|
5334
|
+
const value = await fn();
|
|
5335
|
+
track({
|
|
5336
|
+
event: "mcp_tool_called",
|
|
5337
|
+
properties: buildMcpToolCalledProps({
|
|
5338
|
+
tool,
|
|
5339
|
+
durationMs: performance.now() - startedAt,
|
|
5340
|
+
ok: true
|
|
5341
|
+
})
|
|
5342
|
+
});
|
|
5343
|
+
return ok(value);
|
|
5115
5344
|
} catch (e) {
|
|
5345
|
+
track({
|
|
5346
|
+
event: "mcp_tool_called",
|
|
5347
|
+
properties: buildMcpToolCalledProps({
|
|
5348
|
+
tool,
|
|
5349
|
+
durationMs: performance.now() - startedAt,
|
|
5350
|
+
ok: false,
|
|
5351
|
+
errorKind: errorKindFromException(e)
|
|
5352
|
+
})
|
|
5353
|
+
});
|
|
5116
5354
|
return err(e instanceof Error ? e.message : String(e));
|
|
5117
5355
|
}
|
|
5118
5356
|
};
|
|
@@ -5124,25 +5362,27 @@ const buildServer = () => {
|
|
|
5124
5362
|
server.registerTool(aislopScanTool.name, {
|
|
5125
5363
|
description: aislopScanTool.description,
|
|
5126
5364
|
inputSchema: aislopScanInputSchema.shape
|
|
5127
|
-
}, (input) =>
|
|
5365
|
+
}, (input) => instrument("aislop_scan", () => handleAislopScan(input)));
|
|
5128
5366
|
server.registerTool(aislopFixTool.name, {
|
|
5129
5367
|
description: aislopFixTool.description,
|
|
5130
5368
|
inputSchema: aislopFixInputSchema.shape
|
|
5131
|
-
}, (input) =>
|
|
5369
|
+
}, (input) => instrument("aislop_fix", () => handleAislopFix(input)));
|
|
5132
5370
|
server.registerTool(aislopWhyTool.name, {
|
|
5133
5371
|
description: aislopWhyTool.description,
|
|
5134
5372
|
inputSchema: aislopWhyInputSchema.shape
|
|
5135
|
-
}, (input) =>
|
|
5373
|
+
}, (input) => instrument("aislop_why", () => handleAislopWhy(input)));
|
|
5136
5374
|
server.registerTool(aislopBaselineTool.name, {
|
|
5137
5375
|
description: aislopBaselineTool.description,
|
|
5138
5376
|
inputSchema: aislopBaselineInputSchema.shape
|
|
5139
|
-
}, (input) =>
|
|
5377
|
+
}, (input) => instrument("aislop_baseline", () => handleAislopBaseline(input)));
|
|
5140
5378
|
return server;
|
|
5141
5379
|
};
|
|
5142
5380
|
const main = async () => {
|
|
5143
5381
|
const server = buildServer();
|
|
5144
5382
|
const transport = new StdioServerTransport();
|
|
5145
5383
|
await server.connect(transport);
|
|
5384
|
+
track({ event: "mcp_server_started" });
|
|
5385
|
+
await flushTelemetry();
|
|
5146
5386
|
};
|
|
5147
5387
|
main().catch((e) => {
|
|
5148
5388
|
process.stderr.write(`aislop-mcp failed to start: ${e instanceof Error ? e.message : String(e)}\n`);
|
|
@@ -29,7 +29,7 @@ const getEngineLabel = (engine) => ENGINE_INFO[engine].label;
|
|
|
29
29
|
|
|
30
30
|
//#endregion
|
|
31
31
|
//#region src/version.ts
|
|
32
|
-
const APP_VERSION = "0.
|
|
32
|
+
const APP_VERSION = "0.9.0";
|
|
33
33
|
|
|
34
34
|
//#endregion
|
|
35
35
|
export { ENGINE_INFO as n, getEngineLabel as r, APP_VERSION as t };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aislop",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "The engineering standards layer and quality gate for AI-written code. Define your standard once. Every agent — Claude Code, Cursor, Codex — is held to it automatically, on every edit and every PR. Catches the slop they leave behind, enforces the rules your team sets. 8+ languages. Deterministic.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|